diff --git a/crates/cargo-anvil/docs/design/ado.md b/crates/cargo-anvil/docs/design/ado.md index df3e7059..c8e45144 100644 --- a/crates/cargo-anvil/docs/design/ado.md +++ b/crates/cargo-anvil/docs/design/ado.md @@ -368,6 +368,7 @@ The contract is intentionally small and stable: | Parameter | Type | Required | Meaning | |-------------|------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `name` | `string` | yes | Job name; ADO derives the display name from it. | +| `group` | `string` | no | The anvil check group this job runs (`impact`, `pr-fast`, `pr-test`, `pr-runtime-analysis`, `pr-mutants`, `scheduled-*`). The default wrapper ignores it; extension-template wrappers use it to vary per-job `templateContext:`. Per-OS job names repeat across stages (`linux` / `windows` in every pr-\* and scheduled-\* stage, `compute_linux` / `compute_windows` in impact), so `name` alone cannot identify the group, and `templateContext:` is evaluated at template-expansion time so a runtime stage-name condition is not available either. Defaults to `''` so a caller may omit it — but a wrapper that does not *declare* the parameter is rejected by ADO once the stages templates pass it, so an adopter who owns this file takes the wrapper and stages updates together. | | `pool` | `object` | yes | Pool block, passed verbatim to ADO's `pool:` key. `linuxPool` and `windowsPool` at the stage level are object parameters, so users can override their shape (e.g. `{ name, os, image }` for 1ESPT). | | `steps` | `stepList` | yes | Body of the job. Templated step lists are fine — the wrapper splices them in via `${{ each step in parameters.steps }}: - ${{ step }}`. | | `artifacts` | `object` | no | List of pipeline artifacts to publish. Each item: `{ name: string, path: string }`. Default wrapper appends one `PublishPipelineArtifact@1` per entry; 1ESPT wrappers translate the same list into `templateContext.outputs.pipelineArtifact` blocks. The stages templates don't need to know which backend they're targeting. | @@ -377,6 +378,7 @@ The default wrapper anvil ships is six lines of logic: ```yaml parameters: - { name: name, type: string } + - { name: group, type: string, default: '' } - { name: pool, type: object } - { name: steps, type: stepList } - { name: artifacts, type: object, default: [] } diff --git a/crates/cargo-anvil/src/anvil/artifacts/ado.rs b/crates/cargo-anvil/src/anvil/artifacts/ado.rs index b138f19d..26d37333 100644 --- a/crates/cargo-anvil/src/anvil/artifacts/ado.rs +++ b/crates/cargo-anvil/src/anvil/artifacts/ado.rs @@ -254,6 +254,7 @@ mod tests { fn job_wrapper_declares_expected_contract() { for needle in [ "name: name", + "name: group", "name: pool", "name: steps", "type: stepList", @@ -264,6 +265,44 @@ mod tests { } } + #[test] + fn stages_identify_the_check_group_for_every_job() { + // Per-OS job names repeat across stages (`linux` / `windows` in every + // pr-* and scheduled-* stage, `compute_linux` / `compute_windows` in + // impact), so `name` cannot tell an extension-template wrapper which + // group it is rendering. `group` carries that, letting a wrapper vary + // per-job `templateContext:` (which is evaluated at template-expansion + // time, so a runtime stage-name condition is not an option). + for (template, groups) in [ + ( + PR_STAGES, + &["impact", "pr-fast", "pr-test", "pr-runtime-analysis", "pr-mutants"][..], + ), + ( + SCHEDULED_STAGES, + &[ + "scheduled-test", + "scheduled-advisories", + "scheduled-runtime-analysis", + "scheduled-exhaustive", + ][..], + ), + ] { + for group in groups { + assert_eq!( + template.matches(&format!("group: {group}\n")).count(), + 2, + "group '{group}' must be declared on both per-OS jobs" + ); + } + assert_eq!( + template.matches("- template: steps/job.yml").count(), + template.matches("\n group: ").count(), + "every steps/job.yml invocation must pass a group" + ); + } + } + #[test] fn render_group_step_has_include_inputs_and_env() { let body = render_group_step("pr-fast"); diff --git a/crates/cargo-anvil/templates/ado/pr-stages.yml b/crates/cargo-anvil/templates/ado/pr-stages.yml index 6e1ac2f8..51bec51a 100644 --- a/crates/cargo-anvil/templates/ado/pr-stages.yml +++ b/crates/cargo-anvil/templates/ado/pr-stages.yml @@ -40,12 +40,14 @@ stages: - template: steps/job.yml parameters: name: compute_linux + group: impact pool: ${{ parameters.linuxPool }} steps: - template: steps/impact.yml - template: steps/job.yml parameters: name: compute_windows + group: impact pool: ${{ parameters.windowsPool }} steps: - template: steps/impact.yml @@ -77,6 +79,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-fast pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-fast.yml @@ -97,6 +100,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-fast pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-fast.yml @@ -137,6 +141,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-test pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-test.yml @@ -153,6 +158,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-test pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-test.yml @@ -181,6 +187,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-runtime-analysis pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-runtime-analysis.yml @@ -191,6 +198,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-runtime-analysis pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-runtime-analysis.yml @@ -215,6 +223,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-mutants pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-mutants.yml @@ -225,6 +234,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-mutants pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-mutants.yml diff --git a/crates/cargo-anvil/templates/ado/scheduled-stages.yml b/crates/cargo-anvil/templates/ado/scheduled-stages.yml index f1cb349d..d1c516cd 100644 --- a/crates/cargo-anvil/templates/ado/scheduled-stages.yml +++ b/crates/cargo-anvil/templates/ado/scheduled-stages.yml @@ -23,6 +23,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-test pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-test.yml @@ -35,6 +36,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: scheduled-test pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-test.yml @@ -54,12 +56,14 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-advisories pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-advisories.yml - template: steps/job.yml parameters: name: windows + group: scheduled-advisories pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-advisories.yml @@ -75,12 +79,14 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-runtime-analysis pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-runtime-analysis.yml - template: steps/job.yml parameters: name: windows + group: scheduled-runtime-analysis pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-runtime-analysis.yml @@ -97,12 +103,14 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-exhaustive pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-exhaustive.yml - template: steps/job.yml parameters: name: windows + group: scheduled-exhaustive pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-exhaustive.yml diff --git a/crates/cargo-anvil/templates/ado/steps/job.yml b/crates/cargo-anvil/templates/ado/steps/job.yml index 028b1ccd..975be926 100644 --- a/crates/cargo-anvil/templates/ado/steps/job.yml +++ b/crates/cargo-anvil/templates/ado/steps/job.yml @@ -15,6 +15,22 @@ # # Contract (intentionally small and stable): # - name (string) Job name; ADO derives the display name from it. +# - group (string) Optional. The anvil check group this job runs +# (`impact`, `pr-fast`, `pr-mutants`, ...). The +# default wrapper ignores it; extension-template +# wrappers use it to vary per-job `templateContext:`, +# which cannot be expressed any other way: per-OS job +# names repeat across stages (`linux` / `windows` in +# every pr-* and scheduled-* stage, `compute_linux` / +# `compute_windows` in impact), so `name` alone does +# not identify the group, and `templateContext:` is +# evaluated at template-expansion time so a runtime +# stage-name condition is not available either. +# Defaults to '' so a caller may omit it. A wrapper +# that does not DECLARE the parameter is rejected by +# ADO once the stages templates pass it, so an adopter +# who owns this file takes the wrapper and stages +# updates together. # - pool (object) Pool block, passed verbatim to ADO's `pool:` key. # - steps (stepList) Body of the job. Templated step lists are fine. # - artifacts (object) Optional list of pipeline artifacts to publish. @@ -29,6 +45,9 @@ parameters: - name: name type: string + - name: group + type: string + default: '' - name: pool type: object - name: steps diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap index d0db7681..6086182d 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap @@ -1357,12 +1357,14 @@ stages: - template: steps/job.yml parameters: name: compute_linux + group: impact pool: ${{ parameters.linuxPool }} steps: - template: steps/impact.yml - template: steps/job.yml parameters: name: compute_windows + group: impact pool: ${{ parameters.windowsPool }} steps: - template: steps/impact.yml @@ -1394,6 +1396,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-fast pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-fast.yml @@ -1414,6 +1417,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-fast pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-fast.yml @@ -1454,6 +1458,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-test pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-test.yml @@ -1470,6 +1475,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-test pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-test.yml @@ -1498,6 +1504,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-runtime-analysis pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-runtime-analysis.yml @@ -1508,6 +1515,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-runtime-analysis pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-runtime-analysis.yml @@ -1532,6 +1540,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: pr-mutants pool: ${{ parameters.linuxPool }} steps: - template: steps/pr-mutants.yml @@ -1542,6 +1551,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: pr-mutants pool: ${{ parameters.windowsPool }} steps: - template: steps/pr-mutants.yml @@ -1576,6 +1586,7 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-test pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-test.yml @@ -1588,6 +1599,7 @@ stages: - template: steps/job.yml parameters: name: windows + group: scheduled-test pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-test.yml @@ -1607,12 +1619,14 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-advisories pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-advisories.yml - template: steps/job.yml parameters: name: windows + group: scheduled-advisories pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-advisories.yml @@ -1628,12 +1642,14 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-runtime-analysis pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-runtime-analysis.yml - template: steps/job.yml parameters: name: windows + group: scheduled-runtime-analysis pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-runtime-analysis.yml @@ -1650,12 +1666,14 @@ stages: - template: steps/job.yml parameters: name: linux + group: scheduled-exhaustive pool: ${{ parameters.linuxPool }} steps: - template: steps/scheduled-exhaustive.yml - template: steps/job.yml parameters: name: windows + group: scheduled-exhaustive pool: ${{ parameters.windowsPool }} steps: - template: steps/scheduled-exhaustive.yml @@ -1876,6 +1894,22 @@ steps: # # Contract (intentionally small and stable): # - name (string) Job name; ADO derives the display name from it. +# - group (string) Optional. The anvil check group this job runs +# (`impact`, `pr-fast`, `pr-mutants`, ...). The +# default wrapper ignores it; extension-template +# wrappers use it to vary per-job `templateContext:`, +# which cannot be expressed any other way: per-OS job +# names repeat across stages (`linux` / `windows` in +# every pr-* and scheduled-* stage, `compute_linux` / +# `compute_windows` in impact), so `name` alone does +# not identify the group, and `templateContext:` is +# evaluated at template-expansion time so a runtime +# stage-name condition is not available either. +# Defaults to '' so a caller may omit it. A wrapper +# that does not DECLARE the parameter is rejected by +# ADO once the stages templates pass it, so an adopter +# who owns this file takes the wrapper and stages +# updates together. # - pool (object) Pool block, passed verbatim to ADO's `pool:` key. # - steps (stepList) Body of the job. Templated step lists are fine. # - artifacts (object) Optional list of pipeline artifacts to publish. @@ -1890,6 +1924,9 @@ steps: parameters: - name: name type: string + - name: group + type: string + default: '' - name: pool type: object - name: steps