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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b77e89a9f507723bab01e37522020c8ac82d34a34275bcf3e43fbfff85dba43e
4
- data.tar.gz: 043d1fe1aef50f6180dd7d808b1e8bafc3e82d5688b858b39b85cec998988f1a
3
+ metadata.gz: 955e4807e9528133c7c3334b6ce70acb637e63a0450ea08be389cfdb5a429f63
4
+ data.tar.gz: 364adfbd23ffbeddbd4ce89166160000a8c6b101089527a7e581afe13b54bce0
5
5
  SHA512:
6
- metadata.gz: 0a25b071168803c2705e9ce7377ad61a8c20c2077d1c6c7feabff0b80cc5afa53615a804907022353b188819042a1005daba19e0edb8d2c278c38f240f6b7150
7
- data.tar.gz: d43a2314a03e768d62cf63c9e3de3e757d79f548d965af097ff178d009ea8b2c7cefe11b4d65070ca434ff0938e41047b8c56947ef4035e024470e197b23774b
6
+ metadata.gz: de3070d906d5610b9acfa4bfdd49ee8f09fd4f59e64f2476d062cd1345acdc5e644f20bd16fe00fa70b42309925ee47a5f44e0aa5b10b83676da80667c326de7
7
+ data.tar.gz: da7edb8258f8fe5d0445594deebf63a0488a6cbb6f483750e6b9118bc1e2e6323082ae06607bfddeb0e345211ed074e18ed6f4f95c3be19bcc7081feb28f0d32
data/bin/setup CHANGED
@@ -5,4 +5,3 @@ IFS=$'\n\t'
5
5
  gem install bundler --conservative
6
6
  bundle install
7
7
  ln -s ../../bin/check .git/hooks/pre-commit
8
-
@@ -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
- system("sem create notifications #{project_name} " \
43
- "--projects #{project_name} " \
44
- '--branches "main,develop" ' \
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
- system("which op > /dev/null") || abort("op is not installed. Please install it (e.g. brew install 1password-cli).")
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 -1; fi
22
+ - if heroku run -x rails db:migrate; then heroku dyno:restart; else heroku rollback; exit 1; fi
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Renuo
4
4
  module Cli
5
- VERSION = "4.5.2"
5
+ VERSION = "4.6.0"
6
6
  NAME = "renuo-cli"
7
7
  end
8
8
  end
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.5.2
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-10-09 00:00:00.000000000 Z
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.16
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