diff --git a/gems/gitlab-backup-cli/.rubocop.yml b/gems/gitlab-backup-cli/.rubocop.yml index b67751b139cb45453d8532c6375acce3fef4272f..11e619c2b042b61ddee330596533bc100529766f 100644 --- a/gems/gitlab-backup-cli/.rubocop.yml +++ b/gems/gitlab-backup-cli/.rubocop.yml @@ -11,3 +11,6 @@ Rails/Exit: RSpec/MultipleMemoizedHelpers: Max: 25 AllowSubject: true + +Rails/RakeEnvironment: + Enabled: false diff --git a/gems/gitlab-backup-cli/Rakefile b/gems/gitlab-backup-cli/Rakefile index cca7175449300ac09160bf9df759076b53696d25..bc60e76f5c61e35b678750271e6fc806b35b35c9 100644 --- a/gems/gitlab-backup-cli/Rakefile +++ b/gems/gitlab-backup-cli/Rakefile @@ -10,3 +10,7 @@ require "rubocop/rake_task" RuboCop::RakeTask.new task default: %i[spec rubocop] + +task :version do |_| + puts Gitlab::Backup::Cli::VERSION +end diff --git a/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils.rb b/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils.rb index 5c8293602e45b6661bd24f4e322bc0710ad520d8..0234f17cd68e394fbd04452459a85fb72cfb3b71 100644 --- a/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils.rb +++ b/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils.rb @@ -6,6 +6,7 @@ module Cli module Utils autoload :Compression, 'gitlab/backup/cli/utils/compression' autoload :PgDump, 'gitlab/backup/cli/utils/pg_dump' + autoload :Rake, 'gitlab/backup/cli/utils/rake' autoload :Tar, 'gitlab/backup/cli/utils/tar' end end diff --git a/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils/rake.rb b/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils/rake.rb new file mode 100644 index 0000000000000000000000000000000000000000..3c532077d1e8290236a75349504e514d1e234032 --- /dev/null +++ b/gems/gitlab-backup-cli/lib/gitlab/backup/cli/utils/rake.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Gitlab + module Backup + module Cli + module Utils + class Rake + # @return [Array<String>] a list of tasks to be executed + attr_reader :tasks + + # @return [String|Pathname] a path where rake tasks are run from + attr_reader :chdir + + # @param [Array<String>] *tasks a list of tasks to be executed + # @param [String|Pathname] chdir a path where rake tasks are run from + def initialize(*tasks, chdir: Gitlab::Backup::Cli.root) + @tasks = tasks + @chdir = chdir + end + + # @return [self] + def execute + Bundler.with_original_env do + @result = Shell::Command.new(*rake_command, chdir: chdir).capture + end + + self + end + + # Return whether the execution was a success or not + # + # @return [Boolean] whether the execution was a success + def success? + @result&.status&.success? || false + end + + # Return the captured rake output + # + # @return [String] stdout content + def output + @result&.stdout || '' + end + + # Return the captured error content + # + # @return [String] stdout content + def stderr + @result&.stderr || '' + end + + # Return the captured execution duration + # + # @return [Float] execution duration + def duration + @result&.duration || 0.0 + end + + private + + # Return a list of commands necessary to execute `rake` + # + # @return [Array<String (frozen)>] array of commands to be used by Shellout + def rake_command + %w[bundle exec rake] + tasks + end + end + end + end + end +end diff --git a/gems/gitlab-backup-cli/spec/gitlab/backup/cli/utils/rake_spec.rb b/gems/gitlab-backup-cli/spec/gitlab/backup/cli/utils/rake_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3fc3c19ce67a79f88c7a658f48d8acbffcedb37b --- /dev/null +++ b/gems/gitlab-backup-cli/spec/gitlab/backup/cli/utils/rake_spec.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +RSpec.describe Gitlab::Backup::Cli::Utils::Rake do + subject(:rake) { described_class.new('version') } + + describe '#execute' do + it 'clears out bundler environment' do + expect(Bundler).to receive(:with_original_env).and_yield + + rake.execute + end + + it 'runs rake using bundle exec' do + expect_next_instance_of(Gitlab::Backup::Cli::Shell::Command) do |shell| + expect(shell.cmd_args).to start_with(%w[bundle exec rake]) + end + + rake.execute + end + + it 'runs rake command with the defined tasks' do + expect_next_instance_of(Gitlab::Backup::Cli::Shell::Command) do |shell| + expect(shell.cmd_args).to end_with(%w[version]) + end + + rake.execute + + expect(rake.success?).to eq(true) + end + + context 'when chdir is set' do + let(:tmpdir) { Dir.mktmpdir } + + after do + FileUtils.rmdir(tmpdir) + end + + subject(:rake) { described_class.new('version', chdir: tmpdir) } + + it 'runs rake in the provided chdir directory' do + expect_next_instance_of(Gitlab::Backup::Cli::Shell::Command) do |shell| + expect(shell.chdir).to eq(tmpdir) + end + + rake.execute + + expect(rake.success?).to eq(false) + expect(rake.stderr).to match('Could not locate Gemfile or .bundle/ directory') + end + end + end + + describe '#success?' do + subject(:rake) { described_class.new('--version') } # valid command that has no side-effect + + context 'with a successful rake execution' do + it 'returns true' do + rake.execute + + expect(rake.success?).to be_truthy + end + end + + context 'with a failed rake execution', :hide_output do + subject(:invalid_rake) { described_class.new('--invalid') } # valid command that has no side-effect + + it 'returns false when a previous execution failed' do + invalid_rake.execute + + expect(invalid_rake.duration).to be > 0.0 + expect(invalid_rake.success?).to be_falsey + end + end + + it 'returns false when no execution was done before' do + expect(rake.success?).to be_falsey + end + end + + describe '#output' do + it 'returns the output from running a rake task' do + rake.execute + + expect(rake.output).to match(Gitlab::Backup::Cli::VERSION) + end + + it 'returns an empty string when the task has not been run' do + expect(rake.output).to eq('') + end + end + + describe '#stderr' do + subject(:invalid_rake) { described_class.new('--invalid') } # valid command that has no side-effect + + it 'returns the content from stderr when available' do + invalid_rake.execute + + expect(invalid_rake.stderr).to match('invalid option: --invalid') + end + + it 'returns an empty string when the task has not been run' do + expect(invalid_rake.stderr).to eq('') + end + end + + describe '#duration' do + it 'returns a duration time' do + rake.execute + + expect(rake.duration).to be > 0.0 + end + + it 'returns 0.0 when the task has not been run' do + expect(rake.duration).to eq(0.0) + end + end +end