Udostępnij za pośrednictwem


Warunki potoku

Azure DevOps Services | Azure DevOps Server 2022 — Azure DevOps Server 2019

W tym artykule opisano warunki, w których jest uruchamiany etap, zadanie lub krok usługi Azure Pipelines oraz sposób określania różnych warunków. Aby uzyskać więcej kontekstu na etapach, zadaniach i krokach, zobacz Kluczowe pojęcia dotyczące usługi Azure Pipelines.

  • Domyślnie zadanie lub etap jest uruchamiane, jeśli nie zależy od innego zadania lub etapu, lub jeśli wszystkie jego zależności zostały ukończone i zakończyły się pomyślnie. To wymaganie dotyczy nie tylko bezpośrednich zależności, ale także ich zależności pośrednich obliczanych rekursywnie.

  • Domyślnie krok jest uruchamiany, jeśli jeszcze nic nie powiodło się, a krok bezpośrednio poprzedzający jego ukończenie.

To zachowanie można zastąpić lub dostosować, wymuszając uruchomienie etapu, zadania lub kroku, nawet jeśli poprzednia zależność zakończy się niepowodzeniem lub przez określenie warunku niestandardowego.

Uwaga

W tym artykule omówiono możliwości potoku YAML. W przypadku potoków klasycznych można określić pewne warunki, w których zadania lub zadania są uruchamiane w obszarze Opcje sterowania każdego zadania, oraz w dodatkowych opcjach zadania w potoku wydania.

Warunki, w których jest uruchamiany etap, zadanie lub krok

W definicji potoku YAML można określić następujące warunki, w których jest uruchamiany etap, zadanie lub krok:

  • Tylko wtedy, gdy wszystkie poprzednie zależności bezpośrednie i pośrednie z tą samą pulą agentów kończą się powodzeniem. Jeśli masz różne pule agentów, te etapy lub zadania są uruchamiane współbieżnie. Ten warunek jest domyślny, jeśli w YAML nie ustawiono żadnego warunku.

  • Nawet jeśli poprzednia zależność nie powiedzie się, chyba że przebieg zostanie anulowany. Użyj succeededOrFailed() w pliku YAML dla tego warunku.

  • Nawet jeśli poprzednia zależność nie powiedzie się, a nawet jeśli przebieg zostanie anulowany. Użyj always() w pliku YAML dla tego warunku.

  • Tylko wtedy, gdy poprzednia zależność zakończy się niepowodzeniem. Użyj failed() w pliku YAML dla tego warunku.

  • Warunki niestandardowe.

Domyślnie etapy, zadania i kroki są uruchamiane, jeśli wszystkie zależności bezpośrednie i pośrednie powiedzą się. Ten stan jest taki sam, jak w przypadku określania condition: succeeded()wartości . Aby uzyskać więcej informacji, zobacz funkcja stanu powodzenia.

Po określeniu condition właściwości etapu, zadania lub kroku zastąpisz wartość domyślną condition: succeeded(). Określenie własnych warunków może spowodować uruchomienie etapu, zadania lub kroku, nawet jeśli kompilacja zostanie anulowana. Upewnij się, że zapisane warunki uwzględniają stan etapu nadrzędnego lub zadania.

Poniższy przykład YAML przedstawia always() warunki i failed() . Krok w pierwszym zadaniu jest uruchamiany, nawet jeśli zależności kończą się niepowodzeniem lub kompilacja zostanie anulowana. Drugie zadanie jest uruchamiane tylko wtedy, gdy pierwsze zadanie zakończy się niepowodzeniem.

jobs:
- job: Foo

  steps:
  - script: echo Hello!
    condition: always() # this step runs, even if the build is canceled

- job: Bar
  dependsOn: Foo
  condition: failed() # this job runs only if Foo fails

Zmienne można również ustawiać i używać w warunkach. Poniższy przykład ustawia zmienną i używa zmiennej isMain do wyznaczenia Build.SourceBranchmain jako .

variables:
  isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]

stages:
- stage: A
  jobs:
  - job: A1
    steps:
      - script: echo Hello Stage A!

- stage: B
  condition: and(succeeded(), eq(variables.isMain, true))
  jobs:
  - job: B1
    steps:
      - script: echo Hello Stage B!
      - script: echo $(isMain)

Ważne

Warunki są oceniane w celu określenia, czy należy rozpocząć etap, zadanie lub krok. W związku z tym nic nie jest obliczane w czasie wykonywania w ramach tej jednostki pracy. Jeśli na przykład masz zadanie, które ustawia zmienną przy użyciu wyrażenia środowiska uruchomieniowego ze składnią $[ ] , nie można użyć tej zmiennej w warunku niestandardowym w tym zadaniu.

Warunki niestandardowe

Jeśli wbudowane warunki nie spełniają Twoich potrzeb, możesz określić warunki niestandardowe. Warunki są zapisywane jako wyrażenia w definicjach potoku YAML.

Agent oblicza wyrażenie rozpoczynające się od najbardziej wewnętrznej funkcji i przechodząc na zewnątrz. Końcowy wynik jest wartością logiczną, która określa, czy zadanie, zadanie lub etap powinny być uruchamiane. Aby uzyskać pełny przewodnik po składni, zobacz Wyrażenia.

Jeśli którykolwiek z warunków umożliwia uruchomienie zadania nawet po anulowaniu kompilacji, określ rozsądną wartość limitu czasu anulowania, aby te zadania miały wystarczający czas do ukończenia po anulowaniu przebiegu przez użytkownika.

Wyniki warunku po anulowaniu kompilacji

Anulowanie kompilacji nie oznacza, że wszystkie jej etapy, zadania lub kroki przestaną działać. Etapy, zadania lub kroki przestają działać, zależą od określonych warunków i w jakim momencie wykonania potoku anulowano kompilację. Jeśli element nadrzędny etapu, zadania lub kroku zostanie pominięty, zadanie nie zostanie uruchomione, niezależnie od warunków.

Etap, zadanie lub krok jest uruchamiany za każdym razem, gdy jego warunki są obliczane na truewartość . Jeśli warunek nie uwzględnia stanu nadrzędnego zadania, zadanie może zostać uruchomione nawet wtedy, gdy jego element nadrzędny zostanie anulowany. Aby kontrolować, czy etapy, zadania lub kroki z warunkami są uruchamiane po anulowaniu kompilacji, pamiętaj, aby uwzględnić funkcję sprawdzania stanu zadania w warunkach.

W poniższych przykładach przedstawiono wyniki różnych warunków ustawionych na etapach, zadaniach lub krokach po anulowaniu kompilacji.

Przykład etapu 1

W poniższym potoku domyślnie stage2 będzie zależeć od stage1elementu , ale stage2 ma ustawioną condition wartość do uruchomienia za każdym razem, gdy gałąź źródłowa ma mainwartość , niezależnie od stage1 stanu.

Jeśli kolejkujesz kompilację w main gałęzi i anulujesz ją podczas stage1 działania, nadal jest uruchamiana, stage2 ponieważ eq(variables['Build.SourceBranch'], 'refs/heads/main') daje wartość .true

stages:
- stage: stage1
  jobs:
  - job: A
    steps:
      - script: echo 1; sleep 30
- stage: stage2
  condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
  jobs:
  - job: B
    steps:
      - script: echo 2

Przykład etapu 2

W poniższym potoku stage2 domyślnie zależy stage1 od tego. Zadanie B w programie stage2 ma condition zestaw. Jeśli kolejkujesz kompilację w main gałęzi i anulujesz ją podczas stage1 działania, nie zostanie uruchomiona, stage2 mimo że zawiera zadanie, którego warunek daje wartość true.

Przyczyną jest to, że stage2 ma wartość domyślną condition: succeeded(), która daje wartość w przypadku falsestage1 anulowania. stage2 W związku z tym nie jest pomijany, a żadne z jego zadań nie jest uruchamiane.

stages:
- stage: stage1
  jobs:
  - job: A
    steps:
      - script: echo 1; sleep 30
- stage: stage2
  jobs:
  - job: B
    condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
    steps:
      - script: echo 2

Przykład etapu 3

W poniższym potoku domyślnie stage2 zależy od stage1elementu , a krok wewnątrz zadania B ma condition ustawiony zestaw.

Jeśli kolejkujesz kompilację na main gałęzi i anulujesz ją podczas stage1 działania, nie zostanie uruchomiona, stage2 mimo że zawiera krok w zadaniu B , którego warunek daje wartość true. Przyczyną jest stage2 pominięcie w odpowiedzi na stage1 anulowanie.

stages:
- stage: stage1
  jobs:
  - job: A
    steps:
      - script: echo 1; sleep 30
- stage: stage2
  jobs:
  - job: B
    steps:
      - script: echo 2
        condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')

Przykład zadania 1

W poniższym potoku YAML zadanie B zależy od zadania A domyślnie, ale zadanie B ma ustawioną condition wartość do uruchomienia za każdym razem, gdy gałąź źródłowa ma wartość main. Jeśli tworzysz kompilację w main gałęzi i anulujesz ją podczas uruchamiania zadaniaA, zadanie B nadal jest uruchamiane, ponieważ eq(variables['Build.SourceBranch'], 'refs/heads/main') daje wartość .true

jobs:
- job: A
  steps:
  - script: sleep 30
- job: B
  dependsOn: A 
  condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
  steps:
    - script: echo step 2.1

Jeśli chcesz, aby zadanie B było uruchamiane tylko wtedy, gdy zadanie A zakończy się pomyślnie, a źródłem kompilacji jest main gałąź , condition powinna to być and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')).

Przykład zadania 2

W poniższym potoku zadanie B jest domyślnie zależne od zadania A . Jeśli kolejkujesz kompilację w main gałęzi i anulujesz ją podczas uruchamiania zadaniaA, zadanie B nie zostanie uruchomionetrue, mimo że jego krok ma condition wartość .

Przyczyną jest to, że zadanie B ma wartość domyślną condition: succeeded(), która ocenia false , kiedy zadanie A jest anulowane. W związku z tym zadanie B jest pomijane i żaden z jego kroków nie jest uruchamiany.

jobs:
- job: A
  steps:
  - script: sleep 30
- job: B
  dependsOn: A 
  steps:
    - script: echo step 2.1
      condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
      

Przykładowy krok

Możesz również mieć warunki dotyczące kroków.

W poniższym potoku krok 2.3 ma condition zestaw do uruchomienia za każdym razem, gdy gałąź źródłowa to main. Jeśli kolejkujesz kompilację w main gałęzi i anulujesz ją podczas wykonywania kroków 2.1 lub 2.2, krok 2.3 nadal działa, ponieważ eq(variables['Build.SourceBranch'], 'refs/heads/main') daje wartość .true

steps:
  - script: echo step 2.1
  - script: echo step 2.2; sleep 30
  - script: echo step 2.3
    condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')

Ustawienia warunku

W poniższej tabeli przedstawiono przykładowe condition ustawienia umożliwiające uzyskanie różnych wyników.

Uwaga

Release.Artifacts.{artifact-alias}.SourceBranch jest równoważne z Build.SourceBranch.

Żądany wynik Przykładowe ustawienie warunku
Uruchom polecenie , jeśli gałąź źródłowa jest główna, nawet jeśli element nadrzędny lub poprzedni etap, zadanie lub krok zakończył się niepowodzeniem lub został anulowany. eq(variables['Build.SourceBranch'], 'refs/heads/main')
Uruchom polecenie , jeśli gałąź źródłowa jest główna, a poprzedni etap, zadanie lub krok zakończył się pomyślnie. and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
Uruchom polecenie , jeśli gałąź źródłowa nie jest główna, a poprzedni etap, zadanie lub krok zakończył się pomyślnie. and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/main'))
Uruchom polecenie dla gałęzi tematu użytkownika, jeśli element nadrzędny lub poprzedni etap, zadanie lub krok zakończył się pomyślnie. and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/users/'))
Uruchom polecenie w celu utworzenia kompilacji ciągłej integracji, jeśli nadrzędny lub poprzedzający etap, zadanie lub krok zakończył się pomyślnie. and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'))
Uruchom polecenie , jeśli kompilacja została wyzwolona przez zasady gałęzi dla żądania ściągnięcia, a element nadrzędny lub poprzedni etap, zadanie lub krok zakończył się niepowodzeniem. and(failed(), eq(variables['Build.Reason'], 'PullRequest'))
Uruchom dla zaplanowanej kompilacji, nawet jeśli element nadrzędny lub poprzedni etap, zadanie lub krok zakończył się niepowodzeniem lub został anulowany. eq(variables['Build.Reason'], 'Schedule')
Uruchom polecenie , jeśli zmienna jest ustawiona na wartość true, nawet jeśli element nadrzędny lub poprzedni etap, zadanie lub krok zakończył się niepowodzeniem lub został anulowany. eq(variables['System.debug'], true)

Uwaga

Można ustawić warunek do uruchomienia, jeśli zmienna ma wartość null (pusty ciąg). Ponieważ wszystkie zmienne są traktowane jako ciągi w usłudze Azure Pipelines, pusty ciąg jest odpowiednikiem null następującego potoku:

variables:
- name: testEmpty
  value: ''

jobs:
  - job: A
    steps:
    - script: echo testEmpty is blank
    condition: eq(variables.testEmpty, '')

Parametry w warunkach

Rozszerzanie parametrów odbywa się przed rozważemy warunki. W związku z tym po zadeklarowaniu parametru w tym samym potoku co warunek można osadzić parametr wewnątrz warunku. Skrypt w poniższym pliku YAML jest uruchamiany, ponieważ parameters.doThing ma wartość true.

parameters:
- name: doThing
  default: true
  type: boolean

steps:
- script: echo I did a thing
  condition: ${{ eq(parameters.doThing, true) }}

Element condition w poprzednim potoku łączy dwie funkcje: succeeded() i eq('${{ parameters.doThing }}', true). Funkcja succeeded() sprawdza, czy poprzedni krok zakończył się pomyślnie. Funkcja succeeded() zwraca wartość true , ponieważ nie było poprzedniego kroku.

Funkcja eq('${{ parameters.doThing }}', true) sprawdza, czy doThing parametr jest równy true. Ponieważ wartość domyślna parametru doThing to true, warunek jest zwracany true domyślnie, chyba że potok ustawi inną wartość.

Parametry szablonu w warunkach

Po przekazaniu parametru do szablonu należy ustawić wartość parametru w szablonie lub użyć parametru TemplateContext, aby przekazać parametr do szablonu.

Na przykład następujący plik parameters.yml deklaruje parametr i wartość domyślną doThing :

# parameters.yml
parameters:
- name: doThing
  default: true # value passed to the condition
  type: boolean

jobs:
  - job: B
    steps:
    - script: echo I did a thing
    condition: ${{ eq(parameters.doThing, true) }}

Kod potoku odwołuje się do szablonu parameters.yml . Dane wyjściowe potoku są I did a thing spowodowane tym, że parametr doThing ma wartość true.

# azure-pipeline.yml
parameters:
- name: doThing
  default: true 
  type: boolean

trigger:
- none

extends:
  template: parameters.yml

Aby uzyskać więcej przykładów parametrów szablonu, zobacz dokumentację użycia szablonu.

Zmienne wyjściowe zadania używane w kolejnych warunkach zadania

Możesz udostępnić zmienną przyszłym zadaniu i określić ją w warunku. Zmienne dostępne dla przyszłych zadań muszą być oznaczone jako zmienne wyjściowe z wieloma zadaniami przy użyciu polecenia isOutput=true, jak w poniższym kodzie:

jobs:
- job: Foo
  steps:
  - bash: |
      echo "This is job Foo."
      echo "##vso[task.setvariable variable=doThing;isOutput=true]Yes" #set variable doThing to Yes
    name: DetermineResult
- job: Bar
  dependsOn: Foo
  condition: eq(dependencies.Foo.outputs['DetermineResult.doThing'], 'Yes') #map doThing and check the value
  steps:
  - script: echo "Job Foo ran and doThing is Yes."

Zmienne utworzone w kroku używanym w kolejnych warunkach

Możesz utworzyć zmienną dostępną dla przyszłych kroków, która będzie określana w warunku. Zmienne utworzone na podstawie kroków są domyślnie dostępne dla przyszłych kroków i nie muszą być oznaczone jako zmienne wyjściowe z wieloma zadaniami.

Istnieje kilka ważnych kwestii, które należy wziąć pod uwagę podczas określania zakresu zmiennych utworzonych na podstawie kroków.

  • Zmienne utworzone w kroku zadania są ograniczone do kroków w tym samym zadaniu.
  • Zmienne utworzone w kroku są dostępne w kolejnych krokach tylko jako zmienne środowiskowe.
  • Zmiennych utworzonych w kroku nie można używać w kroku, który je definiuje.

W poniższym przykładzie pokazano tworzenie zmiennej potoku w kroku i używanie zmiennej w warunku i skrypsie kolejnego kroku.

steps:

# This step creates a new pipeline variable: doThing. This variable is available to subsequent steps.
- bash: |
    echo "##vso[task.setvariable variable=doThing]Yes"
  displayName: Step 1

# This step is able to use doThing, so it uses doThing in its condition
- script: |
    # Access the variable from Step 1 as an environment variable.
    echo "Value of doThing (as DOTHING env var): $DOTHING."
  displayName: Step 2
  condition: and(succeeded(), eq(variables['doThing'], 'Yes')) # or and(succeeded(), eq(variables.doThing, 'Yes'))

Często zadawane pytania

Jak mogę wyzwolić zadanie, jeśli poprzednie zadanie zakończyło się z błędami?

Możesz użyć wyniku poprzedniego zadania w warunku. Na przykład w poniższym języku YAML warunek eq(dependencies.A.result,'SucceededWithIssues') umożliwia uruchomienie zadania B , ponieważ zadanie A zakończyło się pomyślnie.

jobs:
- job: A
  displayName: Job A
  continueOnError: true # next job starts even if this one fails
  steps:
  - script: echo Job A ran
  - script: exit 1

- job: B
  dependsOn: A
  condition: eq(dependencies.A.result,'SucceededWithIssues') # targets the result of the previous job 
  displayName: Job B
  steps:
  - script: echo Job B ran

Anulowano moją kompilację, ale nadal działa. Dlaczego?

Ten problem może wystąpić, jeśli warunek skonfigurowany na etapie nie zawiera funkcji sprawdzania stanu zadania. Aby rozwiązać ten problem, dodaj funkcję sprawdzania stanu zadania do warunku.

Jeśli anulujesz zadanie na etapie kolejki, ale nie zostanie uruchomione, całe zadanie zostanie anulowane, w tym wszystkie pozostałe etapy. Aby uzyskać więcej informacji, zobacz Wyniki warunku, gdy kompilacja zostanie anulowana wcześniej w tym artykule.