ethos-gemkit 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6874e64af38ffa0301d9db238dc2a7a4a95e4de66df211003491ec5c68f74a0
4
- data.tar.gz: 1ef1d85750e28953db05b02d142b4dd728879a3f7c6bfc79525b1fae7c29bcf0
3
+ metadata.gz: a47dcf57b9f1dfaa0cfee1422dec8eb6ba3af0169358843f67ed36ac957ea294
4
+ data.tar.gz: 478f8436259e03d5a332a8f88006dbea5a11114d205024effa04cb8dcf19952d
5
5
  SHA512:
6
- metadata.gz: 13b6137a5f8de672582a52d84c8084d60e9af03718bae99f4d1b3274ccaeac3a97a93a50217e04ade33cdb8421f8b27a9e7c70aa0614582ba061879f677d7994
7
- data.tar.gz: f12acfadd4abb54a6f99a9c6eed7ac94747e497bc575c59018ab68ac0631cd6f7e46b4255773d0d9a45af9646d8d79108bbfc01118332483e92f0f90793e8065
6
+ metadata.gz: 3361ad93a5b3ec3720601b9a98644868e61b7d5b0e90c626b7adeca3dd66118e1c0773124d8a0d7b218ea3193931db0a01b8c7bc2c429f07f8c5695305f71ca4
7
+ data.tar.gz: 514aae6c1c69381f0d88b32a75c40194389266b391e8db39d385a9af79800fe8eafeb36fea6fca55888f2508a2f90e14bcf1c6ebdc2e0230c860aca06125d9d7
data/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.2] - 2026-11-08
9
+
10
+ ### Changed
11
+
12
+ - pin native release tools with mise
13
+
14
+
15
+ ### Documentation
16
+
17
+ - make Ethos Link the canonical documentation home
18
+ - keep audited technical guidance alongside the code
19
+
8
20
  ## [0.3.1] - 2026-11-05
9
21
 
10
22
  ### Changed
data/README.md CHANGED
@@ -4,17 +4,33 @@ Shared development defaults for Ethos Link gems: Ruby 4, Standard, optional Rail
4
4
  8 linting, hooks, package checks and one shared release workflow. The toolkit
5
5
  belongs in the development/test Gemfile, never a consumer's runtime gemspec.
6
6
 
7
+ ## Documentation
8
+
9
+ This README and the linked repository guides describe the checked-out code.
10
+ The [Ethos Link project page](https://www.ethos-link.com/opensource/ethos-gemkit)
11
+ provides the canonical public project guide, overview and resources.
12
+
13
+ - [Release preparation, registries and recovery](docs/releasing.md)
14
+
15
+ ## Requirements
16
+
17
+ Ruby 4.0 or newer, Bundler, Git and mise. Install the pinned native tools with
18
+ `bundle exec rake tools:install` after installing the bundle. Rails is optional;
19
+ Rails-specific linting activates when Rails 8 components are in the bundle.
20
+
21
+ ## Setup
22
+
7
23
  Install the published gem in the development/test Gemfile:
8
24
 
9
25
  ```ruby
10
- gem "ethos-gemkit", "0.2.1", group: [:development, :test], require: false
26
+ gem "ethos-gemkit", "0.3.1", group: [:development, :test], require: false
11
27
  ```
12
28
 
13
29
  Pin workflow callers to the full commit behind the installed Gemkit release tag.
14
30
  Resolve that commit with:
15
31
 
16
32
  ```sh
17
- git ls-remote https://github.com/ethos-link/ethos-gemkit.git 'refs/tags/v0.2.1^{}'
33
+ git ls-remote https://github.com/ethos-link/ethos-gemkit.git 'refs/tags/v0.3.1^{}'
18
34
  ```
19
35
 
20
36
  Upgrade the gem version and workflow pins together. Consumer READMEs should cover
@@ -53,6 +69,46 @@ release tasks while a repository is adopting the toolkit.
53
69
  `bundle exec rake verify` runs lint, registered checks, a disposable native gem
54
70
  build, and git-cliff validation.
55
71
 
72
+ The gem ships `mise.toml` and `mise.lock` to pin development tools for local use
73
+ and CI. No Node.js or npm installation is needed for Gemkit.
74
+
75
+ | Tools | Installation and version ownership |
76
+ | --- | --- |
77
+ | git-cliff 2.12.0, GitHub CLI 2.103.2 | Native binaries installed by mise from the shipped lockfile |
78
+ | Ruby 4.0.9 | Local mise pin; matching `ruby/setup-ruby` pin in CI |
79
+ | Bundler 4.0.11 | Explicit CI pin; install the same version locally |
80
+ | Standard, Standard Rails, Rake, Lefthook | Bundler and the consumer's `Gemfile.lock` |
81
+ | Git, SSH, sha256sum, shell utilities | System prerequisites; hosted CI uses the Ubuntu runner image |
82
+ | Consumer-specific binaries | Consumer local setup |
83
+
84
+ Install mise (CI uses 2026.10.19), Ruby and Bundler, then run:
85
+
86
+ ```sh
87
+ bundle install
88
+ bundle exec rake tools:install
89
+ bundle exec rake verify
90
+ ```
91
+
92
+ The install task trusts the gem's mise configuration and installs its pinned
93
+ native git-cliff and GitHub CLI binaries. Verification and release preparation
94
+ resolve those binaries through mise using the installed gem's configuration,
95
+ even when called from a consumer directory. They do not fall back to global
96
+ installations or download tools on demand. Re-run installation after upgrading
97
+ Gemkit. Consumer repositories need no npm manifest or copied tool pins.
98
+
99
+ For work on Gemkit itself, install the Ruby and CLI pins with
100
+ `mise install --locked ruby git-cliff gh`; activate mise in your shell or run
101
+ `mise exec ruby git-cliff gh -- bundle exec rake verify`. The lockfile covers
102
+ Linux and macOS on x64 and arm64. Ruby version parity with CI is checked by
103
+ the tests.
104
+ Git and OS utilities still come from the host; identical tool versions do not
105
+ provide an identical operating system.
106
+
107
+ The release build workflow loads the installed gem's configuration through a
108
+ SHA-pinned mise action. The isolated release-notes job has its own
109
+ exact GitHub CLI pin, checked against `mise.toml` by the tests, so it can publish
110
+ notes without loading consumer code.
111
+
56
112
  Run verification locally before pushing and when preparing a release. GitHub
57
113
  Actions checks commit messages on ordinary PRs and main pushes; it does not run
58
114
  tests, lint, browser checks or integration suites. Release workflows validate
@@ -78,173 +134,14 @@ token. See [GitHub's registry guide](https://docs.github.com/en/packages/working
78
134
 
79
135
  ## Releasing a gem
80
136
 
81
- **Run `release:prepare` from clean, up-to-date `main`.** It creates the conventional
82
- release branch and opens a PR. **Merging that release PR starts publication.**
83
- This is the same process for Gemkit itself and its adopted consumer gems.
84
- Ordinary feature/fix PRs run commitlint; only a release PR starts publication.
85
-
86
- ### One-time prerequisites
87
-
88
- - Commit `Gemfile.lock`. Before its first commit, run
89
- `bundle lock --add-checksums`; frozen CI installs reject empty registry
90
- checksum entries, even when the gems are already installed locally.
91
- - Ignore `/.bundle/`, `/vendor/bundle/` and `/pkg/` in `.gitignore`. The shared
92
- workflows use Ruby setup's native `vendor/bundle` cache; generated files must
93
- leave the release checkout clean.
94
- - Install the bundle, Git, git-cliff and GitHub CLI. Configure your Git identity,
95
- authenticate with `gh auth login`, and install hooks with
96
- `bundle exec lefthook install`. You need permission to push branches and open PRs.
97
- - Public gems: configure a matching RubyGems trusted publisher for **each gem**
98
- before merging its first release PR. Use the exact settings below. Gemkit's
99
- publisher does not authorize consumer gems.
100
- - A new gem also needs a pending trusted publisher. Supply its numeric RubyGems
101
- owner through the caller's `rubygems-owner` input or the repository/organization
102
- variable `RUBYGEMS_OWNER` (the publisher account used by Tunnel is `27209`).
103
- - Private gems: set `registry: github_packages`. Publishing uses the workflow's
104
- short-lived `GITHUB_TOKEN`; the package must grant its repository Actions access.
105
- Pass `PACKAGES_TOKEN` only when an explicit token override is needed. Local
106
- installation from other private repositories still needs `read:packages` access.
107
- - Configure the `rubygems` GitHub environment to allow `main` and `v*` tags.
108
- Release callers grant `contents: write`, `id-token: write` and `packages: write`.
109
- Repository rules must permit the workflow's annotated release tags.
110
-
111
- The SDK release workflow listens directly for merged release PRs and version-tag
112
- pushes. Consumer callers must listen for both `pull_request: types: [closed]`
113
- against `main` and `push: tags: ["v*"]`, and pin the commit matching the installed
114
- Gemkit release.
115
- See the [Tunnel caller](https://github.com/ethos-link/cloudflare-tunnel/blob/main/.github/workflows/release.yml).
116
-
117
- Projects keep their own local checks. Engines can register `checks: [ci:local]`
118
- in `.ethos-gemkit.yml` and have that task run `bin/ci`. Provision PostgreSQL or
119
- browser dependencies locally before running verification. Release callers do
120
- not install test dependencies or accept `build-setup`.
121
-
122
- ### RubyGems trusted-publisher settings
123
-
124
- On RubyGems, open the **consumer gem's** page, then **Trusted publishers**. For
125
- Cloudflare Tunnel, create or update the publisher with these exact values:
126
-
127
- | RubyGems field | Value |
128
- |---|---|
129
- | Repository owner | `ethos-link` |
130
- | Repository name | `cloudflare-tunnel` |
131
- | Workflow filename | `release.yml` |
132
- | Environment | `rubygems` |
133
- | Workflow Repository Owner | `ethos-link` |
134
- | Workflow Repository Name | `ethos-gemkit` |
135
-
136
- The repository identifies the consumer; the Workflow Repository fields identify
137
- the repository containing the shared workflow file. Those last two fields are
138
- required for consumers,
139
- even though RubyGems labels them optional. For another consumer, substitute its
140
- repository name. For Gemkit itself, use repository name `ethos-gemkit` and leave
141
- both Workflow Repository fields blank because the workflow is in the same repo.
142
-
143
- The numeric `rubygems-owner` input identifies the account for pending publishers;
144
- it does not register a publisher or grant access to a consumer gem. See the
145
- [upstream reusable-workflow instructions](https://guides.rubygems.org/trusted-publishing/#using-reusable-workflows).
146
-
147
- ### Prepare and review
148
-
149
- For a normal patch release:
150
-
151
- ```sh
152
- git switch main
153
- git pull --ff-only
154
- bundle install
155
- bundle exec rake release:prepare
156
- ```
157
-
158
- The default is `patch`. Select another target explicitly:
137
+ Run `bundle exec rake release:prepare` only from clean, current `main` when
138
+ preparing an actual release. It updates the version, changelog and lockfile,
139
+ runs verification, pushes a release branch and opens a PR. Merging that release
140
+ PR starts publication; `rake verify` alone does not publish.
159
141
 
160
- ```sh
161
- bundle exec rake 'release:prepare[minor]'
162
- bundle exec rake 'release:prepare[major]'
163
- bundle exec rake 'release:prepare[1.2.0]'
164
- ```
165
-
166
- For an initial, unpublished version that is already in the gemspec and has no
167
- tag, an explicit current version is supported. For example, a new gem starting
168
- at 0.1.0 can use `bundle exec rake 'release:prepare[0.1.0]'` after pending-publisher
169
- setup.
170
-
171
- The task prints each step and streams command output as it runs. It checks the
172
- working tree, canonical origin, current main, installed hooks and target tag.
173
- It creates `chore/release-vX.Y.Z`, updates the version and
174
- changelog, runs `bundle lock --add-checksums` and the full `rake verify`, then
175
- commits the three metadata files with hooks enabled, pushes the branch, and opens a
176
- `chore(release): prepare vX.Y.Z` PR. Main stays unchanged. You can also start on
177
- that exact pre-created release branch if its HEAD still equals `origin/main`.
178
- When starting from main, a leftover local release branch is recreated only if
179
- all its commits are already in main; unmerged work is preserved and stops the task.
180
-
181
- Review the generated notes, lockfile and version in the PR. Add or adjust upgrade
182
- notes in a follow-up commit when needed, rerun affected checks locally, and wait
183
- for commitlint before merging. The task
184
- prints the PR URL and makes clear that merging it publishes the release.
185
-
186
- ### Merge and publish
187
-
188
- Merging a same-repository `chore/release-vX.Y.Z` PR into main runs the shared
189
- workflow against its exact merge commit, including squash and rebase merges:
190
-
191
- 1. Verify the expected version, main ancestry, notes and committed package bytes;
192
- build one release artifact through Bundler. Tests and lint already ran locally
193
- during `release:prepare` and are not repeated in Actions.
194
- 2. Create and push the annotated `vX.Y.Z` tag without overwriting existing tags
195
- or following unrelated local tags.
196
- 3. In an isolated job, verify the artifact's SHA-256 checksums, obtain the proper
197
- registry credentials, and publish that exact gem.
198
- 4. In a separate job, create the GitHub release with the same gem and notes.
199
-
200
- There is no manual tagging step in the normal flow. Build, tag and publication
201
- continue in the same run because a tag pushed by GitHub's `GITHUB_TOKEN` does not
202
- start another workflow. Existing manually pushed annotated version tags remain a
203
- supported trigger and receive full canonical-tag verification.
204
-
205
- Publish and notes jobs never check out or evaluate consumer code. Public gems
206
- use short-lived OIDC credentials; private gems use the workflow token or an
207
- explicit override. Both profiles push the same verified artifact to their
208
- configured host; no registry fallback exists.
209
-
210
- ### Failures and retries
211
-
212
- If preparation fails, inspect `git status` and `git diff`. A failed verification
213
- leaves changes on the local release branch without a release commit or push.
214
- Fix and finish that ordinary branch, or restore the changes before starting over.
215
- If the commit/push succeeded but opening the PR failed, use
216
- `gh pr create --base main --head chore/release-vX.Y.Z --fill` after fixing access.
217
- There is no journal or automatic reset of your working tree.
218
-
219
- If credential setup fails with `No trusted publisher configured for this workflow`,
220
- check the consumer's RubyGems settings against the table above. A successful
221
- build and tag do not mean the gem was published. When `gem push` was skipped,
222
- correct the publisher settings, then rerun **failed jobs only** in the original
223
- workflow run. This reuses its verified artifact and existing tag; do not run
224
- `release:prepare` again, bump the version or replace the tag for this failure.
225
-
226
- ```sh
227
- gh run rerun RUN_ID --repo OWNER/REPOSITORY --failed
228
- ```
229
-
230
- If a failed build needs a source fix and no tag or upload exists, keep the
231
- prepared version and notes. Update its `chore/release-vX.Y.Z` branch from main,
232
- commit the fix, run verification and open a replacement release PR. Merge that
233
- PR to run the corrected source. The original run stays pinned to its original
234
- commit; rerunning it cannot pick up a source fix. Do not replace an existing tag
235
- or reuse a version that was already published.
236
-
237
- For transient CI failures, retry **failed jobs in the original run** within GitHub's 30-day
238
- retry window. Artifacts are retained for 90 days. A failed tag step can reuse an
239
- existing annotated tag only when it points to the same verified commit. A failed
240
- notes job reuses the original artifact without uploading again. Ambiguous uploads,
241
- already published versions, existing GitHub releases or expired runs/artifacts
242
- require registry/release reconciliation. Never replace a tag or rebuild a
243
- published version to repair release notes.
244
-
245
- Provider references: [reusable RubyGems trusted publishers](https://guides.rubygems.org/trusted-publishing/#using-reusable-workflows),
246
- [GitHub token-trigger behavior](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow),
247
- and [failed-job retries](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/re-run-workflows-and-jobs).
142
+ See the [release guide](docs/releasing.md) for registry permissions, trusted
143
+ publishers, version selection, merge behaviour and recovery. The guide is
144
+ versioned with the release tooling it describes.
248
145
 
249
146
  GitLab is a separate optional [workflow](.github/workflows/sync-gitlab.yml).
250
147
  Only add its caller when a target exists, passing an SSH `url`, a project write
@@ -254,19 +151,24 @@ push, without tags, force or deletions. Provision target visibility no broader
254
151
  than the source. Local bare-repository fixtures cover repeat/stale events and
255
152
  divergence; live SSH credentials and host keys still require target validation.
256
153
 
154
+ ## Development and releases
155
+
257
156
  Develop with `bundle install` and `bundle exec rake verify`. Release and registry
258
157
  fixtures live in tests, using real Git and native gem builds with fake network
259
158
  publishers. No production rehearsal command or registry client is required.
260
159
 
261
- ## Built by Ethos Link
160
+ ## License
161
+
162
+ MIT. See [LICENSE.txt](LICENSE.txt).
163
+
164
+ ## About Ethos Link
165
+
166
+ [Ethos Link](https://www.ethos-link.com) is a software company founded by
167
+ [Paulo Fidalgo](https://www.fidalgo.pt). This gem is part of the open-source
168
+ tooling we publish alongside our business products:
262
169
 
263
- [Ethos Link](https://www.ethos-link.com) builds business software and integrations
264
- that replace manual handoffs with connected workflows. We help teams automate
265
- routine work, use their data and improve the processes their business runs on.
170
+ - [Reviato](https://www.reviato.com): collect private customer feedback and analyse public reviews.
171
+ - [Nuntio](https://www.nuntiohq.com): prepare, review and schedule social posts.
172
+ - [EthosPlaces](https://www.ethos.place): find places, opening hours and contact details.
266
173
 
267
- - [Reviato](https://www.reviato.com): Read public review trends and collect
268
- private customer feedback, so your team can decide what to improve.
269
- - [EthosPlaces](https://www.ethos.place): Give customers the details they need to
270
- choose and visit your business, from opening hours to directions.
271
- - [Nuntio](https://www.nuntiohq.com): Draft, review and schedule social posts in
272
- one workspace, then track each publishing result.
174
+ Explore our [open-source projects](https://www.ethos-link.com/opensource).
data/UPGRADE.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Upgrading Gemkit
2
2
 
3
+ ## Next release
4
+
5
+ Install mise (CI uses 2026.10.19) and run `bundle exec rake tools:install` after
6
+ upgrading the gem and matching workflow pins. Gemkit now uses native git-cliff
7
+ and GitHub CLI binaries pinned in its shipped `mise.toml` and `mise.lock`.
8
+ Node.js/npm is not required. Existing global CLI installations are no longer
9
+ used by verification or release preparation. git-cliff stays at 2.12.0 for this
10
+ installation change; GitHub CLI is pinned to 2.103.2.
11
+
12
+ ## Maintaining tool versions
13
+
14
+ Dependabot checks Ruby dependencies and GitHub Actions weekly. Review the mise
15
+ CLI, tool pins and system dependencies monthly, or sooner for security fixes;
16
+ Dependabot does not update mise tool versions. Do not auto-merge tool upgrades.
17
+
18
+ To update a tool, edit its exact version in `mise.toml`, then regenerate the
19
+ lockfile for every supported platform and install it:
20
+
21
+ ```sh
22
+ mise lock --platform linux-x64,linux-arm64,macos-x64,macos-arm64
23
+ bundle exec rake tools:install
24
+ bundle exec rake verify
25
+ ```
26
+
27
+ Commit `mise.toml` and `mise.lock` together. For Ruby updates, also update
28
+ `.ruby-version` and every `ruby/setup-ruby` pin; preserve native Bundler caching
29
+ in CI. For GitHub CLI updates, also update the release-notes job's isolated mise
30
+ configuration. Tests reject version drift in these duplicated pins. For mise
31
+ updates, keep the action's `version` input aligned across jobs and verify with
32
+ that version locally. Review Bundler's explicit version separately and keep
33
+ local installation aligned with the workflow pins.
34
+
35
+ Verification exercises changelog parsing, release preparation against disposable
36
+ Git repositories, and registry fixtures. Review changed changelog output before
37
+ accepting an upgrade, and wait for commitlint before merging. Tests and lint remain local. Never
38
+ use a real consumer release, tag or registry publication as a test. Update
39
+ consumer gem and workflow pins together after the toolkit release.
40
+
41
+ Git and shell utilities follow the host or CI runner image. Review image
42
+ upgrades separately; exact OS parity would require a shared container. Keep
43
+ Bundler-owned tools in Bundler rather than adding them to mise.
44
+
3
45
  ## 0.3.1
4
46
 
5
47
  Run `bundle exec rake verify` locally before pushing. `release:prepare` still
data/docs/releasing.md ADDED
@@ -0,0 +1,172 @@
1
+ # Releasing a gem
2
+
3
+ [README](../README.md) · [Project guide](https://www.ethos-link.com/opensource/ethos-gemkit)
4
+
5
+ **Run `release:prepare` from clean, up-to-date `main`.** It creates the conventional
6
+ release branch and opens a PR. **Merging that release PR starts publication.**
7
+ This is the same process for Gemkit itself and its adopted consumer gems.
8
+ Ordinary feature/fix PRs run commitlint; only a release PR starts publication.
9
+
10
+ ## One-time prerequisites
11
+
12
+ - Commit `Gemfile.lock`. Before its first commit, run
13
+ `bundle lock --add-checksums`; frozen CI installs reject empty registry
14
+ checksum entries, even when the gems are already installed locally.
15
+ - Ignore `/.bundle/`, `/vendor/bundle/` and `/pkg/` in `.gitignore`. The shared
16
+ workflows use Ruby setup's native `vendor/bundle` cache; generated files must
17
+ leave the release checkout clean.
18
+ - Install the bundle, Git and mise. Run
19
+ `bundle exec rake tools:install`. Configure your Git identity,
20
+ authenticate with `gh auth login`, and install hooks with
21
+ `bundle exec lefthook install`. You need permission to push branches and open PRs.
22
+ - Public gems: configure a matching RubyGems trusted publisher for **each gem**
23
+ before merging its first release PR. Use the exact settings below. Gemkit's
24
+ publisher does not authorize consumer gems.
25
+ - A new gem also needs a pending trusted publisher. Supply its numeric RubyGems
26
+ owner through the caller's `rubygems-owner` input or the repository/organization
27
+ variable `RUBYGEMS_OWNER` (the publisher account used by Tunnel is `27209`).
28
+ - Private gems: set `registry: github_packages`. Publishing uses the workflow's
29
+ short-lived `GITHUB_TOKEN`; the package must grant its repository Actions access.
30
+ Pass `PACKAGES_TOKEN` only when an explicit token override is needed. Local
31
+ installation from other private repositories still needs `read:packages` access.
32
+ - Configure the `rubygems` GitHub environment to allow `main` and `v*` tags.
33
+ Release callers grant `contents: write`, `id-token: write` and `packages: write`.
34
+ Repository rules must permit the workflow's annotated release tags.
35
+
36
+ The SDK release workflow listens directly for merged release PRs and version-tag
37
+ pushes. Consumer callers must listen for both `pull_request: types: [closed]`
38
+ against `main` and `push: tags: ["v*"]`, and pin the commit matching the installed
39
+ Gemkit release.
40
+ See the [Tunnel caller](https://github.com/ethos-link/cloudflare-tunnel/blob/main/.github/workflows/release.yml).
41
+
42
+ Projects keep their own local checks. Engines can register `checks: [ci:local]`
43
+ in `.ethos-gemkit.yml` and have that task run `bin/ci`. Provision PostgreSQL or
44
+ browser dependencies locally before running verification. Release callers do
45
+ not install test dependencies or accept `build-setup`.
46
+
47
+ ## RubyGems trusted-publisher settings
48
+
49
+ On RubyGems, open the **consumer gem's** page, then **Trusted publishers**. For
50
+ Cloudflare Tunnel, create or update the publisher with these exact values:
51
+
52
+ | RubyGems field | Value |
53
+ |---|---|
54
+ | Repository owner | `ethos-link` |
55
+ | Repository name | `cloudflare-tunnel` |
56
+ | Workflow filename | `release.yml` |
57
+ | Environment | `rubygems` |
58
+ | Workflow Repository Owner | `ethos-link` |
59
+ | Workflow Repository Name | `ethos-gemkit` |
60
+
61
+ The repository identifies the consumer; the Workflow Repository fields identify
62
+ the repository containing the shared workflow file. Those last two fields are
63
+ required for consumers,
64
+ even though RubyGems labels them optional. For another consumer, substitute its
65
+ repository name. For Gemkit itself, use repository name `ethos-gemkit` and leave
66
+ both Workflow Repository fields blank because the workflow is in the same repo.
67
+
68
+ The numeric `rubygems-owner` input identifies the account for pending publishers;
69
+ it does not register a publisher or grant access to a consumer gem. See the
70
+ [upstream reusable-workflow instructions](https://guides.rubygems.org/trusted-publishing/#using-reusable-workflows).
71
+
72
+ ## Prepare and review
73
+
74
+ For a normal patch release:
75
+
76
+ ```sh
77
+ git switch main
78
+ git pull --ff-only
79
+ bundle install
80
+ bundle exec rake release:prepare
81
+ ```
82
+
83
+ The default is `patch`. Select another target explicitly:
84
+
85
+ ```sh
86
+ bundle exec rake 'release:prepare[minor]'
87
+ bundle exec rake 'release:prepare[major]'
88
+ bundle exec rake 'release:prepare[1.2.0]'
89
+ ```
90
+
91
+ For an initial, unpublished version that is already in the gemspec and has no
92
+ tag, an explicit current version is supported. For example, a new gem starting
93
+ at 0.1.0 can use `bundle exec rake 'release:prepare[0.1.0]'` after pending-publisher
94
+ setup.
95
+
96
+ The task prints each step and streams command output as it runs. It checks the
97
+ working tree, canonical origin, current main, installed hooks and target tag.
98
+ It creates `chore/release-vX.Y.Z`, updates the version and
99
+ changelog, runs `bundle lock --add-checksums` and the full `rake verify`, then
100
+ commits the three metadata files with hooks enabled, pushes the branch, and opens a
101
+ `chore(release): prepare vX.Y.Z` PR. Main stays unchanged. You can also start on
102
+ that exact pre-created release branch if its HEAD still equals `origin/main`.
103
+ When starting from main, a leftover local release branch is recreated only if
104
+ all its commits are already in main; unmerged work is preserved and stops the task.
105
+
106
+ Review the generated notes, lockfile and version in the PR. Add or adjust upgrade
107
+ notes in a follow-up commit when needed, rerun affected checks locally, and wait
108
+ for commitlint before merging. The task
109
+ prints the PR URL and makes clear that merging it publishes the release.
110
+
111
+ ## Merge and publish
112
+
113
+ Merging a same-repository `chore/release-vX.Y.Z` PR into main runs the shared
114
+ workflow against its exact merge commit, including squash and rebase merges:
115
+
116
+ 1. Verify the expected version, main ancestry, notes and committed package bytes;
117
+ build one release artifact through Bundler. Tests and lint already ran locally
118
+ during `release:prepare` and are not repeated in Actions.
119
+ 2. Create and push the annotated `vX.Y.Z` tag without overwriting existing tags
120
+ or following unrelated local tags.
121
+ 3. In an isolated job, verify the artifact's SHA-256 checksums, obtain the proper
122
+ registry credentials, and publish that exact gem.
123
+ 4. In a separate job, create the GitHub release with the same gem and notes.
124
+
125
+ There is no manual tagging step in the normal flow. Build, tag and publication
126
+ continue in the same run because a tag pushed by GitHub's `GITHUB_TOKEN` does not
127
+ start another workflow. Existing manually pushed annotated version tags remain a
128
+ supported trigger and receive full canonical-tag verification.
129
+
130
+ Publish and notes jobs never check out or evaluate consumer code. Public gems
131
+ use short-lived OIDC credentials; private gems use the workflow token or an
132
+ explicit override. Both profiles push the same verified artifact to their
133
+ configured host; no registry fallback exists.
134
+
135
+ ## Failures and retries
136
+
137
+ If preparation fails, inspect `git status` and `git diff`. A failed verification
138
+ leaves changes on the local release branch without a release commit or push.
139
+ Fix and finish that ordinary branch, or restore the changes before starting over.
140
+ If the commit/push succeeded but opening the PR failed, use
141
+ `gh pr create --base main --head chore/release-vX.Y.Z --fill` after fixing access.
142
+ There is no journal or automatic reset of your working tree.
143
+
144
+ If credential setup fails with `No trusted publisher configured for this workflow`,
145
+ check the consumer's RubyGems settings against the table above. A successful
146
+ build and tag do not mean the gem was published. When `gem push` was skipped,
147
+ correct the publisher settings, then rerun **failed jobs only** in the original
148
+ workflow run. This reuses its verified artifact and existing tag; do not run
149
+ `release:prepare` again, bump the version or replace the tag for this failure.
150
+
151
+ ```sh
152
+ gh run rerun RUN_ID --repo OWNER/REPOSITORY --failed
153
+ ```
154
+
155
+ If a failed build needs a source fix and no tag or upload exists, keep the
156
+ prepared version and notes. Update its `chore/release-vX.Y.Z` branch from main,
157
+ commit the fix, run verification and open a replacement release PR. Merge that
158
+ PR to run the corrected source. The original run stays pinned to its original
159
+ commit; rerunning it cannot pick up a source fix. Do not replace an existing tag
160
+ or reuse a version that was already published.
161
+
162
+ For transient CI failures, retry **failed jobs in the original run** within GitHub's 30-day
163
+ retry window. Artifacts are retained for 90 days. A failed tag step can reuse an
164
+ existing annotated tag only when it points to the same verified commit. A failed
165
+ notes job reuses the original artifact without uploading again. Ambiguous uploads,
166
+ already published versions, existing GitHub releases or expired runs/artifacts
167
+ require registry/release reconciliation. Never replace a tag or rebuild a
168
+ published version to repair release notes.
169
+
170
+ Provider references: [reusable RubyGems trusted publishers](https://guides.rubygems.org/trusted-publishing/#using-reusable-workflows),
171
+ [GitHub token-trigger behavior](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow),
172
+ and [failed-job retries](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/re-run-workflows-and-jobs).
@@ -4,6 +4,7 @@ require "open3"
4
4
  require "bundler"
5
5
  require_relative "configuration"
6
6
  require_relative "branch"
7
+ require_relative "tools"
7
8
 
8
9
  module Ethos
9
10
  module Gemkit
@@ -18,6 +19,8 @@ module Ethos
18
19
 
19
20
  # Release metadata uses an ordinary branch and PR; main is never committed.
20
21
  def prepare(target = "patch")
22
+ git_cliff = Tools.executable("git-cliff")
23
+ github = Tools.executable("gh")
21
24
  progress "Checking working tree and repository"
22
25
  clean
23
26
  canonical_origin
@@ -53,7 +56,7 @@ module Ethos
53
56
  raise Error, "Start from main or #{branch} at origin/main"
54
57
  end
55
58
  progress "Checking GitHub authentication"
56
- run("gh", "auth", "status", "--hostname", "github.com")
59
+ run(github, "auth", "status", "--hostname", "github.com")
57
60
  progress "Preparing #{branch}"
58
61
  if current_branch == "main"
59
62
  unless git("branch", "--list", branch).empty?
@@ -67,7 +70,7 @@ module Ethos
67
70
  Branch.check(@config.root)
68
71
  progress "Updating version and changelog to #{target}"
69
72
  File.write(file, text.sub(literal, %(VERSION = "#{target}")))
70
- run("git-cliff", "--config", "cliff.toml", "--unreleased", "--tag", "v#{target}", "--prepend", "CHANGELOG.md", live: true)
73
+ run(git_cliff, "--config", "cliff.toml", "--unreleased", "--tag", "v#{target}", "--prepend", "CHANGELOG.md", live: true)
71
74
  progress "Updating Gemfile.lock"
72
75
  run("bundle", "lock", "--add-checksums", live: true)
73
76
  progress "Running verification (lint, tests, package, changelog)"
@@ -85,7 +88,7 @@ module Ethos
85
88
  progress "Pushing #{branch}"
86
89
  run("git", "push", "--no-follow-tags", "--set-upstream", "origin", branch, live: true)
87
90
  progress "Opening release PR"
88
- url = run("gh", "pr", "create", "--repo", @config.data.fetch("repository"),
91
+ url = run(github, "pr", "create", "--repo", @config.data.fetch("repository"),
89
92
  "--base", "main", "--head", branch, "--title", title,
90
93
  "--body", "#{body}\n\nMerging this PR creates annotated tag v#{target} and publishes the verified gem.").strip
91
94
  "#{url}\nMerge this release PR to tag and publish v#{target}."
@@ -3,6 +3,7 @@
3
3
  require "standard/rake"
4
4
  require_relative "configuration"
5
5
  require_relative "package"
6
+ require_relative "tools"
6
7
 
7
8
  config = Ethos::Gemkit::Configuration.load
8
9
  standard = YAML.safe_load_file(config.path(".standard.yml"), aliases: false)
@@ -11,6 +12,11 @@ unless standard.is_a?(Hash) && standard["ruby_version"].to_s == "4.0" && Array(s
11
12
  end
12
13
  task lint: :standard
13
14
  task "lint:fix" => "standard:fix"
15
+ desc "Install pinned development binaries with mise"
16
+ task "tools:install" do
17
+ sh "mise", "trust", File.join(Ethos::Gemkit::Tools::ROOT, "mise.toml")
18
+ sh "mise", "--cd", Ethos::Gemkit::Tools::ROOT, "install", "--locked", "git-cliff", "gh"
19
+ end
14
20
  task "package:verify" do
15
21
  Ethos::Gemkit::Package.new(config).verify
16
22
  end
@@ -18,5 +24,5 @@ end
18
24
  desc "Run lint, gem checks, package validation and changelog validation"
19
25
  task verify: [:lint, *config.checks, "package:verify"] do
20
26
  require "tempfile"
21
- Tempfile.create("gemkit-changelog") { |file| sh "git-cliff", "--config", "cliff.toml", "--unreleased", "--output", file.path }
27
+ Tempfile.create("gemkit-changelog") { |file| sh Ethos::Gemkit::Tools.executable("git-cliff"), "--config", "cliff.toml", "--unreleased", "--output", file.path }
22
28
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require_relative "../gemkit"
5
+
6
+ module Ethos
7
+ module Gemkit
8
+ module Tools
9
+ ROOT = File.expand_path("../../..", __dir__)
10
+
11
+ # Resolve against the installed gem, even when called from a consumer.
12
+ # --tool prevents an unrelated executable on PATH from satisfying lookup.
13
+ def self.executable(name)
14
+ output, error, status = Open3.capture3("mise", "--cd", ROOT, "which", "--tool", name, name)
15
+ unless status.success? && File.executable?(output.strip)
16
+ raise Error, "Install pinned #{name} with bundle exec rake tools:install: #{error.strip}"
17
+ end
18
+ output.strip
19
+ rescue Errno::ENOENT
20
+ raise Error, "Install mise, then run bundle exec rake tools:install"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ethos
4
4
  module Gemkit
5
- VERSION = "0.3.1"
5
+ VERSION = "0.3.2"
6
6
  end
7
7
  end
data/mise.lock ADDED
@@ -0,0 +1,91 @@
1
+ # @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html
2
+
3
+ lockfile_version = 3
4
+
5
+ [[tools.gh]]
6
+ version = "2.103.2"
7
+ backend = "aqua:cli/cli"
8
+ specifiers = ["2.103.2"]
9
+
10
+ [tools.gh."platforms.linux-arm64"]
11
+ checksum = "sha256:4c3e99a50bd8b181a3fe9d69b25dd978bac768148d88f01507c6b4d1ef61a443"
12
+ url = "https://github.com/cli/cli/releases/download/v2.103.2/gh_2.103.2_linux_arm64.tar.gz"
13
+ url_api = "https://api.github.com/repos/cli/cli/releases/assets/670305069"
14
+ provenance = "github-attestations"
15
+
16
+ [tools.gh."platforms.linux-x64"]
17
+ checksum = "sha256:62ccf747115ddc61237efffdde66a3c8f70ba249433dc64f70801089b59c59c8"
18
+ url = "https://github.com/cli/cli/releases/download/v2.103.2/gh_2.103.2_linux_amd64.tar.gz"
19
+ url_api = "https://api.github.com/repos/cli/cli/releases/assets/670305062"
20
+ provenance = "github-attestations"
21
+
22
+ [tools.gh."platforms.macos-arm64"]
23
+ checksum = "sha256:5416000f5d17580a187339e0c4068a01ca5c87f7d4fe6ca64933696f967bc418"
24
+ url = "https://github.com/cli/cli/releases/download/v2.103.2/gh_2.103.2_macOS_arm64.zip"
25
+ url_api = "https://api.github.com/repos/cli/cli/releases/assets/670305145"
26
+ provenance = "github-attestations"
27
+
28
+ [tools.gh."platforms.macos-x64"]
29
+ checksum = "sha256:2dc7f1fc4761f96732995f6e4f4c6b4d705f2635da4126620c8b30eaa67b9c98"
30
+ url = "https://github.com/cli/cli/releases/download/v2.103.2/gh_2.103.2_macOS_amd64.zip"
31
+ url_api = "https://api.github.com/repos/cli/cli/releases/assets/670305131"
32
+ provenance = "github-attestations"
33
+
34
+ [[tools.git-cliff]]
35
+ version = "2.12.0"
36
+ backend = "aqua:orhun/git-cliff"
37
+ specifiers = ["2.12.0"]
38
+
39
+ [tools.git-cliff."platforms.linux-arm64"]
40
+ checksum = "sha256:9d7aa3c1a860d9c9813458fcdd1846e2859c560d86c7b401e5e58dc10790f94b"
41
+ checksum_source = "mise-versions"
42
+ url = "https://github.com/orhun/git-cliff/releases/download/v2.12.0/git-cliff-2.12.0-aarch64-unknown-linux-gnu.tar.gz"
43
+ url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/343377984"
44
+
45
+ [tools.git-cliff."platforms.linux-x64"]
46
+ checksum = "sha256:6241bd23554daf527ca8ff0dc475a272b0155bede8a000e7a9d74b771036a7bd"
47
+ checksum_source = "mise-versions"
48
+ url = "https://github.com/orhun/git-cliff/releases/download/v2.12.0/git-cliff-2.12.0-x86_64-unknown-linux-gnu.tar.gz"
49
+ url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/343377955"
50
+
51
+ [tools.git-cliff."platforms.macos-arm64"]
52
+ checksum = "sha256:2ae72a0061bee98d0e375f2ea8e0f4b23b4915ac2e37fa45a705066de49b43a0"
53
+ checksum_source = "mise-versions"
54
+ url = "https://github.com/orhun/git-cliff/releases/download/v2.12.0/git-cliff-2.12.0-aarch64-apple-darwin.tar.gz"
55
+ url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/343378832"
56
+
57
+ [tools.git-cliff."platforms.macos-x64"]
58
+ checksum = "sha256:fd4bce35ea8a6f3af6ac4891073781ca24c654c36c83c865bc30bab332c05a14"
59
+ checksum_source = "mise-versions"
60
+ url = "https://github.com/orhun/git-cliff/releases/download/v2.12.0/git-cliff-2.12.0-x86_64-apple-darwin.tar.gz"
61
+ url_api = "https://api.github.com/repos/orhun/git-cliff/releases/assets/343379425"
62
+
63
+ [[tools.ruby]]
64
+ version = "4.0.9"
65
+ backend = "core:ruby"
66
+ specifiers = ["4.0.9"]
67
+
68
+ [tools.ruby.options]
69
+ compile = "false"
70
+ precompiled_url = "jdx/ruby"
71
+ ruby_build_repo = "https://github.com/rbenv/ruby-build.git"
72
+ ruby_install = "false"
73
+
74
+ [tools.ruby."platforms.linux-arm64"]
75
+ checksum = "sha256:e115ae4dce7193d862e1f105d7969472f0fcead4a440bbb08c9af92528ed0dd9"
76
+ url = "https://github.com/jdx/ruby/releases/download/4.0.9-1/ruby-4.0.9.arm64_linux.tar.gz"
77
+ provenance = "github-attestations"
78
+
79
+ [tools.ruby."platforms.linux-x64"]
80
+ checksum = "sha256:7e74db7ddb8f44f534fa4937d98b6d1691e053c5c190af6d130464b0467e87c4"
81
+ url = "https://github.com/jdx/ruby/releases/download/4.0.9-1/ruby-4.0.9.x86_64_linux.tar.gz"
82
+ provenance = "github-attestations"
83
+
84
+ [tools.ruby."platforms.macos-arm64"]
85
+ checksum = "sha256:6eca5d2aaf6bb6c805daa31b4139a3c974526f41dae990ab0cef0ee3db8ea5d1"
86
+ url = "https://github.com/jdx/ruby/releases/download/4.0.9-1/ruby-4.0.9.macos.tar.gz"
87
+ provenance = "github-attestations"
88
+
89
+ [tools.ruby."platforms.macos-x64"]
90
+ checksum = "sha256:c35350682ff050b79702d57ade4516e7336063f510155d19fb2fb5b3f3909511"
91
+ url = "https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.9.tar.gz"
data/mise.toml ADDED
@@ -0,0 +1,4 @@
1
+ [tools]
2
+ ruby = "4.0.9"
3
+ git-cliff = "2.12.0"
4
+ gh = "2.103.2"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ethos-gemkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethos Link
@@ -92,6 +92,7 @@ files:
92
92
  - LICENSE.txt
93
93
  - README.md
94
94
  - UPGRADE.md
95
+ - docs/releasing.md
95
96
  - exe/ethos-gemkit
96
97
  - lib/ethos-gemkit.rb
97
98
  - lib/ethos/gemkit.rb
@@ -104,11 +105,17 @@ files:
104
105
  - lib/ethos/gemkit/release.rb
105
106
  - lib/ethos/gemkit/release_tasks.rb
106
107
  - lib/ethos/gemkit/tasks.rb
108
+ - lib/ethos/gemkit/tools.rb
107
109
  - lib/ethos/gemkit/version.rb
108
- homepage: https://github.com/ethos-link/ethos-gemkit
110
+ - mise.lock
111
+ - mise.toml
112
+ homepage: https://www.ethos-link.com/opensource/ethos-gemkit
109
113
  licenses:
110
114
  - MIT
111
115
  metadata:
116
+ homepage_uri: https://www.ethos-link.com/opensource/ethos-gemkit
117
+ documentation_uri: https://www.ethos-link.com/opensource/ethos-gemkit
118
+ bug_tracker_uri: https://github.com/ethos-link/ethos-gemkit/issues
112
119
  allowed_push_host: https://rubygems.org
113
120
  source_code_uri: https://github.com/ethos-link/ethos-gemkit
114
121
  changelog_uri: https://github.com/ethos-link/ethos-gemkit/blob/main/CHANGELOG.md