Skip to content

ci: skip macOS validation on PRs with no macOS-relevant changes - #130

Draft
David-Engel wants to merge 3 commits into
mainfrom
david/ci-macos-conditional-skip
Draft

ci: skip macOS validation on PRs with no macOS-relevant changes#130
David-Engel wants to merge 3 commits into
mainfrom
david/ci-macos-conditional-skip

Conversation

@David-Engel

Copy link
Copy Markdown
Contributor

Summary

Speeds up PR validation by skipping the macOS build/test jobs on PRs whose changes cannot affect the macOS build, while keeping full macOS coverage on every non-PR (merge/CI) build.

All Apple/macOS-specific code lives in the mssql-tds crate and is limited to the native security libraries — Security.framework/CommonCrypto (Always Encrypted crypto), Security.framework TLS, and the macOS GSSAPI/Kerberos framework linking. When a PR touches none of the relevant paths, the three macOS jobs add wall-clock time without adding coverage.

Changes

  • Refactor the PR-only EvaluateDuplicate stage into a single EvaluateRequirements gate. It now runs the existing duplicate-run check plus a new macOS relevance check in one job (one agent allocation), and is the home for future "smart" skip optimizations. The skipDuplicate output and step name are unchanged.
  • Add .pipeline/scripts/evaluate-macos-relevance.py. It diffs the PR against its target branch, matches the changed files against a moderate allowlist, and emits macRelevant. It fails safe (emits true, i.e. run macOS) on any error, missing PR context, or non-PR build.
  • Gate Build_MacOS, Test_MacOS, and Build_mssql_python_MacOS on macRelevant. They always run on non-PR builds and skip only when a PR's diff is macOS-irrelevant.

macOS-relevant allowlist (moderate)

  • mssql-tds/src/security/**
  • mssql-tds/src/connection/transport.rs, mssql-tds/src/connection/transport/**
  • mssql-tds/tests/test_kerberos_gssapi.rs
  • **/Cargo.toml, Cargo.lock, rust-toolchain*
  • .pipeline/** (any pipeline change forces a macOS run)

Conditions / CI behavior

The macOS jobs use not(canceled()) (not succeeded()) so the PR-only EvaluateRequirements stage being skipped in CI does not cascade the jobs to skipped — the same fail-safe pattern already used by the Build and Build_mssql_python stage conditions.

Trade-off

Under the moderate allowlist, pure mssql-odbc / mssql-python PRs skip macOS during PR validation. They remain covered by the full macOS run on merge to development. This can be widened later if desired.

Testing

  • Unit-checked the allowlist matcher against representative paths (positives for security/transport/manifests/pipeline; negatives for mssql-odbc, mssql-python, non-transport mssql-tds, and docs).
  • Validated validation-stages.yml parses as YAML.
  • End-to-end skip/run behavior will be observable on this PR's validation run (the guard reads Azure DevOps PR environment variables).

Refactor the PR-only EvaluateDuplicate stage into a single EvaluateRequirements
gate that runs both the duplicate-run check and a new macOS relevance check.
The macOS jobs (Build_MacOS, Test_MacOS, Build_mssql_python_MacOS) now skip on
PRs whose diff touches no macOS-relevant paths, and always run on non-PR builds.

macOS-relevant paths (moderate allowlist): mssql-tds security/transport modules,
the macOS Kerberos test, Cargo manifests/lock, rust-toolchain, and .pipeline/**.
The guard fails safe (runs macOS) on any error or missing PR context.
The EvaluateRequirements stage is PR-only and is skipped in CI (non-PR). A bare
succeeded() on the macOS jobs risks cascading to skipped when that stage is
skipped, mirroring the earlier downstream-stage incident. not(canceled()) keeps
the macOS jobs running on non-PR builds and matches the fail-safe pattern used by
the Build and Build_mssql_python stage conditions.
Revert the not(canceled()) change and drop the accompanying comments. Whether a
job-level succeeded() cascades to skipped when the PR-only EvaluateRequirements
stage is skipped will be validated empirically in the PR run rather than assumed
in the YAML. The stage-level not(canceled()) fail-safes are unchanged.
@David-Engel

Copy link
Copy Markdown
Contributor Author

Validation plan for the succeeded() job conditions

The three macOS jobs gate on and(succeeded(), or(ne(Build.Reason,'PullRequest'), eq(...SetMacRelevance.macRelevant,'true'))). The open question is whether a job-level succeeded() cascades to skipped when the PR-only EvaluateRequirements stage is skipped (the non-PR / CI case). Research indicates job-level succeeded() only inspects in-stage job dependencies (these jobs have none), so it should stay true — but we'll confirm empirically rather than assume it in the YAML.

How to validate (Option 1 — manual non-PR queue):

  1. Manually queue this pipeline against david/ci-macos-conditional-skip so Build.Reason = Manual.
  2. EvaluateRequirements is skipped (its condition requires PullRequest); the Build stage still runs via its not(canceled()).
  3. Confirm Build_MacOS and Test_MacOS run (not skipped) under succeeded(). This is the exact CI graph: a job with succeeded() inside a stage that depends on a skipped stage.

Build_mssql_python_MacOS is not covered by this run because its Build_mssql_python stage is PR-only and is skipped on non-PR builds. That job never faces a skipped dependency (on a PR, EvaluateRequirements runs), so it needs no separate check.

Outcome:

  • If the macOS jobs run → succeeded() is confirmed correct; keep as-is.
  • If they skip → switch the three conditions to not(canceled()) and document the cascade behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant