renuo-cli 4.5.2 → 4.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
- data/bin/setup +0 -1
- data/lib/renuo/cli/app/configure_semaphore.rb +6 -7
- data/lib/renuo/cli/app/github_replace.rb +51 -0
- data/lib/renuo/cli/app/secrets_fetcher.rb +29 -27
- data/lib/renuo/cli/app/templates/semaphore/notification.yml.erb +25 -0
- data/lib/renuo/cli/app/templates/semaphore/semaphore-deploy.yml.erb +1 -1
- data/lib/renuo/cli/version.rb +1 -1
- data/lib/renuo/cli.rb +20 -0
- data/notification.yml +25 -0
- data/renuo-cli.gemspec +0 -1
- metadata +9 -21
- data/.tool-versions +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 955e4807e9528133c7c3334b6ce70acb637e63a0450ea08be389cfdb5a429f63
|
4
|
+
data.tar.gz: 364adfbd23ffbeddbd4ce89166160000a8c6b101089527a7e581afe13b54bce0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de3070d906d5610b9acfa4bfdd49ee8f09fd4f59e64f2476d062cd1345acdc5e644f20bd16fe00fa70b42309925ee47a5f44e0aa5b10b83676da80667c326de7
|
7
|
+
data.tar.gz: da7edb8258f8fe5d0445594deebf63a0488a6cbb6f483750e6b9118bc1e2e6323082ae06607bfddeb0e345211ed074e18ed6f4f95c3be19bcc7081feb28f0d32
|
data/bin/setup
CHANGED
@@ -4,17 +4,18 @@ require "commander"
|
|
4
4
|
require_relative "environments"
|
5
5
|
|
6
6
|
class ConfigureSemaphore
|
7
|
-
attr_accessor :project_name, :environment
|
7
|
+
attr_accessor :project_name, :environment, :slack_endpoint
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
@project_name = File.basename(Dir.getwd)
|
11
|
+
@slack_endpoint = "https://hooks.slack.com/services/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"
|
11
12
|
end
|
12
13
|
|
13
14
|
# rubocop:disable Metrics/MethodLength
|
14
15
|
def call
|
15
16
|
return unless semaphore_cli_installed?
|
16
17
|
|
17
|
-
FileUtils.mkdir_p(%w[.semaphore .semaphore/bin])
|
18
|
+
FileUtils.mkdir_p(%w[.semaphore .semaphore/bin tmp])
|
18
19
|
|
19
20
|
write_or_warn(".semaphore/semaphore.yml", render("templates/semaphore/semaphore.yml.erb"))
|
20
21
|
%w[main develop].each do |environment|
|
@@ -39,11 +40,9 @@ class ConfigureSemaphore
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def create_semaphore_notification
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
"--slack-channels \"#project-#{project_name}\" " \
|
46
|
-
'--slack-endpoint "https://hooks.slack.com/services/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"')
|
43
|
+
File.write("tmp/notification.#{project_name}.yml", render("templates/semaphore/notification.yml.erb"))
|
44
|
+
system("sem create -f tmp/notification.#{project_name}.yml")
|
45
|
+
FileUtils.rm("tmp/notification.#{project_name}.yml")
|
47
46
|
end
|
48
47
|
|
49
48
|
def create_semaphore_secrets
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GithubReplace
|
4
|
+
def run(args, opts)
|
5
|
+
validate_arguments args
|
6
|
+
validate_options opts
|
7
|
+
|
8
|
+
opts.projects.split(",").each do |repo|
|
9
|
+
base = clone_and_checkout repo
|
10
|
+
find_and_replace args, repo, opts.files.split(",")
|
11
|
+
create_pr opts, repo, base
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate_arguments(args)
|
18
|
+
abort ">> specify a search term and replace term" if args.size != 2
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate_options(opts)
|
22
|
+
abort ">> specify one or multiple comma-separated projects" unless opts.projects
|
23
|
+
abort ">> specify a branch" unless opts.branch
|
24
|
+
abort ">> specify a title" unless opts.title
|
25
|
+
abort ">> specify a body" unless opts.body
|
26
|
+
abort ">> specify comma-separated files to check" unless opts.files
|
27
|
+
end
|
28
|
+
|
29
|
+
def clone_and_checkout(repo)
|
30
|
+
puts `cd #{repo} || git clone --depth=1 git@github.com:renuo/#{repo}.git`
|
31
|
+
puts `cd #{repo} && echo git checkout -b "#{opts.branch}"`
|
32
|
+
`cd #{repo} && git branch -rl origin/main origin/master`.strip
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_and_replace(args, repo, files)
|
36
|
+
files.each do |file|
|
37
|
+
file = "#{repo}/#{file}"
|
38
|
+
puts "Replacing '#{args[0]}' with '#{args[1]}' in #{file}"
|
39
|
+
content = File.read(file).gsub args[0], args[1]
|
40
|
+
File.write file, content
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_pr(opts, repo, base)
|
45
|
+
puts `cd "#{repo}" \
|
46
|
+
&& echo git add . \
|
47
|
+
&& echo git commit -S -m "#{opts.title}" \
|
48
|
+
&& echo git push --set-upstream origin "#{opts.branch}" \
|
49
|
+
&& gh pr create -a @me -b "#{opts.body}" -t "#{opts.title}" -B "#{base}" -H "#{opts.branch}"`
|
50
|
+
end
|
51
|
+
end
|
@@ -4,11 +4,14 @@ require "yaml"
|
|
4
4
|
require "fileutils"
|
5
5
|
require "json"
|
6
6
|
|
7
|
-
CONFIG_FILE = "config/1password-secrets.yml"
|
8
|
-
|
9
7
|
class SecretsFetcher
|
8
|
+
CONFIG_FILE = "config/1password-secrets.yml"
|
9
|
+
|
10
10
|
def run
|
11
|
-
|
11
|
+
unless ENV["CI"]
|
12
|
+
system("which op > /dev/null") || abort("op is not installed. Please install it (e.g. brew install " \
|
13
|
+
"1password-cli).")
|
14
|
+
end
|
12
15
|
|
13
16
|
abort("Config file #{CONFIG_FILE} not found.") unless File.exist?(CONFIG_FILE)
|
14
17
|
config = YAML.load_file(CONFIG_FILE).deep_symbolize_keys
|
@@ -20,7 +23,7 @@ class SecretsFetcher
|
|
20
23
|
|
21
24
|
private
|
22
25
|
|
23
|
-
def elaborate_item(item) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
26
|
+
def elaborate_item(item) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
24
27
|
private_link = item[:private_link]
|
25
28
|
if private_link.nil?
|
26
29
|
warn "Private link not found in your config file."
|
@@ -43,6 +46,28 @@ class SecretsFetcher
|
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
49
|
+
def extract_item_id(private_link)
|
50
|
+
/&i=([^&]+)/.match(private_link)[1]
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_item(item_id)
|
54
|
+
output = execute_command(command: "op item get #{item_id} --format json",
|
55
|
+
success_message: "",
|
56
|
+
error_message: "Error fetching item #{item_id}." \
|
57
|
+
"Check `private_link` in your #{CONFIG_FILE} file.")
|
58
|
+
JSON.parse(output) if output
|
59
|
+
end
|
60
|
+
|
61
|
+
def execute_command(command:, success_message:, error_message:)
|
62
|
+
output = `#{command}`
|
63
|
+
if $CHILD_STATUS.success?
|
64
|
+
puts success_message unless success_message.empty?
|
65
|
+
output
|
66
|
+
else
|
67
|
+
warn error_message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
46
71
|
def process_env_variable(name, item_id, item_json)
|
47
72
|
env_json = item_json["fields"].find { |field| field["label"] == name }
|
48
73
|
if env_json.nil?
|
@@ -51,7 +76,6 @@ class SecretsFetcher
|
|
51
76
|
value = env_json["value"]
|
52
77
|
update_or_add_variable(".env", name, /^#{name}=/, "#{name}=#{value}")
|
53
78
|
update_or_add_variable("config/application.yml", name, /^#{name}:.*$/, "#{name}: \"#{value}\"")
|
54
|
-
|
55
79
|
end
|
56
80
|
end
|
57
81
|
|
@@ -73,28 +97,6 @@ class SecretsFetcher
|
|
73
97
|
File.write(file_path, updated_contents)
|
74
98
|
end
|
75
99
|
|
76
|
-
def get_item(item_id)
|
77
|
-
output = execute_command(command: "op item get #{item_id} --format json",
|
78
|
-
success_message: "",
|
79
|
-
error_message: "Error fetching item #{item_id}." \
|
80
|
-
"Check `private_link` in your #{CONFIG_FILE} file.")
|
81
|
-
JSON.parse(output) if output
|
82
|
-
end
|
83
|
-
|
84
|
-
def execute_command(command:, success_message:, error_message:)
|
85
|
-
output = `#{command}`
|
86
|
-
if $CHILD_STATUS.success?
|
87
|
-
puts success_message unless success_message.empty?
|
88
|
-
output
|
89
|
-
else
|
90
|
-
warn error_message
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def extract_item_id(private_link)
|
95
|
-
/&i=([^&]+)/.match(private_link)[1]
|
96
|
-
end
|
97
|
-
|
98
100
|
def process_file(output_folder, filename, item, item_id)
|
99
101
|
FileUtils.mkdir_p(output_folder)
|
100
102
|
output_path = File.join(output_folder, filename)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
apiVersion: v1alpha
|
2
|
+
kind: Notification
|
3
|
+
metadata:
|
4
|
+
name: <%= project_name %>
|
5
|
+
spec:
|
6
|
+
rules:
|
7
|
+
- name: deployment notifications
|
8
|
+
filter:
|
9
|
+
projects: [<%= project_name %>]
|
10
|
+
branches: [main, develop]
|
11
|
+
pipelines: [/.*-deploy.yml/]
|
12
|
+
notify:
|
13
|
+
slack:
|
14
|
+
endpoint: <%= slack_endpoint %>
|
15
|
+
channels: ["#project-<%= project_name %>"]
|
16
|
+
- name: build notifications
|
17
|
+
filter:
|
18
|
+
projects: [<%= project_name %>]
|
19
|
+
branches: [main, develop]
|
20
|
+
pipelines: [semaphore.yml]
|
21
|
+
results: [failed]
|
22
|
+
notify:
|
23
|
+
slack:
|
24
|
+
endpoint: <%= slack_endpoint %>
|
25
|
+
channels: ["#project-<%= project_name %>"]
|
@@ -19,4 +19,4 @@ blocks:
|
|
19
19
|
- checkout --use-cache
|
20
20
|
- heroku git:remote -a $HEROKU_APP_NAME
|
21
21
|
- git push heroku -f $SEMAPHORE_GIT_BRANCH:main
|
22
|
-
- if heroku run -x rails db:migrate; then heroku dyno:restart; else heroku rollback; exit
|
22
|
+
- if heroku run -x rails db:migrate; then heroku dyno:restart; else heroku rollback; exit 1; fi
|
data/lib/renuo/cli/version.rb
CHANGED
data/lib/renuo/cli.rb
CHANGED
@@ -28,6 +28,7 @@ require "renuo/cli/app/renuo_version"
|
|
28
28
|
require "renuo/cli/app/create_slidev_presentation"
|
29
29
|
require "renuo/cli/app/commit_leaderboard_stage"
|
30
30
|
require "renuo/cli/app/commit_leaderboard_sync"
|
31
|
+
require "renuo/cli/app/github_replace"
|
31
32
|
require "renuo/cli/app/secrets_fetcher"
|
32
33
|
require "highline"
|
33
34
|
|
@@ -292,6 +293,25 @@ module Renuo
|
|
292
293
|
end
|
293
294
|
end
|
294
295
|
|
296
|
+
command "github-replace" do |c|
|
297
|
+
c.syntax = "renuo github-replace"
|
298
|
+
c.summary = "Replaces text in multiple GitHub projects and automatically creates a pull request"
|
299
|
+
c.description = "Finds and replaces the contents of specific files in Renuo GitHub projects and " \
|
300
|
+
"automatically creates a pull request"
|
301
|
+
c.option "--projects <name,name,..>", String, "The github project to clone and edit"
|
302
|
+
c.option "--branch <name>", String, "The branch to create"
|
303
|
+
c.option "--title <name>", String, "The title of the pull request"
|
304
|
+
c.option "--body <text>", String, "The body of the pull request"
|
305
|
+
c.option "--files <files,files,..>", String, "The files to check"
|
306
|
+
c.example "Update Semaphore Ubuntu version",
|
307
|
+
"renuo github-replace ubuntu1804 ubuntu2204 --projects=renuo-cli,renuo-website-v3 " \
|
308
|
+
'--branch=feature/1234-update-ubuntu --title="Update os_image version" --body=TICKET-1234 ' \
|
309
|
+
"--files=.semaphore/semaphore.yml"
|
310
|
+
c.action do |args, opts|
|
311
|
+
GithubReplace.new.run(args, opts)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
295
315
|
command "fetch-secrets" do |c|
|
296
316
|
c.syntax = "renuo fetch-secrets"
|
297
317
|
c.summary = "Fetches the needed secrets in a project from the renuo secrets store"
|
data/notification.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
apiVersion: v1alpha
|
2
|
+
kind: Notification
|
3
|
+
metadata:
|
4
|
+
name: <%= project_name %>
|
5
|
+
spec:
|
6
|
+
rules:
|
7
|
+
- name: deployment notifications
|
8
|
+
filter:
|
9
|
+
projects: [<%= project_name %>]
|
10
|
+
branches: [main, develop]
|
11
|
+
pipelines: [/.*-deploy.yml/]
|
12
|
+
notify:
|
13
|
+
slack:
|
14
|
+
endpoint: <%= slack_url %>
|
15
|
+
channels: ["#project-<%= project_name %>"]
|
16
|
+
- name: build notifications
|
17
|
+
filter:
|
18
|
+
projects: [<%= project_name %>]
|
19
|
+
branches: [main, develop]
|
20
|
+
pipelines: [semaphore.yml]
|
21
|
+
results: [failed]
|
22
|
+
notify:
|
23
|
+
slack:
|
24
|
+
endpoint: <%= slack_url %>
|
25
|
+
channels: ["#project-<%= project_name %>"]
|
data/renuo-cli.gemspec
CHANGED
@@ -40,7 +40,6 @@ Gem::Specification.new do |spec|
|
|
40
40
|
spec.add_development_dependency "rake", "~> 13.0"
|
41
41
|
spec.add_development_dependency "renuocop"
|
42
42
|
spec.add_development_dependency "rspec", "~> 3.5"
|
43
|
-
spec.add_development_dependency "rubocop", "~> 1.62"
|
44
43
|
spec.add_development_dependency "simplecov"
|
45
44
|
spec.add_development_dependency "simplecov-console"
|
46
45
|
spec.add_development_dependency "vcr", "~> 6.2"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: renuo-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renuo AG
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeresource
|
@@ -234,20 +234,6 @@ dependencies:
|
|
234
234
|
- - "~>"
|
235
235
|
- !ruby/object:Gem::Version
|
236
236
|
version: '3.5'
|
237
|
-
- !ruby/object:Gem::Dependency
|
238
|
-
name: rubocop
|
239
|
-
requirement: !ruby/object:Gem::Requirement
|
240
|
-
requirements:
|
241
|
-
- - "~>"
|
242
|
-
- !ruby/object:Gem::Version
|
243
|
-
version: '1.62'
|
244
|
-
type: :development
|
245
|
-
prerelease: false
|
246
|
-
version_requirements: !ruby/object:Gem::Requirement
|
247
|
-
requirements:
|
248
|
-
- - "~>"
|
249
|
-
- !ruby/object:Gem::Version
|
250
|
-
version: '1.62'
|
251
237
|
- !ruby/object:Gem::Dependency
|
252
238
|
name: simplecov
|
253
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -323,7 +309,6 @@ files:
|
|
323
309
|
- ".semaphore/bin/cache_store"
|
324
310
|
- ".semaphore/main-deploy.yml"
|
325
311
|
- ".semaphore/semaphore.yml"
|
326
|
-
- ".tool-versions"
|
327
312
|
- Gemfile
|
328
313
|
- LICENSE.txt
|
329
314
|
- README.md
|
@@ -347,6 +332,7 @@ files:
|
|
347
332
|
- lib/renuo/cli/app/environments.rb
|
348
333
|
- lib/renuo/cli/app/fetch_emails.rb
|
349
334
|
- lib/renuo/cli/app/generate_password.rb
|
335
|
+
- lib/renuo/cli/app/github_replace.rb
|
350
336
|
- lib/renuo/cli/app/heroku_apps.rb
|
351
337
|
- lib/renuo/cli/app/heroku_users.rb
|
352
338
|
- lib/renuo/cli/app/list_large_git_files.rb
|
@@ -365,6 +351,7 @@ files:
|
|
365
351
|
- lib/renuo/cli/app/setup_uptimerobot.rb
|
366
352
|
- lib/renuo/cli/app/templates/semaphore/bin/cache_restore.erb
|
367
353
|
- lib/renuo/cli/app/templates/semaphore/bin/cache_store.erb
|
354
|
+
- lib/renuo/cli/app/templates/semaphore/notification.yml.erb
|
368
355
|
- lib/renuo/cli/app/templates/semaphore/semaphore-deploy.yml.erb
|
369
356
|
- lib/renuo/cli/app/templates/semaphore/semaphore.yml.erb
|
370
357
|
- lib/renuo/cli/app/templates/slidev/README.md.erb
|
@@ -379,6 +366,7 @@ files:
|
|
379
366
|
- lib/renuo/cli/app/upgrade_laptop/upgrade_mac_os.rb
|
380
367
|
- lib/renuo/cli/app/work.rb
|
381
368
|
- lib/renuo/cli/version.rb
|
369
|
+
- notification.yml
|
382
370
|
- renuo-cli.gemspec
|
383
371
|
- vcr_cassettes/successful_uptimerobot_calls.yml
|
384
372
|
- vcr_cassettes/unsuccessful_uptimerobot_calls.yml
|
@@ -387,7 +375,7 @@ licenses:
|
|
387
375
|
- MIT
|
388
376
|
metadata:
|
389
377
|
rubygems_mfa_required: 'true'
|
390
|
-
post_install_message:
|
378
|
+
post_install_message:
|
391
379
|
rdoc_options: []
|
392
380
|
require_paths:
|
393
381
|
- lib
|
@@ -402,8 +390,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
402
390
|
- !ruby/object:Gem::Version
|
403
391
|
version: '0'
|
404
392
|
requirements: []
|
405
|
-
rubygems_version: 3.5.
|
406
|
-
signing_key:
|
393
|
+
rubygems_version: 3.5.18
|
394
|
+
signing_key:
|
407
395
|
specification_version: 4
|
408
396
|
summary: The Renuo CLI automates some common workflows.
|
409
397
|
test_files: []
|
data/.tool-versions
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby 3.2.3
|