-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
azure-pipelines.yml
249 lines (223 loc) · 9.97 KB
/
azure-pipelines.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# Trigger types. This needs to include all the triggers for the different
# pipelines we might want to run.
#
# Each of these individually triggers the pipeline compilation step, but it's
# the templating expressions in the `stages` list that actually set what runs.
trigger:
branches:
include:
- 'main'
- 'stable/*'
- 'gh-readonly-queue/*'
pr:
autoCancel: true
branches:
include:
- '*'
# A schedule only runs on branches that match include rules from _both_ `main`
# and the branch itself. On `main`, we blanket include all branches that might
# want to be enabled, then particular branches can override it to exclude
# themselves by removing themselves from the trigger list. For example, old
# stable branches can remove `stable/*` from their copy of this file once they
# reach their end-of-life.
schedules:
- cron: "20 6 * * *"
displayName: "Complete matrix test"
branches:
include: [ "main", "stable/*" ]
always: false # Only run if the code changed since the last cron sync.
# Configuration. In theory a manual trigger on the Azure website or embedding
# this pipeline as a template can override these, but we're not interested in
# that. We just want to give names to things to make it easier to read.
parameters:
- name: "supportedPythonVersions"
displayName: "All supported versions of Python"
type: object
default: ["3.9", "3.10", "3.11", "3.12", "3.13"]
- name: "minimumPythonVersion"
displayName: "Minimum supported version of Python"
type: string
default: "3.9"
- name: "maximumPythonVersion"
displayName: "Maximum supported version of Python"
type: string
default: "3.13"
# These two versions of Python can be chosen somewhat arbitrarily, but we get
# slightly better coverage per PR if they're neither the maximum nor minimum
# supported versions.
- name: "branchPushPythonVersion"
displayName: "Version of Python to run simple tests on pushes to protected branches"
type: string
default: "3.9"
# Sync with 'python-version' in '.github/workflows/docs_deploy.yml'.
- name: "documentationPythonVersion"
displayName: "Version of Python to use to build Sphinx documentation"
type: string
default: "3.9"
# Conditional compilation logic. This is all the logic for "what to run"; each
# stage in turn delegates to various templates in ".azure" that provide the
# information on "how to run" them.
#
# The conditional conditions use the template-expression syntax `${{ }}` so only
# the relevant stages even appear in the job list. The documentation on the
# expression syntax is here:
#
# https://docs.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops
#
# Not all variables are available at template-expansion time - this happens
# before any machine is provisioned, so mostly you can access things from
# GitHub, but nothing about the actual machine. This is the list of variables
# (look in the "available in templates" column):
#
# https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
#
# The main differentiator is `variables['Build.Reason']`, which contains the
# trigger type:
# - cron (`Schedule`)
# - push to a git reference like a branch or tag (`IndividualCI`)
# - push to a pull request (`PullRequest`)
# For `IndividualCI` (push/merge to a branch/tag on Qiskit/qiskit-terra), you
# need to examine `variables['Build.SourceBranch']` to determine whether it's a
# branch or a tag, and if a branch, then whether it's in the merge queue or a
# push to a "real" branch.
stages:
# Nightly cron job.
#
# For this to run on a branch, the `schedules` trigger up at the top of this
# file needs to match on _both_ `main` and the branch itself.
- ${{ if eq(variables['Build.Reason'], 'Schedule') }}:
- stage: "Nightly"
displayName: "Nightly complete matrix tests"
jobs:
- ${{ each version in parameters.supportedPythonVersions }}:
- template: ".azure/test-linux.yml"
parameters:
pythonVersion: ${{ version }}
testImages: false
testRust: false
installOptionals: true
- template: ".azure/test-macos.yml"
parameters:
pythonVersion: ${{ version }}
installOptionals: true
- template: ".azure/test-windows.yml"
parameters:
pythonVersion: ${{ version }}
installOptionals: true
- stage: "Nightly_Failure"
displayName: "Comment on nightly failure"
dependsOn: "Nightly"
condition: failed()
pool: {vmImage: 'ubuntu-latest'}
jobs:
- job: "Comment"
steps:
- task: GitHubComment@0
inputs:
gitHubConnection: Qiskit
repositoryName: ${{ variables['Build.Repository.Name'] }}
id: 7864
comment: Nightly test job failed at commit $(Build.SourceVersion). View the logs at $(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId).
# Full PR suite. PRs need to pass this pipeline in order to be moved to the
# merge queue, where they'll use the next rule as the branch-protection rule
# for the final merge to the base branch.
- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
# The preliminary stage should be small in both total runtime (including
# provisioning) and resources required. About half of PR commits result in
# a CI failure, and over 90% of these are in linting, documention or a test
# failure that would affect _any_ OS or Python version. The goal in the
# first stage is to catch the vast majority of failures with minimal cost.
- stage: "Lint_Docs_Prelim_Tests"
displayName: "Preliminary tests"
jobs:
- template: ".azure/lint_docs-linux.yml"
parameters:
pythonVersion: ${{ parameters.minimumPythonVersion }}
- template: ".azure/test-linux.yml"
parameters:
pythonVersion: ${{ parameters.minimumPythonVersion }}
# A PR is more likely to fail CI because it introduces a logic error
# into an existing test than because it adds a new test / optional
# dependency that isn't accounted for in the test-skipping logic
# (and such a failure would need fewer iterations to fix). We want
# to fail fast in the first CI stage.
installOptionals: true
testRust: true
testImages: true
# The rest of the PR pipeline is to test the oldest and newest supported
# versions of Python. It's very rare for a failure to be specific to an
# intermediate version of Python, so we just catch those in the cron-job
# pipeline to reduce the amount of resources used.
- stage: "Tests"
displayName: "Main tests"
dependsOn: "Lint_Docs_Prelim_Tests"
jobs:
- template: ".azure/test-linux.yml"
parameters:
pythonVersion: ${{ parameters.maximumPythonVersion }}
testRust: false
testImages: false
installFromSdist: true
installOptionals: false
- template: ".azure/test-macos.yml"
parameters:
pythonVersion: ${{ parameters.minimumPythonVersion }}
installOptionals: true
- template: ".azure/test-macos.yml"
parameters:
pythonVersion: ${{ parameters.maximumPythonVersion }}
installOptionals: false
- template: ".azure/test-windows.yml"
parameters:
pythonVersion: ${{ parameters.minimumPythonVersion }}
installOptionals: true
- template: ".azure/test-windows.yml"
parameters:
pythonVersion: ${{ parameters.maximumPythonVersion }}
installOptionals: false
# Merge queue. A PR that reaches here has already passed the more rigorous PR
# suite, so is very likely to pass. The main reasons for failures here are
# flaky VMs timing out (which we can't do much about), or a merge conflict
# with another PR that is also in the merge queue.
#
# There's no reason to have multiple stages in this case, because we're
# expecting it to pass. Having more than one stage frustrates parallel
# throughput in low-contention cases, and guarantees a longer critical path.
- ${{ if and(eq(variables['Build.Reason'], 'IndividualCI'), contains(variables['Build.SourceBranch'], 'gh-readonly-queue')) }}:
- stage: "Merge_Queue"
displayName: "Merge queue"
jobs:
- template: ".azure/lint_docs-linux.yml"
parameters:
pythonVersion: ${{ parameters.minimumPythonVersion }}
- template: ".azure/test-linux.yml"
parameters:
pythonVersion: ${{ parameters.minimumPythonVersion }}
installOptionals: true
testRust: true
testImages: true
- template: ".azure/test-linux.yml"
parameters:
pythonVersion: ${{ parameters.maximumPythonVersion }}
installOptionals: false
testRust: false
testImages: false
- template: ".azure/test-macos.yml"
parameters:
pythonVersion: ${{ parameters.maximumPythonVersion }}
installOptionals: false
- template: ".azure/test-windows.yml"
parameters:
pythonVersion: ${{ parameters.maximumPythonVersion }}
installOptionals: false
# Push to main or the stable branches. The triggering branches also need to
# be in the triggers at the top of this file.
- ${{ if and(eq(variables['Build.Reason'], 'IndividualCI'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/stable/'))) }}:
- stage: "Push"
jobs:
- template: ".azure/test-linux.yml"
parameters:
pythonVersion: ${{ parameters.branchPushPythonVersion }}
testRust: true
testImages: true
installOptionals: false