ethos-gemkit 0.1.0 → 0.2.1

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: 5445351e6ccbd6c2155a603d7c7fcf5d57e3e6a2e275cafa307431c4f4ae63fb
4
- data.tar.gz: 8b2a74b858376f970c096b2599e5607eb88ca8b78e2ba53f11485d4a2b4d8059
3
+ metadata.gz: ea8ac801fd96cef32c35240e93271d04792235c4121c95f8261918f87795b2b1
4
+ data.tar.gz: 87a5464f90175cd5cf5f088f573ab2d47886ea2a702f5cb183f722081eb8bb47
5
5
  SHA512:
6
- metadata.gz: 9cdf0c22ba2d534f270e02904ddc018ebad5448b68bf656ecdd3fceea8f8408b241f108da2f6024a253c67d291d63dbae7e13e3a3fd14c628d8bdcaeab2a5138
7
- data.tar.gz: d9464b72094dafe244db34ac048e8dda59154784df181db4005c674b217fe946f8d873ecb323617531543b5faa13ffde4f22af1d44b352f40f5576209ed41033
6
+ metadata.gz: eb7aef3f0ccab2964c6a318649f72fbdc0f9fe9615814828c4161c386463794f10bcffc2383f001bfe9d7ba12bb46ff53a3e2280dc18481508df6b768ac1d62c
7
+ data.tar.gz: 74ba19f731bbbcfaa9a113e5d138929636fab47e2c35120ba410ed40019f04a797546d43911e18ef5b1bc5cac37f2953e6df277c974300f9554df1a5a64134c3
data/CHANGELOG.md CHANGED
@@ -5,6 +5,51 @@ 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.2.1] - 2026-11-05
9
+
10
+
11
+ ### Documentation
12
+
13
+ - clarify current setup
14
+
15
+ - document checksums for frozen installs
16
+
17
+ - distinguish source fixes from workflow retries
18
+
19
+
20
+
21
+
22
+ ### Fixed
23
+
24
+ - preserve checksums during preparation
25
+
26
+
27
+
28
+ ## [0.2.0] - 2026-11-04
29
+
30
+
31
+ ### Added
32
+
33
+ - support native private publishing and project setup
34
+
35
+
36
+
37
+
38
+ ### Documentation
39
+
40
+ - document the published Gemkit release
41
+
42
+ - clarify per-gem publishers and safe retries
43
+
44
+
45
+
46
+
47
+ ### Fixed
48
+
49
+ - show preparation progress and live command output
50
+
51
+
52
+
8
53
  ## [0.1.0] - 2026-11-04
9
54
 
10
55
 
data/README.md CHANGED
@@ -4,9 +4,21 @@ 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
- During bootstrap, pin the Git dependency and workflow callers to the same reviewed
8
- commit; the toolkit has not been published. See the working
9
- [Cloudflare Tunnel Gemfile](https://github.com/ethos-link/cloudflare-tunnel/blob/feat/ethos-gemkit/Gemfile).
7
+ Install the published gem in the development/test Gemfile:
8
+
9
+ ```ruby
10
+ gem "ethos-gemkit", "0.2.1", group: [:development, :test], require: false
11
+ ```
12
+
13
+ Pin workflow callers to the full commit behind the installed Gemkit release tag.
14
+ Resolve that commit with:
15
+
16
+ ```sh
17
+ git ls-remote https://github.com/ethos-link/ethos-gemkit.git 'refs/tags/v0.2.1^{}'
18
+ ```
19
+
20
+ Upgrade the gem version and workflow pins together. Consumer READMEs should cover
21
+ their own APIs and checks, then link here for shared setup and release details.
10
22
 
11
23
  A standard gem needs this Rakefile:
12
24
 
@@ -41,6 +53,21 @@ release tasks while a repository is adopting the toolkit.
41
53
  `bundle exec rake verify` runs lint, registered checks, a disposable native gem
42
54
  build, and git-cliff validation.
43
55
 
56
+ ## Private gem access
57
+
58
+ To install private gems locally, use a GitHub personal access token (classic)
59
+ with `read:packages` and access to the package. Configure Bundler once, replacing
60
+ `USERNAME` and `TOKEN` with your credentials:
61
+
62
+ ```sh
63
+ bundle config set --global https://rubygems.pkg.github.com/ethos-link USERNAME:TOKEN
64
+ ```
65
+
66
+ Keep credentials out of Gemfiles. Each gem documents its scoped source block.
67
+ Actions publishing uses `GITHUB_TOKEN`; installing another private repository's
68
+ package requires that repository to grant the workflow access or an explicit
69
+ token. See [GitHub's registry guide](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-rubygems-registry).
70
+
44
71
  ## Releasing a gem
45
72
 
46
73
  **Run `release:prepare` from clean, up-to-date `main`.** It creates the conventional
@@ -50,31 +77,65 @@ Ordinary feature/fix PRs run verification; only a release PR starts publication.
50
77
 
51
78
  ### One-time prerequisites
52
79
 
80
+ - Commit `Gemfile.lock`. Before its first commit, run
81
+ `bundle lock --add-checksums`; frozen CI installs reject empty registry
82
+ checksum entries, even when the gems are already installed locally.
53
83
  - Ignore `/.bundle/`, `/vendor/bundle/` and `/pkg/` in `.gitignore`. The shared
54
84
  workflows use Ruby setup's native `vendor/bundle` cache; generated files must
55
85
  leave the release checkout clean.
56
86
  - Install the bundle, Git, git-cliff and GitHub CLI. Configure your Git identity,
57
87
  authenticate with `gh auth login`, and install hooks with
58
88
  `bundle exec lefthook install`. You need permission to push branches and open PRs.
59
- - Public gems: configure RubyGems trusted publishing for the gem. Use environment
60
- `rubygems`, workflow filename `release.yml`, and the consumer owner/repository.
61
- For a consumer such as Tunnel, set workflow repository owner `ethos-link` and
62
- workflow repository `ethos-gemkit`. For Gemkit's own publisher, leave those
63
- optional workflow-repository fields blank because it is the same repository.
89
+ - Public gems: configure a matching RubyGems trusted publisher for **each gem**
90
+ before merging its first release PR. Use the exact settings below. Gemkit's
91
+ publisher does not authorize consumer gems.
64
92
  - A new gem also needs a pending trusted publisher. Supply its numeric RubyGems
65
93
  owner through the caller's `rubygems-owner` input or the repository/organization
66
- variable `RUBYGEMS_OWNER` (the Ethos account used by Tunnel is `27209`).
67
- - Private gems: set the GitHub Packages registry profile and pass a scoped
68
- `PACKAGES_TOKEN` secret to the release workflow. The two profiles use the same
69
- native `gem push` with their respective host and credentials.
70
- - Configure the `rubygems` GitHub environment to allow releases from `main` and
71
- `v*` tags. Grant the release workflow contents-write and id-token-write
72
- permissions; repository rules must permit its release tags.
94
+ variable `RUBYGEMS_OWNER` (the publisher account used by Tunnel is `27209`).
95
+ - Private gems: set `registry: github_packages`. Publishing uses the workflow's
96
+ short-lived `GITHUB_TOKEN`; the package must grant its repository Actions access.
97
+ Pass `PACKAGES_TOKEN` only when an explicit token override is needed. Local
98
+ installation from other private repositories still needs `read:packages` access.
99
+ - Configure the `rubygems` GitHub environment to allow `main` and `v*` tags.
100
+ Release callers grant `contents: write`, `id-token: write` and `packages: write`.
101
+ Repository rules must permit the workflow's annotated release tags.
73
102
 
74
103
  The SDK release workflow listens directly for merged release PRs and version-tag
75
104
  pushes. Consumer callers must listen for both `pull_request: types: [closed]`
76
- against `main` and `push: tags: ["v*"]`, and pin the same SDK commit as the Gemfile.
77
- See the [Tunnel caller](https://github.com/ethos-link/cloudflare-tunnel/blob/feat/ethos-gemkit/.github/workflows/release.yml).
105
+ against `main` and `push: tags: ["v*"]`, and pin the commit matching the installed
106
+ Gemkit release.
107
+ See the [Tunnel caller](https://github.com/ethos-link/cloudflare-tunnel/blob/main/.github/workflows/release.yml).
108
+
109
+ Projects keep their own checks. Engines can register `checks: [ci:local]` in
110
+ `.ethos-gemkit.yml` and have that task run `bin/ci`. Set the release caller's
111
+ optional `build-setup` input to provision those checks' dependencies, such as
112
+ PostgreSQL or browser packages. Setup runs only in the read-only build job;
113
+ publishing credentials remain in the separate publish job.
114
+
115
+ ### RubyGems trusted-publisher settings
116
+
117
+ On RubyGems, open the **consumer gem's** page, then **Trusted publishers**. For
118
+ Cloudflare Tunnel, create or update the publisher with these exact values:
119
+
120
+ | RubyGems field | Value |
121
+ |---|---|
122
+ | Repository owner | `ethos-link` |
123
+ | Repository name | `cloudflare-tunnel` |
124
+ | Workflow filename | `release.yml` |
125
+ | Environment | `rubygems` |
126
+ | Workflow Repository Owner | `ethos-link` |
127
+ | Workflow Repository Name | `ethos-gemkit` |
128
+
129
+ The repository identifies the consumer; the Workflow Repository fields identify
130
+ the repository containing the shared workflow file. Those last two fields are
131
+ required for consumers,
132
+ even though RubyGems labels them optional. For another consumer, substitute its
133
+ repository name. For Gemkit itself, use repository name `ethos-gemkit` and leave
134
+ both Workflow Repository fields blank because the workflow is in the same repo.
135
+
136
+ The numeric `rubygems-owner` input identifies the account for pending publishers;
137
+ it does not register a publisher or grant access to a consumer gem. See the
138
+ [upstream reusable-workflow instructions](https://guides.rubygems.org/trusted-publishing/#using-reusable-workflows).
78
139
 
79
140
  ### Prepare and review
80
141
 
@@ -96,13 +157,15 @@ bundle exec rake 'release:prepare[1.2.0]'
96
157
  ```
97
158
 
98
159
  For an initial, unpublished version that is already in the gemspec and has no
99
- tag, an explicit current version is supported. Gemkit's initial release can use
100
- `bundle exec rake 'release:prepare[0.1.0]'` after pending-publisher setup.
101
-
102
- The task checks the working tree, canonical origin, current main, installed hooks
103
- and target tag. It creates `chore/release-vX.Y.Z`, updates the version and
104
- changelog, runs `bundle lock --local` and the full `rake verify`, then commits the
105
- three metadata files with hooks enabled, pushes the branch, and opens a
160
+ tag, an explicit current version is supported. For example, a new gem starting
161
+ at 0.1.0 can use `bundle exec rake 'release:prepare[0.1.0]'` after pending-publisher
162
+ setup.
163
+
164
+ The task prints each step and streams command output as it runs. It checks the
165
+ working tree, canonical origin, current main, installed hooks and target tag.
166
+ It creates `chore/release-vX.Y.Z`, updates the version and
167
+ changelog, runs `bundle lock --add-checksums` and the full `rake verify`, then
168
+ commits the three metadata files with hooks enabled, pushes the branch, and opens a
106
169
  `chore(release): prepare vX.Y.Z` PR. Main stays unchanged. You can also start on
107
170
  that exact pre-created release branch if its HEAD still equals `origin/main`.
108
171
  When starting from main, a leftover local release branch is recreated only if
@@ -131,8 +194,9 @@ start another workflow. Existing manually pushed annotated version tags remain a
131
194
  supported trigger and receive full canonical-tag verification.
132
195
 
133
196
  Publish and notes jobs never check out or evaluate consumer code. Public gems
134
- use short-lived OIDC credentials; private gems use the supplied scoped token.
135
- No registry fallback exists. Live private publication still needs a private pilot.
197
+ use short-lived OIDC credentials; private gems use the workflow token or an
198
+ explicit override. Both profiles push the same verified artifact to their
199
+ configured host; no registry fallback exists.
136
200
 
137
201
  ### Failures and retries
138
202
 
@@ -143,7 +207,25 @@ If the commit/push succeeded but opening the PR failed, use
143
207
  `gh pr create --base main --head chore/release-vX.Y.Z --fill` after fixing access.
144
208
  There is no journal or automatic reset of your working tree.
145
209
 
146
- For CI failures, retry **failed jobs in the original run** within GitHub's 30-day
210
+ If credential setup fails with `No trusted publisher configured for this workflow`,
211
+ check the consumer's RubyGems settings against the table above. A successful
212
+ build and tag do not mean the gem was published. When `gem push` was skipped,
213
+ correct the publisher settings, then rerun **failed jobs only** in the original
214
+ workflow run. This reuses its verified artifact and existing tag; do not run
215
+ `release:prepare` again, bump the version or replace the tag for this failure.
216
+
217
+ ```sh
218
+ gh run rerun RUN_ID --repo OWNER/REPOSITORY --failed
219
+ ```
220
+
221
+ If a failed build needs a source fix and no tag or upload exists, keep the
222
+ prepared version and notes. Update its `chore/release-vX.Y.Z` branch from main,
223
+ commit the fix, run verification and open a replacement release PR. Merge that
224
+ PR to run the corrected source. The original run stays pinned to its original
225
+ commit; rerunning it cannot pick up a source fix. Do not replace an existing tag
226
+ or reuse a version that was already published.
227
+
228
+ For transient CI failures, retry **failed jobs in the original run** within GitHub's 30-day
147
229
  retry window. Artifacts are retained for 90 days. A failed tag step can reuse an
148
230
  existing annotated tag only when it points to the same verified commit. A failed
149
231
  notes job reuses the original artifact without uploading again. Ambiguous uploads,
@@ -166,3 +248,16 @@ divergence; live SSH credentials and host keys still require target validation.
166
248
  Develop with `bundle install` and `bundle exec rake verify`. Release and registry
167
249
  fixtures live in tests, using real Git and native gem builds with fake network
168
250
  publishers. No production rehearsal command or registry client is required.
251
+
252
+ ## Built by Ethos Link
253
+
254
+ [Ethos Link](https://www.ethos-link.com) builds business software and integrations
255
+ that replace manual handoffs with connected workflows. We help teams automate
256
+ routine work, use their data and improve the processes their business runs on.
257
+
258
+ - [Reviato](https://www.reviato.com): Read public review trends and collect
259
+ private customer feedback, so your team can decide what to improve.
260
+ - [EthosPlaces](https://www.ethos.place): Give customers the details they need to
261
+ choose and visit your business, from opening hours to directions.
262
+ - [Nuntio](https://www.nuntiohq.com): Draft, review and schedule social posts in
263
+ one workspace, then track each publishing result.
data/UPGRADE.md ADDED
@@ -0,0 +1,27 @@
1
+ # Upgrading Gemkit
2
+
3
+ ## 0.2.1
4
+
5
+ Release preparation now fetches registry checksums with Bundler instead of
6
+ using local-only resolution. Network access to configured gem sources is
7
+ required. Existing compatible dependency versions stay locked; complete
8
+ checksums prevent frozen CI installs from rejecting local cache metadata.
9
+
10
+ ## 0.2.0
11
+
12
+ Update the gem version and pin each workflow caller to the commit behind the
13
+ matching release tag. Release callers must grant `contents: write`,
14
+ `id-token: write` and `packages: write`, including public-gem callers: the shared
15
+ publisher supports both registries.
16
+
17
+ GitHub Packages publication now defaults to the workflow's `GITHUB_TOKEN`.
18
+ Grant the repository Actions access to its package. Existing `PACKAGES_TOKEN`
19
+ overrides remain supported; no new personal access token is required.
20
+
21
+ Release preparation prints each phase and streams verification, hook and push
22
+ output. Versioning, review and publication remain the same: prepare from clean,
23
+ current main, review the release PR, then merge to publish through Actions.
24
+
25
+ Projects with system-dependent checks can pass `build-setup` to the release
26
+ workflow. Keep those checks in the project's existing command; setup only
27
+ provisions dependencies before the read-only build job runs verification.
@@ -18,8 +18,10 @@ module Ethos
18
18
 
19
19
  # Release metadata uses an ordinary branch and PR; main is never committed.
20
20
  def prepare(target = "patch")
21
+ progress "Checking working tree and repository"
21
22
  clean
22
23
  canonical_origin
24
+ progress "Fetching origin/main"
23
25
  git("fetch", "--no-tags", "origin", "refs/heads/main:refs/remotes/origin/main")
24
26
  unless git("rev-parse", "HEAD") == git("rev-parse", "origin/main")
25
27
  raise Error, "Start from clean main at origin/main; fetch and fast-forward before preparing a release"
@@ -43,13 +45,16 @@ module Ethos
43
45
  end
44
46
  literal = %(VERSION = "#{current}")
45
47
  raise Error, "Expected a literal #{literal} in version_file" unless text.include?(literal)
48
+ progress "Checking release tag v#{target}"
46
49
  raise Error, "Release tag already exists" unless git("tag", "--list", "v#{target}").empty? && git("ls-remote", "--tags", "origin", "refs/tags/v#{target}").empty?
47
50
  branch = "chore/release-v#{target}"
48
51
  current_branch = git("branch", "--show-current")
49
52
  unless ["main", branch].include?(current_branch)
50
53
  raise Error, "Start from main or #{branch} at origin/main"
51
54
  end
55
+ progress "Checking GitHub authentication"
52
56
  run("gh", "auth", "status", "--hostname", "github.com")
57
+ progress "Preparing #{branch}"
53
58
  if current_branch == "main"
54
59
  unless git("branch", "--list", branch).empty?
55
60
  unless git("rev-list", "--count", "origin/main..#{branch}") == "0"
@@ -60,20 +65,26 @@ module Ethos
60
65
  git("switch", "-c", branch)
61
66
  end
62
67
  Branch.check(@config.root)
68
+ progress "Updating version and changelog to #{target}"
63
69
  File.write(file, text.sub(literal, %(VERSION = "#{target}")))
64
- run("git-cliff", "--config", "cliff.toml", "--unreleased", "--tag", "v#{target}", "--prepend", "CHANGELOG.md")
65
- run("bundle", "lock", "--local")
66
- run("bundle", "exec", "rake", "verify")
70
+ run("git-cliff", "--config", "cliff.toml", "--unreleased", "--tag", "v#{target}", "--prepend", "CHANGELOG.md", live: true)
71
+ progress "Updating Gemfile.lock"
72
+ run("bundle", "lock", "--add-checksums", live: true)
73
+ progress "Running verification (lint, tests, package, changelog)"
74
+ run("bundle", "exec", "rake", "verify", live: true)
67
75
  files = [@config.data.fetch("version_file"), "CHANGELOG.md", "Gemfile.lock"]
68
76
  unless (git("diff", "--name-only").lines.map(&:strip) - files).empty? && git("ls-files", "--others", "--exclude-standard").empty?
69
77
  raise Error, "Verification changed unrelated files; review git diff before committing"
70
78
  end
71
79
  title = "chore(release): prepare v#{target}"
72
80
  body = "Prepare #{spec.name} #{target} for publication.\n\nRecord the version, generated notes and lockfile after verification."
81
+ progress "Committing release metadata with hooks enabled"
73
82
  git("add", "--", *files)
74
- git("commit", "-m", title, "-m", body)
83
+ run("git", "commit", "-m", title, "-m", body, live: true)
75
84
  clean
76
- git("push", "--no-follow-tags", "--set-upstream", "origin", branch)
85
+ progress "Pushing #{branch}"
86
+ run("git", "push", "--no-follow-tags", "--set-upstream", "origin", branch, live: true)
87
+ progress "Opening release PR"
77
88
  url = run("gh", "pr", "create", "--repo", @config.data.fetch("repository"),
78
89
  "--base", "main", "--head", branch, "--title", title,
79
90
  "--body", "#{body}\n\nMerging this PR creates annotated tag v#{target} and publishes the verified gem.").strip
@@ -122,9 +133,19 @@ module Ethos
122
133
  run("git", *arguments).strip
123
134
  end
124
135
 
125
- def run(*arguments)
136
+ def progress(message)
137
+ $stdout.puts "[release:prepare] #{message}..."
138
+ $stdout.flush
139
+ end
140
+
141
+ def run(*arguments, live: false)
126
142
  environment = {"BUNDLE_GEMFILE" => File.join(@config.root, "Gemfile"),
127
143
  "GEM_PATH" => [*Gem.path, *Gem.loaded_specs.values.map(&:base_dir)].uniq.join(File::PATH_SEPARATOR)}
144
+ if live
145
+ success = Bundler.with_unbundled_env { system(environment, *arguments, chdir: @config.root) }
146
+ raise Error, "#{arguments.first(3).join(" ")} failed; see output above" unless success
147
+ return ""
148
+ end
128
149
  output, error, status = Bundler.with_unbundled_env { Open3.capture3(environment, *arguments, chdir: @config.root) }
129
150
  raise Error, "#{arguments.first(3).join(" ")} failed: #{output}#{error}" unless status.success?
130
151
  output
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ethos
4
4
  module Gemkit
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.1"
6
6
  end
7
7
  end
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.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethos Link
@@ -91,6 +91,7 @@ files:
91
91
  - CHANGELOG.md
92
92
  - LICENSE.txt
93
93
  - README.md
94
+ - UPGRADE.md
94
95
  - exe/ethos-gemkit
95
96
  - lib/ethos-gemkit.rb
96
97
  - lib/ethos/gemkit.rb