From 105df556229e8d43108011e527a512fa7f30f4b3 Mon Sep 17 00:00:00 2001 From: mshddev Date: Fri, 27 Mar 2026 12:13:42 +0700 Subject: [PATCH 1/3] Add changelog-based release workflow --- .github/workflows/release.yml | 17 +++++++- AGENTS.md | 6 +++ CHANGELOG.md | 27 ++++++++++++ CONTRIBUTING.md | 65 +++++++++++++++++++++++++++++ README.md | 1 + scripts/changelog-release-notes.sh | 67 ++++++++++++++++++++++++++++++ 6 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md create mode 100755 scripts/changelog-release-notes.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5075155..a0698df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,6 +77,9 @@ jobs: needs: build runs-on: ubuntu-latest steps: + - name: Check out repository + uses: actions/checkout@v6 + - name: Download release archives uses: actions/download-artifact@v8 with: @@ -90,6 +93,13 @@ jobs: set -euo pipefail shasum -a 256 *.tar.gz > checksums.txt + - name: Prepare release notes + env: + VERSION: ${{ github.ref_name }} + run: | + set -euo pipefail + ./scripts/changelog-release-notes.sh "$VERSION" > dist/release-notes.md + - name: Create or update GitHub release env: GITHUB_TOKEN: ${{ github.token }} @@ -104,11 +114,16 @@ jobs: fi if gh release view "$VERSION" >/dev/null 2>&1; then + gh release edit "$VERSION" \ + --title "$VERSION" \ + --notes-file dist/release-notes.md \ + "${prerelease_args[@]}" gh release upload "$VERSION" dist/*.tar.gz dist/checksums.txt --clobber else gh release create "$VERSION" \ --verify-tag \ - --generate-notes \ + --title "$VERSION" \ + --notes-file dist/release-notes.md \ "${prerelease_args[@]}" \ dist/*.tar.gz \ dist/checksums.txt diff --git a/AGENTS.md b/AGENTS.md index b72ed5a..6f83291 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,3 +11,9 @@ The project currently targets: - Follow `CONTRIBUTING.md` for repository workflow, local environment setup, and testing policy. - Follow `tests/README.md` for end-to-end test execution and reporting. + +# Release Requests + +- If the user asks to release and does not provide a version, ask for the exact release tag first, for example `v0.1.0` or `v0.1.0-rc.1`. +- After the version is known, follow the release runbook in `CONTRIBUTING.md` instead of inventing a separate flow. +- Treat `CHANGELOG.md` as the source of truth for release notes. Do not create or push a release tag unless the matching changelog section exists and is ready. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..65ca2c1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,27 @@ +# Changelog + +All notable user-facing changes to `sonacli` are documented in this file. + +`CHANGELOG.md` is the source of truth for GitHub release notes. Follow +[CONTRIBUTING.md](CONTRIBUTING.md) for when and how to update it. + +## [Unreleased] +- Nothing yet. + +## [v0.1.0-rc.1] - 2026-03-27 + +- Initial public pre-release of the `sonacli` CLI for SonarQube Community + Build `v25.x+`. +- Authentication setup and status commands for storing and validating + SonarQube access locally. +- Project and issue commands for listing projects, listing project issues, and + showing a single issue by key or SonarQube URL. +- Skill install and uninstall commands for Codex and Claude Code. +- Source-based CLI reference, contributor setup docs, local SonarQube + bootstrap helpers, and end-to-end test guidance. +- GitHub Actions CI, release automation, and release archives for Linux and + macOS. +- Security policy for vulnerability reporting and supported version guidance. + +[Unreleased]: https://github.com/mshddev/sonacli/compare/v0.1.0-rc.1...HEAD +[v0.1.0-rc.1]: https://github.com/mshddev/sonacli/releases/tag/v0.1.0-rc.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f85d9d9..64a2bcb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,3 +106,68 @@ The built binary is written to `./sonacli`. ## Workflow - Any behavior change must ship with unit coverage and matching end-to-end coverage: add a new E2E case for new behavior, and update existing E2E cases when behavior changes. - Follow `tests/README.md` for end-to-end test execution and reporting + +## Changelog + +`CHANGELOG.md` is the source of truth for user-facing release notes and the +body of each GitHub release. + +### When to update it + +Update `CHANGELOG.md` in the same change whenever you modify: + +- CLI behavior, flags, output, or configuration +- supported platforms, version support, install flow, or packaged artifacts +- security guidance or other release-facing project policy + +You can usually skip changelog updates for internal-only refactors, test-only +changes, and contributor workflow edits that do not affect shipped artifacts or +how users consume the project. + +### How to update it + +- Add concise bullets under `## [Unreleased]`. +- Keep entries focused on the user or maintainer-visible outcome, not the + implementation details. +- Replace `- Nothing yet.` when there is real release content. +- Do not create a tag unless the matching changelog entry already exists. + +### Release flow + +When preparing a release tag such as `v1.2.3` or `v1.2.3-rc.1`: + +1. Replace the `## [Unreleased]` heading with `## [] - YYYY-MM-DD`. +2. Insert a fresh `## [Unreleased]` section above it with `- Nothing yet.`. +3. Commit the changelog update before pushing the tag. +4. Push the tag only after the changelog contains that exact heading. + +The release workflow reads release notes from the matching section in +`CHANGELOG.md`. If the heading is missing or empty, the tagged GitHub release +job fails. + +### Release runbook + +Use this flow for a manual release and as the agent procedure for release +requests. + +1. Determine the exact release tag first, for example `v0.1.0` or + `v0.1.0-rc.1`. +2. Review `CHANGELOG.md` and make sure `## [Unreleased]` contains the release + notes to ship. If it still says `- Nothing yet.`, stop and write the release + notes before continuing. +3. Replace the `## [Unreleased]` heading with the final version heading + `## [] - YYYY-MM-DD`. +4. Insert a fresh `## [Unreleased]` section above it with `- Nothing yet.`. +5. Run the required validation for the release candidate. + At minimum: `make test` + For behavior changes: follow `tests/README.md` and run the affected E2E + coverage as well. +6. Commit the release preparation changes, including the changelog. +7. Create the git tag locally, for example `git tag v0.1.0`. +8. Push the branch and the tag, for example `git push origin main --tags`. +9. Monitor the GitHub Actions release workflow. It builds archives, extracts + release notes from `CHANGELOG.md`, and publishes the GitHub release. + +If the release workflow fails because the changelog section is missing or +empty, fix `CHANGELOG.md`, commit the correction, and rerun the release by +updating the release notes or pushing a corrected tag as appropriate. diff --git a/README.md b/README.md index e454f47..340d73a 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ sonacli issue show 'https://sonarqube.example.com/project/issues?id=my-project&i ## Documentation +- [CHANGELOG.md](CHANGELOG.md): user-facing release notes and release history - [docs/cli.md](docs/cli.md): source-derived command reference, config details, skill installation behavior, and versioning notes - [CONTRIBUTING.md](CONTRIBUTING.md): local environment setup, SonarQube bootstrap, and repository workflow - [tests/README.md](tests/README.md): end-to-end execution and reporting rules diff --git a/scripts/changelog-release-notes.sh b/scripts/changelog-release-notes.sh new file mode 100755 index 0000000..f6a1c8a --- /dev/null +++ b/scripts/changelog-release-notes.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +set -eu + +usage() { + cat <<'EOF' +Usage: + ./scripts/changelog-release-notes.sh [changelog-path] + +Extract the body of a versioned CHANGELOG section for use as release notes. +The version must match the changelog heading exactly, for example: + ## [v1.2.3] - 2026-03-27 +EOF +} + +version="${1:-}" +changelog_path="${2:-CHANGELOG.md}" + +if [ -z "$version" ]; then + usage >&2 + exit 1 +fi + +if [ ! -f "$changelog_path" ]; then + printf '%s\n' "Missing changelog file: $changelog_path" >&2 + exit 1 +fi + +awk -v version="$version" ' +BEGIN { + heading = "## [" version "]" + in_section = 0 + found = 0 + has_content = 0 +} +index($0, heading) == 1 { + suffix = substr($0, length(heading) + 1) + if (suffix == "" || suffix ~ /^ - /) { + in_section = 1 + found = 1 + next + } +} +in_section && /^## \[/ { + exit +} +in_section && /^\[[^]]+\]: / { + exit +} +in_section { + if (!has_content && $0 == "") { + next + } + has_content = 1 + print +} +END { + if (!found) { + printf "Release heading not found for %s in %s\n", version, FILENAME > "/dev/stderr" + exit 2 + } + if (!has_content) { + printf "Release section for %s is empty in %s\n", version, FILENAME > "/dev/stderr" + exit 3 + } +} +' "$changelog_path" From 1a621f85c6e301a167ce9f01c93b872da62aa3b1 Mon Sep 17 00:00:00 2001 From: mshddev Date: Fri, 27 Mar 2026 12:28:10 +0700 Subject: [PATCH 2/3] Document protected main workflow --- AGENTS.md | 3 +++ CONTRIBUTING.md | 47 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6f83291..6b0df49 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,9 +11,12 @@ The project currently targets: - Follow `CONTRIBUTING.md` for repository workflow, local environment setup, and testing policy. - Follow `tests/README.md` for end-to-end test execution and reporting. +- `main` is protected. Create or switch to a non-`main` branch before making edits or commits. +- Do not push changes directly to `main`; use a branch and merge through the normal review flow. # Release Requests - If the user asks to release and does not provide a version, ask for the exact release tag first, for example `v0.1.0` or `v0.1.0-rc.1`. - After the version is known, follow the release runbook in `CONTRIBUTING.md` instead of inventing a separate flow. - Treat `CHANGELOG.md` as the source of truth for release notes. Do not create or push a release tag unless the matching changelog section exists and is ready. +- Prepare release changes on a non-`main` branch, merge that branch to `main`, then create and push the tag from the merged `main` commit. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64a2bcb..b226f90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,6 +107,22 @@ The built binary is written to `./sonacli`. - Any behavior change must ship with unit coverage and matching end-to-end coverage: add a new E2E case for new behavior, and update existing E2E cases when behavior changes. - Follow `tests/README.md` for end-to-end test execution and reporting +## Branch workflow + +`main` is protected. Do not commit directly on `main` and do not push changes +straight to `main`. + +Before making changes: + +```sh +git switch main +git pull --ff-only origin main +git switch -c +``` + +Do all commits on the topic branch. Push the branch and merge through a pull +request instead of direct pushes to `main`. + ## Changelog `CHANGELOG.md` is the source of truth for user-facing release notes and the @@ -136,10 +152,12 @@ how users consume the project. When preparing a release tag such as `v1.2.3` or `v1.2.3-rc.1`: -1. Replace the `## [Unreleased]` heading with `## [] - YYYY-MM-DD`. -2. Insert a fresh `## [Unreleased]` section above it with `- Nothing yet.`. -3. Commit the changelog update before pushing the tag. -4. Push the tag only after the changelog contains that exact heading. +1. Prepare the release changes on a non-`main` branch. +2. Replace the `## [Unreleased]` heading with `## [] - YYYY-MM-DD`. +3. Insert a fresh `## [Unreleased]` section above it with `- Nothing yet.`. +4. Merge the release-preparation branch to `main`. +5. Create and push the tag from the merged `main` commit only after the + changelog contains that exact heading. The release workflow reads release notes from the matching section in `CHANGELOG.md`. If the heading is missing or empty, the tagged GitHub release @@ -152,20 +170,25 @@ requests. 1. Determine the exact release tag first, for example `v0.1.0` or `v0.1.0-rc.1`. -2. Review `CHANGELOG.md` and make sure `## [Unreleased]` contains the release +2. Start from an up-to-date `main` and create a dedicated release branch. +3. Review `CHANGELOG.md` and make sure `## [Unreleased]` contains the release notes to ship. If it still says `- Nothing yet.`, stop and write the release notes before continuing. -3. Replace the `## [Unreleased]` heading with the final version heading +4. Replace the `## [Unreleased]` heading with the final version heading `## [] - YYYY-MM-DD`. -4. Insert a fresh `## [Unreleased]` section above it with `- Nothing yet.`. -5. Run the required validation for the release candidate. +5. Insert a fresh `## [Unreleased]` section above it with `- Nothing yet.`. +6. Run the required validation for the release candidate. At minimum: `make test` For behavior changes: follow `tests/README.md` and run the affected E2E coverage as well. -6. Commit the release preparation changes, including the changelog. -7. Create the git tag locally, for example `git tag v0.1.0`. -8. Push the branch and the tag, for example `git push origin main --tags`. -9. Monitor the GitHub Actions release workflow. It builds archives, extracts +7. Commit the release preparation changes, including the changelog, on the + release branch. +8. Push the release branch and open or update the pull request. +9. Merge the release branch to `main`. +10. Update local `main` to the merged commit. +11. Create the git tag locally from `main`, for example `git tag v0.1.0`. +12. Push only the tag, for example `git push origin v0.1.0`. +13. Monitor the GitHub Actions release workflow. It builds archives, extracts release notes from `CHANGELOG.md`, and publishes the GitHub release. If the release workflow fails because the changelog section is missing or From 240eea113639d63c126e4d1820ec0b0b64a7e33e Mon Sep 17 00:00:00 2001 From: mshddev Date: Fri, 27 Mar 2026 12:42:04 +0700 Subject: [PATCH 3/3] Prepare v0.1.0-rc.2 release --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65ca2c1..9edabc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ All notable user-facing changes to `sonacli` are documented in this file. ## [Unreleased] - Nothing yet. +## [v0.1.0-rc.2] - 2026-03-27 + +- Added a project changelog and documented release history for `sonacli`. +- GitHub releases now publish notes from `CHANGELOG.md` instead of generated + release notes. +- Documented the protected-`main` branch workflow and the release runbook for + contributors and agents. + ## [v0.1.0-rc.1] - 2026-03-27 - Initial public pre-release of the `sonacli` CLI for SonarQube Community @@ -23,5 +31,6 @@ All notable user-facing changes to `sonacli` are documented in this file. macOS. - Security policy for vulnerability reporting and supported version guidance. -[Unreleased]: https://github.com/mshddev/sonacli/compare/v0.1.0-rc.1...HEAD +[Unreleased]: https://github.com/mshddev/sonacli/compare/v0.1.0-rc.2...HEAD +[v0.1.0-rc.2]: https://github.com/mshddev/sonacli/releases/tag/v0.1.0-rc.2 [v0.1.0-rc.1]: https://github.com/mshddev/sonacli/releases/tag/v0.1.0-rc.1