From 90a35790b889ac925d8bd8d76ff6dbee04c332f5 Mon Sep 17 00:00:00 2001 From: "Michael J. Giarlo" Date: Mon, 6 Jan 2025 16:28:06 -0800 Subject: [PATCH] [SPIKE] Improve CLI documentation and implement git tag operations as thor subcommands --- .rubocop_todo.yml | 14 ++-- README.md | 134 ++++++++++++++++++++---------- bin/sdr | 202 +-------------------------------------------- lib/deployer.rb | 8 +- lib/git_tag_cli.rb | 41 +++++++++ lib/sdr_cli.rb | 158 +++++++++++++++++++++++++++++++++++ lib/tagger.rb | 19 +++-- 7 files changed, 309 insertions(+), 267 deletions(-) create mode 100644 lib/git_tag_cli.rb create mode 100644 lib/sdr_cli.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 33a27c2..d9bdca5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -12,13 +12,13 @@ # URISchemes: http, https Layout/LineLength: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' # Offense count: 7 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max. Metrics/AbcSize: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' - 'lib/auditor.rb' - 'lib/cocina_checker.rb' - 'lib/deployer.rb' @@ -28,20 +28,20 @@ Metrics/AbcSize: # Configuration parameters: CountComments, Max, CountAsOne. Metrics/ClassLength: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' # Offense count: 4 # Configuration parameters: AllowedMethods, AllowedPatterns, Max. Metrics/CyclomaticComplexity: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' - 'lib/cocina_checker.rb' # Offense count: 7 # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' - 'lib/auditor.rb' - 'lib/cocina_checker.rb' - 'lib/deployer.rb' @@ -51,11 +51,11 @@ Metrics/MethodLength: # Configuration parameters: AllowedMethods, AllowedPatterns, Max. Metrics/PerceivedComplexity: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' - 'lib/cocina_checker.rb' # Offense count: 2 # This cop supports safe autocorrection (--autocorrect). Style/IfUnlessModifier: Exclude: - - 'bin/sdr' + - 'lib/sdr_cli.rb' diff --git a/README.md b/README.md index 8ef94a7..a91a8c4 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ Make sure that: * You have properly configured your local SSH setup (see below) * You have logged into `sdr-infra.stanford.edu` and cloned this repository. * You have previously `ssh`-ed into all servers. - * NOTE: If you are unsure about this, run `bin/sdr check_ssh -e [qa|stage|prod]` and watch the output for any errors! -* NOTE: if you run `bin/sdr check_cocina`, you may need to ensure that you have the contribsys gem credentials available for google-books to install the sidekiq-pro gem locally (the credential is already on our deploy target VMs). + * NOTE: If you are unsure about this, run `sdr check_ssh -e [qa|stage|prod]` and watch the output for any errors! +* NOTE: if you run `sdr check_cocina`, you may need to ensure that you have the contribsys gem credentials available for google-books to install the sidekiq-pro gem locally (the credential is already on our deploy target VMs). * The credentials are set to an environment variable on the server via puppet from values stored in vault (vault info: https://consul.stanford.edu/display/systeam/Vault+for+Developers). To fetch without digging into vault, go to a server that has them set via puppet and view the environment variable. See below under "Configure bundler for your local path" for an example. * NOTE: You *may* invoke the `bin/` scripts via `bundle exec`. @@ -80,20 +80,22 @@ user123:pass678 ``` Usage: - bin/sdr check_ssh -e, --environment=ENVIRONMENT + sdr check_ssh -e, --environment=ENVIRONMENT Options: - [--only=one two three] # Update only these repos - [--except=one two three] # Update all except these repos - -s, [--skip-update], [--no-skip-update] # Skip update repos - -e, --environment=ENVIRONMENT # Environment (["qa", "prod", "stage"]) - # Possible values: qa, prod, stage - [--skip-control-master] # Skip checking for active SSH control master connection + [--only=one two three] # Check connections only to these services + [--except=one two three] # Check connections except for these services + -s, [--skip-update] # Skip refreshing the local git repository cache + # Default: false + -e, --environment=ENVIRONMENT # Check connections in the given environment + # Possible values: qa, prod, stage + [--skip-control-master] # Skip checking for an active SSH controlmaster connection + # Default: false -check SSH connections +Check SSH connections Example: - bin/sdr check_ssh -s -e qa --except sul-dlss/technical-metadata-service sul-dlss/argo + sdr check_ssh -s -e qa --except sul-dlss/technical-metadata-service sul-dlss/argo ``` NOTE: Watch the output for any errors @@ -102,42 +104,78 @@ NOTE: Watch the output for any errors ``` Usage: - bin/sdr check_cocina + sdr check_cocina Options: - -s, [--skip-update], [--no-skip-update] # Skip update repos - -t, --branch, [--tag=TAG] # Check cocina version in the given tag or branch instead of the default branch + -s, [--skip-update] # Skip refreshing the local git repository cache + # Default: false + -t, --branch, [--tag=TAG] # Check cocina version in the given tag or branch instead of the default branch -check for cocina-models version mismatches +Check for Cocina data model mismatches Example: - bin/sdr check_cocina -s -t rel-2022-08-01 - bin/sdr check_cocina -t my-wip-branch + sdr check_cocina -s -t rel-2022-08-01 + sdr check_cocina -t my-wip-branch ``` This will let you know which versions of cocina-models are used by each project with it in Gemfile.lock. -### Create repository tags +### Manage repository tags -This command tags repositories in parallel. +This command performs tag operations on repositories in parallel. **NOTE**: We conventionally name tags `rel-{YYYY}-{MM}-{DD}`. +#### Create a tag + +``` +Usage: + sdr tag create TAG_NAME + +Options: + -m, [--message=MESSAGE] # Message to describe a newly created tag + -c, [--skip-non-cocina] # Include only repos depending on new Cocina models releases + # Default: false + +Create a git tag locally and remotely + +Examples: + sdr tag -m 'coordinating the deploy of dependency updates' rel-2022-09-05 + sdr tag -c -m 'coordinating the release of cocina-models 0.66.6' rel-2022-09-14 +``` + +#### Verify a tag + ``` Usage: - bin/sdr tag TAG_NAME + sdr tag verify TAG_NAME Options: - -m, [--message=TAG MESSAGE] # Message to describe a newly created tag - -d, [--delete=DELETE], [--no-delete] # Delete the tag locally and remotely - -v, [--verify] # Verify the tags exist remotely - -c, [--cocina], [--no-cocina] # Only update repos affected by new cocina-models gem release + -c, [--skip-non-cocina] # Include only repos depending on new Cocina models releases + # Default: false -create, delete, or verify a tag named TAG_NAME +Verify a git tag exists remotely Examples: - bin/sdr tag -m 'coordinating the deploy of dependency updates' rel-2022-09-05 - bin/sdr tag -c -m 'coordinating the release of cocina-models 0.66.6' rel-2022-09-14 + sdr tag verify rel-2022-09-05 + sdr tag verify --skip-non-cocina rel-2022-09-14 +``` + +#### Delete a tag + +``` +Usage: + sdr tag delete TAG_NAME + +Options: + -c, [--skip-non-cocina] # Include only repos depending on new Cocina models releases + # Default: false + +Delete a git tag locally and remotely + +Examples: + sdr tag delete rel-2022-09-05 + sdr tag delete --skip-non-cocina rel-2022-09-14 ``` ### Run the deploys @@ -146,23 +184,27 @@ This command deploys repositories in parallel. ``` Usage: - bin/sdr deploy -e, --environment=ENVIRONMENT + sdr deploy -e, --environment=ENVIRONMENT Options: - [--only=one two three] # Update only these repos - [--except=one two three] # Update all except these repos - -c, [--cocina], [--no-cocina] # Only update repos affected by new cocina-models gem release - -b, [--before-command=BEFORE_COMMAND] # Run this command on each host before deploying - -t, --branch, [--tag=TAG] # Deploy the given tag or branch instead of the default branch - -s, [--skip-update], [--no-skip-update] # Skip update repos - -e, --environment=ENVIRONMENT # Deployment environment - # Possible values: qa, prod, stage - [--skip-control-master] # Skip checking for active SSH control master connection -deploy all the services in an environment + [--only=one two three] # Deploy only these services + [--except=one two three] # Deploy all except these services + -c, [--skip-non-cocina] # Deploy only services depending on new Cocina models releases + # Default: false + -b, [--before-command=BEFORE_COMMAND] # Run this command on each host before deploying + -t, --branch, [--tag=TAG] # Deploy the given tag or branch instead of the default branch + -s, [--skip-update] # Skip refreshing the local git repository cache + # Default: false + -e, --environment=ENVIRONMENT # Deployment environment + # Possible values: qa, prod, stage + [--skip-control-master] # Skip checking for active SSH control master connection + # Default: false + +Deploy services to a given environment Examples: - bin/sdr deploy -s -e qa -t my-wip-branch --only=sul-dlss/technical-metadata-service - bin/sdr deploy -c -e qa -t rel-2022-09-14 + sdr deploy -s -e qa -t my-wip-branch --only=sul-dlss/technical-metadata-service + sdr deploy -c -e qa -t rel-2022-09-14 ``` **NOTE 0**: @@ -187,7 +229,7 @@ If there is a problem, you can use `SKIP_UPDATE_STRSCAN` env var for an individu You can update a gem for all apps for a given environment, like this: ``` - bin/sdr deploy -e stage -b 'gem install io-wait' + sdr deploy -e stage -b 'gem install io-wait' ``` Or you can update a gem for a specific app like this: @@ -236,7 +278,7 @@ Then ``` # -e can be qa or stage or prod -bin/sdr deploy -e stage -c +sdr deploy -e stage -c ``` ### Only Refresh Repositories @@ -245,11 +287,13 @@ If you have a need to pull main for all of the repositories without checking ssh ``` Usage: - bin/sdr refresh_repos + sdr refresh_repos Options: - [--only=one two three] # Update only these repos - [--except=one two three] # Update all except these repos + [--only=one two three] # Update the cache only for these repos + [--except=one two three] # Update the cache except for these repos + +Refresh the local git repository cache ``` ### Notes and tips: diff --git a/bin/sdr b/bin/sdr index da7b4b9..1a79cc9 100755 --- a/bin/sdr +++ b/bin/sdr @@ -2,206 +2,6 @@ # frozen_string_literal: true $LOAD_PATH.unshift 'lib' - require 'sdr_deploy' -# SDR CLI -class CLI < Thor - def self.exit_on_failure? - true - end - - no_commands do - def check_control_master(skip) - return if skip - return if system("ssh -O check #{Settings.control_master_host}", err: File::NULL) - - say('Control master not detected. Please start a control master session.') - exit - end - end - - option :skip_update, - type: :boolean, - default: false, - desc: 'Skip update repos', - aliases: '-s' - option :tag, - type: :string, - desc: 'Check cocina version in the given tag or branch instead of the default branch', - aliases: ['-t', '--branch'] - desc 'check_cocina', 'check for cocina-models version mismatches' - def check_cocina - repositories = Settings.repositories.select(&:cocina_models_update) - RepoUpdater.update(repos: repositories) unless options[:skip_update] - CocinaChecker.check(repos: repositories, tag: options[:tag]) - end - - option :message, - required: false, - banner: 'TAG_MESSAGE', - desc: 'Message to describe a newly created tag', - aliases: '-m' - option :delete, - required: false, - type: :boolean, - default: false, - banner: 'DELETE', - desc: 'Delete the tag locally and remotely', - aliases: '-d' - option :verify, - required: false, - type: :boolean, - default: false, - banner: 'VERIFY', - desc: 'Verify the tag remotely', - aliases: '-v' - option :cocina, - type: :boolean, - default: false, - desc: 'Only tag repos affected by new cocina-models gem release', - aliases: '-c' - desc 'tag TAG_NAME', 'create or delete a tag named TAG_NAME' - def tag(tag_name) - repositories = if options[:cocina] - Settings.repositories.select(&:cocina_models_update) - else - Settings.repositories - end - - RepoUpdater.update(repos: repositories) - if options[:delete] - Tagger.delete(tag_name:, repos: repositories) - elsif options[:verify] - Tagger.verify(tag_name:, repos: repositories) - else - Tagger.create(tag_name:, tag_message: options.fetch(:message, 'created by sdr-deploy'), repos: repositories) - end - end - - option :only, - type: :array, - default: [], - desc: 'Update only these repos' - option :except, - type: :array, - default: [], - desc: 'Update all except these repos' - option :skip_update, - type: :boolean, - default: false, - desc: 'Skip update repos', - aliases: '-s' - option :environment, - required: true, - enum: ::Settings.supported_envs.keys.map(&:to_s), - banner: 'ENVIRONMENT', - desc: "Environment (#{Settings.supported_envs.keys.map(&:to_s)})", - aliases: '-e' - option :skip_control_master, - type: :boolean, - default: false, - desc: 'Skip checking for active SSH control master connection' - desc 'check_ssh', 'check SSH connections' - def check_ssh - raise Thor::Error, 'Use only one of --only or --except' if options[:only].any? && options[:except].any? - - check_control_master(options[:skip_control_master]) - - repositories = if options[:only].any? - Settings.repositories.select { |repo| options[:only].include?(repo.name) } - elsif options[:except].any? - Settings.repositories.reject { |repo| options[:except].include?(repo.name) } - else - Settings.repositories - end - - # Do not prune repos if operating on a subset of repos else legitimate current repos get unnecessarily pruned - RepoUpdater.update(repos: repositories, prune: options.slice(:only, :except).none?) unless options[:skip_update] - SshChecker.check(environment: options[:environment], repos: repositories) - end - - option :only, - type: :array, - default: [], - desc: 'Update only these repos' - option :except, - type: :array, - default: [], - desc: 'Update all except these repos' - option :cocina, - type: :boolean, - default: false, - desc: 'Only update repos affected by new cocina-models gem release', - aliases: '-c' - option :before_command, - type: :string, - desc: 'Run this command on each host before deploying', - aliases: '-b' - option :tag, - type: :string, - desc: 'Deploy the given tag or branch instead of the default branch', - aliases: ['-t', '--branch'] - option :skip_update, - type: :boolean, - default: false, - desc: 'Skip update repos', - aliases: '-s' - option :environment, - required: true, - enum: Settings.supported_envs.keys.map(&:to_s), - banner: 'ENVIRONMENT', - desc: 'Deployment environment', - aliases: '-e' - option :skip_control_master, - type: :boolean, - default: false, - desc: 'Skip checking for active SSH control master connection' - desc 'deploy', 'deploy all the services in an environment' - def deploy - raise Thor::Error, 'Use only one of --only or --except' if options[:only].any? && options[:except].any? - - check_control_master(options[:skip_control_master]) - - repositories = if options[:cocina] - Settings.repositories.select(&:cocina_models_update) - else - Settings.repositories - end - - if options[:only].any? - repositories.select! { |repo| options[:only].include?(repo.name) } - elsif options[:except].any? - repositories.reject! { |repo| options[:except].include?(repo.name) } - end - - repositories.reject! { |repo| Array(repo.skip_envs).include?(options[:environment]) } - - # Do not prune repos if operating on a subset of repos else legitimate current repos get unnecessarily pruned - RepoUpdater.update(repos: repositories, prune: options.slice(:only, :except, :cocina, :skip_envs).none?) unless options[:skip_update] - cocina_repos = Settings.repositories.select(&:cocina_models_update) - abort 'ABORTING: due to cocina-models version divergence' unless CocinaChecker.check(repos: cocina_repos, tag: options[:tag]) - - Deployer.deploy( - environment: options[:environment], - repos: repositories, - tag: options[:tag], - before_command: options[:before_command] - ) - end - - option :only, - type: :array, - default: [], - desc: 'Update only these repos' - option :except, - type: :array, - default: [], - desc: 'Update all except these repos' - desc 'refresh_repos', 'refresh the local repos' - def refresh_repos - RepoUpdater.update(repos: Settings.repositories, prune: options.slice(:only, :except).none?) - end -end - -CLI.start(ARGV) +SdrCLI.start(ARGV) diff --git a/lib/deployer.rb b/lib/deployer.rb index 9c0de99..8c30a7e 100644 --- a/lib/deployer.rb +++ b/lib/deployer.rb @@ -3,8 +3,7 @@ require 'English' # Service class for deploying -# rubocop:disable Metrics/ClassLength -class Deployer +class Deployer # rubocop:disable Metrics/ClassLength Result = Struct.new(:repo, :env, :status, :output) def self.deploy(environment:, repos:, tag: nil, before_command: nil) @@ -26,8 +25,7 @@ def initialize(environment:, repos:, tag: nil, before_command: nil) ensure_tag_present_in_all_repos! if tag end - # rubocop:disable Metrics/CyclomaticComplexity - def deploy_all + def deploy_all # rubocop:disable Metrics/CyclomaticComplexity render_markdown('***') render_markdown("# Deploying the following repositories to #{environment} (#{tag || 'default branch'})") render_markdown(repos.map { |repo| "* #{repo.name}" }.join("\n")) @@ -72,7 +70,6 @@ def deploy_all render_markdown("**Deployments to #{environment} complete**") render_markdown("[Check service status](#{status_url})") end - # rubocop:enable Metrics/CyclomaticComplexity def ensure_tag_present_in_all_repos! return if repos_missing_tag.empty? @@ -176,4 +173,3 @@ def set_deploy_target! end end end -# rubocop:enable Metrics/ClassLength diff --git a/lib/git_tag_cli.rb b/lib/git_tag_cli.rb new file mode 100644 index 0000000..01e3445 --- /dev/null +++ b/lib/git_tag_cli.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Container for git tag subcommands +class GitTagCLI < Thor + class_option :skip_non_cocina, + type: :boolean, + default: false, + desc: 'Include only repos depending on new Cocina models releases', + aliases: '-c' + + option :message, + desc: 'Message to describe a newly created tag', + aliases: '-m' + desc 'create TAG_NAME', 'Create a git tag locally and remotely' + def create(tag_name) + RepoUpdater.update(repos: repositories) + Tagger.create(tag_name:, tag_message: options.fetch(:message, 'created by sdr-deploy'), repos: repositories) + end + + desc 'verify TAG_NAME', 'Verify a git tag exists remotely' + def verify(tag_name) + RepoUpdater.update(repos: repositories) + Tagger.verify(tag_name:, repos: repositories) + end + + desc 'delete TAG_NAME', 'Delete a git tag locally and remotely' + def delete(tag_name) + RepoUpdater.update(repos: repositories) + Tagger.delete(tag_name:, repos: repositories) + end + + private + + def repositories + if parent_options[:skip_non_cocina] + Settings.repositories.select(&:cocina_models_update) + else + Settings.repositories + end + end +end diff --git a/lib/sdr_cli.rb b/lib/sdr_cli.rb new file mode 100644 index 0000000..0dd5583 --- /dev/null +++ b/lib/sdr_cli.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +# SDR command-line interface +class SdrCLI < Thor + def self.exit_on_failure? + true + end + + no_commands do + def check_control_master(skip) + return if skip + return if system("ssh -O check #{Settings.control_master_host}", err: File::NULL) + + say('Control master not detected. Please start a control master session.') + exit + end + end + + option :skip_update, + type: :boolean, + default: false, + desc: 'Skip refreshing the local git repository cache', + aliases: '-s' + option :tag, + type: :string, + desc: 'Check cocina version in the given tag or branch instead of the default branch', + aliases: ['-t', '--branch'] + desc 'check_cocina', 'Check for Cocina data model mismatches' + def check_cocina + repositories = Settings.repositories.select(&:cocina_models_update) + RepoUpdater.update(repos: repositories) unless options[:skip_update] + CocinaChecker.check(repos: repositories, tag: options[:tag]) + end + + desc 'tag SUBCOMMAND TAG_NAME', 'Create, delete, or verify a git tag named TAG_NAME' + subcommand 'tag', GitTagCLI + + option :only, + type: :array, + default: [], + desc: 'Check connections only to these services' + option :except, + type: :array, + default: [], + desc: 'Check connections except for these services' + option :skip_update, + type: :boolean, + default: false, + desc: 'Skip refreshing the local git repository cache', + aliases: '-s' + option :environment, + required: true, + enum: ::Settings.supported_envs.keys.map(&:to_s), + desc: 'Check connections in the given environment', + aliases: '-e' + option :skip_control_master, + type: :boolean, + default: false, + desc: 'Skip checking for an active SSH controlmaster connection' + desc 'check_ssh', 'Check SSH connections' + def check_ssh + raise Thor::Error, 'Use only one of --only or --except' if options[:only].any? && options[:except].any? + + check_control_master(options[:skip_control_master]) + + repositories = if options[:only].any? + Settings.repositories.select { |repo| options[:only].include?(repo.name) } + elsif options[:except].any? + Settings.repositories.reject { |repo| options[:except].include?(repo.name) } + else + Settings.repositories + end + + # Do not prune repos if operating on a subset of repos else legitimate current repos get unnecessarily pruned + RepoUpdater.update(repos: repositories, prune: options.slice(:only, :except).none?) unless options[:skip_update] + SshChecker.check(environment: options[:environment], repos: repositories) + end + + option :only, + type: :array, + default: [], + desc: 'Deploy only these services' + option :except, + type: :array, + default: [], + desc: 'Deploy all except these services' + option :skip_non_cocina, + type: :boolean, + default: false, + desc: 'Deploy only services depending on new Cocina models releases', + aliases: '-c' + option :before_command, + type: :string, + desc: 'Run this command on each host before deploying', + aliases: '-b' + option :tag, + type: :string, + desc: 'Deploy the given tag or branch instead of the default branch', + aliases: ['-t', '--branch'] + option :skip_update, + type: :boolean, + default: false, + desc: 'Skip refreshing the local git repository cache', + aliases: '-s' + option :environment, + required: true, + enum: Settings.supported_envs.keys.map(&:to_s), + desc: 'Deployment environment', + aliases: '-e' + option :skip_control_master, + type: :boolean, + default: false, + desc: 'Skip checking for active SSH control master connection' + desc 'deploy', 'Deploy services to a given environment' + def deploy + raise Thor::Error, 'Use only one of --only or --except' if options[:only].any? && options[:except].any? + + check_control_master(options[:skip_control_master]) + + repositories = if options[:skip_non_cocina] + Settings.repositories.select(&:cocina_models_update) + else + Settings.repositories + end + + if options[:only].any? + repositories.select! { |repo| options[:only].include?(repo.name) } + elsif options[:except].any? + repositories.reject! { |repo| options[:except].include?(repo.name) } + end + + repositories.reject! { |repo| Array(repo.skip_envs).include?(options[:environment]) } + + # Do not prune repos if operating on a subset of repos else legitimate current repos get unnecessarily pruned + RepoUpdater.update(repos: repositories, prune: options.slice(:only, :except, :skip_non_cocina).none?) unless options[:skip_update] + abort 'ABORTING: due to cocina-models version divergence' unless CocinaChecker.check(repos: Settings.repositories.select(&:cocina_models_update), tag: options[:tag]) + + Deployer.deploy( + environment: options[:environment], + repos: repositories, + tag: options[:tag], + before_command: options[:before_command] + ) + end + + option :only, + type: :array, + default: [], + desc: 'Update the cache only for these repos' + option :except, + type: :array, + default: [], + desc: 'Update the cache except for these repos' + desc 'refresh_repos', 'Refresh the local git repository cache' + def refresh_repos + RepoUpdater.update(repos: Settings.repositories, prune: options.slice(:only, :except).none?) + end +end diff --git a/lib/tagger.rb b/lib/tagger.rb index 67b6616..d35de35 100644 --- a/lib/tagger.rb +++ b/lib/tagger.rb @@ -22,10 +22,11 @@ def initialize(tag_name:, repos:) end def create(tag_message:) - puts "creating tag in repos: #{repos.map(&:name).join(', ')}" + render_markdown('***') + render_markdown("# Creating tag '#{tag_name}'") + render_markdown(repos.map { |repo| "* #{repo.name}" }.join("\n")) Parallel.each(repos, in_processes: Settings.num_parallel_processes) do |repo| within_project_dir(repo:) do - puts "creating tag '#{tag_name}' for #{repo.name}: #{tag_message}" ErrorEmittingExecutor.execute("git tag -a #{tag_name} -m '#{tag_message}'", exit_on_error: true) ErrorEmittingExecutor.execute("git push origin #{tag_name}", exit_on_error: true) end @@ -33,9 +34,10 @@ def create(tag_message:) end def verify - puts "verifying tag in repos: #{repos.map(&:name).join(', ')}" - repos.each do |repo| - puts "verifying tag '#{tag_name}' in #{repo.name}" + render_markdown('***') + render_markdown("# Verifying tag '#{tag_name}'") + render_markdown(repos.map { |repo| "* #{repo.name}" }.join("\n")) + Parallel.each(repos, in_processes: Settings.num_parallel_processes) do |repo| within_project_dir(repo:) do ErrorEmittingExecutor.execute('git fetch --tags') out, err, status = Open3.capture3("git tag -l #{tag_name}") @@ -44,7 +46,7 @@ def verify next end if out.include?(tag_name) - puts "tag '#{tag_name}' found in #{repo.name}" + puts colorize_success("tag '#{tag_name}' found in #{repo.name}") else puts colorize_failure("tag '#{tag_name}' not found in #{repo.name}") end @@ -53,10 +55,11 @@ def verify end def delete - puts "deleting tag in repos: #{repos.map(&:name).join(', ')}" + render_markdown('***') + render_markdown("# Deleting tag '#{tag_name}'") + render_markdown(repos.map { |repo| "* #{repo.name}" }.join("\n")) Parallel.each(repos, in_processes: Settings.num_parallel_processes) do |repo| within_project_dir(repo:) do - puts "deleting tag '#{tag_name}' from #{repo.name}" ErrorEmittingExecutor.execute("git tag -d #{tag_name}", exit_on_error: true) ErrorEmittingExecutor.execute("git push --delete origin #{tag_name}", exit_on_error: true) end