renuo-cli 4.5.2 → 4.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|