Skip to content

Commit a15f0c1

Browse files
authored
ci(labels): automatic PR label management (#727)
1 parent 12c3cc4 commit a15f0c1

File tree

4 files changed

+151
-5
lines changed

4 files changed

+151
-5
lines changed

.github/pull_request_template.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
Please check the boxes below to confirm that you have followed the
77
required guidelines for contributions:
88

9+
- [ ] All commits are [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification).
10+
- [ ] The title for this pull request is the same as the first commit's message and it follows the [conventional commits specification](https://www.conventionalcommits.org). See commit history for examples.
911
- [ ] If this pull request includes code changes, they were all properly tested. Automated tests were also included where possible.
1012
- [ ] If applicable, this pull request includes the relevant documentation for this change.
1113
- [ ] If this pull request is related to an existing issue, you can use the same description below but in any case include a [link to the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue) like `Fixes #ISSUE_NUMBER.` or `Closes #ISSUE_NUMBER.`.
12-
- [ ] All the commits in this pull request were squashed into a single commit. That commit is [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification).
1314

1415
<!-- prettier-ignore-start -->
1516
<!-- markdownlint-disable-next-line MD041 -->

.github/release.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
changelog:
2+
exclude:
3+
labels:
4+
- no-release-notes
5+
categories:
6+
- title: "New Features :sparkles:"
7+
labels:
8+
- feat
9+
- title: "Bug Fixes :bug:"
10+
labels:
11+
- fix
12+
- title: "Dependency Upgrades :package:"
13+
labels:
14+
- dependencies
15+
- title: "Other Changes :broom:"
16+
labels:
17+
- "*"

.github/workflows/check-pr.yml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
name: "Check PR"
3+
on: pull_request
4+
5+
permissions:
6+
actions: write
7+
contents: write
8+
pull-requests: write
9+
10+
jobs:
11+
check:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Check commits
15+
shell: bash
16+
run: |
17+
# Check the commits
18+
commits_json=$(curl -fsSL -H "Authorization: token ${GITHUB_TOKEN}" "${PR_COMMITS_URL}")
19+
echo -n 'Commits: '
20+
echo "${commits_json}" | jq '.'
21+
commit_count="$(echo "${commits_json}" | jq -r 'length')"
22+
# Check single commit
23+
if [ "${commit_count}" -eq 1 ] ; then
24+
commit_title="$(echo "${commits_json}" | jq -r '.[0].commit.message' | head -n 1)"
25+
echo "Commit title: ${commit_title}"
26+
if [[ "${commit_title}" != "${PR_TITLE}" ]] ; then
27+
>&2 echo 'Single commit must have same title as PR.'
28+
exit 1
29+
fi
30+
fi
31+
# Check that all commits are signed
32+
for ((i = 0 ; i < commit_count ; i++ )); do
33+
if [[ "$(echo "${commits_json}" | jq -r ".[${i}].commit.verification.verified")" == 'false' ]] ; then
34+
>&2 echo "Commit $(echo "${commits_json}" | jq -r ".[${i}].sha") must be signed."
35+
exit 1
36+
fi
37+
done
38+
env:
39+
PR_TITLE: ${{github.event.pull_request.title}}
40+
PR_COMMITS_URL: ${{github.event.pull_request.commits_url}}
41+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
42+
- name: Update PR labels
43+
shell: bash
44+
run: |
45+
# Check PR title is a conventional commit message
46+
regexp='^((build|chore|ci|docs|feat|fix|perf|refactor|style|test)(\([a-zA-Z0-9\-]+\))?)!?: .*$'
47+
if ! [[ "${PR_TITLE}" =~ ${regexp} ]] ; then
48+
>&2 echo 'Non conventional PR title.'
49+
exit 1
50+
fi
51+
scoped_type="${BASH_REMATCH[1]}"
52+
type="${BASH_REMATCH[2]}"
53+
add_labels=()
54+
remove_labels=()
55+
# Remove the labels we manage
56+
for label in build chore ci docs feat fix perf refactor test style ; do
57+
if [[ "${label}" == "${type}" ]]; then
58+
echo "Label to add: ${label}"
59+
# shellcheck disable=SC2076
60+
if [[ "${PR_LABELS}" =~ "\"${label}\"" ]] ; then
61+
echo "Label ${label} already present"
62+
else
63+
add_labels+=("${label}")
64+
fi
65+
else
66+
echo "Label to remove: ${label}"
67+
# shellcheck disable=SC2076
68+
if [[ "${PR_LABELS}" =~ "\"${label}\"" ]] ; then
69+
remove_labels+=("${label}")
70+
else
71+
echo "Label ${label} not present"
72+
fi
73+
fi
74+
done
75+
# If scope is dependency-related, add 'dependencies' label
76+
regexp2='^[a-zA-Z0-9]+\([a-zA-Z0-9\-]*deps\)$'
77+
if [[ "${scoped_type}" =~ ${regexp2} ]] ; then
78+
echo "Label to add: dependencies"
79+
# shellcheck disable=SC2076
80+
if [[ "${PR_LABELS}" =~ "\"dependencies\"" ]] ; then
81+
echo "Label dependencies already present"
82+
else
83+
add_labels+=('dependencies')
84+
fi
85+
# otherwise do not remove it since we are not the only ones to manage this label (e.g. dependabot)
86+
fi
87+
# For certain types/scopes, add 'no-release-notes' label
88+
if [[ "${type}" == 'chore' \
89+
|| "${type}" == 'ci' \
90+
|| "${type}" == 'docs' \
91+
|| "${type}" == 'style' \
92+
|| "${type}" == 'test' ]] ; then
93+
echo "Label to add: no-release-notes"
94+
# shellcheck disable=SC2076
95+
if [[ "${PR_LABELS}" =~ "\"no-release-notes\"" ]] ; then
96+
echo "Label no-release-notes already present"
97+
else
98+
add_labels+=('no-release-notes')
99+
fi
100+
else
101+
echo "Label to remove: no-release-notes"
102+
# shellcheck disable=SC2076
103+
if [[ "${PR_LABELS}" =~ "\"no-release-notes\"" ]] ; then
104+
remove_labels+=('no-release-notes')
105+
else
106+
echo "Label no-release-notes not present"
107+
fi
108+
fi
109+
# Update the labels
110+
function join_by { local IFS="$1"; shift; echo "$*"; }
111+
if [ ${#add_labels[@]} -eq 0 ] && [ ${#remove_labels[@]} -eq 0 ]; then
112+
echo 'No label to change'
113+
elif [ ${#add_labels[@]} -eq 0 ]; then
114+
echo "Removing labels: $(join_by , "${remove_labels[@]}")"
115+
gh pr edit "${PR_URL}" --remove-label "$(join_by , "${remove_labels[@]}")"
116+
elif [ ${#remove_labels[@]} -eq 0 ]; then
117+
echo "Adding labels: $(join_by , "${add_labels[@]}")"
118+
gh pr edit "${PR_URL}" --add-label "$(join_by , "${add_labels[@]}")"
119+
else
120+
echo "Adding labels: $(join_by , "${add_labels[@]}")"
121+
echo "Removing labels: $(join_by , "${remove_labels[@]}")"
122+
gh pr edit "${PR_URL}" --add-label "$(join_by , "${add_labels[@]}")" --remove-label "$(join_by , "${remove_labels[@]}")"
123+
fi
124+
env:
125+
PR_TITLE: ${{github.event.pull_request.title}}
126+
PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
127+
PR_URL: ${{github.event.pull_request.html_url}}
128+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

CONTRIBUTING.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ request. We then kindly ask that:
1919
- all code changes must be tested manually and automated tests should
2020
be included when possible.
2121
- all necessary documentation should be included as well.
22-
- commit messages must follow the [conventional commits specification](https://www.conventionalcommits.org).
22+
- the first commit's message on a pull request must follow the
23+
[conventional commits specification](https://www.conventionalcommits.org).
2324
See commit history for examples.
24-
- commits on a single pull request must be squashed together to keep
25-
make reviews easier.
26-
- commits must be signed (this is supported by most Git clients as
25+
- all commits must be signed (this is supported by most Git clients as
2726
well as the GitHub web UI, see link below).
2827

2928
## Resources
3029

3130
- [Managing commit signature verification](https://docs.github.com/en/authentication/managing-commit-signature-verification)
3231
- [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)
32+
- [Commit Message Format](https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md)

0 commit comments

Comments
 (0)