From 8bb1b99ae9bf032fb4f271b30670dc900f5a1730 Mon Sep 17 00:00:00 2001 From: Ryan Hamamura <58859899+ryanhamamura@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:43:46 -1000 Subject: [PATCH] chore: add PR workflow and worktree-aware release process --- .claude/commands/pr-create.md | 12 ++++++++++++ .claude/commands/pr-merge.md | 9 +++++++++ .claude/commands/pr.md | 16 ++++++++++++++++ .claude/commands/release.md | 27 +++++++++++++++++---------- CLAUDE.md | 18 +++++++++++++++++- 5 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 .claude/commands/pr-create.md create mode 100644 .claude/commands/pr-merge.md create mode 100644 .claude/commands/pr.md diff --git a/.claude/commands/pr-create.md b/.claude/commands/pr-create.md new file mode 100644 index 0000000..7718b3f --- /dev/null +++ b/.claude/commands/pr-create.md @@ -0,0 +1,12 @@ +Create a PR from the current branch on both GitHub and Gitea. + +1. If in a worktree (working directory contains `.claude/worktrees/`), you are already on a feature branch — do NOT create a new one. Otherwise, create a new branch from main with a descriptive name. +2. Stage and commit all changes with a clean, semantic commit message. No Claude attribution lines. +3. Fetch latest main: `git fetch origin main`. +4. Rebase onto main: `git rebase origin/main`. + - If conflicts occur, abort the rebase (`git rebase --abort`), analyze the conflicting files, write a plan to resolve them, and present the plan to the user before proceeding. +5. Push the branch to origin with `-u` (use `--force-with-lease` if the branch was already pushed). +6. Push the branch to gitea: `git push gitea `. +7. Create a GitHub PR: `gh pr create`. Reference related issues with `#X`. Only use `Closes #X` if the PR fully resolves the issue. +8. Create a Gitea PR: `tea pr create --head --base main` with the same title and description. +9. Report both PR URLs. diff --git a/.claude/commands/pr-merge.md b/.claude/commands/pr-merge.md new file mode 100644 index 0000000..e86e62e --- /dev/null +++ b/.claude/commands/pr-merge.md @@ -0,0 +1,9 @@ +PR checks pass. Squash and merge the PR on both GitHub and Gitea. + +1. Squash-merge on GitHub: `gh pr merge --squash` with a clean, semantic commit message including the PR number. No Claude attribution lines. +2. Squash-merge on Gitea: `tea pr merge --style squash` with the same message. +3. Push main to gitea to keep commits in sync: `git push gitea main`. +4. Delete the remote feature branch on origin: `git push origin --delete `. +5. Delete the remote feature branch on gitea: `git push gitea --delete `. +6. Prune remote tracking refs: `git remote prune origin && git remote prune gitea`. +7. If in a worktree, leave the local branch alone — Claude Code handles worktree cleanup on session exit. If NOT in a worktree, delete the local feature branch and switch to main. diff --git a/.claude/commands/pr.md b/.claude/commands/pr.md new file mode 100644 index 0000000..ed4b9ae --- /dev/null +++ b/.claude/commands/pr.md @@ -0,0 +1,16 @@ +Create a PR, wait for CI, and squash-merge it on both GitHub and Gitea. This is the standard single-command workflow. + +1. If in a worktree (working directory contains `.claude/worktrees/`), you are already on a feature branch — do NOT create a new one. Otherwise, create a new branch from main with a descriptive name. +2. Stage and commit all changes with a clean, semantic commit message. No Claude attribution lines. +3. Fetch latest main and rebase: `git fetch origin main && git rebase origin/main`. + - If conflicts occur, abort the rebase (`git rebase --abort`), analyze the conflicting files, write a plan to resolve them, and present the plan to the user before proceeding. +4. Push the branch to origin with `-u` (use `--force-with-lease` if already pushed). Also push to gitea. +5. Create a GitHub PR: `gh pr create`. Reference related issues with `#X`. Only use `Closes #X` if the PR fully resolves the issue. +6. Create a Gitea PR: `tea pr create --head --base main` with the same title and description. +7. Wait for CI to pass: poll with `gh pr checks` or `gh run watch`. If CI fails, report the failure and stop — do not merge. +8. Once CI passes, squash-merge on GitHub: `gh pr merge --squash` with a clean, semantic commit message including the PR number. No Claude attribution lines. +9. Squash-merge on Gitea: `tea pr merge --style squash` with the same message. +10. Push main to gitea: `git push gitea main`. +11. Clean up remote branches: `git push origin --delete && git push gitea --delete `. +12. Prune refs: `git remote prune origin && git remote prune gitea`. +13. Report both merged PR URLs. diff --git a/.claude/commands/release.md b/.claude/commands/release.md index ed6952a..6794eac 100644 --- a/.claude/commands/release.md +++ b/.claude/commands/release.md @@ -1,14 +1,21 @@ -Create a new release for this project. Steps: +Create a new release for this project. -1. Fetch tags from all remotes so the version list is current. -2. Check for uncommitted changes. If any exist, commit them with a clean semantic commit message. No Claude attribution lines. -3. Review the commits since the last tag. Based on their content, recommend a semver bump: +## Pre-flight + +1. **Worktree guard**: If the working directory is inside `.claude/worktrees/`, STOP and tell the user: "Releases must be created from a non-worktree session on main. Exit this worktree or start a new session, then run /release." Do not proceed. +2. Verify you are on `main`. If not, STOP. +3. Verify there are no uncommitted changes. If there are, STOP — they should go through a PR. +4. Run `git pull --ff-only` on main. Fetch tags from all remotes. + +## Release + +5. Review commits since the last tag. Recommend a semver bump: - **major**: breaking/incompatible API changes - **minor**: new features, meaningful new behavior - **patch**: bug fixes, docs, refactoring with no new features - Present the proposed version, the bump rationale, and the commit list. Wait for user approval before continuing. -4. Tag the new version and push the tag + commits to all remotes (origin, gitea, etc.). -5. Generate release notes from the commits since the last tag, grouped by type (features, fixes, docs/refactoring). -6. Create a GitHub release using `gh release create`. -7. Create a Gitea release using `tea releases create` with the same notes. -8. Report both release URLs and confirm all remotes are up to date. + Present the proposed version, bump rationale, and commit list. Wait for user approval. +6. Tag the new version. Push the tag to all remotes (origin, gitea). +7. Generate release notes grouped by type (features, fixes, chores). +8. Create a GitHub release with `gh release create`. +9. Create a Gitea release with `tea releases create` using the same notes. +10. Report both release URLs and confirm all remotes are up to date. diff --git a/CLAUDE.md b/CLAUDE.md index 6e0181e..cbbca60 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,5 +1,21 @@ # Via Project Instructions +## Workflow + +All changes go through PRs: + +1. Enter a worktree (`EnterWorktree`) at session start. +2. Make changes, commit with semantic messages. +3. `/pr` to push, open a PR, wait for CI, and squash-merge. + (Or use `/pr-create` and `/pr-merge` separately for more control.) + +## Releasing + +Run `/release` from a **non-worktree session on main**. It tags and publishes +what is already on main — it does not commit new changes. + ## Worktree Usage -Always enter a worktree at the start of a session using the `EnterWorktree` tool. This prevents parallel Claude Code sessions from interfering with each other. +Always enter a worktree at the start of a session using the `EnterWorktree` +tool. This prevents parallel Claude Code sessions from interfering with each +other.