shahar1 opened a new pull request, #75720: URL: https://github.com/apache/airflow/pull/75720
The **CI passed** step that fails a run where a job hit its `timeout-minutes` tested `!cancelled()`. Inside the `always()` gate job, a step's `cancelled()` is false even when the whole run was cancelled, because the job only starts after the cancellation. So every duplicate run that concurrency cancels, and every run cancelled by hand, shows a failed **CI passed (run cancelled)** next to the passing run of the same commit. Two examples are run [40442992585](https://github.com/apache/airflow/actions/runs/40442992585) on `main` and run [40453574496](https://github.com/apache/airflow/actions/runs/40453574496) on #75710. It doesn't block merges, since only **CI passed** is required, but it shows up on most backport and stacked PRs. I suggested that `!cancelled()` condition in my review of #75578 without testing it. This time I checked the candidate signals on throwaway workflows in my fork before changing anything: | Signal | Duplicate cancelled by concurrency | Job timeout, run not cancelled | Manual cancel | |---|---|---|---| | step-level `cancelled()` in the `always()` gate | false | false | false | | job-level `if: cancelled()` | **true** | **false** | **true** | | `job.status` in the gate | success | success | success | | run `status` / `conclusion`, read from the gate | in_progress / null | in_progress / null | in_progress / null | | a newer run of the workflow exists | yes | no | no | The fork runs are [40458389763](https://github.com/shahar1/airflow/actions/runs/40458389763), [40459065389](https://github.com/shahar1/airflow/actions/runs/40459065389) and [40459274039](https://github.com/shahar1/airflow/actions/runs/40459274039). The run's final conclusion is `cancelled` for a timeout too. `cancelled()` can't be used in a job `name:` or a step `env:`. Only a job-level `if` tells the cases apart, so the timeout check is now a job of its own, **Check for timed-out CI jobs**. It needs the same jobs as the gate and runs only when a job was cancelled while the run was not. Its failure fails the gate through the existing "any job failed" step. The same shape in the fork: - Duplicate cancelled by concurrency: **(run cancelled)** passes ([40459694261](https://github.com/shahar1/airflow/actions/runs/40459694261)). - Job timeout: the new job fails, and so does the gate, under its plain name ([40461097026](https://github.com/shahar1/airflow/actions/runs/40461097026)). - Timeout of one matrix leg in a reusable workflow, the shape of most `ci-amd.yml` jobs: the same ([40463821624](https://github.com/shahar1/airflow/actions/runs/40463821624)). - Manual cancel: **(run cancelled)** passes ([40461873429](https://github.com/shahar1/airflow/actions/runs/40461873429)). A run with a timed-out job now fails the required **CI passed** itself, rather than **CI passed (run cancelled)**. `check-ci-gate-needs` now also fails when the new job's `needs` drift from the gate's. This should be backported to `v3-4-test`, which has the same step; #75710 hit it there. --- ##### Was generative AI tooling used to co-author this PR? - [X] Yes (please specify the tool below) Generated-by: Claude Code (Opus 5.5) following [the guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions) --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
