From 62c22f8b5b2f253e44ef876c905edef6c3f61263 Mon Sep 17 00:00:00 2001 From: Amir Nathoo Date: Sun, 22 Feb 2026 22:03:18 -0800 Subject: [PATCH 1/5] chore: move TUI roadmap into docs/plans, add release pipeline plan Move docs/TUI_PLAN.md to docs/plans/tui-roadmap.md so all plan documents live in the same directory. Add release pipeline plan. Co-Authored-By: Claude Opus 4.6 --- docs/plans/release-pipeline.md | 32 ++++++++++++++++++++++ docs/{TUI_PLAN.md => plans/tui-roadmap.md} | 0 2 files changed, 32 insertions(+) create mode 100644 docs/plans/release-pipeline.md rename docs/{TUI_PLAN.md => plans/tui-roadmap.md} (100%) diff --git a/docs/plans/release-pipeline.md b/docs/plans/release-pipeline.md new file mode 100644 index 0000000..9ceed6a --- /dev/null +++ b/docs/plans/release-pipeline.md @@ -0,0 +1,32 @@ +# Release Pipeline Plan + +## Goal + +Add a tag-triggered release workflow using GitHub's native release process. +Push a semver tag → CI runs → GitHub Release created with auto-generated notes. + +## Approach + +- `.github/release.yml` configures how GitHub categorizes PRs in release notes +- `.github/workflows/release.yml` triggers on `v*` tags, runs `make ci`, then + creates a GitHub Release via `gh release create --generate-notes` +- Version/commit/date embedded in binary via ldflags (`--version` flag) +- Makefile `build` target updated to inject git info automatically + +## Files + +| File | Action | +|------|--------| +| `.github/release.yml` | Create — release notes categories | +| `.github/workflows/release.yml` | Create — tag-triggered release workflow | +| `cmd/questcore/main.go` | Update — version vars + `--version` flag | +| `Makefile` | Update — ldflags in build target | + +## Task List + +- [ ] Add version vars and `--version` flag to `cmd/questcore/main.go` +- [ ] Update Makefile build target with ldflags +- [ ] Create `.github/release.yml` +- [ ] Create `.github/workflows/release.yml` +- [ ] Verify `make ci` passes +- [ ] Push branch, open PR diff --git a/docs/TUI_PLAN.md b/docs/plans/tui-roadmap.md similarity index 100% rename from docs/TUI_PLAN.md rename to docs/plans/tui-roadmap.md From d6537dce310a21d68af0b3af30b651ba21a41d30 Mon Sep 17 00:00:00 2001 From: Amir Nathoo Date: Sun, 22 Feb 2026 22:13:11 -0800 Subject: [PATCH 2/5] feat: add --version flag with build-time version embedding Add version/commit/date variables to main, injected via ldflags at build time. Makefile build target now uses git describe for version. Co-Authored-By: Claude Opus 4.6 --- Makefile | 9 +++++++-- cmd/questcore/main.go | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 37a911f..01960f5 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,16 @@ GO := go GOFLAGS := -v TIMEOUT := 120s +VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") +COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "none") +DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ) +LDFLAGS := -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(DATE) + .PHONY: build test lint vet fmt-check fmt ci clean -## build: Compile the questcore binary +## build: Compile the questcore binary with version info build: - $(GO) build $(GOFLAGS) -o $(BINARY) ./cmd/questcore + $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BINARY) ./cmd/questcore ## test: Run all tests with race detection test: diff --git a/cmd/questcore/main.go b/cmd/questcore/main.go index 1ae91eb..514288d 100644 --- a/cmd/questcore/main.go +++ b/cmd/questcore/main.go @@ -1,5 +1,5 @@ // QuestCore is a deterministic, data-driven game engine for text adventures. -// Usage: questcore [--plain] +// Usage: questcore [--version] [--plain] package main import ( @@ -12,12 +12,22 @@ import ( "github.com/nathoo/questcore/tui" ) +// Set via -ldflags at build time. +var ( + version = "dev" + commit = "none" + date = "unknown" +) + func main() { plain := false var gameDir string for _, arg := range os.Args[1:] { switch arg { + case "--version": + fmt.Printf("questcore %s (commit %s, built %s)\n", version, commit, date) + return case "--plain": plain = true default: @@ -28,7 +38,7 @@ func main() { } if gameDir == "" { - fmt.Fprintf(os.Stderr, "Usage: questcore [--plain] \n") + fmt.Fprintf(os.Stderr, "Usage: questcore [--version] [--plain] \n") os.Exit(1) } From ce1c35e071cf35d25c7add4fc1679fbe6c692e3b Mon Sep 17 00:00:00 2001 From: Amir Nathoo Date: Sun, 22 Feb 2026 22:14:01 -0800 Subject: [PATCH 3/5] ci: add PR title validation for conventional commits Enforce that PR titles follow conventional commit format using semantic-pull-request action. Required for changelog generation. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/pr-title.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/pr-title.yml diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..de859af --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,29 @@ +name: PR Title + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + check: + name: Validate Conventional Commit Title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + chore + docs + style + refactor + test + ci + perf + revert From 1cf70aa541d1ba86a0e1ef2b3a1a5cb04d42f012 Mon Sep 17 00:00:00 2001 From: Amir Nathoo Date: Sun, 22 Feb 2026 22:14:47 -0800 Subject: [PATCH 4/5] ci: add tag-triggered release workflow On semver tag push, runs make ci then generates changelog from conventional commits via conventional-changelog and creates a GitHub Release. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/release.yml | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b841e6d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: + contents: write + +jobs: + release: + name: Create Release + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version: "1.24" + + - name: Install golangci-lint + uses: golangci/golangci-lint-action@v7 + with: + version: v2.10 + install-mode: binary + args: --help + + - name: Run CI + run: make ci + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Generate changelog + run: | + npx conventional-changelog-cli -p conventionalcommits -r 1 -o RELEASE_NOTES.md + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create ${{ github.ref_name }} \ + --title "${{ github.ref_name }}" \ + --notes-file RELEASE_NOTES.md From b217fc801ffda3383ce8447d3ce7ccb675d31748 Mon Sep 17 00:00:00 2001 From: Amir Nathoo Date: Sun, 22 Feb 2026 22:15:00 -0800 Subject: [PATCH 5/5] docs: update release pipeline plan Co-Authored-By: Claude Opus 4.6 --- docs/plans/release-pipeline.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/plans/release-pipeline.md b/docs/plans/release-pipeline.md index 9ceed6a..981f1be 100644 --- a/docs/plans/release-pipeline.md +++ b/docs/plans/release-pipeline.md @@ -2,31 +2,34 @@ ## Goal -Add a tag-triggered release workflow using GitHub's native release process. -Push a semver tag → CI runs → GitHub Release created with auto-generated notes. +Automate versioning, changelog, and GitHub Releases from conventional commits. -## Approach +## How It Works -- `.github/release.yml` configures how GitHub categorizes PRs in release notes -- `.github/workflows/release.yml` triggers on `v*` tags, runs `make ci`, then - creates a GitHub Release via `gh release create --generate-notes` -- Version/commit/date embedded in binary via ldflags (`--version` flag) -- Makefile `build` target updated to inject git info automatically +1. PRs use conventional commit titles (`feat:`, `fix:`, `chore:`, etc.) +2. Squash merge with "PR title + commit details" — the PR title becomes the + conventional commit message on main +3. When ready to release, push a semver tag (`git tag v0.1.0 && git push --tags`) +4. Release workflow runs `make ci`, then generates CHANGELOG via + conventional-changelog and creates a GitHub Release +5. PR title format is enforced by the semantic-pull-request action ## Files | File | Action | |------|--------| -| `.github/release.yml` | Create — release notes categories | | `.github/workflows/release.yml` | Create — tag-triggered release workflow | +| `.github/workflows/pr-title.yml` | Create — enforce conventional commit PR titles | | `cmd/questcore/main.go` | Update — version vars + `--version` flag | | `Makefile` | Update — ldflags in build target | +| `package.json` | Create — conventional-changelog dependency | ## Task List - [ ] Add version vars and `--version` flag to `cmd/questcore/main.go` - [ ] Update Makefile build target with ldflags -- [ ] Create `.github/release.yml` +- [ ] Create `.github/workflows/pr-title.yml` (semantic-pull-request) +- [ ] Set up conventional-changelog - [ ] Create `.github/workflows/release.yml` - [ ] Verify `make ci` passes - [ ] Push branch, open PR