Specificare i processi della pipeline

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

È possibile organizzare la pipeline in processi. Ogni pipeline ha almeno un processo. Un processo è una serie di passaggi eseguiti in sequenza come unità. In altre parole, un processo è l'unità di lavoro più piccola che può essere pianificata per l'esecuzione.

Per informazioni sui concetti chiave e sui componenti che costituiscono una pipeline, vedere Concetti chiave per i nuovi utenti di Azure Pipelines.

Azure Pipelines non supporta la priorità dei processi per le pipeline YAML. Per controllare quando vengono eseguiti i processi, è possibile specificare condizioni e dipendenze.

Definire un singolo processo

Nel caso più semplice, una pipeline ha un singolo processo. In tal caso, non è necessario usare in modo esplicito la job parola chiave a meno che non si usi un modello. È possibile specificare direttamente i passaggi nel file YAML.

Questo file YAML include un processo eseguito in un agente ospitato da Microsoft e restituisce Hello world.

pool:
  vmImage: 'ubuntu-latest'
steps:
- bash: echo "Hello world"

Potrebbe essere necessario specificare più proprietà in tale processo. In tal caso, è possibile usare la job parola chiave .

jobs:
- job: myJob
  timeoutInMinutes: 10
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - bash: echo "Hello world"

La pipeline potrebbe avere più processi. In tal caso, usare la jobs parola chiave .

jobs:
- job: A
  steps:
  - bash: echo "A"

- job: B
  steps:
  - bash: echo "B"

La pipeline può avere più fasi, ognuna con più processi. In tal caso, usare la stages parola chiave .

stages:
- stage: A
  jobs:
  - job: A1
  - job: A2

- stage: B
  jobs:
  - job: B1
  - job: B2

La sintassi completa per specificare un processo è:

- job: string  # name of the job, A-Z, a-z, 0-9, and underscore
  displayName: string  # friendly name to display in the UI
  dependsOn: string | [ string ]
  condition: string
  strategy:
    parallel: # parallel strategy
    matrix: # matrix strategy
    maxParallel: number # maximum number simultaneous matrix legs to run
    # note: `parallel` and `matrix` are mutually exclusive
    # you may specify one or the other; including both is an error
    # `maxParallel` is only valid with `matrix`
  continueOnError: boolean  # 'true' if future jobs should run even if this job fails; defaults to 'false'
  pool: pool # agent pool
  workspace:
    clean: outputs | resources | all # what to clean up before the job runs
  container: containerReference # container to run this job inside
  timeoutInMinutes: number # how long to run the job before automatically cancelling
  cancelTimeoutInMinutes: number # how much time to give 'run always even if cancelled tasks' before killing them
  variables: { string: string } | [ variable | variableReference ] 
  steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
  services: { string: string | container } # container resources to run as a service container

La sintassi completa per specificare un processo è:

- job: string  # name of the job, A-Z, a-z, 0-9, and underscore
  displayName: string  # friendly name to display in the UI
  dependsOn: string | [ string ]
  condition: string
  strategy:
    parallel: # parallel strategy
    matrix: # matrix strategy
    maxParallel: number # maximum number simultaneous matrix legs to run
    # note: `parallel` and `matrix` are mutually exclusive
    # you may specify one or the other; including both is an error
    # `maxParallel` is only valid with `matrix`
  continueOnError: boolean  # 'true' if future jobs should run even if this job fails; defaults to 'false'
  pool: pool # agent pool
  workspace:
    clean: outputs | resources | all # what to clean up before the job runs
  container: containerReference # container to run this job inside
  timeoutInMinutes: number # how long to run the job before automatically cancelling
  cancelTimeoutInMinutes: number # how much time to give 'run always even if cancelled tasks' before killing them
  variables: { string: string } | [ variable | variableReference ] 
  steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
  services: { string: string | container } # container resources to run as a service container
  uses: # Any resources (repos or pools) required by this job that are not already referenced
    repositories: [ string ] # Repository references to Azure Git repositories
    pools: [ string ] # Pool names, typically when using a matrix strategy for the job

Se lo scopo principale del processo è distribuire l'app (anziché compilare o testare l'app), è possibile usare un tipo speciale di processo denominato processo di distribuzione.

La sintassi per un processo di distribuzione è:

- deployment: string        # instead of job keyword, use deployment keyword
  pool:
    name: string
    demands: string | [ string ]
  environment: string
  strategy:
    runOnce:
      deploy:
        steps:
        - script: echo Hi!

Sebbene sia possibile aggiungere passaggi per le attività di distribuzione in un job, è consigliabile usare invece un processo di distribuzione. Un processo di distribuzione offre alcuni vantaggi. Ad esempio, è possibile eseguire la distribuzione in un ambiente, che include vantaggi come la possibilità di visualizzare la cronologia degli elementi distribuiti.

Tipi di processi

I processi possono essere di tipi diversi, a seconda della posizione in cui vengono eseguiti.

  • I processi del pool di agenti vengono eseguiti in un agente in un pool di agenti.
  • I processi del server vengono eseguiti in Azure DevOps Server.
  • I processi contenitore vengono eseguiti in un contenitore su un agente in un pool di agenti. Per altre informazioni sulla scelta dei contenitori, vedere Definire i processi del contenitore.
  • I processi del pool di agenti vengono eseguiti in un agente in un pool di agenti.
  • I processi del server vengono eseguiti in Azure DevOps Server.

Processi del pool di agenti

Si tratta del tipo di processi più comune e vengono eseguiti in un agente in un pool di agenti.

  • Quando si usano agenti ospitati da Microsoft, ogni processo in una pipeline ottiene un nuovo agente.
  • Usare le richieste con agenti self-hosted per specificare quali funzionalità deve essere necessario che un agente esegua il processo. È possibile ottenere lo stesso agente per i processi consecutivi, a seconda che nel pool di agenti siano presenti più agenti che corrispondano alle esigenze della pipeline. Se nel pool è presente un solo agente che corrisponde alle richieste della pipeline, la pipeline attende fino a quando l'agente non è disponibile.

Nota

Le richieste e le funzionalità sono progettate per l'uso con agenti self-hosted in modo che i processi possano essere confrontati con un agente che soddisfi i requisiti del processo. Quando si usano agenti ospitati da Microsoft, si seleziona un'immagine per l'agente che soddisfa i requisiti del processo, quindi anche se è possibile aggiungere funzionalità a un agente ospitato da Microsoft, non è necessario usare le funzionalità con gli agenti ospitati da Microsoft.

pool:
  name: myPrivateAgents    # your job runs on an agent in this pool
  demands: agent.os -equals Windows_NT    # the agent must have this capability to run the job
steps:
- script: echo hello world

O più richieste:

pool:
  name: myPrivateAgents
  demands:
  - agent.os -equals Darwin
  - anotherCapability -equals somethingElse
steps:
- script: echo hello world

Altre informazioni sulle funzionalità dell'agente.

Processi server

Le attività in un processo del server vengono orchestrate e eseguite nel server (Azure Pipelines o TFS). Un processo del server non richiede un agente o un computer di destinazione. In un processo del server sono supportate solo alcune attività. Il tempo massimo per un processo server è di 30 giorni.

Attività supportate dai processi senza agente

Attualmente sono supportate solo le attività seguenti per i processi senza agente:

Poiché le attività sono estendibili, è possibile aggiungere altre attività senza agente usando le estensioni. Il timeout predefinito per i processi senza agente è 60 minuti.

La sintassi completa per specificare un processo del server è:

jobs:
- job: string
  timeoutInMinutes: number
  cancelTimeoutInMinutes: number
  strategy:
    maxParallel: number
    matrix: { string: { string: string } }

  pool: server # note: the value 'server' is a reserved keyword which indicates this is an agentless job

È anche possibile usare la sintassi semplificata:

jobs:
- job: string
  pool: server # note: the value 'server' is a reserved keyword which indicates this is an agentless job

Dipendenze

Quando si definiscono più processi in una singola fase, è possibile specificare le dipendenze tra di esse. Le pipeline devono contenere almeno un processo senza dipendenze. Per impostazione predefinita, i processi della pipeline YAML di Azure DevOps vengono eseguiti in parallelo, a meno che il dependsOn valore non sia impostato.

Nota

Ogni agente può eseguire un solo processo alla volta. Per eseguire più processi in parallelo, è necessario configurare più agenti. Sono necessari anche processi paralleli sufficienti.

La sintassi per la definizione di più processi e le relative dipendenze è:

jobs:
- job: string
  dependsOn: string
  condition: string

Processi di esempio che compilano in sequenza:

jobs:
- job: Debug
  steps:
  - script: echo hello from the Debug build
- job: Release
  dependsOn: Debug
  steps:
  - script: echo hello from the Release build

Processi di esempio compilati in parallelo (nessuna dipendenza):

jobs:
- job: Windows
  pool:
    vmImage: 'windows-latest'
  steps:
  - script: echo hello from Windows
- job: macOS
  pool:
    vmImage: 'macOS-latest'
  steps:
  - script: echo hello from macOS
- job: Linux
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - script: echo hello from Linux

Esempio di fan out:

jobs:
- job: InitialJob
  steps:
  - script: echo hello from initial job
- job: SubsequentA
  dependsOn: InitialJob
  steps:
  - script: echo hello from subsequent A
- job: SubsequentB
  dependsOn: InitialJob
  steps:
  - script: echo hello from subsequent B

Esempio di fan-in:

jobs:
- job: InitialA
  steps:
  - script: echo hello from initial A
- job: InitialB
  steps:
  - script: echo hello from initial B
- job: Subsequent
  dependsOn:
  - InitialA
  - InitialB
  steps:
  - script: echo hello from subsequent

Condizioni

È possibile specificare le condizioni in base alle quali eseguire ogni processo. Per impostazione predefinita, un processo viene eseguito se non dipende da altri processi o se tutti i processi da cui dipende sono stati completati e completati. È possibile personalizzare questo comportamento forzando l'esecuzione di un processo anche se un processo precedente ha esito negativo o specificando una condizione personalizzata.

Esempio per eseguire un processo in base allo stato di esecuzione di un processo precedente:

jobs:
- job: A
  steps:
  - script: exit 1

- job: B
  dependsOn: A
  condition: failed()
  steps:
  - script: echo this will run when A fails

- job: C
  dependsOn:
  - A
  - B
  condition: succeeded('B')
  steps:
  - script: echo this will run when B runs and succeeds

Esempio di utilizzo di una condizione personalizzata:

jobs:
- job: A
  steps:
  - script: echo hello

- job: B
  dependsOn: A
  condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/main'))
  steps:
  - script: echo this only runs for master

È possibile specificare che un processo viene eseguito in base al valore di una variabile di output impostata in un processo precedente. In questo caso, è possibile usare solo le variabili impostate in processi dipendenti direttamente:

jobs:
- job: A
  steps:
  - script: "echo '##vso[task.setvariable variable=skipsubsequent;isOutput=true]false'"
    name: printvar

- job: B
  condition: and(succeeded(), ne(dependencies.A.outputs['printvar.skipsubsequent'], 'true'))
  dependsOn: A
  steps:
  - script: echo hello from B

Timeout

Per evitare di occupare risorse quando il processo non risponde o è in attesa troppo a lungo, è consigliabile impostare un limite per quanto tempo è consentito l'esecuzione del processo. Usare l'impostazione di timeout del processo per specificare il limite in minuti per l'esecuzione del processo. L'impostazione del valore su zero indica che il processo può essere eseguito:

  • Per sempre sugli agenti self-hosted
  • Per 360 minuti (6 ore) sugli agenti ospitati da Microsoft con un progetto pubblico e un repository pubblico
  • Per 60 minuti sugli agenti ospitati da Microsoft con un progetto privato o un repository privato (a meno che non venga pagata capacità aggiuntiva)

Il periodo di timeout inizia all'avvio dell'esecuzione del processo. Non include il momento in cui il processo è in coda o è in attesa di un agente.

timeoutInMinutes consente di impostare un limite per il tempo di esecuzione del processo. Se non specificato, il valore predefinito è 60 minuti. Quando 0 viene specificato, viene usato il limite massimo (descritto in precedenza).

cancelTimeoutInMinutes consente di impostare un limite per l'ora di annullamento del processo quando l'attività di distribuzione è impostata per continuare l'esecuzione se un'attività precedente non è riuscita. Se non specificato, il valore predefinito è 5 minuti. Il valore deve essere compreso tra 1 e 35790 minuti.

jobs:
- job: Test
  timeoutInMinutes: 10 # how long to run the job before automatically cancelling
  cancelTimeoutInMinutes: 2 # how much time to give 'run always even if cancelled tasks' before stopping them

I timeout hanno il livello di precedenza seguente.

  1. Negli agenti ospitati da Microsoft, i processi sono limitati per quanto tempo possono essere eseguiti in base al tipo di progetto e se vengono eseguiti usando un processo parallelo a pagamento. Quando è trascorso l'intervallo di timeout del processo ospitato da Microsoft, il processo viene terminato. Negli agenti ospitati da Microsoft i processi non possono essere eseguiti più a lungo di questo intervallo, indipendentemente dai timeout a livello di processo specificati nel processo.
  2. Il timeout configurato a livello di processo specifica la durata massima per l'esecuzione del processo. Quando viene trascorso l'intervallo di timeout a livello di processo, il processo viene terminato. Se il processo viene eseguito in un agente ospitato da Microsoft, l'impostazione del timeout a livello di processo su un intervallo maggiore del timeout predefinito del processo ospitato da Microsoft non ha alcun effetto e viene usato il timeout del processo ospitato da Microsoft.
  3. È anche possibile impostare il timeout per ogni attività singolarmente. Vedere le opzioni di controllo delle attività. Se l'intervallo di timeout a livello di processo è trascorso prima del completamento dell'attività, il processo in esecuzione viene terminato, anche se l'attività è configurata con un intervallo di timeout più lungo.

Configurazione multi-processo

Da un singolo processo creato, è possibile eseguire più processi su più agenti in parallelo. Alcuni esempi includono:

  • Compilazioni con più configurazioni: è possibile compilare più configurazioni in parallelo. Ad esempio, è possibile compilare un'app Visual C++ per entrambe debug le configurazioni e release in entrambe x86 le piattaforme e x64 . Per altre informazioni, vedere Compilazione di Visual Studio - più configurazioni per più piattaforme.

  • Distribuzioni con più configurazioni: è possibile eseguire più distribuzioni in parallelo, ad esempio in aree geografiche diverse.

  • Test con più configurazioni: è possibile eseguire test di più configurazioni in parallelo.

  • La configurazione multipla genererà sempre almeno un processo, anche se una variabile multiconfigurazione è vuota.

La matrix strategia consente di inviare più volte un processo, con set di variabili diversi. Il maxParallel tag limita la quantità di parallelismo. Il processo seguente viene inviato tre volte con i valori di Location e Browser impostati come specificato. Tuttavia, solo due processi vengono eseguiti contemporaneamente.

jobs:
- job: Test
  strategy:
    maxParallel: 2
    matrix: 
      US_IE:
        Location: US
        Browser: IE
      US_Chrome:
        Location: US
        Browser: Chrome
      Europe_Chrome:
        Location: Europe
        Browser: Chrome

Nota

I nomi di configurazione della matrice (come US_IE sopra) devono contenere solo lettere alfabetici latine di base (A-Z, a-z), numeri e caratteri di sottolineatura (_). Devono iniziare con una lettera. Inoltre, devono essere di almeno 100 caratteri.

È anche possibile usare le variabili di output per generare una matrice. Questo può essere utile se è necessario generare la matrice usando uno script.

matrix accetta un'espressione di runtime contenente un oggetto JSON stringato. L'oggetto JSON, se espanso, deve corrispondere alla sintassi di matrice. Nell'esempio seguente è stata hardcoded la stringa JSON, ma potrebbe essere generata da un linguaggio di scripting o da un programma da riga di comando.

jobs:
- job: generator
  steps:
  - bash: echo "##vso[task.setVariable variable=legs;isOutput=true]{'a':{'myvar':'A'}, 'b':{'myvar':'B'}}"
    name: mtrx
  # This expands to the matrix
  #   a:
  #     myvar: A
  #   b:
  #     myvar: B
- job: runner
  dependsOn: generator
  strategy:
    matrix: $[ dependencies.generator.outputs['mtrx.legs'] ]
  steps:
  - script: echo $(myvar) # echos A or B depending on which leg is running

Affettare

È possibile usare un processo dell'agente per eseguire un gruppo di test in parallelo. Ad esempio, è possibile eseguire un gruppo di grandi dimensioni di 1000 test su un singolo agente. In alternativa, è possibile usare due agenti ed eseguire 500 test su ognuno in parallelo.

Per applicare il sezionamento, le attività nel processo devono essere sufficientemente intelligenti da comprendere la sezione a cui appartengono.

L'attività Test di Visual Studio è un'attività di questo tipo che supporta il sezionamento dei test. Se sono stati installati più agenti, è possibile specificare il modo in cui l'attività test di Visual Studio viene eseguita in parallelo su questi agenti.

La parallel strategia consente di duplicare un processo più volte. Le variabili System.JobPositionInPhase e System.TotalJobsInPhase vengono aggiunte a ogni processo. Le variabili possono quindi essere usate all'interno degli script per dividere il lavoro tra i processi. Vedere Parallel and multiple execution using agent jobs (Parallel and multiple execution using agent jobs).

Il processo seguente viene inviato cinque volte con i valori di System.JobPositionInPhase e System.TotalJobsInPhase impostato in modo appropriato.

jobs:
- job: Test
  strategy:
    parallel: 5

Variabili di processo

Se si usa YAML, è possibile specificare variabili nel processo. Le variabili possono essere passate agli input dell'attività usando la sintassi della macro $(variableName) o accessibili all'interno di uno script usando la variabile di fase.

Di seguito è riportato un esempio di definizione delle variabili in un processo e dell'uso all'interno delle attività.

variables:
  mySimpleVar: simple var value
  "my.dotted.var": dotted var value
  "my var with spaces": var with spaces value

steps:
- script: echo Input macro = $(mySimpleVar). Env var = %MYSIMPLEVAR%
  condition: eq(variables['agent.os'], 'Windows_NT')
- script: echo Input macro = $(mySimpleVar). Env var = $MYSIMPLEVAR
  condition: in(variables['agent.os'], 'Darwin', 'Linux')
- bash: echo Input macro = $(my.dotted.var). Env var = $MY_DOTTED_VAR
- powershell: Write-Host "Input macro = $(my var with spaces). Env var = $env:MY_VAR_WITH_SPACES"

Per informazioni sull'uso di una condizione, vedere Specificare le condizioni.

Area di lavoro

Quando si esegue un processo del pool di agenti, viene creata un'area di lavoro nell'agente. L'area di lavoro è una directory in cui scarica l'origine, esegue i passaggi e produce output. È possibile fare riferimento alla directory dell'area di lavoro nel processo usando Pipeline.Workspace la variabile . In questo caso vengono create varie sottodirectory:

  • Build.SourcesDirectory è dove le attività scaricano il codice sorgente dell'applicazione.
  • Build.ArtifactStagingDirectory è la posizione in cui le attività scaricano gli artefatti necessari per la pipeline o caricano gli artefatti prima della pubblicazione.
  • Build.BinariesDirectory è dove le attività scrivono i relativi output.
  • Common.TestResultsDirectory è dove le attività caricano i risultati dei test.

e $(Build.ArtifactStagingDirectory)$(Common.TestResultsDirectory) vengono sempre eliminati e ricreati prima di ogni compilazione.

Quando si esegue una pipeline in un agente self-hosted, per impostazione predefinita, nessuna delle sottodirectory diverse da $(Build.ArtifactStagingDirectory) e $(Common.TestResultsDirectory) viene pulita tra due esecuzioni consecutive. Di conseguenza, è possibile eseguire compilazioni e distribuzioni incrementali, purché le attività vengano implementate per usarle. È possibile eseguire l'override di questo comportamento usando l'impostazione workspace nel processo.

Importante

Le opzioni di pulizia dell'area di lavoro sono applicabili solo per gli agenti self-hosted. I processi vengono sempre eseguiti in un nuovo agente con agenti ospitati da Microsoft.

- job: myJob
  workspace:
    clean: outputs | resources | all # what to clean up before the job runs

Quando si specifica una delle clean opzioni, queste vengono interpretate come segue:

  • outputs: elimina Build.BinariesDirectory prima di eseguire un nuovo processo.
  • resources: elimina Build.SourcesDirectory prima di eseguire un nuovo processo.
  • all: eliminare l'intera Pipeline.Workspace directory prima di eseguire un nuovo processo.
  jobs:
  - deployment: MyDeploy
    pool:
      vmImage: 'ubuntu-latest'
    workspace:
      clean: all
    environment: staging

Nota

A seconda delle funzionalità dell'agente e delle richieste di pipeline, ogni processo può essere indirizzato a un agente diverso nel pool self-hosted. Di conseguenza, è possibile ottenere un nuovo agente per le esecuzioni successive della pipeline (o fasi o processi nella stessa pipeline), pertanto non è garantito che le esecuzioni, i processi o le fasi successive saranno in grado di accedere agli output di esecuzioni, processi o fasi precedenti. È possibile configurare le funzionalità dell'agente e le richieste di pipeline per specificare quali agenti vengono usati per eseguire un processo della pipeline, ma a meno che nel pool non sia presente un solo agente che soddisfi le richieste, non esiste alcuna garanzia che i processi successivi useranno lo stesso agente dei processi precedenti. Per altre informazioni, vedere Specificare le richieste.

Oltre alla pulizia dell'area di lavoro, è anche possibile configurare la pulizia configurando l'impostazione Pulisci nell'interfaccia utente delle impostazioni della pipeline. Quando l'impostazione Pulisci è true, che è anche il valore predefinito, equivale a specificare clean: true per ogni passaggio di estrazione nella pipeline. Quando si specifica clean: true, si eseguirà git clean -ffdx seguito da git reset --hard HEAD prima del recupero git. Per configurare l'impostazione Pulisci :

  1. Modificare la pipeline, scegliere ...e selezionare Trigger.

    Modificare i trigger.

  2. Selezionare YAML, Recupera origini e configurare l'impostazione Pulisci desiderata. Il valore predefinito è true.

    Impostazione pulita.

Download artefatto

Questo file YAML di esempio pubblica l'artefatto WebSite e quindi scarica l'artefatto in $(Pipeline.Workspace). Il processo Distribuisci viene eseguito solo se il processo di compilazione ha esito positivo.

# test and upload my code as an artifact named WebSite
jobs:
- job: Build
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - script: npm test
  - task: PublishBuildArtifacts@1
    inputs:
      pathtoPublish: '$(System.DefaultWorkingDirectory)'
      artifactName: WebSite

# download the artifact and deploy it only if the build job succeeded
- job: Deploy
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - checkout: none #skip checking out the default repository resource
  - task: DownloadBuildArtifacts@0
    displayName: 'Download Build Artifacts'
    inputs:
      artifactName: WebSite
      downloadPath: $(Pipeline.Workspace)

  dependsOn: Build
  condition: succeeded()

Per informazioni sull'uso di dependsOn e condizione, vedere Specificare le condizioni.

Accesso al token OAuth

È possibile consentire agli script in esecuzione in un processo di accedere al token di sicurezza OAuth o Azure Pipelines corrente. Il token può essere usato per eseguire l'autenticazione all'API REST di Azure Pipelines.

Il token OAuth è sempre disponibile per le pipeline YAML. Deve essere mappato in modo esplicito all'attività o al passaggio usando env. Ecco un esempio:

steps:
- powershell: |
    $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=4.1-preview"
    Write-Host "URL: $url"
    $pipeline = Invoke-RestMethod -Uri $url -Headers @{
      Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
    }
    Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
  env:
    SYSTEM_ACCESSTOKEN: $(system.accesstoken)

Passaggi successivi