ethos-gemkit 0.1.0 → 0.2.0

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: 248ba6ddb45bb0374b8d8fb4a59a987606ce2c2494a5b74d45b5f1c70911c84c
4
+ data.tar.gz: 0fd71c3766c11333163d12bf77399dc0b16748a0743aeed9b0cd5d09cc4c560e
5
5
  SHA512:
6
- metadata.gz: 9cdf0c22ba2d534f270e02904ddc018ebad5448b68bf656ecdd3fceea8f8408b241f108da2f6024a253c67d291d63dbae7e13e3a3fd14c628d8bdcaeab2a5138
7
- data.tar.gz: d9464b72094dafe244db34ac048e8dda59154784df181db4005c674b217fe946f8d873ecb323617531543b5faa13ffde4f22af1d44b352f40f5576209ed41033
6
+ metadata.gz: 0c18eed79a4fdc2482c4d24addd491c2c663c2db3aa48f8188c02af3e0032b763c8568f651b7a0be9b72a2f84417fc982b72b3fec2f551fd9aedf66d7c870d05
7
+ data.tar.gz: 756aaa36df80a27b01f14e87093b4849f973ad690c6af486b38a948a7762e6028c5b9f9b2baf0034ccb8bda805525da7810912401398bf1e848dc35abfd1a8d5
data/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ 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.0] - 2026-11-04
9
+
10
+
11
+ ### Added
12
+
13
+ - support native private publishing and project setup
14
+
15
+
16
+
17
+
18
+ ### Documentation
19
+
20
+ - document the published Gemkit release
21
+
22
+ - clarify per-gem publishers and safe retries
23
+
24
+
25
+
26
+
27
+ ### Fixed
28
+
29
+ - show preparation progress and live command output
30
+
31
+
32
+
8
33
  ## [0.1.0] - 2026-11-04
9
34
 
10
35
 
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.0", 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.0^{}'
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
 
@@ -56,25 +68,56 @@ Ordinary feature/fix PRs run verification; only a release PR starts publication.
56
68
  - Install the bundle, Git, git-cliff and GitHub CLI. Configure your Git identity,
57
69
  authenticate with `gh auth login`, and install hooks with
58
70
  `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.
71
+ - Public gems: configure a matching RubyGems trusted publisher for **each gem**
72
+ before merging its first release PR. Use the exact settings below. Gemkit's
73
+ publisher does not authorize consumer gems.
64
74
  - A new gem also needs a pending trusted publisher. Supply its numeric RubyGems
65
75
  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.
76
+ variable `RUBYGEMS_OWNER` (the publisher account used by Tunnel is `27209`).
77
+ - Private gems: set `registry: github_packages`. Publishing uses the workflow's
78
+ short-lived `GITHUB_TOKEN`; the package must grant its repository Actions access.
79
+ Pass `PACKAGES_TOKEN` only when an explicit token override is needed. Local
80
+ installation from other private repositories still needs `read:packages` access.
81
+ - Configure the `rubygems` GitHub environment to allow `main` and `v*` tags.
82
+ Release callers grant `contents: write`, `id-token: write` and `packages: write`.
83
+ Repository rules must permit the workflow's annotated release tags.
73
84
 
74
85
  The SDK release workflow listens directly for merged release PRs and version-tag
75
86
  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).
87
+ against `main` and `push: tags: ["v*"]`, and pin the commit matching the installed
88
+ Gemkit release.
89
+ See the [Tunnel caller](https://github.com/ethos-link/cloudflare-tunnel/blob/main/.github/workflows/release.yml).
90
+
91
+ Projects keep their own checks. Engines can register `checks: [ci:local]` in
92
+ `.ethos-gemkit.yml` and have that task run `bin/ci`. Set the release caller's
93
+ optional `build-setup` input to provision those checks' dependencies, such as
94
+ PostgreSQL or browser packages. Setup runs only in the read-only build job;
95
+ publishing credentials remain in the separate publish job.
96
+
97
+ ### RubyGems trusted-publisher settings
98
+
99
+ On RubyGems, open the **consumer gem's** page, then **Trusted publishers**. For
100
+ Cloudflare Tunnel, create or update the publisher with these exact values:
101
+
102
+ | RubyGems field | Value |
103
+ |---|---|
104
+ | Repository owner | `ethos-link` |
105
+ | Repository name | `cloudflare-tunnel` |
106
+ | Workflow filename | `release.yml` |
107
+ | Environment | `rubygems` |
108
+ | Workflow Repository Owner | `ethos-link` |
109
+ | Workflow Repository Name | `ethos-gemkit` |
110
+
111
+ The repository identifies the consumer; the Workflow Repository fields identify
112
+ the repository containing the shared workflow file. Those last two fields are
113
+ required for consumers,
114
+ even though RubyGems labels them optional. For another consumer, substitute its
115
+ repository name. For Gemkit itself, use repository name `ethos-gemkit` and leave
116
+ both Workflow Repository fields blank because the workflow is in the same repo.
117
+
118
+ The numeric `rubygems-owner` input identifies the account for pending publishers;
119
+ it does not register a publisher or grant access to a consumer gem. See the
120
+ [upstream reusable-workflow instructions](https://guides.rubygems.org/trusted-publishing/#using-reusable-workflows).
78
121
 
79
122
  ### Prepare and review
80
123
 
@@ -96,11 +139,13 @@ bundle exec rake 'release:prepare[1.2.0]'
96
139
  ```
97
140
 
98
141
  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.
142
+ tag, an explicit current version is supported. For example, a new gem starting
143
+ at 0.1.0 can use `bundle exec rake 'release:prepare[0.1.0]'` after pending-publisher
144
+ setup.
101
145
 
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
146
+ The task prints each step and streams command output as it runs. It checks the
147
+ working tree, canonical origin, current main, installed hooks and target tag.
148
+ It creates `chore/release-vX.Y.Z`, updates the version and
104
149
  changelog, runs `bundle lock --local` and the full `rake verify`, then commits the
105
150
  three metadata files with hooks enabled, pushes the branch, and opens a
106
151
  `chore(release): prepare vX.Y.Z` PR. Main stays unchanged. You can also start on
@@ -131,8 +176,9 @@ start another workflow. Existing manually pushed annotated version tags remain a
131
176
  supported trigger and receive full canonical-tag verification.
132
177
 
133
178
  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.
179
+ use short-lived OIDC credentials; private gems use the workflow token or an
180
+ explicit override. Both profiles push the same verified artifact to their
181
+ configured host; no registry fallback exists.
136
182
 
137
183
  ### Failures and retries
138
184
 
@@ -143,6 +189,17 @@ If the commit/push succeeded but opening the PR failed, use
143
189
  `gh pr create --base main --head chore/release-vX.Y.Z --fill` after fixing access.
144
190
  There is no journal or automatic reset of your working tree.
145
191
 
192
+ If credential setup fails with `No trusted publisher configured for this workflow`,
193
+ check the consumer's RubyGems settings against the table above. A successful
194
+ build and tag do not mean the gem was published. When `gem push` was skipped,
195
+ correct the publisher settings, then rerun **failed jobs only** in the original
196
+ workflow run. This reuses its verified artifact and existing tag; do not run
197
+ `release:prepare` again, bump the version or replace the tag for this failure.
198
+
199
+ ```sh
200
+ gh run rerun RUN_ID --repo OWNER/REPOSITORY --failed
201
+ ```
202
+
146
203
  For CI failures, retry **failed jobs in the original run** within GitHub's 30-day
147
204
  retry window. Artifacts are retained for 90 days. A failed tag step can reuse an
148
205
  existing annotated tag only when it points to the same verified commit. A failed
@@ -166,3 +223,16 @@ divergence; live SSH credentials and host keys still require target validation.
166
223
  Develop with `bundle install` and `bundle exec rake verify`. Release and registry
167
224
  fixtures live in tests, using real Git and native gem builds with fake network
168
225
  publishers. No production rehearsal command or registry client is required.
226
+
227
+ ## Built by Ethos Link
228
+
229
+ [Ethos Link](https://www.ethos-link.com) builds business software and integrations
230
+ that replace manual handoffs with connected workflows. We help teams automate
231
+ routine work, use their data and improve the processes their business runs on.
232
+
233
+ - [Reviato](https://www.reviato.com): Read public review trends and collect
234
+ private customer feedback, so your team can decide what to improve.
235
+ - [EthosPlaces](https://www.ethos.place): Give customers the details they need to
236
+ choose and visit your business, from opening hours to directions.
237
+ - [Nuntio](https://www.nuntiohq.com): Draft, review and schedule social posts in
238
+ one workspace, then track each publishing result.
data/UPGRADE.md ADDED
@@ -0,0 +1,20 @@
1
+ # Upgrading Gemkit
2
+
3
+ ## 0.2.0
4
+
5
+ Update the gem version and pin each workflow caller to the commit behind the
6
+ matching release tag. Release callers must grant `contents: write`,
7
+ `id-token: write` and `packages: write`, including public-gem callers: the shared
8
+ publisher supports both registries.
9
+
10
+ GitHub Packages publication now defaults to the workflow's `GITHUB_TOKEN`.
11
+ Grant the repository Actions access to its package. Existing `PACKAGES_TOKEN`
12
+ overrides remain supported; no new personal access token is required.
13
+
14
+ Release preparation prints each phase and streams verification, hook and push
15
+ output. Versioning, review and publication remain the same: prepare from clean,
16
+ current main, review the release PR, then merge to publish through Actions.
17
+
18
+ Projects with system-dependent checks can pass `build-setup` to the release
19
+ workflow. Keep those checks in the project's existing command; setup only
20
+ 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", "--local", 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.0"
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.0
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