Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 16 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 }}
Expand All @@ -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
Expand Down
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +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.
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 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.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
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.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
88 changes: 88 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,91 @@ 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

## 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 <branch-name>
```

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
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. Prepare the release changes on a non-`main` branch.
2. Replace the `## [Unreleased]` heading with `## [<tag>] - 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
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. 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.
4. Replace the `## [Unreleased]` heading with the final version heading
`## [<tag>] - YYYY-MM-DD`.
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.
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
empty, fix `CHANGELOG.md`, commit the correction, and rerun the release by
updating the release notes or pushing a corrected tag as appropriate.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 67 additions & 0 deletions scripts/changelog-release-notes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/sh

set -eu

usage() {
cat <<'EOF'
Usage:
./scripts/changelog-release-notes.sh <version> [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"