Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
First shot at splitting off evaluator
  • Loading branch information
tremble committed Jan 13, 2025
commit 210050f21d321ea7909f8ff9059b804eb1cde9bc
54 changes: 54 additions & 0 deletions .github/actions/changelog_evaluator/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
name: Changelog based PR evaluator
author: Mark Chappell (tremble)
branding:
icon: git-branch
color: gray-dark
description: |
This action evaluates the contents of changelog fragments in "changelogs/fragments/" to assess
which branches it may be appropriate to backport a change to.

A PR is evaluated as needing a "major release" if it includes at least one of "major_changes",
"breaking_changes", or "removed_features".

A PR is evaluated as needing a "minor release" if it includes at least one of "minor_changes" or
"deprecated_features".

A PR is evaluated as being a "bugfix" PR if it includes at least one of "bugfixes" or
"security_fixes".

The output values of this action are "bash-ian" booleans ("0" == True, anything else == False)

outputs:
major_release:
description: Whether the changelogs indicate that a major release would be needed.
value: ${{ steps.evaluate.outputs.major }}
minor_release:
description: Whether the changelogs indicate that a minor release would be needed.
value: ${{ steps.evaluate.outputs.minor }}
bugfix_release:
description: Whether the changelogs indicate that a the PR includes bugfixes.
value: ${{ steps.evaluate.outputs.bugfix }}

runs:
using: composite
steps:
- uses: actions/checkout@v2
id: checkout
- name: Fetch change types from changelog fragments
id: evaluate
shell: bash {0}
run: |
gh pr -R "${GITHUB_REPOSITORY}" diff "${{ github.event.pull_request.number }}" --name-only | \
grep -E '^changelogs/fragments/' | \
while read -r line
do cat "${line}" | \
python -c 'import sys, yaml; change = yaml.safe_load(sys.stdin.read()) ; print("\n".join(change.keys()));' \
| tee -a all-changelog-types
done
# Beware, these are bash-ian booleans: "true == 0"
grep -qE '(release_summary|breaking_changes|major_changes|removed_features)' all-changelog-types ; echo "major=${?}" >>${GITHUB_OUTPUT}
grep -qE '(deprecated_features|minor_changes)' all-changelog-types ; echo "minor=${?}" >>${GITHUB_OUTPUT}
grep -qE '(bugfixes|security_fixes)' all-changelog-types ; echo "bugfix=${?}" >>${GITHUB_OUTPUT}
env:
GH_TOKEN: ${{ github.token }}
61 changes: 61 additions & 0 deletions .github/actions/changelog_labeller/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: Apply backporting labels
author: Mark Chappell (tremble)
branding:
icon: git-branch
color: gray-dark
description: |
Applies backporting labels to a PR.

inputs:
purge_labels:
description: Whether to purge existing labels
required: false
default: false
purge_prefix:
description: The prefix used when purging labels
required: false
default: 'backport-'
label_to_add:
description: The label(s) to be applied to the PR
required: true

runs:
using: composite
steps:
- name: Strip existing labels and add new labels
id: label-strip-add
# If breaking_changes or major_changes are pushed, then we always apply do_not_backport
# and strip any existing backport-* labels
if: ${{ inputs.purge_labels }}
shell: bash {0}
run: |
# If this includes breaking changes, then set the do_not_backport label and remove all
# labels starting with "backport-".
CURRENT_LABELS=$(
gh pr -R "${GITHUB_REPOSITORY}" view "${{ github.event.pull_request.number }}" \
--json labels \
--jq '[.labels[] | select(.name | startswith("${{ inputs.purge_prefix }}"))] | map(.name) | join(",")'
)
echo "Apply '${{ inputs.label_to_add }}' (remove '${CURRENT_LABELS}')"
if [[ -n ${CURRENT_LABELS} ]] ; then
gh pr -R "${GITHUB_REPOSITORY}" edit "${{ github.event.pull_request.number }}" \
--add-label ${{ inputs.label_to_add }} \
--remove-label "${CURRENT_LABELS}"
else
gh pr -R "${GITHUB_REPOSITORY}" edit "${{ github.event.pull_request.number }}" \
--add-label ${{ inputs.label_to_add }}
fi
env:
GH_TOKEN: ${{ github.token }}

- name: Apply labels
id: label-add
if: ${{ ! inputs.purge_labels }}
shell: bash {0}
run: |
echo "Apply '${{ inputs.label_to_add }}'"
gh pr -R "${GITHUB_REPOSITORY}" edit "${{ github.event.pull_request.number }}" \
--add-label ${{ inputs.label_to_add }}
env:
GH_TOKEN: ${{ github.token }}
107 changes: 107 additions & 0 deletions .github/workflows/backport-labeller.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
name: Apply labels for backporting

on:
workflow_call:
inputs:
label_major_release:
default: 'do_not_backport'
required: false
type: string
description: |
The label to apply if the PR includes a change that would necessitate a major release.
label_minor_release:
required: true
type: string
description: |
The label to apply if the PR only includes a change that would necessitate a minor
release. This will also be applied by default if the PR doesn't necessitate a major
release.
label_bugfix_release:
required: true
type: string
description: |
The label to apply if the PR only includes a bugfix or security release.
label_skip:
default: 'do_not_backport'
required: false
type: string
description: |
If this label has been applied, then the PR will not be re-assessed.
label_mergeit:
default: 'mergeit'
required: false
type: string
description: |
Which label will be used to trigger labelling for minor/bugfix backporting.
We look for major releases when a change is pushed, and minor/bugfixes when the PR
has been approved for merging and the mergeit label has been applied to trigger
the merge.

jobs:
changelog-types:
# We always skip if do_not_backport has previously been applied.
# Otherwise, if someone applies 'mergeit', opens the PR, or pushes a new commit
# we'll examine the contents of changelog fragments to try to guess the best backport strategy.
if: ${{
! contains(github.event.pull_request.labels.*.name, inputs.label_skip)
&& (
(github.event.action == 'labeled' && github.event.label.name == inputs.label_mergeit)
|| (github.event.action == 'synchronize')
|| (github.event.action == 'opened')
)
}}
permissions:
pull-requests: read
runs-on: ubuntu-latest
outputs:
no_backport: ${{ steps.evaluate.outputs.major_release }}
bugfix: ${{ steps.evaluate.outputs.bugfix_release }}
minor_only: ${{ steps.evaluate.outputs.minor_release }}
steps:
- name: Evaluate change types
id: evaluate
uses: ansible-network/github_actions/.github/actions/changelog_evaluator@main

changelog-labeling:
permissions:
pull-requests: write
runs-on: ubuntu-latest
needs:
- changelog-types
steps:
- name: Strip tags for backporting and apply do_not_backport
id: no-backport
# If breaking_changes or major_changes are pushed, then we always apply do_not_backport
# and strip any existing backport-* labels
if: ${{ needs.changelog-types.outputs.no_backport == '0' }}
uses: ansible-network/github_actions/.github/actions/changelog_labeller@main
with:
purge_labels: true
label_to_add: ${{ inputs.label_major_release }}

- name: Apply tag for backporting to at least the most recent major release
id: minor-only
if: ${{
(github.event.action == 'labeled' && github.event.label.name == inputs.label_mergeit )
&& ! ( needs.changelog-types.outputs.no_backport == '0' )
&& (
( needs.changelog-types.outputs.minor_only == '0' )
|| ! (needs.changelog-types.outputs.bugfix == '0' )
)
}}
uses: ansible-network/github_actions/.github/actions/changelog_labeller@main
with:
label_to_add: ${{ inputs.label_minor_release }}

- name: Apply tag for backporting to at least the two most recent major releases
id: security-or-bugfix
if: ${{
(github.event.action == 'labeled' && github.event.label.name == inputs.label_mergeit )
&& ! ( needs.changelog-types.outputs.no_backport == '0' )
&& ! ( needs.changelog-types.outputs.minor_only == '0' )
&& ( needs.changelog-types.outputs.bugfix == '0' )
}}
uses: ansible-network/github_actions/.github/actions/changelog_labeller@main
with:
label_to_add: ${{ inputs.label_minor_release }},${{ inputs.label_bugfix_release }}