Repository navigation
134 lines (124 loc) · 6.47 KB
/
Copy pathcommit-queue.yml
File metadata and controls
134 lines (124 loc) · 6.47 KB
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
# Landing a pull request when it is labelled for the queue.
#
# `pull_request_target` runs in the context of the base branch and can reach
# secrets, which `pull_request` cannot do for a fork. That is only safe while
# nothing from the pull request reaches this runner, and nothing does: the
# checkout is this repository at the base branch, and the commit messages
# being read come from the API rather than from a fetch.
#
# Never add a build, an install or a test step here, and never check out the
# branch under review. Those belong in the checks this workflow waits for,
# which run without a token that can write anything.
#
# Actions are pinned by commit, never by tag.
name: Commit Queue
on:
pull_request_target:
types: [labeled]
permissions:
contents: read
# Two labels applied in quick succession should not race each other into the
# same merge.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: false
jobs:
land:
name: Land
# Quoted whole: the label name contains a colon, which an unquoted
# scalar would read as a mapping.
if: "github.event.label.name == '🚀 Status: Commit Queue'"
runs-on: ubuntu-latest
steps:
- name: Mint a token for the app
id: token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.LAND_APP_ID }}
private-key: ${{ secrets.LAND_APP_PRIVATE_KEY }}
# No `ref:`. For this event the default is already the base branch, and
# naming it explicitly, even as `base.ref`, is indistinguishable to a
# reader -- and to a scanner -- from naming the branch under review.
# Nothing from that branch is fetched at all: its commit messages are
# asked of the API, so a stranger's code never reaches this runner.
- name: Check out this repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Nothing here pushes, and a token left in .git/config is one more
# thing that could be picked up by something that should not have it.
persist-credentials: false
- name: Set up Node.js runtime
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: 'package.json'
- name: Land it
id: land
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
# Whoever applied the label, whose right to push is checked before
# anything is merged. Applying a label needs only triage.
LAND_ACTOR: ${{ github.event.sender.login }}
NUMBER: ${{ github.event.pull_request.number }}
# What this job reports as, which is the `name:` above. A refusal
# exits non-zero and leaves a failed check behind, so without this
# the first one would be cited by every attempt after it.
LAND_CHECK_NAME: Land
# Do not read a check that has not reported as one that passed.
# These are this repository's own gates, and every pull request gets
# all of them, so one missing means the run has not started yet.
LAND_REQUIRED_CHECKS: >-
Lint and test,Analyze (javascript-typescript),CodeQL,Title and
description,Scan
run: node build/tasks/land-pull-request.mts "${NUMBER}"
# The label is a request, not a state: once the queue has answered it,
# one way or the other, it has been spent. Leaving it on a landed pull
# request would say the queue still had something to do.
#
# `unlabeled` is not among the events above, so taking it off cannot
# start another run. Failing to take it off is not worth failing a run
# that has already merged, hence the `|| true`.
# Both of these go through the REST API rather than `gh pr edit` and
# `gh pr comment`, which reach for GraphQL and so want organization
# permissions neither task needs. The app happens to satisfy them today;
# tightening its permissions, or installing it somewhere with fewer,
# would break these silently behind the `|| true`. The endpoints below
# need the app's `Issues: write` -- labels and comments are issue
# endpoints even when the number is a pull request's -- and the label one
# names a single label rather than trusting a flag to be subtractive.
- name: Take the label back off
if: always() && steps.token.outcome == 'success'
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
NUMBER: ${{ github.event.pull_request.number }}
LABEL: ${{ github.event.label.name }}
run: |
# The name sits in a URL path, where an emoji would not survive
# being interpolated raw.
gh api --silent -X DELETE \
"repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/labels/$(jq -rn --arg l "$LABEL" '$l|@uri')" \
|| true
# Everything that reports back needs the app's token, so a token that
# never minted leaves a bare red check and no reason for it -- the label
# still on, nothing said, in the one failure that greets a queue nobody
# has run yet. An annotation needs no token and no permission, so this is
# the one report that always survives.
- name: Say why no token could be minted
if: failure() && steps.token.outcome != 'success'
run: |
echo '::error title=The commit queue could not authenticate::' \
'No installation token could be minted, so nothing was read and' \
'nothing was merged. Either the app is not installed on this' \
'repository, or LAND_APP_ID / LAND_APP_PRIVATE_KEY is wrong --' \
'the private key must be the whole PEM, BEGIN and END lines' \
'included. The label is still on this pull request, and' \
'reapplying it starts nothing until it is taken off first.'
- name: Say why it did not land
if: failure() && steps.token.outcome == 'success'
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
NUMBER: ${{ github.event.pull_request.number }}
RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
gh api --silent -X POST \
"repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments" \
-f "body=The commit queue did not land this. See ${RUN} — the label has been taken back off, so re-applying it is a deliberate second try."