name: publish-release description: Automates RoEFactura releases by analyzing commits vs main, inferring semver bump, drafting CHANGELOG, then after a single user approval creates r/x.x.x, packs, pushes NuGet, and optionally tags/GitHub release. Use when the user asks to release, publish, bump version, push to NuGet, or cut a new release.
Publish RoEFactura Release (automated)
Overview
- Branch naming:
r/x.x.x(e.g.r/1.2.0) - Version source of truth:
<Version>inRoEFactura/RoEFactura.csproj - Packages output to:
nupkgs/ - CHANGELOG: Keep a Changelog with
## [Unreleased]at the top (CHANGELOG.md) - One user interaction only: show the approval block below; if the user approves (
yes), run the rest without further prompts.
Phase A — Automated analysis (read-only, no questions)
Run this phase fully before showing the approval prompt.
A1 — Preconditions (fail fast)
NUGET_API_KEYmust be set in the environment. If missing, stop immediately and tell the user toexport NUGET_API_KEY=.... Do not show the approval prompt until this is set.dotnetmust be available.
A2 — Current version
grep '<Version>' RoEFactura/RoEFactura.csproj
Parse MAJOR.MINOR.PATCH (strip any -local / pre-release suffix for bump math).
A3 — Commit range vs main
Record the branch being released:
SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
Update refs, then list everything not on upstream main:
git fetch origin main 2>/dev/null || true
git log origin/main..HEAD --oneline
git log origin/main..HEAD --no-merges --format='%s%n%b%n---'
git diff --stat origin/main...HEAD
If origin/main..HEAD is empty, stop: there is nothing to release from this branch relative to main (or explain if main is not the right base).
A4 — Semver bump rules (conventional commits)
Inspect subject lines and bodies of commits in origin/main..HEAD. Apply the highest matching rule:
| Priority | Signal | Bump |
|---|---|---|
| 1 | BREAKING CHANGE in body, or subject matches ^[a-z]+(\([^)]+\))?!: (e.g. feat(api)!:) | major |
| 2 | Subject starts with feat (feat: or feat(scope):) | minor |
| 3 | Everything else (fix, chore, docs, refactor, style, perf, test, …) | patch |
Compute NEW_VERSION from current MAJOR.MINOR.PATCH accordingly.
If the user explicitly stated a version or bump type in the same request, that overrides the table (still show it in the plan for transparency).
A5 — CHANGELOG draft
- Read
CHANGELOG.mdfrom## [Unreleased]until the next## [heading. - Reuse those bullets under the correct
### Added/### Changed/### Fixedheadings when possible. - For commits not yet reflected, add concise bullets:
feat→ usually### Addedor### Changedfix→### Fixeddocs/chore/ internal-only →### Changedor omit if not user-facing
- If nothing meaningful remains, use a single
### Changedbullet: maintenance / release alignment.
Use today’s date in ISO format (YYYY-MM-DD) for the new section.
A6 — GitHub CLI (optional step)
If you will create a GitHub release, require gh authenticated; if missing, note in the plan that step P will be skipped or manual.
Phase B — Single approval prompt (only user gate)
Show exactly this structure (fill in placeholders). Do not ask follow-up questions in the same turn—wait for one reply.
RELEASE PLAN
============
Current version : OLD_VERSION
Proposed version: NEW_VERSION (MAJOR|MINOR|PATCH bump — one-line reason)
Source branch : SOURCE_BRANCH
Base : origin/main..HEAD (N commits)
Branch to push : r/NEW_VERSION
Files changed vs main (summary):
<key paths or stat one-liner>
CHANGELOG entry:
### Added
- ...
### Changed
- ...
### Fixed
- ...
Next steps after approval (no further prompts):
merge SOURCE_BRANCH into r/NEW_VERSION from main, bump .csproj, update CHANGELOG, build, pack, push branch, nuget push, tag vNEW_VERSION, gh release.
Approve? (yes to proceed, anything else to cancel)
Approval: proceed only if the user clearly agrees (e.g. yes, y, approve, go). Otherwise stop.
Phase C — Execute without pausing (after approval)
Assume repository root is ro-efactura. Replace NEW_VERSION / SOURCE_BRANCH with concrete values.
C1 — Release branch with all analyzed commits
git fetch origin main
git checkout main
git pull origin main
git checkout -b "r/NEW_VERSION"
git merge --no-ff "SOURCE_BRANCH" -m "merge(SOURCE_BRANCH): release NEW_VERSION"
Resolve conflicts if any; release must not proceed with unresolved conflicts.
C2 — Bump version in .csproj
Set <Version>NEW_VERSION</Version> in RoEFactura/RoEFactura.csproj. Remove -local or other pre-release suffixes from that property.
C3 — Write CHANGELOG.md
Insert below ## [Unreleased]:
## [Unreleased]
## [NEW_VERSION] - YYYY-MM-DD
### Added
...
### Changed
...
### Fixed
...
Leave ## [Unreleased] empty (or a blank line) under it for future work.
C4 — Build and pack
dotnet build -c Release
dotnet pack -c Release -o nupkgs/
Confirm nupkgs/RoeFactura.NEW_VERSION.nupkg exists.
C5 — Commit version + changelog (if not already committed by merge)
If merge did not include .csproj / CHANGELOG.md edits:
git add RoEFactura/RoEFactura.csproj CHANGELOG.md
git commit -m "chore(release): bump version to NEW_VERSION"
Then:
git push -u origin "r/NEW_VERSION"
C6 — NuGet.org
dotnet nuget push "nupkgs/RoeFactura.NEW_VERSION.nupkg" \
--api-key "$NUGET_API_KEY" \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate
C7 — Tag and GitHub release
git tag -a "vNEW_VERSION" -m "vNEW_VERSION"
git push origin "vNEW_VERSION"
Create the GitHub release with the ## [NEW_VERSION] - … block from CHANGELOG.md verbatim as the release notes (copy that section into gh --notes or a temp file and pass --notes-file). Attach the nupkg:
gh release create "vNEW_VERSION" \
--title "vNEW_VERSION" \
--notes-file /path/to/release-notes.md \
"nupkgs/RoeFactura.NEW_VERSION.nupkg"
If gh is unavailable, skip and tell the user to create the release manually.
C8 — Done
Print a short summary: branch, tag, NuGet package version, and links if known.
Checklist (agent self-verify)
-
NUGET_API_KEYverified before approval - Semver bump justified from commit scan
- Single approval obtained
-
r/NEW_VERSIONincludes mergedSOURCE_BRANCHwork -
.csprojversion andCHANGELOG.mdupdated -
dotnet build/dotnet packsucceeded - Branch pushed; NuGet push succeeded
- Tag
vNEW_VERSIONpushed; GitHub release created or skipped with reason
Notes
- Package ID is
RoeFactura(no hyphen). - Do not merge
r/*intomainautomatically unless the user asks; release branches can stay open for hotfixes. - Multi-targeting (
net9.0/net10.0) still yields one.nupkgper version. - If the analyzed branch should not be merged (e.g. release from
mainonly), the user must say so before approval; otherwise default is mergeSOURCE_BRANCHas in C1.