renuo-cli 4.11.1 → 4.12.1

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/bin/renuo +1 -1
  3. data/lib/renuo/cli/{app → commands}/check_deploio_status.rb +21 -7
  4. data/lib/renuo/cli/{app → commands}/commit_leaderboard_stage.rb +16 -1
  5. data/lib/renuo/cli/{app → commands}/commit_leaderboard_sync.rb +18 -11
  6. data/lib/renuo/cli/{app → commands}/configure_semaphore.rb +15 -14
  7. data/lib/renuo/cli/{app → commands}/configure_sentry.rb +10 -4
  8. data/lib/renuo/cli/{app → commands}/create_aws_project.rb +27 -4
  9. data/lib/renuo/cli/{app → commands}/create_deploio_app.rb +22 -11
  10. data/lib/renuo/cli/{app → commands}/create_heroku_app.rb +10 -4
  11. data/lib/renuo/cli/commands/create_new_logins.rb +41 -0
  12. data/lib/renuo/cli/{app/github_pull_request_creator.rb → commands/create_pr.rb} +15 -6
  13. data/lib/renuo/cli/{app → commands}/create_slidev_presentation.rb +9 -10
  14. data/lib/renuo/cli/{app/name_display.rb → commands/display_name.rb} +20 -10
  15. data/lib/renuo/cli/{app → commands}/fetch_emails.rb +13 -11
  16. data/lib/renuo/cli/{app/secrets_fetcher.rb → commands/fetch_secrets.rb} +22 -6
  17. data/lib/renuo/cli/commands/generate_password.rb +15 -0
  18. data/lib/renuo/cli/{app → commands}/github_replace.rb +18 -1
  19. data/lib/renuo/cli/commands/heroku_users.rb +29 -0
  20. data/lib/renuo/cli/commands/list_large_git_files.rb +19 -0
  21. data/lib/renuo/cli/{app/release_project.rb → commands/release.rb} +11 -5
  22. data/lib/renuo/cli/{app → commands}/setup_uptimerobot.rb +11 -4
  23. data/lib/renuo/cli/{app/upgrade_laptop/upgrade_mac_os.rb → commands/upgrade_laptop.rb} +33 -6
  24. data/lib/renuo/cli/{app/services → services}/cloudfront_config_service.rb +1 -1
  25. data/lib/renuo/cli/{app/services → services}/markdown_parser_service.rb +1 -1
  26. data/lib/renuo/cli/{app/services → services}/renuo_cli_config.rb +1 -3
  27. data/lib/renuo/cli/{app/templates → templates}/semaphore/semaphore.yml.erb +0 -2
  28. data/lib/renuo/cli/version.rb +2 -2
  29. data/lib/renuo/cli.rb +32 -321
  30. metadata +36 -42
  31. data/lib/renuo/cli/app/create_new_logins.rb +0 -33
  32. data/lib/renuo/cli/app/generate_password.rb +0 -9
  33. data/lib/renuo/cli/app/heroku_apps.rb +0 -13
  34. data/lib/renuo/cli/app/heroku_users.rb +0 -15
  35. data/lib/renuo/cli/app/list_large_git_files.rb +0 -9
  36. data/lib/renuo/cli/app/local_storage.rb +0 -32
  37. data/lib/renuo/cli/app/package.json +0 -14
  38. data/lib/renuo/cli/app/secrets_initializer.rb +0 -17
  39. data/lib/renuo/cli/app/upgrade_laptop/upgrade_laptop_execution.rb +0 -40
  40. data/lib/renuo/cli/app/upgrade_laptop.rb +0 -22
  41. /data/lib/renuo/cli/{app → helpers}/command_helper.rb +0 -0
  42. /data/lib/renuo/cli/{app → helpers}/environments.rb +0 -0
  43. /data/lib/renuo/cli/{app → helpers}/renuo_version.rb +0 -0
  44. /data/lib/renuo/cli/{app/templates → templates}/semaphore/bin/cache_restore.erb +0 -0
  45. /data/lib/renuo/cli/{app/templates → templates}/semaphore/bin/cache_store.erb +0 -0
  46. /data/lib/renuo/cli/{app/templates → templates}/semaphore/notification.yml.erb +0 -0
  47. /data/lib/renuo/cli/{app/templates → templates}/semaphore/semaphore-deploy.yml.erb +0 -0
  48. /data/lib/renuo/cli/{app/templates → templates}/slidev/README.md.erb +0 -0
  49. /data/lib/renuo/cli/{app/templates → templates}/slidev/package.json.erb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cb7d9d47317f9d563c0c6f137f3f88e4e903c4820a5e4ebb66bd8436f3bafe9
4
- data.tar.gz: 07c1d63e87957b9935487c97ab76b2a01ae3ffff00e58fe223b9371e5b5aab8d
3
+ metadata.gz: c1c4d2cc7480aa3e88836256e9a7abede1acd40d1dcd3c6f303a02dd05dbdd07
4
+ data.tar.gz: dd0682726f598a8cfcf7e4f39e61886fcfce9ab0cd100692117f104d5ecfda74
5
5
  SHA512:
6
- metadata.gz: 8d438c6a0287224a8d1d44e6a0fba8de3f12a19911ceafd97c6dac5d58a7926fd7ad4f563cbe91148a6a7380e88fad0b818fecf6246ddda24bc819a8aa2ff5b3
7
- data.tar.gz: f9b1bb7d97f7904d44ce66d0b76a3eb7000f715d8d778f2a1044b0f78115f00dd749af45cb9ce04a801c8afc12a731b4cd5fb3e30b6d0b7419f4ca419a7fb04a
6
+ metadata.gz: 9bc669c28ab9d53fed2add3b0907650a67245a59616aadd6402c692dfb3126aa687ac0ff1c79b9370ef727f782013348b7f40b8637137ff2bda475bc58d117bb
7
+ data.tar.gz: f0561c592f523d8a6807b2bc1b4c95270bd786a7845130b2c69beed7b186cd15a6784f377926cbf256266db3db018ae9bccf5c1ba36770148a3556afabc2a378
data/bin/renuo CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'renuo/cli'
4
- Renuo::CLI.new.start
4
+ Renuo::Cli.new.start
@@ -1,20 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "open3"
4
- require "psych"
5
-
6
3
  # :nocov:
7
- class CheckDeploioStatus
4
+ class Renuo::Cli::Commands::CheckDeploioStatus
8
5
  TIMEOUT_IN_SECONDS = 600
9
6
  INTERVAL_IN_SECONDS = 30
10
7
 
11
8
  APP_NAME = ENV.fetch "DEPLOIO_APP_NAME", nil
12
9
  PROJECT = ENV.fetch "DEPLOIO_PROJECT", nil
13
10
 
14
- def initialize(opts)
11
+ command "check-deploio-status" do |c|
12
+ c.syntax = "renuo check-deploio-status"
13
+ c.summary = "Checks the build and release status of the deployment."
14
+ c.description = "Checks the build and release status of the deployment."
15
+ c.option "--git-revision <revision>", String, "The git revision to check"
16
+ c.action { |_, options| new(options).run }
17
+ end
18
+
19
+ def initialize(options)
15
20
  abort "missing env DEPLOIO_APP_NAME" if APP_NAME.nil?
16
21
  abort "missing env DEPLOIO_PROJECT" if PROJECT.nil?
17
- @revision = opts.git_revision || `git rev-parse HEAD`.strip
22
+ @revision = options.git_revision || `git rev-parse HEAD`.strip
18
23
  end
19
24
 
20
25
  def run
@@ -41,6 +46,14 @@ class CheckDeploioStatus
41
46
  Psych.load_stream stdout
42
47
  end
43
48
 
49
+ def fetch_build_logs
50
+ command = "nctl logs build -a #{APP_NAME} -p #{PROJECT} -l 100 --no-labels"
51
+ stdout, stderr, status = Open3.capture3 command
52
+
53
+ abort "error fetching build logs: #{stderr}" unless status.success?
54
+ stdout
55
+ end
56
+
44
57
  def build
45
58
  @build ||= fetch("builds").find do |build|
46
59
  build.dig("spec", "forProvider", "sourceConfig", "git", "revision") == @revision
@@ -65,12 +78,13 @@ class CheckDeploioStatus
65
78
  release.dig("status", "atProvider", "releaseStatus")
66
79
  end
67
80
 
68
- def succeeded?(status, type)
81
+ def succeeded?(status, type) # rubocop:disable Metrics/MethodLength
69
82
  case status
70
83
  when "available", "success"
71
84
  puts "#{type} succeeded"
72
85
  true
73
86
  when "error", "failed"
87
+ puts fetch_build_logs
74
88
  abort "#{type} failed"
75
89
  else
76
90
  puts "#{type} status is #{status}, waiting..."
@@ -1,8 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CommitLeaderboardStage
3
+ class Renuo::Cli::Commands::CommitLeaderboardStage
4
4
  attr_accessor :queue_file_path, :author_username, :auhor_avatar_url, :options
5
5
 
6
+ command "commit-leaderboard-stage" do |c|
7
+ c.syntax = "renuo commit-leaderboard-stage [username] [avatar-url] [queue-path]"
8
+ c.summary = "Adds local commits to a local queue for the commit leaderboard"
9
+ c.option "--verbose", "Prints the latest commit"
10
+ c.description = <<~DESCRIPTION
11
+ Add post-commit hook to `git config core.hookspath` with the following contents:
12
+
13
+ #!/usr/bin/env sh
14
+ renuo commit-leaderboard-stage CuddlyBunion341 "https://avatars.githubusercontent.com/u/53896675?v=4" ~/.renuo-commit-leaderboard.json
15
+
16
+ # You can get the GitHub avatar url using `gh api user | jq .avatar_url`
17
+ DESCRIPTION
18
+ c.action { |args, options| new.run(args, options) }
19
+ end
20
+
6
21
  def run(args, options)
7
22
  abort "No author username given." if args[0].nil?
8
23
  abort "No author avatar url given." if args[1].nil?
@@ -1,23 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "net/http"
3
+ class Renuo::Cli::Commands::CommitLeaderboardSync
4
+ class SyncError < StandardError; end
4
5
 
5
- class SyncError < StandardError; end
6
-
7
- class CommitLeaderboardSync
8
6
  attr_accessor :queue_file_path, :leaderboard_api_url, :api_secret
9
7
 
8
+ command "commit-leaderboard-sync" do |c|
9
+ c.syntax = "renuo commit-leaderboard-sync [api-secret] [queue-path] [api-url]"
10
+ c.summary = "Sends commits from the queue to the commit leaderboard"
11
+ c.description = <<~DESCRIPTION
12
+ Sends commits from the queue to the commit leaderboard
13
+ Add pre-push hook to `git config core.hookspath` with the following contents:
14
+
15
+ #/usr/bin/env sh
16
+ renuo commit-leaderboard-sync {SECRET} ~/.renuo-commit-leaderboard.json https://dashboard.renuo.ch/api/v1/commit_leaderboard
17
+ DESCRIPTION
18
+ c.option "--verbose", "Prints the configuration, request body and response"
19
+ c.action { |args, options| new.run(args, options) }
20
+ end
21
+
10
22
  def run(args, options)
11
23
  process_args(args)
12
24
  print_configuration if options.verbose
13
25
 
14
- unless File.exist?(@queue_file_path)
15
- abort(">> Commit queue file does not exist.")
16
- end
17
-
18
- unless @leaderboard_api_url.match?(URI::DEFAULT_PARSER.make_regexp)
19
- abort(">> Invalid API URL.")
20
- end
26
+ abort(">> Commit queue file does not exist.") unless File.exist?(@queue_file_path)
27
+ abort(">> Invalid API URL.") unless @leaderboard_api_url.match?(URI::DEFAULT_PARSER.make_regexp)
21
28
 
22
29
  commits = JSON.parse(File.read(@queue_file_path))
23
30
  send_commits(commits)
@@ -1,37 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "commander"
4
- require_relative "environments"
5
-
6
- class ConfigureSemaphore
3
+ class Renuo::Cli::Commands::ConfigureSemaphore
7
4
  attr_accessor :project_name, :environment, :slack_endpoint
8
5
 
6
+ command "configure-semaphore" do |c|
7
+ c.syntax = "renuo configure-semaphore"
8
+ c.summary = "Adds standard semaphore configuration files to a project and creates the notifications"
9
+ c.description = "Run this command with a project, to add the semaphore configuration files " \
10
+ "and create notifications."
11
+ c.action { new.run }
12
+ end
13
+
9
14
  def initialize
10
15
  @project_name = File.basename(Dir.getwd)
11
16
  @slack_endpoint = "https://hooks.slack.com/services/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"
12
17
  end
13
18
 
14
- # rubocop:disable Metrics/MethodLength
15
- def call
19
+ def run # rubocop:disable Metrics/MethodLength
16
20
  return unless semaphore_cli_installed?
17
21
 
18
22
  FileUtils.mkdir_p(%w[.semaphore .semaphore/bin tmp])
19
23
 
20
- write_or_warn(".semaphore/semaphore.yml", render("templates/semaphore/semaphore.yml.erb"))
24
+ write_or_warn(".semaphore/semaphore.yml", render("../templates/semaphore/semaphore.yml.erb"))
21
25
  %w[main develop].each do |environment|
22
26
  @environment = environment
23
- write_or_warn(".semaphore/#{environment}-deploy.yml", render("templates/semaphore/semaphore-deploy.yml.erb"))
27
+ write_or_warn(".semaphore/#{environment}-deploy.yml", render("../templates/semaphore/semaphore-deploy.yml.erb"))
24
28
  end
25
- write_or_warn(".semaphore/bin/cache_restore", render("templates/semaphore/bin/cache_restore.erb"))
26
- write_or_warn(".semaphore/bin/cache_store", render("templates/semaphore/bin/cache_store.erb"))
29
+ write_or_warn(".semaphore/bin/cache_restore", render("../templates/semaphore/bin/cache_restore.erb"))
30
+ write_or_warn(".semaphore/bin/cache_store", render("../templates/semaphore/bin/cache_store.erb"))
27
31
 
28
32
  create_semaphore_notification
29
33
  create_semaphore_secrets
30
34
  create_semaphore_deployment_targets
31
35
  end
32
- # rubocop:enable Metrics/MethodLength
33
-
34
- private
35
36
 
36
37
  def semaphore_cli_installed?
37
38
  semaphore_cli_installed = `sem context | grep '*'`.strip == "* renuo_semaphoreci_com"
@@ -40,7 +41,7 @@ class ConfigureSemaphore
40
41
  end
41
42
 
42
43
  def create_semaphore_notification
43
- File.write("tmp/notification.#{project_name}.yml", render("templates/semaphore/notification.yml.erb"))
44
+ File.write("tmp/notification.#{project_name}.yml", render("../templates/semaphore/notification.yml.erb"))
44
45
  system("sem create -f tmp/notification.#{project_name}.yml")
45
46
  FileUtils.rm("tmp/notification.#{project_name}.yml")
46
47
  end
@@ -1,11 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "commander"
4
- require_relative "environments"
5
-
6
- class ConfigureSentry
3
+ class Renuo::Cli::Commands::ConfigureSentry
7
4
  ADMIN_EMAIL = "admin@renuo.ch"
8
5
 
6
+ command "configure-sentry" do |c|
7
+ c.syntax = "renuo configure-sentry [project-name] [SENTRY_DSN]"
8
+ c.summary = "Generates the script necessary to setup sentry on Heroku."
9
+ c.description = "Generates the script necessary to setup sentry on Heroku."
10
+ c.example "renuo configure-sentry myproject https://randomkey@sentry.io/11223344",
11
+ "generates the command to configure sentry for myproject on Heroku"
12
+ c.action { |args| new.run(args) }
13
+ end
14
+
9
15
  def run(args)
10
16
  project_name = args[0]
11
17
  sentry_dsn = args[1]
@@ -1,9 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "renuo/cli/app/services/cloudfront_config_service"
4
-
5
3
  # :nocov:
6
- class CreateAwsProject
4
+ class Renuo::Cli::Commands::CreateAwsProject
5
+ command "create-aws-project" do |c|
6
+ c.syntax = "renuo create-aws-project"
7
+ c.summary = "Generates necessary commands for our project setup on AWS incl. necessary installations."
8
+ c.description = <<~DESCRIPTION
9
+ This creates commands for creating AWS users, buckets an versioning policies and CloudFront.
10
+ It also guides you to set up the necessary environment.
11
+
12
+ You will be asked for:
13
+ (- installation of aws-cli, if not yet done)
14
+ (- setting up aws user `renuo-app-setup`, if not yet done)
15
+ - project name and suffix so that the script can respect our naming conventions
16
+ - the Redmine project name to tag buckets for AWS billing references
17
+ - whether you want to setup CloudFront to deliver assets via S3
18
+
19
+ The generated commands do the following:
20
+ - create an IAM user for each environment (main, develop) and add it to the renuo apps group.
21
+ - create S3 buckets for each user who owns it
22
+ - tag the buckets
23
+ - enable versioning for main buckets
24
+ (- set up a CloudFront distribution for each environment with the default config or plus alias if configured)
25
+ DESCRIPTION
26
+ c.example "Setup a project (you will be asked for details)", "renuo create-aws-project"
27
+ c.action { new.run }
28
+ end
29
+
7
30
  def initialize
8
31
  ensure_aws_setup?
9
32
  ensure_aws_profile_existing?
@@ -109,7 +132,7 @@ class CreateAwsProject
109
132
 
110
133
  def aws_cloudfront_setup(profile, bucket, redmine_project)
111
134
  tags = [{ Key: "redmine_project", Value: redmine_project }]
112
- cloudfront_config_string = CloudfrontConfigService.new(bucket, tags).to_s
135
+ cloudfront_config_string = Renuo::Cli::Services::CloudfrontConfigService.new(bucket, tags).to_s
113
136
 
114
137
  <<~CLOUDFRONT_COMMANDS
115
138
  aws --profile #{profile} cloudfront create-distribution-with-tags --distribution-config-with-tags '#{cloudfront_config_string}'
@@ -1,12 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CreateDeploioApp # rubocop:disable Metrics/ClassLength
3
+ class Renuo::Cli::Commands::CreateDeploioApp # rubocop:disable Metrics/ClassLength
4
4
  DATABASE_SSH_KEY_FILE = "temporary_database_ssh_key"
5
5
  GITHUB_SSH_KEY_FILE_NAME = "temporary_repository_ssh_key"
6
6
  GITHUB_DEPLOY_KEY_TITLE = "deploio-deploy-key"
7
7
  SSH_ALGORITHM = "Ed25519"
8
8
 
9
- def run(_args)
9
+ command "create-deploio-app" do |c|
10
+ c.syntax = "renuo create-deploio-app"
11
+ c.summary = "Generates the script necessary to setup an application on Deploio."
12
+ c.description = <<~DESC
13
+ Generates the script necessary to setup an application on Deploio.
14
+ This command will:
15
+ - Prompt for the application name, Git URL, PostgreSQL version, and 1Password vault name.
16
+ - Validate the provided inputs.
17
+ - Generate the necessary commands to create a project on Deploio.
18
+ - Configure repository access by generating SSH keys and adding them to 1Password.
19
+ - Create the application and database for each specified environment.
20
+ DESC
21
+ c.example "renuo create-deploio-app",
22
+ "Prompts the user for the necessary information and generates the commands " \
23
+ "to create the project, databases, and apps on Deploio."
24
+ c.action { new.run }
25
+ end
26
+
27
+ def run
10
28
  parse_arguments
11
29
  setup_commands
12
30
  setup_environments
@@ -16,8 +34,7 @@ class CreateDeploioApp # rubocop:disable Metrics/ClassLength
16
34
 
17
35
  private
18
36
 
19
- # rubocop:disable Metrics/MethodLength
20
- def parse_arguments
37
+ def parse_arguments # rubocop:disable Metrics/MethodLength
21
38
  @project_name = ask("Enter the project name (e.g: my_app): ")
22
39
  validate_project_name!
23
40
 
@@ -38,12 +55,6 @@ class CreateDeploioApp # rubocop:disable Metrics/ClassLength
38
55
  validate_vault_name
39
56
  end
40
57
  end
41
- # rubocop:enable Metrics/MethodLength
42
-
43
- def ask(prompt)
44
- print prompt
45
- $stdin.gets.chomp
46
- end
47
58
 
48
59
  def setup_commands
49
60
  say "# Commands to setup your Deploio application\n".bold
@@ -118,7 +129,7 @@ class CreateDeploioApp # rubocop:disable Metrics/ClassLength
118
129
  --git-revision="#{environment}" \\
119
130
  --basic-auth=false \\ # Disabling Deploio basic auth as Rails app handles authentication
120
131
  --build-env=SECRET_KEY_BASE='rails secret' \\ # Don't forget to generate the secret key
121
- --language=ruby-heroku
132
+ --language=ruby
122
133
  OUTPUT
123
134
  end
124
135
 
@@ -1,16 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CreateHerokuApp
3
+ class Renuo::Cli::Commands::CreateHerokuApp
4
4
  ADMIN_EMAIL = "operations@renuo.ch"
5
5
 
6
+ command "create-heroku-app" do |c|
7
+ c.syntax = "renuo create-heroku-app <application-name>"
8
+ c.summary = "Generates the script necessary to setup an application on Heroku."
9
+ c.description = "Generates the script necessary to setup an application on Heroku."
10
+ c.example "renuo create-heroku-app hello", "generates the command to create hello on Heroku"
11
+ c.action { |args| new.run(args) }
12
+ end
13
+
6
14
  def run(args)
7
15
  project_name = args[0]
8
16
  abort(">> Project name must be between 2 and 22 characters.") unless project_name&.length&.between?(2, 22)
9
17
 
10
18
  say "# Commands to setup your Heroku application\n".colorize :green
11
- ENVIRONMENTS.each do |env|
12
- print_environment_commands(env, project_name)
13
- end
19
+ ENVIRONMENTS.each { |env| print_environment_commands(env, project_name) }
14
20
  print_pipelines_commands(project_name)
15
21
  end
16
22
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renuo::Cli::Commands::CreateNewLogins
4
+ include CommandHelper
5
+
6
+ LOGINS = [{ name: "Sentry", sign_up_url: "https://sentry.io/organizations/renuo/members/new/",
7
+ steps: ["Click on add new Member"] },
8
+ { name: "NewRelic", sign_up_url: "https://rpm.newrelic.com/",
9
+ steps: ["Click on Renuo", "Account Settings > Add user"] }].freeze
10
+
11
+ command "create-new-logins" do |c|
12
+ c.syntax = "renuo create-new-logins"
13
+ c.summary = "Guides you through the sign up pages for Sentry, NewRelic and Gemnasium"
14
+ c.description = "Guides you through the sign up pages for Sentry, NewRelic and Gemnasium"
15
+ c.example "renuo create-new-logins", "creates new logins"
16
+ c.action { new.run }
17
+ end
18
+
19
+ def run
20
+ LOGINS.each do |login|
21
+ say login[:name].yellow
22
+ login[:steps].each_with_index do |step, index|
23
+ say "\t#{index + 1}. #{step}"
24
+ end
25
+ open_site login[:sign_up_url]
26
+ end
27
+ say "every thing is set up".green
28
+ end
29
+
30
+ private
31
+
32
+ def open_site(website)
33
+ open_path(website)
34
+ wait_to_continue
35
+ end
36
+
37
+ def wait_to_continue
38
+ system "read -n 1 -s -p 'Press any key to continue...'"
39
+ say "\n"
40
+ end
41
+ end
@@ -1,13 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class GithubPullRequestCreator
4
- def run(opts)
5
- create_pr(opts)
3
+ class Renuo::Cli::Commands::CreatePr
4
+ command "create-pr" do |c|
5
+ c.syntax = "renuo create-pr"
6
+ c.summary = "Creates a PR for the current branch"
7
+ c.description = "Creates a PR, assigns it to you and automatically inserts the Redmine ticket number into " \
8
+ "the PR body"
9
+ c.option "--title <title>", String, "The title of the pull request (optional)"
10
+ c.option "--redmine-ticket <number>", Integer, "The redmine ticket number (optional)"
11
+ c.option "--draft", "Mark the PR as draft"
12
+ c.example "Create a PR with the title 'Implement XYZ'",
13
+ "renuo create-pr --title 'Implement XYZ'"
14
+ c.action { |_, options| new.run(options) }
6
15
  end
7
16
 
8
- private
9
-
10
- def create_pr(opts)
17
+ def run(opts)
11
18
  command = [
12
19
  "gh pr create",
13
20
  "--assignee @me",
@@ -20,6 +27,8 @@ class GithubPullRequestCreator
20
27
  puts `#{command}`
21
28
  end
22
29
 
30
+ private
31
+
23
32
  def pr_title(opts)
24
33
  opts.title ? "--title \"#{opts.title}\"" : "--fill"
25
34
  end
@@ -1,25 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "commander"
4
-
5
- class CreateSlidevPresentation
3
+ class Renuo::Cli::Commands::CreateSlidevPresentation
6
4
  EXAMPLE_SLIDES_URL = "https://raw.githubusercontent.com/renuo/slidev-theme-renuo/main/example.md"
7
5
  SLIDEV_THEME_NAME = "renuo"
8
- TEMPLATE_DIRECTORY = "templates/slidev"
6
+ TEMPLATE_DIRECTORY = "../templates/slidev"
9
7
 
10
8
  attr_accessor :presentation_name, :presentation_author
11
9
 
12
- def initialize
13
- @presentation_name = nil
14
- @presentation_author = nil
10
+ command "create-slidev-presentation" do |c|
11
+ c.syntax = "renuo create-slidev-presentation [presentation-name]"
12
+ c.summary = "Creates a new Slidev presentation with the Renuo theme"
13
+ c.description = "Creates a new Slidev presentation with the Renuo theme"
14
+ c.action { |args| new.run(args) }
15
15
  end
16
16
 
17
17
  def run(args)
18
- presentation_name = args[0]
19
- abort(">> No presentation name given.") unless presentation_name
18
+ @presentation_name = args[0]
19
+ abort(">> No presentation name given.") unless @presentation_name
20
20
 
21
21
  say "# Commands to setup Slidev project with the Renuo theme:".colorize :green
22
- @presentation_name = presentation_name
23
22
  @presentation_author = args[1] || "Renuo AG"
24
23
  print_slidev_project_commands
25
24
  end
@@ -1,15 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "command_helper"
4
-
5
- class NameDisplay
3
+ class Renuo::Cli::Commands::DisplayName
6
4
  include CommandHelper
7
5
 
6
+ HEROKU_APP_NAME = "-a renuo-dashboard-main"
7
+ HEROKU_CLI = "heroku run"
8
+ RENUO_CLI = "rails renuo:welcome"
9
+ SLIDES = "https://docs.google.com/presentation/d/1mPhQjArZnlUWUa2ik5R9IlGmdCKCwc2_H8Qq-AWgV-A/edit"
10
+ WELCOME_MESSAGE = "Welcome to Renuo"
11
+
12
+ command "display-name" do |c|
13
+ c.syntax = "renuo display-name [options]"
14
+ c.summary = "Sets the name of a customer on the Renuo dashboard"
15
+ c.description = "Sets the name of a customer on the Renuo dashboard"
16
+ c.example 'Display "Peter Muster" on the dashboard', 'renuo display-name "Peter Muster"'
17
+ c.example "Remove the current name from the dashboard", "renuo display-name --delete"
18
+ c.example "Override the current message on the dashboard", "renuo display-name Happy friday 🍻 --override"
19
+ c.option "--delete", "Deletes the current name"
20
+ c.option "--override", "Overrides the entire message"
21
+ c.option "--monitor", "Open the Google slides"
22
+ c.action { |args, options| new.run(args, options) }
23
+ end
24
+
8
25
  def run(args, options)
9
26
  return open_path(SLIDES) if options.monitor
10
27
  return display_name(nil) if options.delete
11
28
  return say("empty argument") if args.empty?
12
-
13
29
  return run_heroku_command(args.join(" ")) if options.override
14
30
 
15
31
  display_name(args.join(" "))
@@ -17,12 +33,6 @@ class NameDisplay
17
33
 
18
34
  private
19
35
 
20
- HEROKU_APP_NAME = "-a renuo-dashboard-main"
21
- HEROKU_CLI = "heroku run"
22
- RENUO_CLI = "rails renuo:welcome"
23
- SLIDES = "https://docs.google.com/presentation/d/1mPhQjArZnlUWUa2ik5R9IlGmdCKCwc2_H8Qq-AWgV-A/edit"
24
- WELCOME_MESSAGE = "Welcome to Renuo"
25
-
26
36
  def display_name(name)
27
37
  text_message = [WELCOME_MESSAGE, name, "🥳🔥"].compact.join(" ")
28
38
  run_heroku_command(text_message)
@@ -1,24 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "net/http"
4
- require "uri"
3
+ class Renuo::Cli::Commands::FetchEmails
4
+ EMAIL_LIST_URL = "https://docs.google.com/spreadsheets/d/e/2PACX-1vSqPiedBeGk0N75cxZApEohj5LrIWlHWUxTjfhkmK9aOsUltcqCn24sD1haIasUjVfd8UT8VdUKUc4h/pub?gid=703649940&single=true&output=csv"
5
+
6
+ command "fetch-emails" do |c|
7
+ c.syntax = "renuo fetch-emails"
8
+ c.summary = "Retrieves all renuo employees email addresses"
9
+ c.description = "Retrieves all renuo employees email addresses. One per line."
10
+ c.action { new.run }
11
+ end
5
12
 
6
- class FetchEmails
7
- def initialize
8
- @email_list_url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vSqPiedBeGk0N75cxZApEohj5LrIWlHWUxTjfhkmK9aOsUltcqCn24sD1haIasUjVfd8UT8VdUKUc4h/pub?gid=703649940&single=true&output=csv"
13
+ def run
14
+ say "# Here is a complete list of Renuo email addresses".colorize :green
15
+ say fetch_emails.join("\n")
9
16
  end
10
17
 
11
18
  def fetch_emails
12
- response = get_emails(@email_list_url)
19
+ response = get_emails(EMAIL_LIST_URL)
13
20
  response = handle_redirection(response) if response.is_a?(Net::HTTPRedirection)
14
21
  format_response(response)
15
22
  end
16
23
 
17
- def run(_args)
18
- say "# Here is a complete list of Renuo email addresses".colorize :green
19
- say fetch_emails.join("\n")
20
- end
21
-
22
24
  private
23
25
 
24
26
  def get_emails(url)
@@ -1,12 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "yaml"
4
- require "fileutils"
5
- require "json"
6
-
7
- class SecretsFetcher
3
+ class Renuo::Cli::Commands::FetchSecrets # rubocop:disable Metrics/ClassLength
8
4
  CONFIG_FILE = "config/1password-secrets.yml"
9
5
 
6
+ command "fetch-secrets" do |c|
7
+ c.syntax = "renuo fetch-secrets"
8
+ c.summary = "Fetches the needed secrets in a project from the renuo secrets store"
9
+ c.option "--init <private_vault_link>", String, "Initializes the renuo secrets store"
10
+ c.description = <<~DESCRIPTION
11
+ Run the command within a project folder to fetch the secrets from the renuo secrets store.
12
+ The bin/setup of the project might run this command for you.
13
+ DESCRIPTION
14
+ c.action { |_, options| options.init ? new.init(options.init) : new.run }
15
+ end
16
+
17
+ def init(private_vault_link)
18
+ abort("Config file #{CONFIG_FILE} already exists.") if File.exist?(CONFIG_FILE)
19
+ File.write(CONFIG_FILE, generate_config_file(private_vault_link))
20
+ end
21
+
10
22
  def run
11
23
  unless ENV["CI"]
12
24
  system("which op > /dev/null") || abort("op is not installed. Please install it (e.g. brew install " \
@@ -14,7 +26,7 @@ class SecretsFetcher
14
26
  end
15
27
 
16
28
  abort("Config file #{CONFIG_FILE} not found.") unless File.exist?(CONFIG_FILE)
17
- config = YAML.load_file(CONFIG_FILE).deep_symbolize_keys
29
+ config = Psych.load_file(CONFIG_FILE).deep_symbolize_keys
18
30
 
19
31
  config[:items].each do |item|
20
32
  elaborate_item(item)
@@ -23,6 +35,10 @@ class SecretsFetcher
23
35
 
24
36
  private
25
37
 
38
+ def generate_config_file(private_vault_link)
39
+ { "items" => [{ "private_link" => private_vault_link, "files" => [], "env_variables" => [] }] }.to_yaml
40
+ end
41
+
26
42
  def elaborate_item(item) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
27
43
  private_link = item[:private_link]
28
44
  if private_link.nil?
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Renuo::Cli::Commands::GeneratePassword
4
+ command "generate-password" do |c|
5
+ c.syntax = "renuo generate-password"
6
+ c.summary = "Generates a phrase of random 0-9a-zA-Z characters. Choose a substring of it as a new password."
7
+ c.description = "Generates a phrase of random 0-9a-zA-Z characters. Choose a substring of it as a new password."
8
+ c.example "renuo generate-password", "generates a random password"
9
+ c.action { new.run }
10
+ end
11
+
12
+ def run
13
+ say SecureRandom.base64(200).gsub(%r{[+/=]}, "")[0...100]
14
+ end
15
+ end
@@ -1,6 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class GithubReplace
3
+ class Renuo::Cli::Commands::GithubReplace
4
+ command "github-replace" do |c|
5
+ c.syntax = "renuo github-replace"
6
+ c.summary = "Replaces text in multiple GitHub projects and automatically creates a pull request"
7
+ c.description = "Finds and replaces the contents of specific files in Renuo GitHub projects and " \
8
+ "automatically creates a pull request"
9
+ c.option "--projects <name,name,..>", String, "The github project to clone and edit"
10
+ c.option "--branch <name>", String, "The branch to create"
11
+ c.option "--title <name>", String, "The title of the pull request"
12
+ c.option "--body <text>", String, "The body of the pull request"
13
+ c.option "--files <files,files,..>", String, "The files to check"
14
+ c.example "Update Semaphore Ubuntu version",
15
+ "renuo github-replace ubuntu1804 ubuntu2204 --projects=renuo-cli,renuo-website-v3 " \
16
+ '--branch=feature/1234-update-ubuntu --title="Update os_image version" --body=TICKET-1234 ' \
17
+ "--files=.semaphore/semaphore.yml"
18
+ c.action { |args, options| new.run(args, options) }
19
+ end
20
+
4
21
  def run(args, opts)
5
22
  validate_arguments args
6
23
  validate_options opts