@@ -11,174 +11,24 @@ blocked on a deferrable condition, currently wait time, the queue leaves the |
11 | 11 | label in place and retries later. Other failures continue to the existing |
12 | 12 | landing and failure-reporting path. |
13 | 13 |
|
14 | | -This document gives an overview of how the Commit Queue works, as well as |
15 | | -implementation details, reasoning for design choices, and current limitations. |
16 | | - |
17 | | -## Overview |
18 | | - |
19 | | -From a high-level, the Commit Queue works as follows: |
20 | | - |
21 | | -1. Collaborators will add `commit-queue` label to pull requests they want the |
22 | | - queue to land. The label can be added before the pull request has completed |
23 | | - its wait time. Required approvals must already be in place, and any required |
24 | | - CI must have completed successfully. The commit queue does not request CI on |
25 | | - its own. |
26 | | -2. On each scheduled run, the queue builds a candidate list from open pull |
27 | | - requests with the `commit-queue` label and without the `blocked` label. A |
28 | | - candidate must also either have been created at least two days earlier or |
29 | | - have the `fast-track` label. Other labeled pull requests retain the label |
30 | | - until they become old enough or are fast-tracked. The workflow uses a |
31 | | - five-minute cron, but GitHub Actions scheduled workflows are not guaranteed |
32 | | - to run exactly every five minutes. For each candidate, the queue will: |
33 | | - 1. In the landing job, install and configure `@node-core/utils`, then run a |
34 | | - metadata-only readiness check without checking out the repository |
35 | | - 2. If the metadata check exits with a deferrable readiness code, meaning |
36 | | - the PR is only blocked on wait time, keep the `commit-queue` label and |
37 | | - skip this PR until a later queue run |
38 | | - 3. Run `git node land` for ready PRs and PRs with hard or mixed readiness |
39 | | - failures, keeping the `commit-queue` label in place during the attempt |
40 | | - 4. If it fails: |
41 | | - 1. Replace the `commit-queue` label with the `commit-queue-failed` label |
42 | | - 2. Leave a comment on the PR with the output from `git node land` |
43 | | - 3. Abort the `git node land` session. If the abort succeeds, continue to |
44 | | - the next PR; otherwise, stop the queue in an unknown state |
45 | | - 5. If it succeeds: |
46 | | - 1. Push or merge the changes into nodejs/node |
47 | | - 2. Leave a comment on the PR with `Landed in ...` |
48 | | - 3. Close the PR |
49 | | - 4. Remove the `commit-queue` label |
50 | | - 5. Go to next PR in the queue |
51 | | - |
52 | 14 | To make the Commit Queue squash all the commits of a pull request into the |
53 | 15 | first one, add the `commit-queue-squash` label. |
54 | 16 | To make the Commit Queue land a pull request containing several commits, add the |
55 | 17 | `commit-queue-rebase` label. When using this option, make sure |
56 | 18 | that all commits are self-contained, meaning every commit should pass all tests. |
57 | 19 |
|
| 20 | +The implementation is in `commit-queue.yml` and `commit-queue.sh`. |
| 21 | + |
58 | 22 | ## Current limitations |
59 | 23 |
|
60 | | -The Commit Queue feature is still in early stages, and as such it might not |
61 | | -work for more complex pull requests. These are the currently known limitations |
62 | | -of the commit queue: |
| 24 | +These are the currently known limitations of the commit queue: |
63 | 25 |
|
64 | 26 | 1. All commits in a pull request must either be following commit message |
65 | 27 | guidelines or be a valid [`fixup!`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---fixupamendrewordltcommitgt) |
66 | 28 | commit that will be correctly handled by the [`--autosquash`](https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---autosquash) |
67 | | - option |
68 | | -2. A CI must have run and succeeded since the last change on the PR |
69 | | -3. A collaborator must have approved the PR since the last change |
70 | | -4. Only Jenkins CI and GitHub Actions are checked (V8 CI and CITGM are ignored) |
| 29 | + option. |
| 30 | +2. A CI must have run and succeeded since the last change on the PR. |
| 31 | +3. A collaborator must have approved the PR since the last change. |
| 32 | +4. Only Jenkins CI and GitHub Actions are checked (V8 CI and CITGM are ignored). |
71 | 33 | 5. The PR must target the `main` branch (PRs opened against other branches, such |
72 | | - as backport PRs, are ignored) |
73 | | - |
74 | | -## Implementation |
75 | | - |
76 | | -The [action](../../.github/workflows/commit-queue.yml) runs on scheduled events. |
77 | | -It uses a five-minute cron because that is the smallest interval accepted by |
78 | | -GitHub Actions. Scheduled workflows are not guaranteed to run exactly at that |
79 | | -cadence and might take longer between runs. |
80 | | - |
81 | | -The workflow also uses a concurrency group so only one commit queue run can be |
82 | | -active at a time. If a scheduled run starts while a previous run is still |
83 | | -running, GitHub Actions keeps at most one pending run for the same concurrency |
84 | | -group. A newer pending run replaces an older pending run. |
85 | | - |
86 | | -Using the scheduler is preferable over using pull\_request\_target for two |
87 | | -reasons: |
88 | | - |
89 | | -1. if two Commit Queue Actions execution overlap, there's a high-risk that |
90 | | - the last one to finish will fail because the local branch will be out of |
91 | | - sync with the remote after the first Action pushes. `issue_comment` event |
92 | | - has the same limitation. |
93 | | -2. `pull_request_target` will only run if the Action exists on the base commit |
94 | | - of a pull request, and it will run the Action version present on that |
95 | | - commit, meaning we wouldn't be able to use it for already opened PRs |
96 | | - without rebasing them first. |
97 | | - |
98 | | -The workflow starts with a small candidate job that uses GitHub CLI to fetch |
99 | | -open pull requests with the `commit-queue` label and without the `blocked` |
100 | | -label. It fetches two buckets: pull requests created at least two days earlier |
101 | | -and pull requests with the `fast-track` label. The job de-duplicates the |
102 | | -buckets before passing the candidates to the landing job. Pull requests in |
103 | | -neither bucket remain labeled but are not processed during that run. |
104 | | - |
105 | | -If there are candidate PRs, the landing job installs and configures |
106 | | -`@node-core/utils` once with a personal token and a Jenkins token from |
107 | | -[@nodejs-github-bot](https://github.com/nodejs/github-bot). It then downloads |
108 | | -the workflow commit's README without checking out the repository and runs |
109 | | -`git node metadata --readme --json` for each candidate. This uses the same |
110 | | -`@node-core/utils` PR readiness checks as `git node land`, but does not clone, |
111 | | -fetch, or merge the PR. The filter consumes the structured metadata result |
112 | | -and its exit code instead of matching human-readable output: |
113 | | - |
114 | | -* exit code `0`: the PR is ready and is passed to |
115 | | - [`commit-queue.sh`](../../tools/actions/commit-queue.sh) |
116 | | -* exit codes `20`-`29`: the PR is not ready for a deferrable metadata reason, |
117 | | - currently wait time, so it keeps the `commit-queue` label and is retried |
118 | | - later |
119 | | -* exit codes `40`-`49`: the PR has a hard or mixed metadata readiness failure |
120 | | - and is passed to [`commit-queue.sh`](../../tools/actions/commit-queue.sh) |
121 | | - |
122 | | -The `20`-`29` exit code range is reserved by `@node-core/utils` for deferrable |
123 | | -metadata readiness states, and `40`-`49` is reserved for hard metadata failure |
124 | | -states. Unknown filter failures fail the workflow before starting the landing |
125 | | -script and leave PR labels unchanged so the queue can retry on a later |
126 | | -scheduled run. PRs passed through with exit code `40`-`49` continue through |
127 | | -`commit-queue.sh`. The workflow checks out the repository only when at least |
128 | | -one PR remains after filtering. The script does not separately skip PRs with a |
129 | | -`request-ci` label or pending GitHub checks. Instead, `git node land` performs |
130 | | -the landing checks and the script reports any failure through the normal queue |
131 | | -failure path. |
132 | | - |
133 | | -> The personal token needs permission for public repositories and to read |
134 | | -> profiles. It is used by `@node-core/utils` and by the landing job for |
135 | | -> checkout, label and comment updates, merging, and pushing. Jenkins token is |
136 | | -> required to check CI status. |
137 | | -
|
138 | | -`commit-queue.sh` receives the following positional arguments: |
139 | | - |
140 | | -1. The repository owner |
141 | | -2. The repository name |
142 | | -3. Every positional argument starting at this one will be a pull request ID of |
143 | | - a pull request with commit-queue set. |
144 | | - |
145 | | -The script iterates over the pull requests. For each PR, it uses GitHub CLI to |
146 | | -fetch the labels and select the multiple-commit policy, then runs |
147 | | -`git node land`, forwarding stdout and stderr to a file. It does not perform a |
148 | | -separate CI preflight; `git node land` performs the current readiness and CI |
149 | | -validation. |
150 | | - |
151 | | -The script keeps the `commit-queue` label in place while `git node land` is |
152 | | -running. PRs that are only blocked on wait time should have already been |
153 | | -filtered by the metadata check. A hard or mixed readiness failure is passed |
154 | | -through so `git node land` can produce the failure output. If the landing |
155 | | -attempt fails for that or any other reason, the job replaces the |
156 | | -`commit-queue` label with `commit-queue-failed`, leaves a comment with the |
157 | | -output, and then aborts the landing session. If the abort fails, the queue |
158 | | -stops instead of continuing in an unknown state. |
159 | | - |
160 | | -Fast-tracked PRs use the metadata check before checkout and the landing script. |
161 | | -If the fast-track request has not yet received enough collaborator thumbs-up, |
162 | | -the queue keeps the `commit-queue` label and retries until either the |
163 | | -fast-track request is approved or the PR becomes landable through the regular |
164 | | -wait-time rules. The commit queue does not create the fast-track request |
165 | | -comment; that is handled when the `fast-track` label is added. If that comment |
166 | | -is missing, the queue reports the failure instead of keeping the PR queued. |
167 | | - |
168 | | -If no errors happen during `git node land`, the script either pushes the direct |
169 | | -rebase landing to `main` or uses GitHub's squash merge API for single-commit and |
170 | | -fixup landings. It then leaves a `Landed in ...` comment in the PR. GitHub |
171 | | -closes PRs merged through the merge API automatically; for direct pushes, the |
172 | | -script closes the PR. The script then removes the `commit-queue` label. |
173 | | -Iteration continues until all PRs have done the steps above. |
174 | | - |
175 | | -## Reverting broken commits |
176 | | - |
177 | | -Reverting broken commits is done manually by collaborators, just like when |
178 | | -commits are landed manually via `git node land`. An easy way to revert is a |
179 | | -good feature for the project, but is not explicitly required for the Commit |
180 | | -Queue to work because the Action lands PRs just like collaborators do today. If |
181 | | -once we start using the Commit Queue we notice that the number of required |
182 | | -reverts increases drastically, we can pause the queue until a Revert Queue is |
183 | | -implemented, but until then we can enable the Commit Queue and then work on a |
184 | | -Revert Queue as a follow-up. |
| 34 | + as backport PRs, are ignored). |