bake-gem-github 0.4.0 → 0.6.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/gem/github/release.rb +8 -0
- data/bake/gem/github/setup.rb +22 -2
- data/context/getting-started.md +25 -5
- data/context/preparing-releases.md +12 -3
- data/context/verifying-releases.md +1 -1
- data/lib/bake/gem/github/project.rb +30 -7
- data/lib/bake/gem/github/setup.rb +1 -1
- data/lib/bake/gem/github/trusted_publisher.rb +124 -0
- data/lib/bake/gem/github/version.rb +1 -1
- data/readme.md +9 -0
- data/releases.md +9 -0
- data/templates/release-validate.yaml.erb +1 -1
- data.tar.gz.sig +0 -0
- metadata +2 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 46e9578ab60761af87b7130ba3642b00401e89febdcd7e8cced97d74252e37b6
|
|
4
|
+
data.tar.gz: 53997e6e60991e6e5b057cd62ee7897de5156306d4dceb3d8a6bef2a269cd349
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bef7899e4fbd943cd791a72562739f04e8831f5c1fbc7b4760426c48bb9b99bf6fb96d931de8399423203d147b6775c65f137392b9e55ae7761fcb733aa00cb8
|
|
7
|
+
data.tar.gz: 28a9ccd6198bb07906119a6b89cf0fa23874756a5dcc53d335032bb94eebc5843b79b3f843a4ac5cfb6c911c7fd372a52095e9618d37b2bc5820c7ef463ff8c0
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/bake/gem/github/release.rb
CHANGED
|
@@ -26,6 +26,14 @@ def major(refresh: false)
|
|
|
26
26
|
Bake::Gem::GitHub::Project.new(context.root).prepare(context, "major", refresh: refresh)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
# Regenerate release content and require one release commit; ordinary PRs pass without a commit limit.
|
|
30
|
+
# @parameter base [String] The current target commit.
|
|
31
|
+
# @parameter candidate [String] The proposed PR head.
|
|
32
|
+
# @returns [Hash | Nil] Release metadata, or nil for an ordinary PR.
|
|
33
|
+
def validate(base:, candidate: "HEAD")
|
|
34
|
+
Bake::Gem::GitHub::Project.new(context.root).validate(base: base, candidate: candidate)
|
|
35
|
+
end
|
|
36
|
+
|
|
29
37
|
# Resolve and validate a pushed commit, emitting its merged PR and commit for publishing.
|
|
30
38
|
# @parameter number [String | Nil] A merged PR number for older workflows; defaults to `RELEASE_PR`.
|
|
31
39
|
# @parameter commit [String | Nil] The pushed commit SHA; defaults to `RELEASE_COMMIT` and takes precedence over `number`.
|
data/bake/gem/github/setup.rb
CHANGED
|
@@ -4,9 +4,29 @@
|
|
|
4
4
|
# Copyright, 2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
# Inspect external settings before applying the generated policy.
|
|
7
|
+
# @parameter publisher [Boolean] Authenticate to RubyGems and check the expected publisher registration.
|
|
8
|
+
# @parameter key [Symbol] An explicitly selected RubyGems API key name.
|
|
9
|
+
# @parameter otp [String] An optional RubyGems MFA code.
|
|
7
10
|
# @returns [Hash] Desired and observed settings for review.
|
|
8
|
-
def plan
|
|
9
|
-
context.lookup("gem:github:doctor").call
|
|
11
|
+
def plan(publisher: false, key: nil, otp: nil)
|
|
12
|
+
result = context.lookup("gem:github:doctor").call
|
|
13
|
+
if publisher
|
|
14
|
+
require "bake/gem/github/trusted_publisher"
|
|
15
|
+
|
|
16
|
+
result[:trusted_publisher_status] = Bake::Gem::GitHub::TrustedPublisher.load(context.root, key: key, otp: otp).status
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
return result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Register the configured release workflow as a trusted publisher for an existing gem on RubyGems.org.
|
|
23
|
+
# @parameter key [Symbol] An explicitly selected RubyGems API key name.
|
|
24
|
+
# @parameter otp [String] An optional RubyGems MFA code.
|
|
25
|
+
# @returns [Hash] Whether the publisher was created and its API record.
|
|
26
|
+
def publisher(key: nil, otp: nil)
|
|
27
|
+
require "bake/gem/github/trusted_publisher"
|
|
28
|
+
|
|
29
|
+
Bake::Gem::GitHub::TrustedPublisher.load(context.root, key: key, otp: otp).register
|
|
10
30
|
end
|
|
11
31
|
|
|
12
32
|
# Apply the four managed rulesets and configured environment reviewers using the current gh administrator credentials.
|
data/context/getting-started.md
CHANGED
|
@@ -6,7 +6,7 @@ This guide explains how to configure reviewed Ruby gem releases and prepare the
|
|
|
6
6
|
|
|
7
7
|
Maintainers prepare a release PR containing the version bump and generated release notes. CI regenerates those changes from the current base to verify the content. Native GitHub rules control approval and merging. A push to the default branch starts release inspection; GitHub Actions builds the exact pushed commit only when it is a validated, merged release PR, then publishes its verified artifact to RubyGems.
|
|
8
8
|
|
|
9
|
-
`bake-gem` provides version updates, release hooks, and clean builds. `bake-gem-github` adds PR preparation, GitHub policy, and remote publishing. The supported process uses one gemspec, stable three-part versions,
|
|
9
|
+
`bake-gem` provides version updates, release hooks, and clean builds. `bake-gem-github` adds PR preparation, GitHub policy, and remote publishing. The supported process uses one gemspec, stable three-part versions, single-commit release PRs, and RubyGems.org. Release PRs can be squash merged, rebase merged, or merged with a merge commit.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -48,9 +48,25 @@ The rules require two approvals by default, allow explicit administrator bypass,
|
|
|
48
48
|
|
|
49
49
|
## Configure publishing credentials
|
|
50
50
|
|
|
51
|
-
Create a `rubygems` GitHub environment restricted to the default branch.
|
|
51
|
+
Create a `rubygems` GitHub environment restricted to the default branch. For an existing gem on RubyGems.org, run this task from the repository root as a gem owner:
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
``` bash
|
|
54
|
+
bundle exec bake gem:github:setup:publisher
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The task reads the gem name from its gemspec and the owner/repository and environment from `config/release.yaml`. It registers the **`release-publish.yaml`** workflow with the configured environment (**`rubygems`** by default). An exact existing match is reused, so reruns do not create duplicate registrations. Other publishers are preserved; the task does not remove or replace them.
|
|
58
|
+
|
|
59
|
+
Without an explicitly supplied API key, the task prompts for RubyGems credentials and any required MFA verification. It requests a key with only the `configure_trusted_publishers` scope, expiring after 15 minutes, and keeps it in memory. It does not read or overwrite your default saved push key. To use an existing key with this scope, supply `GEM_HOST_API_KEY` or select a named RubyGems credential with `key=publisher`. Registration and the optional plan check also accept `otp=123456` or `GEM_HOST_OTP_CODE` when needed.
|
|
60
|
+
|
|
61
|
+
To check registration without creating a publisher:
|
|
62
|
+
|
|
63
|
+
``` bash
|
|
64
|
+
bundle exec bake gem:github:setup:plan publisher=true
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This adds `trusted_publisher_status` to the plan, including `configured` and the matching registration. The default plan only reports expected RubyGems values and does not authenticate to RubyGems. Authentication, ownership, and API failures stop the task rather than being reported as a missing registration.
|
|
68
|
+
|
|
69
|
+
For a gem that has never been published, configure a pending publisher manually. Account ownership, MFA enrollment, the GitHub environment, and signing bootstrap remain manual setup steps. See [RubyGems Trusted Publishing](https://guides.rubygems.org/trusted-publishing/) for account setup. Trusted Publishing supplies the publishing credential for each release, so a long-lived RubyGems API key is unnecessary.
|
|
54
70
|
|
|
55
71
|
When `release.cert` exists, setup enables certificate signing. Commit the public certificate and install its matching private key as `GEM_SIGNING_KEY`, either in the `rubygems` environment or as an organization secret available to the repository. The publisher checks certificate validity, key matching, and package signatures. Use `signing=false` during setup to disable certificate signing.
|
|
56
72
|
|
|
@@ -90,7 +106,9 @@ bundle exec bake gem:github:setup:plan
|
|
|
90
106
|
bundle exec bake gem:github:setup:apply
|
|
91
107
|
```
|
|
92
108
|
|
|
93
|
-
Apply updates the four managed rulesets and, when configured, the existing environment's reviewer list. It preserves unrelated rulesets. Other repository and organization protections still apply. Keep check names in `config/release.yaml` synchronized with the workflows, and apply updated rules after renamed jobs are available.
|
|
109
|
+
Apply updates the four managed rulesets and, when configured, the existing environment's reviewer list. It preserves unrelated rulesets. Other repository and organization protections still apply. Keep check names in `config/release.yaml` synchronized with the workflows, and apply updated rules after renamed jobs are available.
|
|
110
|
+
|
|
111
|
+
The generated rules allow merge, squash, and rebase methods; repository settings determine which are available. For linear history, enable squash and/or rebase merging and disable merge commits in repository settings. Release validation requires exactly one commit when the version changes; ordinary PRs have no commit limit. Keep merge queues disabled for this process.
|
|
94
112
|
|
|
95
113
|
## Prepare the first release PR
|
|
96
114
|
|
|
@@ -115,13 +133,15 @@ git diff
|
|
|
115
133
|
|
|
116
134
|
This updates managed files in the working tree and returns their changed paths. Review the diff and selectively retain repository customizations before committing. The task does not stage, commit, or change remote settings. Repeated updates produce no further changes unless customizations differ from the templates. Apply changed rulesets after the corresponding workflows are running.
|
|
117
135
|
|
|
136
|
+
To enable rebase merging on an existing installation, regenerate and merge `release-validate.yaml` so it runs `gem:github:release:validate`, which requires single-commit release PRs. Then review `gem:github:setup:plan` and run `gem:github:setup:apply` to allow rebase merging in the managed rules. Enable rebase merging in repository settings as well. Upgrading the gem alone does not update workflows or live rules.
|
|
137
|
+
|
|
118
138
|
Regenerate existing workflows to adopt publishing on `push` instead of `pull_request_target`. The workflow filename and `rubygems` environment remain the same, so the RubyGems Trusted Publisher configuration does not change. No exception to GitHub's `pull_request_target` execution policy is needed. The resolve task continues to accept PR numbers from older workflows while you migrate.
|
|
119
139
|
|
|
120
140
|
The release workflows follow `bake modernize` action versions and use moving major tags where available. The RubyGems credentials action uses its [documented `@main` reference](https://github.com/rubygems/configure-rubygems-credentials#trusted-publisher-recommended). Repositories that require fixed revisions can customize these references.
|
|
121
141
|
|
|
122
142
|
## Current scope
|
|
123
143
|
|
|
124
|
-
The process has published `bake-gem-github` through GitHub Actions. Each adopting repository still needs its own reviewed setup and successful release. Public single-gem repositories, ordinary stable versions, merge
|
|
144
|
+
The process has published `bake-gem-github` through GitHub Actions. Each adopting repository still needs its own reviewed setup and successful release. Public single-gem repositories, ordinary stable versions, single-commit release PRs using squash/rebase/merge, GitHub-hosted Linux runners, and RubyGems.org are the supported starting point.
|
|
125
145
|
|
|
126
146
|
Native build matrices, reusable publisher workflows, merge queues, automated RubyGems ownership/MFA setup, cross-run artifact recovery, and organization-wide migration are outside the current setup tasks.
|
|
127
147
|
|
|
@@ -19,11 +19,20 @@ gh workflow run release-prepare.yaml -f bump=patch
|
|
|
19
19
|
|
|
20
20
|
Replace `patch` with `minor` or `major`. The wrapper fetches the default branch and tags, refuses a stale local checkout, and validates an existing release PR before returning its URL. A matching local or remote branch is reused if PR creation was interrupted. Multiple open release PRs or a different requested bump stop preparation. GitHub's built-in token may require a writer to approve running workflows for its created PR; enable Actions' permission to create PRs. An organization-owned App token can be adopted later if automatic CI triggering is needed.
|
|
21
21
|
|
|
22
|
-
All release changes belong in the
|
|
22
|
+
All release changes belong in one commit, including the version bump and generated files. Core preparation commits additions and deletions from release hooks but never pushes, tags or publishes. Validation independently generates the expected tree from the current base and requires exactly one commit ahead of that base. A changed base SHA alone is fine; changed generated notes are not. Ordinary PRs with no version change have no commit limit and still build unsigned.
|
|
23
|
+
|
|
24
|
+
To run the same content and commit-count validation locally from a release branch:
|
|
25
|
+
|
|
26
|
+
``` bash
|
|
27
|
+
git fetch origin main
|
|
28
|
+
bundle exec bake gem:github:release:validate base=origin/main
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Replace `main` with your configured default branch. When correcting a release, amend the existing commit or regenerate it with `refresh=true` instead of adding fixup commits. Amended content must still match the generated release; changes to release notes or generation hooks usually belong on the default branch followed by a refresh.
|
|
23
32
|
|
|
24
33
|
## Publish the merged release
|
|
25
34
|
|
|
26
|
-
Merging into the configured default branch triggers `release-publish.yaml` through its `push` event. Inspection uses the exact pushed SHA and resolves its associated PR through GitHub. Publication requires one matching merged PR in this repository, targeting the configured branch, with that exact
|
|
35
|
+
Merging into the configured default branch triggers `release-publish.yaml` through its `push` event. Inspection uses the exact pushed SHA and resolves its associated PR through GitHub. Publication requires one matching merged PR in this repository, targeting the configured branch, with that exact resulting commit. Ordinary changes do not publish; release changes without a matching merged PR fail inspection. Single-commit release PRs support squash merging, rebase merging, and merge commits, including merged fork PRs. Publishing validates against the resulting commit's first parent, which is the default branch immediately before the release landed.
|
|
27
36
|
|
|
28
37
|
Each release must land as the tip of its own push, as it does when merging a PR through GitHub. Later pushes do not change a pending release's source: inspection and publishing remain pinned to the original commit, and reruns use the same event. Do not combine a release and later changes into one direct push. If you automate merging, use a GitHub App or personal access token; pushes made using a workflow's `GITHUB_TOKEN` do not trigger another workflow.
|
|
29
38
|
|
|
@@ -45,4 +54,4 @@ bundle exec bake gem:github:release:patch refresh=true
|
|
|
45
54
|
gh workflow run release-prepare.yaml -f bump=patch -f refresh=true
|
|
46
55
|
```
|
|
47
56
|
|
|
48
|
-
Refresh first pushes the complete previous release commit to `release-backups/vVERSION/OLD_SHA`, including manual edits. It then regenerates in a clean worktree from the current default branch, validates, and updates the existing release branch using an explicit `--force-with-lease`. A concurrent remote edit causes the push to fail. Existing local release branches are left intact. Review the backup against the refreshed PR; incorporate necessary manual changes into the default branch or generation hooks and refresh again. Keep the backup until that review is complete. Replace `main` and `patch` with your configured branch and original bump type.
|
|
57
|
+
Refresh first pushes the complete previous release commit to `release-backups/vVERSION/OLD_SHA`, including manual edits. It then regenerates one release commit in a clean worktree from the current default branch, validates, and updates the existing release branch using an explicit `--force-with-lease`. A concurrent remote edit causes the push to fail. Existing local release branches are left intact. Review the backup against the refreshed PR; incorporate necessary manual changes into the default branch or generation hooks and refresh again. Keep the backup until that review is complete. Replace `main` and `patch` with your configured branch and original bump type.
|
|
@@ -6,7 +6,7 @@ Use this when checking a completed release or confirming which source commit pro
|
|
|
6
6
|
|
|
7
7
|
## What publishing verifies
|
|
8
8
|
|
|
9
|
-
After
|
|
9
|
+
After squash, rebase, or merge, the publishing workflow verifies GitHub's merged PR record and ancestry, then checks out the exact resulting commit. Each release PR contains one commit, so the resulting commit's **first parent** is the default branch immediately before the release landed. Later development on the default branch is allowed. Publishing regenerates against that first parent, builds in a clean worktree, optionally certificate-signs, and creates two attestations over the final bytes:
|
|
10
10
|
|
|
11
11
|
- A Sigstore bundle submitted explicitly with `gem push --attestation` using RubyGems 4.0.21.
|
|
12
12
|
- GitHub's native SLSA provenance covering both the gem and `release.json`. This signed receipt binds the gem digest to the exact release commit, even when the workflow's own default-branch revision is newer.
|
|
@@ -78,7 +78,7 @@ module Bake
|
|
|
78
78
|
candidate = @release.resolve("HEAD")
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
metadata =
|
|
81
|
+
metadata = validate(base: base, candidate: candidate, optional: false)
|
|
82
82
|
raise "Release branch does not contain the requested version #{version}." unless metadata.fetch(:version) == version
|
|
83
83
|
|
|
84
84
|
push("--force-with-lease=#{release_ref}:#{remote_commit}", "#{candidate}:#{release_ref}")
|
|
@@ -90,6 +90,23 @@ module Bake
|
|
|
90
90
|
)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
# Validate PR content and require each proposed release to contain exactly one commit.
|
|
94
|
+
# @parameter base [String] The current target commit.
|
|
95
|
+
# @parameter candidate [String] The proposed PR head.
|
|
96
|
+
# @parameter optional [Boolean] Accept ordinary PRs without a version change.
|
|
97
|
+
# @returns [Hash | Nil] Release metadata, or nil for an ordinary PR.
|
|
98
|
+
# @raises [RuntimeError] If the release content is invalid or the release contains multiple commits.
|
|
99
|
+
def validate(base:, candidate: "HEAD", optional: true)
|
|
100
|
+
metadata = @release.validate(base: base, candidate: candidate, optional: optional)
|
|
101
|
+
if metadata
|
|
102
|
+
range = "#{metadata.fetch(:base)}..#{metadata.fetch(:commit)}"
|
|
103
|
+
count = readlines("git", "rev-list", "--count", range, chdir: @root).join.strip
|
|
104
|
+
raise "Release PRs must contain exactly one commit. Amend or regenerate the release commit instead of adding commits." unless count == "1"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
return metadata
|
|
108
|
+
end
|
|
109
|
+
|
|
93
110
|
# Resolve a merged PR through GitHub, and require its actual merge commit in default-branch history.
|
|
94
111
|
# @parameter number [String | Integer] The positive PR number.
|
|
95
112
|
# @returns [Hash] GitHub PR data with string keys, including `number` and `merge_commit_sha`.
|
|
@@ -164,12 +181,18 @@ module Bake
|
|
|
164
181
|
existing_rules: api("rulesets?per_page=100"),
|
|
165
182
|
environments: api("environments"),
|
|
166
183
|
environment_changes: environment_changes,
|
|
167
|
-
trusted_publisher:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
184
|
+
trusted_publisher: trusted_publisher,
|
|
185
|
+
}
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Describe the RubyGems publisher for the reviewed release workflow.
|
|
189
|
+
# @returns [Hash] Repository, workflow filename, and environment settings.
|
|
190
|
+
def trusted_publisher
|
|
191
|
+
{
|
|
192
|
+
repository_owner: @repository.split("/").first,
|
|
193
|
+
repository_name: @repository.split("/").last,
|
|
194
|
+
workflow_filename: "release-publish.yaml",
|
|
195
|
+
environment: @config.fetch("environment"),
|
|
173
196
|
}
|
|
174
197
|
end
|
|
175
198
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "json"
|
|
7
|
+
require "rubygems/gemcutter_utilities"
|
|
8
|
+
require "rubygems/user_interaction"
|
|
9
|
+
require "uri"
|
|
10
|
+
require_relative "project"
|
|
11
|
+
|
|
12
|
+
module Bake
|
|
13
|
+
module Gem
|
|
14
|
+
module GitHub
|
|
15
|
+
# Registers the reviewed release workflow with RubyGems.org using its owner API.
|
|
16
|
+
class TrustedPublisher
|
|
17
|
+
include ::Gem::UserInteraction
|
|
18
|
+
include ::Gem::GemcutterUtilities
|
|
19
|
+
|
|
20
|
+
# The RubyGems API scope for managing trusted publishers.
|
|
21
|
+
SCOPE = :configure_trusted_publishers
|
|
22
|
+
|
|
23
|
+
# The provider type accepted by the RubyGems trusted publisher API.
|
|
24
|
+
TYPE = "OIDC::TrustedPublisher::GitHubAction"
|
|
25
|
+
|
|
26
|
+
# Load the gem identity and reviewed publisher settings from the current project.
|
|
27
|
+
# @parameter root [String] The repository root, which must also be the working directory.
|
|
28
|
+
# @parameter options [Hash] Authentication options passed to {initialize}.
|
|
29
|
+
# @returns [TrustedPublisher] The configured RubyGems client.
|
|
30
|
+
def self.load(root, **options)
|
|
31
|
+
project = Project.new(root)
|
|
32
|
+
name = Helper.new(root).gemspec.name
|
|
33
|
+
|
|
34
|
+
new(name, project.trusted_publisher, **options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Configure an existing gem's expected GitHub Actions publisher.
|
|
38
|
+
# @parameter name [String] The gem name.
|
|
39
|
+
# @parameter settings [Hash] Repository owner/name, workflow filename, and environment.
|
|
40
|
+
# @parameter key [Symbol | Nil] An explicitly selected key in RubyGems credentials.
|
|
41
|
+
# @parameter otp [String | Nil] An optional MFA code; RubyGems can prompt when required.
|
|
42
|
+
def initialize(name, settings, key: nil, otp: nil)
|
|
43
|
+
@path = "api/v1/gems/#{URI.encode_www_form_component(name)}/trusted_publishers"
|
|
44
|
+
@settings = settings.transform_keys(&:to_s)
|
|
45
|
+
@options = {key: key, otp: otp}
|
|
46
|
+
@host = "https://rubygems.org"
|
|
47
|
+
@api_key = nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @attribute [Hash] Options used by RubyGems authentication and MFA support.
|
|
51
|
+
attr_reader :options
|
|
52
|
+
|
|
53
|
+
# Read the matching publisher without changing publisher configuration.
|
|
54
|
+
# @returns [Hash] Whether the publisher is configured and its existing API record, if any.
|
|
55
|
+
# @raises [RuntimeError] If RubyGems cannot list the gem's publishers.
|
|
56
|
+
def status
|
|
57
|
+
sign_in(scope: SCOPE) unless api_key
|
|
58
|
+
publishers = request(:get, expected: "200")
|
|
59
|
+
raise "Invalid RubyGems trusted publishers response." unless publishers.is_a?(Array)
|
|
60
|
+
publisher = publishers.find{|record| matching?(record)}
|
|
61
|
+
|
|
62
|
+
return {configured: !publisher.nil?, publisher: publisher}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Register a missing publisher, preserving all existing publisher registrations.
|
|
66
|
+
# @returns [Hash] Whether registration was created and the matching API record.
|
|
67
|
+
# @raises [RuntimeError] If RubyGems rejects registration or returns different settings.
|
|
68
|
+
def register
|
|
69
|
+
current = status
|
|
70
|
+
return {created: false, publisher: current.fetch(:publisher)} if current.fetch(:configured)
|
|
71
|
+
|
|
72
|
+
publisher = request(:post, expected: "201", payload: {trusted_publisher_type: TYPE, trusted_publisher: @settings})
|
|
73
|
+
raise "RubyGems returned unexpected trusted publisher settings." unless matching?(publisher)
|
|
74
|
+
|
|
75
|
+
return {created: true, publisher: publisher}
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Use the session key or an explicitly supplied credential, leaving the default push key alone.
|
|
79
|
+
# @returns [String | Nil] The API key used for this session.
|
|
80
|
+
def api_key
|
|
81
|
+
@api_key || ENV["GEM_HOST_API_KEY"] || (options[:key] && verify_api_key(options[:key]))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Keep newly issued credentials in memory rather than changing the user's credentials file.
|
|
85
|
+
# @parameter host [String] The authenticated RubyGems host.
|
|
86
|
+
# @parameter key [String] The newly issued API key.
|
|
87
|
+
def set_api_key(host, key)
|
|
88
|
+
@api_key = key
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def get_mfa_params(profile)
|
|
94
|
+
super.merge(expires_at: (Time.now.utc + 900).strftime("%Y-%m-%d %H:%M:%S UTC"))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def matching?(record)
|
|
98
|
+
return false unless record.fetch("trusted_publisher_type") == TYPE
|
|
99
|
+
settings = record.fetch("trusted_publisher")
|
|
100
|
+
|
|
101
|
+
# Generated publishing workflows run in the configured repository, not a reusable workflow repository:
|
|
102
|
+
@settings.all?{|key, value| settings[key] == value} &&
|
|
103
|
+
settings["workflow_repository_owner"].nil? && settings["workflow_repository_name"].nil?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def request(method, expected:, payload: nil)
|
|
107
|
+
response = rubygems_api_request(method, @path, scope: SCOPE) do |request|
|
|
108
|
+
request["Authorization"] = api_key
|
|
109
|
+
request["Accept"] = "application/json"
|
|
110
|
+
if payload
|
|
111
|
+
request["Content-Type"] = "application/json"
|
|
112
|
+
request.body = JSON.generate(payload)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
unless response.code == expected
|
|
116
|
+
raise "RubyGems trusted publisher #{method.to_s.upcase} failed (HTTP #{response.code}): #{clean_text(response.body)}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
JSON.parse(response.body)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
data/readme.md
CHANGED
|
@@ -24,6 +24,15 @@ Please see the [project documentation](https://socketry.github.io/bake-gem-githu
|
|
|
24
24
|
|
|
25
25
|
Please see the [project releases](https://socketry.github.io/bake-gem-github/releases/index) for all releases.
|
|
26
26
|
|
|
27
|
+
### v0.6.0
|
|
28
|
+
|
|
29
|
+
- Register RubyGems trusted publishers from the gemspec and release configuration with `gem:github:setup:publisher`, reusing existing registrations and RubyGems authentication/MFA support.
|
|
30
|
+
- Check publisher registration explicitly with `gem:github:setup:plan publisher=true`.
|
|
31
|
+
|
|
32
|
+
### v0.5.0
|
|
33
|
+
|
|
34
|
+
- Support rebase merging by requiring each release PR to contain exactly one commit, while leaving ordinary PRs unrestricted. Generated rules allow merge, squash, and rebase methods according to repository settings.
|
|
35
|
+
|
|
27
36
|
### v0.4.0
|
|
28
37
|
|
|
29
38
|
- Reject Secret environment reviewer teams before applying release settings, and verify that GitHub retained the requested reviewers and existing protections after updating the environment.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.6.0
|
|
4
|
+
|
|
5
|
+
- Register RubyGems trusted publishers from the gemspec and release configuration with `gem:github:setup:publisher`, reusing existing registrations and RubyGems authentication/MFA support.
|
|
6
|
+
- Check publisher registration explicitly with `gem:github:setup:plan publisher=true`.
|
|
7
|
+
|
|
8
|
+
## v0.5.0
|
|
9
|
+
|
|
10
|
+
- Support rebase merging by requiring each release PR to contain exactly one commit, while leaving ordinary PRs unrestricted. Generated rules allow merge, squash, and rebase methods according to repository settings.
|
|
11
|
+
|
|
3
12
|
## v0.4.0
|
|
4
13
|
|
|
5
14
|
- Reject Secret environment reviewer teams before applying release settings, and verify that GitHub retained the requested reviewers and existing protections after updating the environment.
|
|
@@ -27,6 +27,6 @@ jobs:
|
|
|
27
27
|
- name: Regenerate release content
|
|
28
28
|
env:
|
|
29
29
|
RELEASE_BASE: ${{ github.event.pull_request.base.sha }}
|
|
30
|
-
run: bundle exec bake gem:release:validate "base=$RELEASE_BASE"
|
|
30
|
+
run: bundle exec bake gem:github:release:validate "base=$RELEASE_BASE"
|
|
31
31
|
- name: Build unsigned package
|
|
32
32
|
run: bundle exec bake gem:build signing_key=false
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bake-gem-github
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -107,6 +107,7 @@ files:
|
|
|
107
107
|
- lib/bake/gem/github/publisher.rb
|
|
108
108
|
- lib/bake/gem/github/registry.rb
|
|
109
109
|
- lib/bake/gem/github/setup.rb
|
|
110
|
+
- lib/bake/gem/github/trusted_publisher.rb
|
|
110
111
|
- lib/bake/gem/github/version.rb
|
|
111
112
|
- license.md
|
|
112
113
|
- readme.md
|
metadata.gz.sig
CHANGED
|
Binary file
|