Guia · 12 min

Fazer deploy a partir do repositório

O repositório é a fonte de uma aplicação Archestack, tal como o código-fonte é a fonte de um programa. Um deployment trata o Archestack como o compilador: um pipeline constrói um Archestack descartável a partir dos ficheiros do repositório, corre os testes contra ele e só quando passam planeia a alteração contra o ambiente alojado e a aplica lá. O ambiente alojado continua a servir os seus utilizadores durante todo o processo.

Estado: a Archestack CLI corre todas as etapas abaixo, a partir de um passo de script em qualquer pipeline. As tarefas de pipeline prontas a usar para o Azure DevOps e o GitHub Actions que a envolvem estão em desenvolvimento; O que corre hoje diz o que cada etapa corre.

O seu sistema de CI

O pipeline

merge to main
  build     a throwaway Archestack made from the repository's files
  test      every package's test cases, each in a sandbox
  plan      against tst: artifacts and SQL, with a plan hash
  deploy    tst: schema, then files, then the release
  approve   the plan against acc, then deploy acc
  approve   the plan against prd, then deploy prd

Um pull request corre a build, os testes e o plano contra teste, para que um revisor veja o que mudaria antes de ser feito o merge de alguma coisa. Um merge para a branch principal corre todas as etapas, e a aceitação e a produção esperam, cada uma, que uma pessoa aprove o seu plano.

1. Build: o Archestack como compilador

O pipeline arranca um Archestack vazio no agente de build, em Docker a partir da mesma imagem da API que os ambientes correm, ou a partir de uma pasta de runtime como aquela com que a extensão do VS Code corre os projetos, e carrega nele o repositório: as tabelas de todos os packages num só deployment, depois os artefactos de cada package, com as dependências antes dos packages que precisam delas. É aqui que um erro aparece primeiro, tal como um erro de compilação: uma referência a uma Business Entity, tabela ou script que não existe, ou um nome que outro package já usa, para o carregamento. O resultado é um ambiente feito apenas a partir dos ficheiros, sem nada que tenha sobrado da máquina de ninguém.

2. Testar

Os casos de teste de todos os packages correm contra a build, cada um numa base de dados sandbox própria, com o email e as notificações registados em vez de enviados. Cada script que um teste corre é compilado primeiro, por isso um script que já não compila faz falhar o seu teste. Um só caso que falhe para o pipeline, e não é feito deploy de nada.

3. Planear contra o destino

Os mesmos ficheiros são planeados contra o ambiente de destino: que artefactos são criados, alterados ou removidos lá, e que alterações de tabelas correm como SQL, com o risco de cada operação e os scripts tipados que, com a alteração, deixariam de compilar. O plano leva um hash. O deployment aplica exatamente o plano que foi aprovado: se entretanto o destino mudou, é recusado e o plano é feito de novo.

4. Deploy: schema, ficheiros, release

  1. Schema. As alterações de tabelas correm como um deployment de base de dados, listado no histórico de deployments do ambiente como qualquer outro. Uma alteração que perde dados só corre quando o pipeline permite explicitamente a perda de dados.
  2. Ficheiros. Os artefactos são escritos numa só transação, por isso os utilizadores veem toda a nova versão de um package ou nada dela. Um deployment toca apenas no que o package contém e cria, e nunca no que cada ambiente decide por si.
  3. Release. Assim que os ficheiros entram, o pipeline publica uma release por si só. É esse o momento em que as novas páginas e os app layouts chegam à aplicação publicada, e ninguém publica à mão. Cada deployment é uma nova versão da aplicação, com uma release própria.

Um ambiente que nunca publicou uma release mostra os seus rascunhos, por isso os novos ficheiros ficariam visíveis no momento em que entram. Antes do seu primeiro deployment para um ambiente assim, o pipeline publica, por isso, uma release do que o ambiente já contém, e a partir daí os novos ficheiros esperam como rascunhos até à sua própria release, como em todos os deployments seguintes.

Porque é que o ambiente continua disponível

  • Nada reinicia. Um deployment são dados nas bases de dados do ambiente, não uma nova build do servidor. A API continua a responder durante todo o processo, e um script alterado é compilado da primeira vez que corre.
  • Os ficheiros entram de uma só vez. Uma transação por package, por isso ninguém trabalha sobre meio package.
  • As páginas mudam num só passo. A aplicação publicada lê a release atual. As novas páginas esperam como rascunhos até a release ser publicada, o que passa todos os utilizadores para elas no mesmo momento. Ativar a release anterior faz o rollback; isso repõe as páginas e os layouts, nunca os dados nem as tabelas.
  • As alterações de tabelas são planeadas e revistas. Acrescentar uma tabela ou uma coluna que aceita nulos não atrapalha ninguém, e tudo o que perde dados precisa de um sim explícito.

Expandir e depois contrair

Os Script Modules, os Business Events e as Business Entities ficam ativos no momento em que os seus ficheiros entram, não na release. Uma alteração que renomeia ou remove uma coluna sai, por isso, em dois deployments:

  1. Expandir. Acrescente a nova tabela ou coluna e faça deploy dos scripts e das páginas que a usam, com a antiga ainda no lugar.
  2. Contrair. Num deployment posterior, quando já nada ler a coluna antiga, remova-a. O plano marca a remoção como perda de dados, e a verificação dos scripts tipados diz se alguma coisa ainda a usa.

Uma alteração que reescreve uma tabela grande, como um novo tipo para uma coluna, mantém um bloqueio sobre essa tabela enquanto corre. Agende essas alterações para um momento calmo.

Ambientes

O repositório lista os seus ambientes em archestack.json. Um ambiente marcado com "mode": "pipeline" só recebe deployments do pipeline, e a extensão do VS Code recusa fazer push para ele à mão:

"environments": {
  "tst": { "url": "https://acme-tst.example.com", "apiUrl": "https://api.example.com", "workspace": "acme-tst.example.com", "mode": "pipeline" },
  "acc": { "url": "https://acme-acc.example.com", "apiUrl": "https://api.example.com", "workspace": "acme-acc.example.com", "mode": "pipeline" },
  "prd": { "url": "https://acme.example.com", "apiUrl": "https://api.example.com", "workspace": "acme.example.com", "mode": "pipeline" }
}

O que cada ambiente decide por si não está nos ficheiros nem em nenhum deployment: os utilizadores e as roles, as permissões das páginas, o que está marcado como público, os acessos concedidos e as chaves da Data API, as contas de email e as ligações a outros sistemas. São os administradores de cada ambiente que os definem, por isso um deployment nunca pode tornar algo público nem dar acesso a ninguém.

O ficheiro do pipeline

O pipeline vive no repositório e faz deploy a partir dele: cada execução faz checkout de um só commit, e são esses ficheiros que passam pela build, pelos testes e pelo deploy. Nada é exportado de um espaço de trabalho. Abaixo está o mesmo pipeline para três sistemas de CI, cada um a levar uma alteração a teste, aceitação e produção. Os comandos archestack são os da Archestack CLI, por isso qualquer outro sistema de CI que corra .NET e Docker em Linux corre os mesmos passos.

  • A etapa Build and test corre em cada pull request e em cada merge para a main. Constrói um Archestack descartável a partir do commit, corre os testes de todos os packages e empacota o repositório num só artefacto, para que todos os ambientes recebam exatamente os mesmos ficheiros.
  • Um passo de plano e um de deploy por ambiente. O plano é feito contra o ambiente e mostrado na execução; o deploy aplica depois exatamente esse plano, após uma aprovação para a aceitação e a produção. Os ambientes seguem-se um após o outro, por isso a aceitação só é planeada depois de feito o deploy para teste, e a produção só depois de feito o deploy para aceitação. Um pull request para depois do plano contra teste.
  • Tokens de deploy. O token de cada ambiente é criado no builder desse ambiente, em Operations, Deploy Tokens. É mostrado uma única vez, atua como administrador e serve apenas para fazer deploy: nunca lê os dados do ambiente. O endereço do ambiente vem de archestack.json.
O seu sistema de CI

Azure DevOps

O pipeline é azure-pipelines.yml na raiz do repositório:

# azure-pipelines.yml: build and test, then plan and deploy test, acceptance and production
trigger:
  branches:
    include: [main]

pr:
  branches:
    include: [main]

parameters:
  - name: environments
    type: object
    default: [tst, acc, prd]
  - name: allowDataLoss
    displayName: Allow changes that lose data
    type: boolean
    default: false

pool:
  vmImage: ubuntu-latest

stages:
  - stage: build
    displayName: Build and test
    jobs:
      - job: build
        steps:
          - checkout: self
            displayName: The repository at this commit
          - script: |
              dotnet tool install --global Archestack.Cli
              echo "##vso[task.prependpath]$HOME/.dotnet/tools"
            displayName: Install the Archestack CLI
          - script: archestack build
            displayName: Build a throwaway Archestack from the repository
          - script: archestack test --junit $(Agent.TempDirectory)/tests.xml
            displayName: Run every package's tests
          - task: PublishTestResults@2
            condition: succeededOrFailed()
            inputs:
              testResultsFormat: JUnit
              testResultsFiles: $(Agent.TempDirectory)/tests.xml
          - script: archestack pack --out $(Build.ArtifactStagingDirectory)/app.zip
            displayName: Pack the repository
          - publish: $(Build.ArtifactStagingDirectory)
            artifact: app

  - ${{ each env in parameters.environments }}:
    - stage: plan_${{ env }}
      displayName: Plan ${{ env }}
      ${{ if ne(env, 'tst') }}:
        condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
      variables:
        - group: archestack-${{ env }}
      jobs:
        - job: plan
          steps:
            - download: current
              artifact: app
            - script: |
                dotnet tool install --global Archestack.Cli
                echo "##vso[task.prependpath]$HOME/.dotnet/tools"
              displayName: Install the Archestack CLI
            - script: >-
                archestack plan --env ${{ env }}
                --from $(Pipeline.Workspace)/app/app.zip
                --allow-data-loss ${{ parameters.allowDataLoss }}
                --out $(Build.ArtifactStagingDirectory)/plan.json
                --summary $(Build.ArtifactStagingDirectory)/plan.md
              displayName: Plan against ${{ env }}
              env:
                ARCHESTACK_TOKEN: $(ARCHESTACK_TOKEN)
            - script: echo "##vso[task.uploadsummary]$(Build.ArtifactStagingDirectory)/plan.md"
              displayName: Show the plan in the run
            - publish: $(Build.ArtifactStagingDirectory)
              artifact: plan-${{ env }}

    - stage: deploy_${{ env }}
      displayName: Deploy ${{ env }}
      condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
      variables:
        - group: archestack-${{ env }}
      jobs:
        - deployment: deploy
          environment: archestack-${{ env }}
          strategy:
            runOnce:
              deploy:
                steps:
                  - download: current
                    artifact: app
                  - download: current
                    artifact: plan-${{ env }}
                  - script: |
                      dotnet tool install --global Archestack.Cli
                      echo "##vso[task.prependpath]$HOME/.dotnet/tools"
                    displayName: Install the Archestack CLI
                  - script: >-
                      archestack deploy --env ${{ env }}
                      --from $(Pipeline.Workspace)/app/app.zip
                      --plan $(Pipeline.Workspace)/plan-${{ env }}/plan.json
                    displayName: Schema, files and release
                    env:
                      ARCHESTACK_TOKEN: $(ARCHESTACK_TOKEN)
  • Aprovações. Crie os ambientes archestack-tst, archestack-acc e archestack-prd em Pipelines, Environments, e acrescente uma verificação Approvals à aceitação e à produção. O Azure DevOps espera então por um aprovador antes de essas etapas de deploy começarem, com o plano no resumo da execução. Os resultados dos testes são publicados na execução.
  • Credenciais. O token de deploy de cada ambiente é o segredo ARCHESTACK_TOKEN num grupo de variáveis com o mesmo nome do ambiente, como archestack-prd.
  • Perda de dados. Allow changes that lose data é uma caixa de verificação quando uma execução é iniciada à mão, desmarcada por predefinição. Se não estiver marcada, um plano que remove uma tabela ou uma coluna para o pipeline.
  • Pull requests no Azure Repos. O Azure Repos ignora a secção pr:; em vez disso, acrescente o pipeline como build validation branch policy na main.
  • Um pipeline criado no editor web é guardado como um novo ficheiro com o nome do pipeline. Aponte o pipeline para azure-pipelines.yml nas suas definições, ou o ficheiro que edita não é o que corre.

GitHub Actions

O workflow é .github/workflows/archestack.yml:

# .github/workflows/archestack.yml: build and test, then plan and deploy test, acceptance and production
name: Archestack

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:
    inputs:
      allow-data-loss:
        description: Allow changes that lose data
        type: boolean
        default: false

permissions:
  contents: read

jobs:
  build:
    name: Build and test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 8.0.x
      - name: Install the Archestack CLI
        run: dotnet tool install --global Archestack.Cli
      - name: Build a throwaway Archestack from the repository
        run: archestack build
      - name: Run every package's tests
        run: archestack test --junit "$RUNNER_TEMP/tests.xml"
      - uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: tests
          path: ${{ runner.temp }}/tests.xml
      - name: Pack the repository
        run: archestack pack --out "$RUNNER_TEMP/app/app.zip"
      - uses: actions/upload-artifact@v4
        with:
          name: app
          path: ${{ runner.temp }}/app

  # A pull request stops after the plan against test.
  tst:
    needs: build
    uses: ./.github/workflows/archestack-deploy.yml
    with:
      environment: tst
      deploy: ${{ github.event_name != 'pull_request' }}
      allow-data-loss: ${{ inputs.allow-data-loss == true }}
    secrets:
      token: ${{ secrets.ARCHESTACK_TOKEN_TST }}

  acc:
    if: github.event_name != 'pull_request'
    needs: tst
    uses: ./.github/workflows/archestack-deploy.yml
    with:
      environment: acc
      allow-data-loss: ${{ inputs.allow-data-loss == true }}
    secrets:
      token: ${{ secrets.ARCHESTACK_TOKEN_ACC }}

  prd:
    if: github.event_name != 'pull_request'
    needs: acc
    uses: ./.github/workflows/archestack-deploy.yml
    with:
      environment: prd
      allow-data-loss: ${{ inputs.allow-data-loss == true }}
    secrets:
      token: ${{ secrets.ARCHESTACK_TOKEN_PRD }}

Cada ambiente é planeado e recebe o deploy pelo mesmo workflow reutilizável ao lado:

# .github/workflows/archestack-deploy.yml: plans the packed files against one environment, then deploys that plan
name: Archestack environment

on:
  workflow_call:
    inputs:
      environment:
        type: string
        required: true
      deploy:
        type: boolean
        default: true
      allow-data-loss:
        type: boolean
        default: false
    secrets:
      token:
        required: true

jobs:
  plan:
    name: Plan ${{ inputs.environment }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: app
          path: app
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 8.0.x
      - run: dotnet tool install --global Archestack.Cli
      - name: Plan against ${{ inputs.environment }}
        run: >-
          archestack plan --env ${{ inputs.environment }}
          --from app/app.zip
          --allow-data-loss ${{ inputs.allow-data-loss }}
          --out plan/plan.json
          --summary plan/plan.md
        env:
          ARCHESTACK_TOKEN: ${{ secrets.token }}
      - name: Show the plan in the run
        if: ${{ !cancelled() }}
        run: cat plan/plan.md >> "$GITHUB_STEP_SUMMARY"
      - uses: actions/upload-artifact@v4
        with:
          name: plan-${{ inputs.environment }}
          path: plan

  deploy:
    name: Deploy ${{ inputs.environment }}
    if: inputs.deploy
    needs: plan
    runs-on: ubuntu-latest
    environment: archestack-${{ inputs.environment }}
    concurrency: archestack-${{ inputs.environment }}
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: app
          path: app
      - uses: actions/download-artifact@v4
        with:
          name: plan-${{ inputs.environment }}
          path: plan
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 8.0.x
      - run: dotnet tool install --global Archestack.Cli
      - name: Schema, files and release
        run: archestack deploy --env ${{ inputs.environment }} --from app/app.zip --plan plan/plan.json
        env:
          ARCHESTACK_TOKEN: ${{ secrets.token }}
  • Aprovações. Crie os ambientes archestack-tst, archestack-acc e archestack-prd em Settings, Environments, e acrescente required reviewers à aceitação e à produção. O job de deploy espera por um revisor, com o plano já no resumo da execução. Num repositório privado, os ambientes precisam do GitHub Pro, Team ou Enterprise.
  • Credenciais. Os tokens de deploy são os segredos do repositório ARCHESTACK_TOKEN_TST, ARCHESTACK_TOKEN_ACC e ARCHESTACK_TOKEN_PRD, para que o plano possa correr antes da aprovação. Um workflow em qualquer branch do repositório pode ler um segredo do repositório; para reservar o token da produção às execuções aprovadas, torne-o antes um segredo do ambiente archestack-prd, e o seu plano passa então a correr depois da aprovação.
  • Perda de dados. Allow changes that lose data é uma caixa de verificação em Run workflow, desmarcada por predefinição.
  • Pull requests a partir de forks não recebem segredos, por isso o seu plano contra teste falha; os pull requests a partir de branches do próprio repositório são planeados como de costume.
  • concurrency impede que duas execuções façam deploy para o mesmo ambiente ao mesmo tempo. Os resultados dos testes ficam guardados como o artefacto tests da execução.

GitLab CI

O pipeline é .gitlab-ci.yml na raiz do repositório:

# .gitlab-ci.yml: build and test, then plan and deploy test, acceptance and production
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

variables:
  ALLOW_DATA_LOSS:
    value: "false"
    description: Allow changes that lose data (true or false)

stages: [build, tst, acc, prd]

default:
  image: mcr.microsoft.com/dotnet/sdk:8.0
  before_script:
    - dotnet tool install --global Archestack.Cli
    - export PATH="$PATH:$HOME/.dotnet/tools"

build:
  stage: build
  # The throwaway Archestack runs in Docker, here a Docker service beside the job.
  services:
    - docker:27-dind
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  script:
    - curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz | tar -xz -C /usr/local/bin --strip-components=1 docker/docker
    - archestack build
    - archestack test --junit tests.xml
    - archestack pack --out app.zip
  artifacts:
    when: always
    paths: [app.zip]
    reports:
      junit: tests.xml

.plan:
  script:
    - archestack plan --env "$TARGET" --from app.zip --allow-data-loss "$ALLOW_DATA_LOSS" --out plan.json --summary plan.md
  artifacts:
    when: always
    expose_as: plan
    paths: [plan.md, plan.json]

.deploy:
  script:
    - archestack deploy --env "$TARGET" --from app.zip --plan plan.json

# A merge request stops after the plan against test.
plan-tst:
  extends: .plan
  stage: tst
  needs: [build]
  variables: { TARGET: tst }

deploy-tst:
  extends: .deploy
  stage: tst
  needs: [build, plan-tst]
  environment: archestack-tst
  resource_group: archestack-tst
  variables: { TARGET: tst }
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

plan-acc:
  extends: .plan
  stage: acc
  needs: [build, deploy-tst]
  variables: { TARGET: acc }
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy-acc:
  extends: .deploy
  stage: acc
  needs: [build, plan-acc]
  environment: archestack-acc
  resource_group: archestack-acc
  variables: { TARGET: acc }
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      when: manual
  allow_failure: false

plan-prd:
  extends: .plan
  stage: prd
  needs: [build, deploy-acc]
  variables: { TARGET: prd }
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy-prd:
  extends: .deploy
  stage: prd
  needs: [build, plan-prd]
  environment: archestack-prd
  resource_group: archestack-prd
  variables: { TARGET: prd }
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      when: manual
  allow_failure: false
  • Docker. A build corre o Archestack descartável num serviço docker:dind ao lado do job, o que precisa de um runner que permita containers privilegiados, como os próprios runners do GitLab.com. DOCKER_HOST diz à CLI onde está o Docker, e é aí que ela chega ao Archestack.
  • Aprovações. O deploy para aceitação e o deploy para produção são jobs manuais que bloqueiam o pipeline, cada um iniciado depois de o seu plano ter sido lido. Cada plano fica guardado com o seu job, e o plano contra teste tem também uma ligação no merge request. No GitLab Premium, proteja também esses ambientes e exija aprovações.
  • Credenciais. Os tokens de deploy são as variáveis CI/CD mascaradas ARCHESTACK_TOKEN_TST, ARCHESTACK_TOKEN_ACC e ARCHESTACK_TOKEN_PRD. Proteja as da aceitação e da produção, para que só a branch principal as leia. Uma variável protegida não chega a um pipeline de merge request, por isso deixe a de teste desprotegida para que os merge requests possam planear contra teste.
  • Perda de dados. Corra o pipeline à mão com ALLOW_DATA_LOSS definido como true. Os resultados dos testes aparecem no merge request.
  • resource_group impede que dois pipelines façam deploy para o mesmo ambiente ao mesmo tempo.

A Archestack CLI

A CLI é a ferramenta .NET Archestack.Cli, instalada com dotnet tool install --global Archestack.Cli em qualquer agente com .NET 8 ou posterior. Os seus comandos correm a partir da raiz do repositório, ou recebem --from com uma pasta ou um ZIP empacotado:

  • archestack build arranca o Archestack descartável e carrega nele o repositório. Corre em Docker a partir da imagem que a secção project de archestack.json indica, ou então da mais recente publicada; --image escolhe outra, e --runtime corre uma pasta de runtime sem Docker. Fica pronto quando os pacotes NuGet que o repositório indica estão restaurados, e continua a correr para o passo seguinte até archestack stop. --nuget-cache <folder> guarda esses downloads para a build seguinte, que de outro modo os descarrega de novo; duas builds a correr ao mesmo tempo precisam cada uma da sua própria pasta.
  • archestack test corre contra ele os casos de teste de todos os packages, quatro de cada vez, e escreve JUnit com --junit.
  • archestack pack --out app.zip empacota archestack.json, packages/ e workspace/. Os mesmos ficheiros dão sempre os mesmos bytes, e o plano regista o seu hash, por isso um deployment recusa ficheiros que não sejam os planeados.
  • archestack plan e archestack deploy só funcionam num ambiente marcado com "mode": "pipeline", com o seu token de deploy em ARCHESTACK_TOKEN_<ENV> (como ARCHESTACK_TOKEN_PRD) ou ARCHESTACK_TOKEN. Um artefacto apagado do repositório é retirado do seu package e deixado no ambiente; planeie com --delete-removed true para o apagar lá também. Um package no ambiente que o repositório não contém é deixado como está e indicado no plano. Quando o repositório indica pacotes NuGet, ambos perguntam primeiro ao ambiente se lá se restauram, e deploy espera até cinco minutos depois do último push que o ambiente os tenha restaurado, antes de publicar a release. Se essa espera falhar, o deploy dos ficheiros fica feito, mas nenhuma release é publicada.

O código de saída diz o que parou um passo: 3 o token foi recusado, 4 o ambiente mudou desde o plano (planeie de novo), 5 os ficheiros não podem ser aplicados tal como estão, 6 o plano perde dados e isso não foi permitido, 7 um teste falhou, 9 o servidor ou a rede falharam, 10 o ambiente corre uma versão major do Archestack diferente da da CLI, ou uma sem suporte para NuGet. Pacotes NuGet que não se restauram com os ficheiros dão 5, tal como um ambiente com os pacotes NuGet ou o acesso a dados tipado desligados. Em plan e deploy, uma falha do NuGet que os ficheiros não podem corrigir dá 9: por exemplo um servidor com pouco espaço em disco, um feed a que não chega, ou uma restauração depois do último push que falhou ou não terminou em cinco minutos. O mesmo passo pode então correr bem quando for executado de novo.

O que corre hoje

  • Build, testes, plano e deploy correm na CLI, a partir de passos de script como nos pipelines acima. Na máquina de um programador, o projeto da extensão do VS Code é a mesma build: Reset Project Database cria-o do zero, e Run Tests corre contra ele os testes de todos os packages.
  • Tarefas de pipeline para o Azure DevOps e o GitHub Actions que envolvem a CLI: em desenvolvimento.

Armadilhas

  • Um rollback não desfaz tabelas nem dados. Cada deployment é uma release, por isso qualquer versão de que o pipeline fez deploy pode ser ativada de novo, mas isso repõe apenas as páginas e os layouts. Levar as tabelas de volta é um deployment próprio, planeado e revisto como qualquer outro.
  • Os Script Modules e os Business Events não esperam pela release. Ficam ativos no momento em que os seus ficheiros entram, e é por isso que uma alteração que remove alguma coisa sai em dois deployments.
  • Cada ambiente descarrega os seus próprios pacotes NuGet. Os pacotes NuGet que o nuget.json de um package declara são descarregados por cada ambiente que o recebe, incluindo a build, por isso cada um precisa de chegar ao nuget.org ou ao feed com que os seus servidores estão configurados. A build lê Scripting__NuGet__Sources e as definições Scripting__NuGet__Feeds__* do ambiente em que a CLI corre. Um push cujos pacotes NuGet não podem ser restaurados é recusado e não muda nada: o plan da CLI verifica isso antes de qualquer deploy, e build e deploy esperam até estarem restaurados.

Para onde seguir a partir daqui

Trabalhar em equipa trata da forma como os programadores partilham o repositório de que o pipeline faz deploy. Espaços de trabalho e alojamento explica os ambientes para onde ele faz deploy, e Database Deployments a etapa do schema.