Skip to content

Commit a568e3f

Browse files
committed
chore(ci): safely label PR based on title
1 parent 433928d commit a568e3f

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: Label PR based on title
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Record PR number"]
6+
types:
7+
- completed
8+
9+
jobs:
10+
upload:
11+
runs-on: ubuntu-latest
12+
# Guardrails to only ever run if PR recording workflow was indeed
13+
# run in a PR event and ran successfully
14+
if: >
15+
${{ github.event.workflow_run.event == 'pull_request' &&
16+
github.event.workflow_run.conclusion == 'success' }}
17+
steps:
18+
- name: 'Download artifact'
19+
uses: actions/github-script@v5
20+
# For security, we only download artifacts tied to the successful PR recording workflow
21+
with:
22+
script: |
23+
const fs = require('fs');
24+
25+
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
26+
owner: context.repo.owner,
27+
repo: context.repo.repo,
28+
run_id: ${{github.event.workflow_run.id }},
29+
});
30+
31+
const matchArtifact = artifacts.data.artifacts.filter(artifact => artifact.name == "pr")[0];
32+
33+
const artifact = await github.rest.actions.downloadArtifact({
34+
owner: context.repo.owner,
35+
repo: context.repo.repo,
36+
artifact_id: matchArtifact.id,
37+
archive_format: 'zip',
38+
});
39+
40+
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(artifact.data));
41+
# NodeJS standard library doesn't provide ZIP capabilities; use system `unzip` command instead
42+
- run: unzip pr.zip
43+
44+
- name: 'Label PR based on title'
45+
uses: actions/github-script@v5
46+
with:
47+
github-token: ${{ secrets.GITHUB_TOKEN }}
48+
# This safely runs in our base repo, not on fork
49+
# thus allowing us to provide a write access token to label based on PR title
50+
# and label PR based on semantic title accordingly
51+
script: |
52+
const fs = require('fs');
53+
const pr_number = Number(fs.readFileSync('./number'));
54+
const pr_title = fs.readFileSync('./title', 'utf-8').trim();
55+
56+
const FEAT_REGEX = /feat(\((\w+)\))?(\:.+)/
57+
const BUG_REGEX = /(fix|bug)(\((\w+)\))?(\:.+)/
58+
const DOCS_REGEX = /(docs|doc)(\((\w+)\))?(\:.+)/
59+
const CHORE_REGEX = /(chore)(\((\w+)\))?(\:.+)/
60+
const DEPRECATED_REGEX = /(deprecated)(\((\w+)\))?(\:.+)/
61+
const REFACTOR_REGEX = /(refactor)(\((\w+)\))?(\:.+)/
62+
63+
const labels = {
64+
"feature": FEAT_REGEX,
65+
"bug": BUG_REGEX,
66+
"documentation": DOCS_REGEX,
67+
"internal": CHORE_REGEX,
68+
"enhancement": REFACTOR_REGEX,
69+
"deprecated": DEPRECATED_REGEX,
70+
}
71+
72+
for (const label in labels) {
73+
const matcher = new RegExp(labels[label])
74+
const isMatch = matcher.exec(pr_title)
75+
if (isMatch != null) {
76+
console.info(`Auto-labeling PR ${pr_number} with ${label}`)
77+
78+
await github.rest.issues.addLabels({
79+
issue_number: pr_number,
80+
owner: context.repo.owner,
81+
repo: context.repo.repo,
82+
labels: [label]
83+
})
84+
85+
break
86+
}
87+
}

.github/workflows/record_pr.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Record PR number
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited]
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- uses: actions/checkout@v2
13+
- name: Save PR number
14+
run: |
15+
mkdir -p ./pr
16+
echo ${{ github.event.number }} > ./pr/number
17+
echo "${{ github.event.pull_request.title }}" > ./pr/title
18+
- uses: actions/upload-artifact@v2
19+
with:
20+
name: pr
21+
path: pr/

0 commit comments

Comments
 (0)