-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
👷 Require a changelog entry when a package's lib changes
#2596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dylanpulver
wants to merge
2
commits into
cfug:main
Choose a base branch
from
dylanpulver:ci/require-changelog-entry
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+154
−0
Open
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # Require a changelog entry whenever a pull request changes a package's `lib/`. | ||
| name: Check changelog entry | ||
|
|
||
| # The workflow deliberately runs for every pull request instead of filtering on | ||
| # paths, so that the check always reports a result and can be made required. | ||
| # `labeled` and `unlabeled` are included so that adding or removing the | ||
| # `skip-changelog` label re-evaluates the pull request. | ||
| on: | ||
| pull_request: | ||
| types: [ opened, reopened, synchronize, labeled, unlabeled ] | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.event.pull_request.number }} | ||
| cancel-in-progress: true | ||
|
|
||
| # Disable permissions for all of the available permissions | ||
| permissions: {} | ||
|
|
||
| jobs: | ||
| verify_changelog: | ||
| name: Verify changelog entries | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
| # The whole history is needed to compare the pull request with its | ||
| # base, `scripts` is the only directory the check itself reads. | ||
| fetch-depth: 0 | ||
| sparse-checkout: scripts | ||
| - name: Check for changelog entries | ||
| env: | ||
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | ||
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||
| PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} | ||
| SKIP_CHANGELOG_LABEL: skip-changelog | ||
| run: ./scripts/check_changelog_entry.sh | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # Fails when a change touches the `lib/` directory of a package that keeps a | ||
| # `CHANGELOG.md` without adding anything to that `CHANGELOG.md`. | ||
| # | ||
| # Usage: | ||
| # scripts/check_changelog_entry.sh [<base-ref> <head-ref>] | ||
| # | ||
| # Without arguments the range comes from `BASE_SHA` and `HEAD_SHA`, and falls | ||
| # back to the parents of the pull request merge commit that `actions/checkout` | ||
| # leaves at `HEAD`. | ||
| # | ||
| # Environment: | ||
| # BASE_SHA Base commit of the pull request. | ||
| # HEAD_SHA Head commit of the pull request. | ||
| # PR_LABELS JSON array of the pull request label names. | ||
| # SKIP_CHANGELOG_LABEL Label that waives the requirement. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| SKIP_LABEL="${SKIP_CHANGELOG_LABEL:-skip-changelog}" | ||
|
|
||
| resolve_commit() { | ||
| local ref="${1:-}" | ||
| [[ -n "$ref" ]] || return 1 | ||
| git rev-parse --verify --quiet "${ref}^{commit}" 2>/dev/null | ||
| } | ||
|
|
||
| if [[ "$#" -eq 2 ]]; then | ||
| base="$(resolve_commit "$1" || true)" | ||
| head="$(resolve_commit "$2" || true)" | ||
| elif [[ "$#" -eq 0 ]]; then | ||
| base="$(resolve_commit "${BASE_SHA:-}" || true)" | ||
| head="$(resolve_commit "${HEAD_SHA:-}" || true)" | ||
| if [[ -z "$base" || -z "$head" ]]; then | ||
| # `actions/checkout` checks out the merge commit for pull requests, whose | ||
| # first parent is the base branch and second parent is the pull request. | ||
| base="$(resolve_commit 'HEAD^1' || true)" | ||
| head="$(resolve_commit 'HEAD^2' || true)" | ||
| fi | ||
| else | ||
| echo "Usage: $0 [<base-ref> <head-ref>]" >&2 | ||
| exit 2 | ||
| fi | ||
|
|
||
| if [[ -z "$base" || -z "$head" ]]; then | ||
| echo "::error::Cannot determine which commits to compare." >&2 | ||
| exit 2 | ||
| fi | ||
|
|
||
| labels="${PR_LABELS:-[]}" | ||
| if jq -e --arg label "$SKIP_LABEL" 'any(.[]; . == $label)' <<< "$labels" > /dev/null 2>&1; then | ||
| echo "The '${SKIP_LABEL}' label is applied, so no changelog entry is required." | ||
| exit 0 | ||
| fi | ||
|
|
||
| declare -A changed_packages=() | ||
| declare -A changelog_additions=() | ||
|
|
||
| # `core.quotePath=false` keeps non-ASCII paths readable instead of escaped. | ||
| diff_stat="$(git -c core.quotePath=false diff --numstat --no-renames "${base}...${head}")" | ||
|
|
||
| while read -r added _deleted path; do | ||
| [[ -n "${path:-}" ]] || continue | ||
| case "$path" in | ||
| */lib/*) | ||
| changed_packages["${path%%/lib/*}"]=1 | ||
| ;; | ||
| */CHANGELOG.md) | ||
| # A changelog that only loses lines does not describe a new change. | ||
| if [[ "$added" != "0" ]]; then | ||
| changelog_additions["${path%/CHANGELOG.md}"]=1 | ||
| fi | ||
| ;; | ||
| esac | ||
| done <<< "$diff_stat" | ||
|
|
||
| missing=() | ||
| for package in "${!changed_packages[@]}"; do | ||
| # Packages without a changelog (examples, shared test helpers) are exempt, | ||
| # because they are not published to pub.dev. | ||
| if ! git cat-file -e "${head}:${package}/CHANGELOG.md" 2> /dev/null; then | ||
| continue | ||
| fi | ||
| if [[ -z "${changelog_additions[$package]:-}" ]]; then | ||
| missing+=("$package") | ||
| fi | ||
| done | ||
|
|
||
| if [[ "${#missing[@]}" -eq 0 ]]; then | ||
| echo "Every package with a modified 'lib/' also has a changelog entry." | ||
| exit 0 | ||
| fi | ||
|
|
||
| while IFS= read -r package; do | ||
| echo "::error::${package}/lib was modified without adding an entry to ${package}/CHANGELOG.md." | ||
| done < <(printf '%s\n' "${missing[@]}" | sort) | ||
|
|
||
| cat >&2 << EOF | ||
|
|
||
| Add one bullet per change under the '## Unreleased' section of the changelog | ||
| of every package listed above, written for the people who use the package. | ||
| Do not bump version numbers, releases are handled by maintainers. | ||
|
|
||
| If the change genuinely needs no entry, a maintainer can apply the | ||
| '${SKIP_LABEL}' label to this pull request and the check will pass. | ||
| EOF | ||
|
|
||
| exit 1 |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would a path glob filter be more effective here?