-
Notifications
You must be signed in to change notification settings - Fork 2.4k
214 lines (203 loc) · 9.02 KB
/
munge-pr.yml
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
name: Munge PR
on:
pull_request_target:
permissions:
contents: read
pull-requests: write
defaults:
run:
shell: 'bash -Eeuo pipefail -x {0}'
env:
# https://github.com/docker-library/bashbrew/issues/10
GIT_LFS_SKIP_SMUDGE: 1
jobs:
gather:
name: Gather Metadata
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# ideally this would be "github.event.pull_request.merge_commit_sha" but according to https://docs.github.com/en/free-pro-team@latest/rest/reference/pulls#get-a-pull-request if "mergeable" is null (meaning there's a background job in-progress to check mergeability), that value is undefined...
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- id: gather
name: Affected Images
run: |
(set +x; echo "::stop-commands::$(echo -n ${{ github.token }} | sha256sum | head -c 64)")
git fetch --quiet https://github.com/docker-library/official-images.git master
externalPins="$(git diff --no-renames --name-only FETCH_HEAD...HEAD -- '.external-pins/*/**')"
externalPinTags="$(
if [ -n "$externalPins" ]; then
# doing backflips to run "tag.sh" from master instead of from the PR
git show FETCH_HEAD:.external-pins/tag.sh > ~/master-external-pins-tag.sh
chmod +x ~/master-external-pins-tag.sh
~/master-external-pins-tag.sh $externalPins
fi
)"
images="$(git diff --no-renames --name-only FETCH_HEAD...HEAD -- library/)"
if [ -n "$images" ]; then
new="$(git diff --no-renames --name-only --diff-filter=A FETCH_HEAD...HEAD -- $images)"
deleted="$(git diff --no-renames --name-only --diff-filter=D FETCH_HEAD...HEAD -- $images)"
else
new=
deleted=
fi
export images new deleted externalPins externalPinTags
images="$(jq -cn '
(env.images | rtrimstr("\n") | split("\n")) as $images
| (env.new | rtrimstr("\n") | split("\n")) as $new
| (env.deleted | rtrimstr("\n") | split("\n")) as $deleted
| (env.externalPins | rtrimstr("\n") | split("\n")) as $externalPins
| (env.externalPinTags | rtrimstr("\n") | split("\n")) as $externalPinTags
| {
images: $images,
count: ($images | length),
new: $new,
deleted: $deleted,
externalPins: $externalPins,
externalPinTags: $externalPinTags,
externalPinsCount: ($externalPins | length),
}
| .imagesAndExternalPinsCount = (.count + .externalPinsCount) # man, I *really* do not love GitHub Actions expressions...
')"
jq . <<<"$images"
set +x
echo "::$(echo -n ${{ github.token }} | sha256sum | head -c 64)::"
echo "images=$images" >> "$GITHUB_OUTPUT"
outputs:
images: '${{ steps.gather.outputs.images }}'
apply-labels:
name: Apply Labels
runs-on: ubuntu-latest
needs: gather
if: fromJSON(needs.gather.outputs.images).imagesAndExternalPinsCount > 0
steps:
- name: Apply Labels
uses: actions/github-script@v7
env:
IMAGES: ${{ needs.gather.outputs.images }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const data = JSON.parse(process.env.IMAGES);
var labels = [
...data.images, // "library/debian", ...
...new Set(data.externalPinTags.map(x => 'external/' + x.replace(/:.+$/, ''))), // "external/mcr.microsoft.com/windows/servercore", ...
];
if (data.new.length > 0) {
labels.push('new-image');
}
console.log(labels);
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: labels,
});
diff:
name: Diff Comment
runs-on: ubuntu-latest
needs: gather
if: fromJSON(needs.gather.outputs.images).imagesAndExternalPinsCount > 0
steps:
- uses: actions/checkout@v4
with:
# again, this would ideally be "github.event.pull_request.merge_commit_sha" but we might not have that yet when this runs, so we compromise by checkout out the latest code from the target branch (so we get the latest "diff-pr.sh" script to run)
ref: ${{ github.event.pull_request.base.ref }}
fetch-depth: 0
- uses: ./.github/workflows/.bashbrew
with:
build: 'docker'
- name: Prepare Environment
run: |
# this avoids running repo-local scripts (to avoid CVE-2020-15228 via the scripts being updated to write nasty things to $GITHUB_ENV)
docker build --tag oisupport/bashbrew:diff-pr .
- name: Gather Maintainers
env:
IMAGES: ${{ needs.gather.outputs.images }}
run: |
files="$(jq <<<"$IMAGES" -r '.images | map(@sh) | join(" ")')"
eval "set -- $files"
for f; do
if [ -s "$f" ]; then
docker run --rm --read-only --tmpfs /tmp oisupport/bashbrew:diff-pr \
bashbrew cat --format ' - `{{ $.RepoName }}`:{{ range .Manifest.Global.Maintainers }} @{{ .Handle }}{{ end }}' "$f"
fi
done | tee "$GITHUB_WORKSPACE/oi-pr.maint"
- name: Generate Diff
env:
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
docker run --rm --read-only --tmpfs /tmp oisupport/bashbrew:diff-pr ./diff-pr.sh "$GITHUB_PR_NUMBER" | tee "$GITHUB_WORKSPACE/oi-pr.diff"
- name: Comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const commentText = 'Diff for ' + context.payload.pull_request.head.sha + ':';
const fs = require('fs');
const diff = fs.readFileSync(process.env.GITHUB_WORKSPACE + '/oi-pr.diff').toString().trimEnd();
var body = "<details>\n<summary>" + commentText + "</summary>\n\n```diff\n" + diff + "\n```\n\n</details>";
const maint = fs.readFileSync(process.env.GITHUB_WORKSPACE + '/oi-pr.maint').toString().trimEnd();
if (maint.length > 0) {
body += "\n\nRelevant Maintainers:\n\n" + maint;
}
fs.writeFileSync(process.env.GITHUB_STEP_SUMMARY, body);
// https://docs.github.com/en/graphql/reference/mutations#minimizecomment
const minimizeql = `
mutation($comment: ID!) {
minimizeComment(input: { classifier: OUTDATED, clientMutationId: "doi-munge-pr", subjectId: $comment }) {
clientMutationId
minimizedComment {
isMinimized
minimizedReason
}
}
}
`;
// https://docs.github.com/en/graphql/reference/mutations#unminimizecomment
const unminimizeql = `
mutation($comment: ID!) {
unminimizeComment(input: { clientMutationId: "doi-munge-pr", subjectId: $comment }) {
clientMutationId
unminimizedComment {
isMinimized
minimizedReason
}
}
}
`;
needNewComment = true;
console.log('Reviewing existing comments...');
for await (const { data: comments } of github.paginate.iterator(
github.rest.issues.listComments,
{
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
}
)) {
for (const comment of comments) {
if (comment.user.login === 'github-actions[bot]') {
if (needNewComment && comment.body.includes(commentText)) {
needNewComment = false;
console.log('Unhiding comment: ' + comment.id + ' (' + comment.node_id + ')');
const result = await github.graphql(unminimizeql, { comment: comment.node_id });
console.log('- result: ' + JSON.stringify(result));
} else {
console.log('Hiding comment: ' + comment.id + ' (' + comment.node_id + ')');
const result = await github.graphql(minimizeql, { comment: comment.node_id });
console.log('- result: ' + JSON.stringify(result));
}
}
}
}
if (needNewComment) {
console.log('Creating new comment...');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: body,
});
}