|
| 1 | +--- |
| 2 | +name: release-modulorails |
| 3 | +description: Release a new version of the Modulorails Ruby gem to RubyGems. Handles version bump, CHANGELOG, commit, tag, push, GitHub release, and gem publication. Trigger this skill whenever the user asks to release, publish, ship, bump, or cut a new version of modulorails — even if they don't explicitly mention "release" or specify a version (ask for it if missing). |
| 4 | +--- |
| 5 | + |
| 6 | +# Release the Modulorails gem |
| 7 | + |
| 8 | +Run the full release pipeline for the `modulorails` gem. The user provides the version number (e.g. `1.7.0`) without the `v` prefix. If they omit it, ask before proceeding. |
| 9 | + |
| 10 | +## Conventions |
| 11 | + |
| 12 | +- `<version>`: the version number without `v` prefix (e.g. `1.7.0`) |
| 13 | +- All commands run from the project root: `/home/claude/modulorails` |
| 14 | +- GitHub repo: `https://github.com/moduloTech/modulorails` |
| 15 | +- Gem published to: `https://rubygems.org/gems/modulorails` |
| 16 | +- Tag format: `v<version>` (e.g. `v1.7.0`) |
| 17 | +- The gemspec has `rubygems_mfa_required = 'true'`, so `gem push` will prompt for an OTP. Tell the user to have their authenticator app ready before step 7. |
| 18 | + |
| 19 | +## Steps |
| 20 | + |
| 21 | +### 1. Pre-flight check |
| 22 | + |
| 23 | +- Run `git status` and `git diff` to surface any uncommitted changes. |
| 24 | +- The release commit should only touch `lib/modulorails/version.rb` and `CHANGELOG.md`. If unrelated changes are pending, ask the user whether to include them, stash them, or abort. |
| 25 | +- Confirm the current branch is `master` (the project's main branch) unless the user specified otherwise. |
| 26 | + |
| 27 | +### 2. Bump the version constant |
| 28 | + |
| 29 | +- Edit `lib/modulorails/version.rb` and replace the value of `VERSION` with `<version>`. |
| 30 | +- The constant looks like: `VERSION = '1.6.0'.freeze` — keep the single quotes and `.freeze` to match the existing style. |
| 31 | + |
| 32 | +### 3. Update CHANGELOG.md |
| 33 | + |
| 34 | +The Modulorails CHANGELOG uses its own format — **do not** convert it to Keep-a-Changelog. The structure is: |
| 35 | + |
| 36 | +``` |
| 37 | +# Unreleased |
| 38 | +
|
| 39 | +# <version> |
| 40 | +
|
| 41 | +<one-line summary, optional> |
| 42 | +
|
| 43 | +## Features |
| 44 | +- ... |
| 45 | +
|
| 46 | +## Improvements |
| 47 | +- ... |
| 48 | +
|
| 49 | +## Fixes |
| 50 | +- ... |
| 51 | +
|
| 52 | +## Deprecations (will be removed in <next major>) |
| 53 | +- ... |
| 54 | +``` |
| 55 | + |
| 56 | +To update: |
| 57 | + |
| 58 | +- Replace the `# Unreleased` heading with `# <version>` (and add a fresh `# Unreleased` line above it for the next cycle). |
| 59 | +- Categorize changes under `## Features`, `## Improvements`, `## Fixes`, or `## Deprecations` as appropriate. Omit sections that have no entries. |
| 60 | +- Run `git log --oneline <last-tag>..HEAD` to find the commits since the previous release; use those as the source of changelog entries. Phrase entries as user-facing descriptions, not commit-message echoes. |
| 61 | + |
| 62 | +### 4. Commit the bump |
| 63 | + |
| 64 | +Stage **only** `lib/modulorails/version.rb` and `CHANGELOG.md`, then commit. Match the project's existing release commit style — prior bumps use messages like `Bump modulorails to 1.6.0`: |
| 65 | + |
| 66 | +```bash |
| 67 | +git add lib/modulorails/version.rb CHANGELOG.md |
| 68 | +git commit -m "$(cat <<'EOF' |
| 69 | +Bump modulorails to <version> |
| 70 | +
|
| 71 | +Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
| 72 | +EOF |
| 73 | +)" |
| 74 | +``` |
| 75 | + |
| 76 | +(Use whichever Co-Authored-By trailer matches the model running the session — don't hardcode an older one.) |
| 77 | + |
| 78 | +### 5. Tag |
| 79 | + |
| 80 | +```bash |
| 81 | +git tag -a v<version> -m "v<version>" |
| 82 | +``` |
| 83 | + |
| 84 | +### 6. Push commit and tag |
| 85 | + |
| 86 | +```bash |
| 87 | +git push origin master |
| 88 | +git push origin v<version> |
| 89 | +``` |
| 90 | + |
| 91 | +### 7. Build and push the gem to RubyGems |
| 92 | + |
| 93 | +```bash |
| 94 | +gem build modulorails.gemspec |
| 95 | +gem push modulorails-<version>.gem |
| 96 | +``` |
| 97 | + |
| 98 | +`gem push` will prompt for the OTP because `rubygems_mfa_required` is set in the gemspec. The user must enter it interactively — surface the prompt to them. |
| 99 | + |
| 100 | +If the user is unauthenticated (`You don't have any sources that contain this gem.` or similar), they need to run `gem signin` first. Don't try to manage their RubyGems credentials. |
| 101 | + |
| 102 | +After a successful push, delete the local `.gem` artifact: `rm modulorails-<version>.gem`. |
| 103 | + |
| 104 | +### 8. Create the GitHub release |
| 105 | + |
| 106 | +```bash |
| 107 | +gh release create v<version> --title "v<version>" --notes "<notes>" |
| 108 | +``` |
| 109 | + |
| 110 | +Notes should mirror the CHANGELOG section for this version (markdown-formatted). Pass the body via a HEREDOC if it's multi-line, e.g.: |
| 111 | + |
| 112 | +```bash |
| 113 | +gh release create v<version> --title "v<version>" --notes "$(cat <<'EOF' |
| 114 | +## Features |
| 115 | +- ... |
| 116 | +
|
| 117 | +## Fixes |
| 118 | +- ... |
| 119 | +EOF |
| 120 | +)" |
| 121 | +``` |
| 122 | + |
| 123 | +### 9. Confirm |
| 124 | + |
| 125 | +- Print the GitHub release URL (`gh release view v<version> --json url -q .url`). |
| 126 | +- Print the RubyGems URL: `https://rubygems.org/gems/modulorails/versions/<version>`. |
| 127 | +- Remind the user that downstream apps can pull the new version via `bundle update modulorails`. |
| 128 | + |
| 129 | +## Alternative: `bundle exec rake release` |
| 130 | + |
| 131 | +The Rakefile already loads `bundler/gem_tasks`, so `bundle exec rake release` will, in one shot: |
| 132 | + |
| 133 | +1. Verify the working tree is clean. |
| 134 | +2. Build `modulorails-<version>.gem`. |
| 135 | +3. Tag `v<version>` from the current HEAD. |
| 136 | +4. Push the tag to `origin`. |
| 137 | +5. `gem push` to RubyGems. |
| 138 | + |
| 139 | +Use this only when: |
| 140 | +- The version bump and CHANGELOG are already committed and pushed (it does **not** create the bump commit). |
| 141 | +- The user explicitly asks for the shortcut. |
| 142 | + |
| 143 | +The downsides vs. the step-by-step flow: if `gem push` fails (bad OTP, network), the tag is already pushed and you need to clean up manually. The manual flow keeps tag and gem push independent so each failure mode is recoverable on its own. |
| 144 | + |
| 145 | +## Troubleshooting |
| 146 | + |
| 147 | +- **`gem push` fails with 401 / OTP rejected**: the OTP window is short — re-run with a fresh code. Don't re-tag or re-commit; just retry the `gem push` step. |
| 148 | +- **Tag already exists locally but push fails**: `git tag -d v<version>` and recreate after fixing the underlying issue. Never force-push a tag that's already on RubyGems. |
| 149 | +- **`gem build` complains about missing files**: the gemspec uses `git ls-files` to enumerate files, so untracked files won't be in the gem. Stage them first if they belong, or `.gitignore` them if not. |
| 150 | +- **GitHub release notes don't render properly**: HEREDOC quoting matters — use `<<'EOF'` (with quotes) to prevent shell expansion in the notes body. |
0 commit comments