configure_trusted_publisher 0.1.6 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/lib/configure_trusted_publisher/cli.rb +93 -101
- data/lib/configure_trusted_publisher/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9618ca80722f42567b997bfc7f392a9c2265bf8bfe504a1a6e2b1fcea797d266
|
4
|
+
data.tar.gz: c64f6c0ec0ddbd143483fc4663826edfafb9c84e6d9a8a82d70c66444ef04347
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a1274ea1f7f908e57801322ecabfe9960d8e6a0a134ae1dd9c3b7238c4f89ec1e0911a86019c4d01e1ff7b99f68f37d2673dcf19dbd702e54b000f4d26b63a8
|
7
|
+
data.tar.gz: 3e49f2378150f87c043d7807031c84eba9b6bf45f402b486efc7ae45330332df4f3522019740a093e0c90b013d99db68adadd1bc7d4f9e1f47d682e80228a6e6
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# ConfigureTrustedPublisher
|
2
2
|
|
3
|
-
A small CLI to automate the process of configuring a trusted publisher for a gem.
|
3
|
+
A small CLI to automate the process of configuring a [trusted publisher](https://guides.rubygems.org/trusted-publishing/) for a gem and [automating gem releases](https://guides.rubygems.org/trusted-publishing/releasing-gems/) with GitHub Actions!.
|
4
4
|
|
5
5
|
## Usage
|
6
6
|
|
@@ -9,6 +9,7 @@ To configure a trusted publisher for a gem, run the following command:
|
|
9
9
|
```console
|
10
10
|
$ gem exec configure_trusted_publisher rubygem
|
11
11
|
Configuring trusted publisher for rubygem0 in /Users/segiddins/Development/github.com/rubygems/configure_trusted_publisher for rubygems/configure_trusted_publisher
|
12
|
+
|
12
13
|
Enter your https://rubygems.org credentials.
|
13
14
|
Don't have an account yet? Create one at https://rubygems.org/sign_up
|
14
15
|
Username/email: : gem-author
|
@@ -9,6 +9,7 @@ require "bundler"
|
|
9
9
|
require "json"
|
10
10
|
require "open3"
|
11
11
|
require "rubygems/gemcutter_utilities"
|
12
|
+
require "yaml"
|
12
13
|
|
13
14
|
Gem.configuration.verbose = true
|
14
15
|
|
@@ -153,24 +154,35 @@ module ConfigureTrustedPublisher
|
|
153
154
|
puts "Configuring trusted publisher for #{rubygem_name} in #{File.expand_path(repository)} for " \
|
154
155
|
"#{github_repository.join('/')}"
|
155
156
|
|
157
|
+
environment = add_environment
|
158
|
+
write_release_action(repository, rubygem_name, environment:)
|
159
|
+
|
156
160
|
gc = GemcutterUtilities.new(
|
157
161
|
say: ->(msg) { puts msg },
|
158
|
-
ask:
|
159
|
-
|
160
|
-
|
162
|
+
ask: lambda { |msg|
|
163
|
+
puts
|
164
|
+
ask msg.strip.chomp(":")
|
165
|
+
},
|
166
|
+
ask_for_password: lambda { |msg|
|
167
|
+
puts
|
168
|
+
ask_secret msg.strip.chomp(":")
|
169
|
+
},
|
170
|
+
terminate_interaction: lambda { |msg|
|
171
|
+
puts
|
172
|
+
exit msg
|
173
|
+
},
|
161
174
|
otp: options[:otp]
|
162
175
|
)
|
163
176
|
gc.sign_in(scope: "configure_trusted_publishers") unless gc.api_key
|
164
177
|
|
165
|
-
write_release_action(repository, rubygem_name)
|
166
|
-
|
167
178
|
owner, name = github_repository
|
168
179
|
config = {
|
169
180
|
"trusted_publisher" => {
|
170
181
|
"repository_name" => name,
|
171
182
|
"repository_owner" => owner,
|
183
|
+
"environment" => environment,
|
172
184
|
"workflow_filename" => "push_gem.yml"
|
173
|
-
},
|
185
|
+
}.compact,
|
174
186
|
"trusted_publisher_type" => "OIDC::TrustedPublisher::GitHubAction"
|
175
187
|
}
|
176
188
|
|
@@ -235,13 +247,46 @@ module ConfigureTrustedPublisher
|
|
235
247
|
raise "No GitHub repository found for #{gemspec.name}"
|
236
248
|
end
|
237
249
|
|
250
|
+
def add_environment
|
251
|
+
puts
|
252
|
+
return unless ask_yes_or_no("Would you like to add a github environment to allow customizing " \
|
253
|
+
"prerequisites for the action?")
|
254
|
+
|
255
|
+
env_name = "rubygems.org"
|
256
|
+
|
257
|
+
owner, name = github_repository
|
258
|
+
puts "Adding GitHub environment to #{owner}/#{name} to protect the action"
|
259
|
+
if (env = Open3.capture2e("gh", "api", "repos/#{owner}/#{name}/environments").then do |output, status|
|
260
|
+
exit "Failed to list environments for #{owner}/#{name} using `gh api`:\n#{output}" unless status.success?
|
261
|
+
|
262
|
+
JSON.parse(output)["environments"].find { |e| e["name"] == env_name }
|
263
|
+
end)
|
264
|
+
|
265
|
+
puts
|
266
|
+
puts "Environment 'rubygems.org' already exists for #{owner}/#{name}:\n #{env['html_url']}"
|
267
|
+
else
|
268
|
+
Open3.capture2e("gh", "api", "--method", "PUT",
|
269
|
+
"repos/#{owner}/#{name}/environments/#{env_name}").then do |output, status|
|
270
|
+
unless status.success?
|
271
|
+
exit "Failed to create rubygems.org environment for #{owner}/#{name} using `gh api`:\n#{output}"
|
272
|
+
end
|
273
|
+
|
274
|
+
env = JSON.parse(output)
|
275
|
+
puts
|
276
|
+
puts "Created environment 'rubygems.org' for #{owner}/#{name}:\n #{env['html_url']}"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
env_name
|
281
|
+
end
|
282
|
+
|
238
283
|
attr_reader :gemspec_source
|
239
284
|
|
240
285
|
def gemspec
|
241
286
|
gemspec_source.specs.first
|
242
287
|
end
|
243
288
|
|
244
|
-
def write_release_action(repository, rubygem_name)
|
289
|
+
def write_release_action(repository, rubygem_name, environment: nil)
|
245
290
|
tag = "Automatically when a new tag matching v* is pushed"
|
246
291
|
manual = "Manually by running a GitHub Action"
|
247
292
|
puts
|
@@ -252,103 +297,50 @@ module ConfigureTrustedPublisher
|
|
252
297
|
],
|
253
298
|
default: "2"
|
254
299
|
)
|
255
|
-
case response
|
256
|
-
when tag
|
257
|
-
write_tag_action(repository)
|
258
|
-
when manual
|
259
|
-
write_manual_action(repository)
|
260
|
-
end
|
261
|
-
end
|
262
300
|
|
263
|
-
def write_tag_action(repository)
|
264
301
|
action_file = File.expand_path(".github/workflows/push_gem.yml", repository)
|
265
302
|
return unless check_action(action_file)
|
266
303
|
|
267
304
|
File.write(
|
268
305
|
action_file,
|
269
|
-
|
270
|
-
name: Push Gem
|
271
|
-
|
272
|
-
on:
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
puts "Created #{action_file}"
|
308
|
-
end
|
309
|
-
|
310
|
-
def write_manual_action(repository)
|
311
|
-
action_file = File.expand_path(".github/workflows/push_gem.yml", repository)
|
312
|
-
return unless check_action(action_file)
|
313
|
-
|
314
|
-
File.write(
|
315
|
-
action_file,
|
316
|
-
<<~YAML
|
317
|
-
name: Push Gem
|
318
|
-
|
319
|
-
on:
|
320
|
-
workflow_dispatch:
|
321
|
-
|
322
|
-
permissions:
|
323
|
-
contents: read
|
324
|
-
|
325
|
-
jobs:
|
326
|
-
push:
|
327
|
-
if: github.repository == '#{github_repository.join('/')}'
|
328
|
-
runs-on: ubuntu-latest
|
329
|
-
|
330
|
-
permissions:
|
331
|
-
contents: write
|
332
|
-
id-token: write
|
333
|
-
|
334
|
-
steps:
|
335
|
-
# Set up
|
336
|
-
- name: Harden Runner
|
337
|
-
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
338
|
-
with:
|
339
|
-
egress-policy: audit
|
340
|
-
|
341
|
-
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
342
|
-
- name: Set up Ruby
|
343
|
-
uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
|
344
|
-
with:
|
345
|
-
bundler-cache: true
|
346
|
-
ruby-version: ruby
|
347
|
-
|
348
|
-
# Release
|
349
|
-
- uses: rubygems/release-gem@612653d273a73bdae1df8453e090060bb4db5f31 # v1
|
350
|
-
YAML
|
351
|
-
|
306
|
+
[
|
307
|
+
"name: Push Gem",
|
308
|
+
nil,
|
309
|
+
"on:",
|
310
|
+
" #{response == tag ? "push:\n tags:\n - 'v*'" : 'workflow_dispatch:'}",
|
311
|
+
nil,
|
312
|
+
"permissions:",
|
313
|
+
" contents: read",
|
314
|
+
nil,
|
315
|
+
"jobs:",
|
316
|
+
" push:",
|
317
|
+
" if: github.repository == '#{github_repository.join('/')}'",
|
318
|
+
" runs-on: ubuntu-latest",
|
319
|
+
if environment
|
320
|
+
"\n environment:\n name: #{environment}\n url: https://rubygems.org/gems/#{rubygem_name}\n"
|
321
|
+
end,
|
322
|
+
" permissions:",
|
323
|
+
" contents: write",
|
324
|
+
" id-token: write",
|
325
|
+
nil,
|
326
|
+
" steps:",
|
327
|
+
" # Set up",
|
328
|
+
" - name: Harden Runner",
|
329
|
+
" uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1",
|
330
|
+
" with:",
|
331
|
+
" egress-policy: audit",
|
332
|
+
nil,
|
333
|
+
" - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4",
|
334
|
+
" - name: Set up Ruby",
|
335
|
+
" uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0",
|
336
|
+
" with:",
|
337
|
+
" bundler-cache: true",
|
338
|
+
" ruby-version: ruby",
|
339
|
+
nil,
|
340
|
+
" # Release",
|
341
|
+
" - uses: rubygems/release-gem@612653d273a73bdae1df8453e090060bb4db5f31 # v1",
|
342
|
+
nil
|
343
|
+
].join("\n")
|
352
344
|
)
|
353
345
|
puts "Created #{action_file}"
|
354
346
|
end
|
@@ -357,9 +349,9 @@ module ConfigureTrustedPublisher
|
|
357
349
|
return FileUtils.mkdir_p(File.dirname(action_file)) || true unless File.exist?(action_file)
|
358
350
|
|
359
351
|
puts
|
360
|
-
response =
|
361
|
-
"#{action_file} already exists, overwrite?",
|
362
|
-
default:
|
352
|
+
response = ask_yes_or_no(
|
353
|
+
"#{action_file} already exists, overwrite?",
|
354
|
+
default: false
|
363
355
|
)
|
364
356
|
return if response == "No"
|
365
357
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configure_trusted_publisher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Giddins
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|