Skip to content

Commit 19a2479

Browse files
authored
workflow and actions for automatically labelling PRs based on changelog fragments (#165)
* First shot at splitting off evaluator * Apply 'prettier', because someone thought it was worth it
1 parent 7c09c8f commit 19a2479

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
name: Changelog based PR evaluator
3+
author: Mark Chappell (tremble)
4+
branding:
5+
icon: git-branch
6+
color: gray-dark
7+
description: |
8+
This action evaluates the contents of changelog fragments in "changelogs/fragments/" to assess
9+
which branches it may be appropriate to backport a change to.
10+
11+
A PR is evaluated as needing a "major release" if it includes at least one of "major_changes",
12+
"breaking_changes", or "removed_features".
13+
14+
A PR is evaluated as needing a "minor release" if it includes at least one of "minor_changes" or
15+
"deprecated_features".
16+
17+
A PR is evaluated as being a "bugfix" PR if it includes at least one of "bugfixes" or
18+
"security_fixes".
19+
20+
The output values of this action are "bash-ian" booleans ("0" == True, anything else == False)
21+
22+
outputs:
23+
major_release:
24+
description: Whether the changelogs indicate that a major release would be needed.
25+
value: ${{ steps.evaluate.outputs.major }}
26+
minor_release:
27+
description: Whether the changelogs indicate that a minor release would be needed.
28+
value: ${{ steps.evaluate.outputs.minor }}
29+
bugfix_release:
30+
description: Whether the changelogs indicate that a the PR includes bugfixes.
31+
value: ${{ steps.evaluate.outputs.bugfix }}
32+
33+
runs:
34+
using: composite
35+
steps:
36+
- uses: actions/checkout@v2
37+
id: checkout
38+
- name: Fetch change types from changelog fragments
39+
id: evaluate
40+
shell: bash {0}
41+
run: |
42+
gh pr -R "${GITHUB_REPOSITORY}" diff "${{ github.event.pull_request.number }}" --name-only | \
43+
grep -E '^changelogs/fragments/' | \
44+
while read -r line
45+
do cat "${line}" | \
46+
python -c 'import sys, yaml; change = yaml.safe_load(sys.stdin.read()) ; print("\n".join(change.keys()));' \
47+
| tee -a all-changelog-types
48+
done
49+
# Beware, these are bash-ian booleans: "true == 0"
50+
grep -qE '(release_summary|breaking_changes|major_changes|removed_features)' all-changelog-types ; echo "major=${?}" >>${GITHUB_OUTPUT}
51+
grep -qE '(deprecated_features|minor_changes)' all-changelog-types ; echo "minor=${?}" >>${GITHUB_OUTPUT}
52+
grep -qE '(bugfixes|security_fixes)' all-changelog-types ; echo "bugfix=${?}" >>${GITHUB_OUTPUT}
53+
env:
54+
GH_TOKEN: ${{ github.token }}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
name: Apply backporting labels
3+
author: Mark Chappell (tremble)
4+
branding:
5+
icon: git-branch
6+
color: gray-dark
7+
description: |
8+
Applies backporting labels to a PR.
9+
10+
inputs:
11+
purge_labels:
12+
description: Whether to purge existing labels
13+
required: false
14+
default: false
15+
purge_prefix:
16+
description: The prefix used when purging labels
17+
required: false
18+
default: "backport-"
19+
label_to_add:
20+
description: The label(s) to be applied to the PR
21+
required: true
22+
23+
runs:
24+
using: composite
25+
steps:
26+
- name: Strip existing labels and add new labels
27+
id: label-strip-add
28+
# If breaking_changes or major_changes are pushed, then we always apply do_not_backport
29+
# and strip any existing backport-* labels
30+
if: ${{ inputs.purge_labels }}
31+
shell: bash {0}
32+
run: |
33+
# If this includes breaking changes, then set the do_not_backport label and remove all
34+
# labels starting with "backport-".
35+
CURRENT_LABELS=$(
36+
gh pr -R "${GITHUB_REPOSITORY}" view "${{ github.event.pull_request.number }}" \
37+
--json labels \
38+
--jq '[.labels[] | select(.name | startswith("${{ inputs.purge_prefix }}"))] | map(.name) | join(",")'
39+
)
40+
echo "Apply '${{ inputs.label_to_add }}' (remove '${CURRENT_LABELS}')"
41+
if [[ -n ${CURRENT_LABELS} ]] ; then
42+
gh pr -R "${GITHUB_REPOSITORY}" edit "${{ github.event.pull_request.number }}" \
43+
--add-label ${{ inputs.label_to_add }} \
44+
--remove-label "${CURRENT_LABELS}"
45+
else
46+
gh pr -R "${GITHUB_REPOSITORY}" edit "${{ github.event.pull_request.number }}" \
47+
--add-label ${{ inputs.label_to_add }}
48+
fi
49+
env:
50+
GH_TOKEN: ${{ github.token }}
51+
52+
- name: Apply labels
53+
id: label-add
54+
if: ${{ ! inputs.purge_labels }}
55+
shell: bash {0}
56+
run: |
57+
echo "Apply '${{ inputs.label_to_add }}'"
58+
gh pr -R "${GITHUB_REPOSITORY}" edit "${{ github.event.pull_request.number }}" \
59+
--add-label ${{ inputs.label_to_add }}
60+
env:
61+
GH_TOKEN: ${{ github.token }}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
name: Apply labels for backporting
3+
4+
on:
5+
workflow_call:
6+
inputs:
7+
label_major_release:
8+
default: "do_not_backport"
9+
required: false
10+
type: string
11+
description: |
12+
The label to apply if the PR includes a change that would necessitate a major release.
13+
label_minor_release:
14+
required: true
15+
type: string
16+
description: |
17+
The label to apply if the PR only includes a change that would necessitate a minor
18+
release. This will also be applied by default if the PR doesn't necessitate a major
19+
release.
20+
label_bugfix_release:
21+
required: true
22+
type: string
23+
description: |
24+
The label to apply if the PR only includes a bugfix or security release.
25+
label_skip:
26+
default: "do_not_backport"
27+
required: false
28+
type: string
29+
description: |
30+
If this label has been applied, then the PR will not be re-assessed.
31+
label_mergeit:
32+
default: "mergeit"
33+
required: false
34+
type: string
35+
description: |
36+
Which label will be used to trigger labelling for minor/bugfix backporting.
37+
We look for major releases when a change is pushed, and minor/bugfixes when the PR
38+
has been approved for merging and the mergeit label has been applied to trigger
39+
the merge.
40+
41+
jobs:
42+
changelog-types:
43+
# We always skip if do_not_backport has previously been applied.
44+
# Otherwise, if someone applies 'mergeit', opens the PR, or pushes a new commit
45+
# we'll examine the contents of changelog fragments to try to guess the best backport strategy.
46+
if: ${{
47+
! contains(github.event.pull_request.labels.*.name, inputs.label_skip)
48+
&& (
49+
(github.event.action == 'labeled' && github.event.label.name == inputs.label_mergeit)
50+
|| (github.event.action == 'synchronize')
51+
|| (github.event.action == 'opened')
52+
)
53+
}}
54+
permissions:
55+
pull-requests: read
56+
runs-on: ubuntu-latest
57+
outputs:
58+
no_backport: ${{ steps.evaluate.outputs.major_release }}
59+
bugfix: ${{ steps.evaluate.outputs.bugfix_release }}
60+
minor_only: ${{ steps.evaluate.outputs.minor_release }}
61+
steps:
62+
- name: Evaluate change types
63+
id: evaluate
64+
uses: ansible-network/github_actions/.github/actions/changelog_evaluator@main
65+
66+
changelog-labeling:
67+
permissions:
68+
pull-requests: write
69+
runs-on: ubuntu-latest
70+
needs:
71+
- changelog-types
72+
steps:
73+
- name: Strip tags for backporting and apply do_not_backport
74+
id: no-backport
75+
# If breaking_changes or major_changes are pushed, then we always apply do_not_backport
76+
# and strip any existing backport-* labels
77+
if: ${{ needs.changelog-types.outputs.no_backport == '0' }}
78+
uses: ansible-network/github_actions/.github/actions/changelog_labeller@main
79+
with:
80+
purge_labels: true
81+
label_to_add: ${{ inputs.label_major_release }}
82+
83+
- name: Apply tag for backporting to at least the most recent major release
84+
id: minor-only
85+
if: ${{
86+
(github.event.action == 'labeled' && github.event.label.name == inputs.label_mergeit )
87+
&& ! ( needs.changelog-types.outputs.no_backport == '0' )
88+
&& (
89+
( needs.changelog-types.outputs.minor_only == '0' )
90+
|| ! (needs.changelog-types.outputs.bugfix == '0' )
91+
)
92+
}}
93+
uses: ansible-network/github_actions/.github/actions/changelog_labeller@main
94+
with:
95+
label_to_add: ${{ inputs.label_minor_release }}
96+
97+
- name: Apply tag for backporting to at least the two most recent major releases
98+
id: security-or-bugfix
99+
if: ${{
100+
(github.event.action == 'labeled' && github.event.label.name == inputs.label_mergeit )
101+
&& ! ( needs.changelog-types.outputs.no_backport == '0' )
102+
&& ! ( needs.changelog-types.outputs.minor_only == '0' )
103+
&& ( needs.changelog-types.outputs.bugfix == '0' )
104+
}}
105+
uses: ansible-network/github_actions/.github/actions/changelog_labeller@main
106+
with:
107+
label_to_add: ${{ inputs.label_minor_release }},${{ inputs.label_bugfix_release }}

0 commit comments

Comments
 (0)