From 331ad1fcabdaf7d953b4df9094b62dabc55362af Mon Sep 17 00:00:00 2001 From: Afeef Ghannam Date: Thu, 17 Sep 2026 09:32:22 +0200 Subject: [PATCH 1/2] Let the changelog check recognise a release pull request --- .github/workflows/test_changelog.yml | 18 ++++++++++++++++++ RELEASE.md | 2 ++ .../fragments/release_pr_changelog_check.yml | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 changelogs/fragments/release_pr_changelog_check.yml diff --git a/.github/workflows/test_changelog.yml b/.github/workflows/test_changelog.yml index ab445dd9..506eeef0 100644 --- a/.github/workflows/test_changelog.yml +++ b/.github/workflows/test_changelog.yml @@ -50,6 +50,24 @@ jobs: exit 0 fi git fetch --no-tags origin "$BASE_REF" + + # A release pull request consumes the fragments instead of adding one: + # antsibull-changelog folds them into changelogs/changelog.yaml, writes + # CHANGELOG.md and deletes them. Recognise that shape, otherwise a release + # could never be merged. See RELEASE.md. + outside=$(git diff --name-only "origin/$BASE_REF...HEAD" \ + | grep -vE '^(CHANGELOG\.md|changelogs/changelog\.yaml|galaxy\.yml|changelogs/fragments/)' \ + || true) + folded=$(git diff --name-only --diff-filter=AM \ + "origin/$BASE_REF...HEAD" -- changelogs/changelog.yaml) + consumed=$(git diff --name-only --diff-filter=D \ + "origin/$BASE_REF...HEAD" -- changelogs/fragments/ \ + | grep -v '^changelogs/fragments/\.keep$' || true) + if [ -z "$outside" ] && [ -n "$folded" ] && [ -n "$consumed" ]; then + echo "Release pull request, the fragments are folded into changelogs/changelog.yaml." + exit 0 + fi + added=$(git diff --name-only --diff-filter=A \ "origin/$BASE_REF...HEAD" -- changelogs/fragments/ \ | grep -v '^changelogs/fragments/\.keep$' || true) diff --git a/RELEASE.md b/RELEASE.md index e1f368ee..21348730 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -42,6 +42,8 @@ antsibull-changelog release --version Steps 1 to 3 change files in the repository. `main` requires an approving review, so open a pull request with the version bump and the generated changelog. Do not push this directly, even though repository admins are technically able to. +The `changelog_fragment` check would normally reject that pull request, because a release consumes the fragments instead of adding one. It recognises a release by its shape, a folded `changelogs/changelog.yaml` together with deleted fragments and nothing else, and skips itself. Keep the release pull request to exactly those files, anything else makes the check ask for a fragment again. + ## 4. Tag the version Tag the merge commit on `main`. No `v` prefix, semantic versioning. diff --git a/changelogs/fragments/release_pr_changelog_check.yml b/changelogs/fragments/release_pr_changelog_check.yml new file mode 100644 index 00000000..7395221d --- /dev/null +++ b/changelogs/fragments/release_pr_changelog_check.yml @@ -0,0 +1,4 @@ +trivial: + - The ``changelog_fragment`` check no longer rejects a release pull request. A release folds + the fragments into ``changelogs/changelog.yaml`` and deletes them instead of adding one, so + the check recognises that shape and skips itself. From 8a8849ce84781320a97231872caedf4a2c979a11 Mon Sep 17 00:00:00 2001 From: Afeef Ghannam Date: Thu, 17 Sep 2026 09:39:54 +0200 Subject: [PATCH 2/2] Start the release procedure with a fresh clone --- RELEASE.md | 42 ++++++++++++------- .../fragments/release_pr_changelog_check.yml | 2 + 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 21348730..118bf2c2 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -12,15 +12,27 @@ How to build, tag and publish a new version of this collection. Maintainers only ``` * The repository or organization secret `GALAXY_API_KEY`, holding an API token of an account that owns the `netways` namespace on Ansible Galaxy. Tokens are created in the account settings on . -* Permission to run workflows in this repository, or the token itself if you intend to publish from your own machine. See step 6. +* Permission to run workflows in this repository, or the token itself if you intend to publish from your own machine. See step 7. Galaxy versions are **immutable**. Once a version is uploaded it cannot be replaced or removed, only superseded by a higher version. -## 1. Set the version +## 1. Clone into a fresh directory + +`git clone` into a directory that does not exist yet, then branch off `main`: + +```bash +git clone git@github.com:NETWAYS/ansible-collection-elasticstack.git release_ +cd release_ +git switch -c release_ +``` + +Do the whole release from that clone. An everyday working copy carries untracked leftovers, and two steps below pick them up: `antsibull-changelog release` folds every file under `changelogs/fragments/` into the changelog, and `ansible-galaxy collection build` packs the working directory rather than the git tree. + +## 2. Set the version Set `version:` in **galaxy.yml** to the version you are about to release. Semantic versioning, no `v` prefix. -## 2. Write the release summary +## 3. Write the release summary This becomes the introductory paragraph of the release in the changelog. @@ -31,7 +43,7 @@ release_summary: | Summary text for this release, for example "Bugfix release". ``` -## 3. Generate the changelog +## 4. Generate the changelog Every pull request brings its own fragment under `changelogs/fragments/`. This folds all of them into `changelogs/changelog.yaml`, renders `CHANGELOG.md` and deletes the fragments. @@ -40,11 +52,11 @@ antsibull-changelog lint antsibull-changelog release --version ``` -Steps 1 to 3 change files in the repository. `main` requires an approving review, so open a pull request with the version bump and the generated changelog. Do not push this directly, even though repository admins are technically able to. +Steps 2 to 4 change files in the repository. `main` requires an approving review, so open a pull request with the version bump and the generated changelog. Do not push this directly, even though repository admins are technically able to. The `changelog_fragment` check would normally reject that pull request, because a release consumes the fragments instead of adding one. It recognises a release by its shape, a folded `changelogs/changelog.yaml` together with deleted fragments and nothing else, and skips itself. Keep the release pull request to exactly those files, anything else makes the check ask for a fragment again. -## 4. Tag the version +## 5. Tag the version Tag the merge commit on `main`. No `v` prefix, semantic versioning. @@ -55,34 +67,34 @@ git tag -a -m "" git push origin ``` -If you cannot push tags, skip this and let GitHub create the tag in step 5 instead. +If you cannot push tags, skip this and let GitHub create the tag in step 6 instead. -## 5. Create the release on GitHub +## 6. Create the release on GitHub [Draft a new release](https://github.com/NETWAYS/ansible-collection-elasticstack/releases/new): -* choose the tag from step 4, or enter the version and let GitHub create the tag now +* choose the tag from step 5, or enter the version and let GitHub create the tag now * use the version as the title * paste this version's section from `CHANGELOG.md` as the release notes * credit people by name where a change came from outside: the author of the pull request, and the reporter of an issue where the report was the contribution. `git shortlog -sn HEAD` lists everyone with their number of commits, folded per person through [.mailmap](.mailmap) -The release has to exist before step 6, because the archive is uploaded to it. +The release has to exist before step 7, because the archive is uploaded to it. -## 6. Publish to Ansible Galaxy +## 7. Publish to Ansible Galaxy **Actions** -> **publish** -> **Run workflow**, then enter the tag. -The workflow checks out that tag, builds the collection, publishes it to Galaxy and attaches the archive to the release from step 5. It is triggered manually and never automatically, so that a tag can be inspected before an immutable version reaches Galaxy. +The workflow checks out that tag, builds the collection, publishes it to Galaxy and attaches the archive to the release from step 6. It is triggered manually and never automatically, so that a tag can be inspected before an immutable version reaches Galaxy. Afterwards confirm on that the version arrived. Publishing can print errors and still have worked. ### If you cannot run workflows -Do the same from your own machine. **Clone the tag into a fresh directory first.** `ansible-galaxy collection build` packs the working directory and not the git tree, so untracked local files end up in the archive unless `build_ignore` happens to cover them. +Do the same from your own machine, from a fresh clone of the tag and not from the clone of step 1, which by now carries the release branch and whatever the earlier steps left behind. ```bash -git clone --branch git@github.com:NETWAYS/ansible-collection-elasticstack.git release_ -cd release_ +git clone --branch git@github.com:NETWAYS/ansible-collection-elasticstack.git publish_ +cd publish_ ansible-galaxy collection build -vvv ansible-galaxy collection publish --token netways-elasticstack-.tar.gz ``` diff --git a/changelogs/fragments/release_pr_changelog_check.yml b/changelogs/fragments/release_pr_changelog_check.yml index 7395221d..0287c1fe 100644 --- a/changelogs/fragments/release_pr_changelog_check.yml +++ b/changelogs/fragments/release_pr_changelog_check.yml @@ -2,3 +2,5 @@ trivial: - The ``changelog_fragment`` check no longer rejects a release pull request. A release folds the fragments into ``changelogs/changelog.yaml`` and deletes them instead of adding one, so the check recognises that shape and skips itself. + - RELEASE.md starts with cloning into a fresh directory now, because the changelog generation + and the archive build both read the working directory and would pick up local leftovers.