Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2021-10-18 14:18:47 UTC using RuboCop version 1.22.1.
# on 2022-02-14 21:55:21 UTC using RuboCop version 1.24.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 8
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: Include.
# Include: **/*.gemspec
Gemspec/RequireMFA:
Exclude:
- 'modulesync.gemspec'

# Offense count: 9
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 60

# Offense count: 2
# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 134
Max: 186

# Offense count: 4
# Offense count: 5
# Configuration parameters: IgnoredMethods.
Metrics/CyclomaticComplexity:
Max: 15

# Offense count: 14
# Offense count: 17
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
Metrics/MethodLength:
Max: 34

# Offense count: 3
# Offense count: 4
# Configuration parameters: IgnoredMethods.
Metrics/PerceivedComplexity:
Max: 16
Expand Down
2 changes: 1 addition & 1 deletion .simplecov
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ SimpleCov.start do
track_files '**/*.rb'
end

if ENV['CODECOV']
if ENV['CODECOV'] == 'yes'
require 'simplecov-console'
require 'codecov'

Expand Down
51 changes: 51 additions & 0 deletions features/execute.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Feature: execute
Use ModuleSync to execute a custom script on each repositories

Scenario: Cloning sourcecodes before running command when modules/ dir is empty
Given a basic setup with a puppet module "puppet-test" from "awesome"
Then the file "modules/awesome/puppet-test/metadata.json" should not exist
When I successfully run `msync exec --verbose -- /bin/true`
Then the stdout should contain "Cloning from 'file://"
And the file "modules/awesome/puppet-test/metadata.json" should exist

@no-clobber
Scenario: No clones before running command when sourcecode have already been cloned
Then the file "modules/awesome/puppet-test/metadata.json" should exist
When I successfully run `msync exec --verbose /bin/true`
Then the stdout should not contain "Cloning from 'file://"

@no-clobber
Scenario: When command run fails, fail fast if option defined
When I run `msync exec --verbose --fail-fast -- /bin/false`
Then the exit status should be 1
And the stderr should contain:
"""
Command execution failed
"""

@no-clobber
Scenario: When command run fails, run all and summarize errors if option fail-fast is not set
When I run `msync exec --verbose --no-fail-fast -- /bin/false`
Then the exit status should be 1
And the stderr should contain:
"""
Error(s) during `execute` command:
*
"""

Scenario: Show fail-fast default value in help
When I successfully run `msync help exec`
Then the stdout should contain:
"""
[--fail-fast], [--no-fail-fast] # Abort the run after a command execution failure
# Default: true
"""

Scenario: Override fail-fast default value using config file
Given the global option "fail_fast" sets to "false"
When I successfully run `msync help exec`
Then the stdout should contain:
"""
[--fail-fast], [--no-fail-fast] # Abort the run after a command execution failure
"""
# NOTE: It seems there is a Thor bug here: default value is missing in help when sets to 'false'
46 changes: 46 additions & 0 deletions features/push.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Feature: push
Push commits to remote

Scenario: Push available commits to remote
Given a mocked git configuration
And a puppet module "puppet-test" from "awesome"
And a file named "managed_modules.yml" with:
"""
---
puppet-test:
namespace: awesome
"""
And a file named "modulesync.yml" with:
"""
---
branch: modulesync
"""
And a git_base option appended to "modulesync.yml" for local tests
And I successfully run `msync reset`
And I cd to "modules/awesome/puppet-test"
And I run `touch hello`
And I run `git add hello`
And I run `git commit -m'Hello!'`
And I cd to "~"
Then the puppet module "puppet-test" from "awesome" should have no commits made by "Aruba"
When I successfully run `msync push --verbose`
Then the puppet module "puppet-test" from "awesome" should have 1 commit made by "Aruba" in branch "modulesync"

Scenario: Push command without a branch sets
Given a basic setup with a puppet module "puppet-test" from "awesome"
When I run `msync push --verbose`
Then the exit status should be 1
And the stderr should contain:
"""
Error: 'branch' option is missing, please set it in configuration or in command line.
"""

Scenario: Report the need to clone repositories if sourcecode was not cloned before
Given a basic setup with a puppet module "puppet-test" from "awesome"
And the global option "branch" sets to "modulesync"
When I run `msync push --verbose`
Then the exit status should be 1
And the stderr should contain:
"""
puppet-test: Repository must be locally available before trying to push
"""
57 changes: 57 additions & 0 deletions features/reset.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Feature: reset
Reset all repositories

Scenario: Running first reset to clone repositories
Given a basic setup with a puppet module "puppet-test" from "awesome"
And the global option "branch" sets to "modulesync"
When I successfully run `msync reset --verbose`
Then the output should contain "Cloning from 'file://"
And the output should not contain "Hard-resetting any local changes to repository in"

@no-clobber
Scenario: Reset when sourcecodes have already been cloned
Given the file "modules/awesome/puppet-test/metadata.json" should exist
And the global option "branch" sets to "modulesync"
When I successfully run `msync reset --verbose`
Then the output should not contain "Cloning from 'file://"
And the output should contain "Hard-resetting any local changes to repository in 'modules/awesome/puppet-test' from branch 'origin/master'"

Scenario: Reset after an upstream file addition
Given a basic setup with a puppet module "puppet-test" from "awesome"
And the global option "branch" sets to "modulesync"
And I successfully run `msync reset`
Then the file "modules/awesome/puppet-test/hello" should not exist
When the puppet module "puppet-test" from "awesome" has a file named "hello" with:
"""
Hello
"""
When I successfully run `msync reset --verbose`
Then the output should contain "Hard-resetting any local changes to repository in 'modules/awesome/puppet-test' from branch 'origin/master'"
And the file "modules/awesome/puppet-test/hello" should exist

Scenario: Reset after an upstream file addition in offline mode
Given a basic setup with a puppet module "puppet-test" from "awesome"
And the global option "branch" sets to "modulesync"
And I successfully run `msync reset`
Then the file "modules/awesome/puppet-test/hello" should not exist
When the puppet module "puppet-test" from "awesome" has a branch named "execute"
And the puppet module "puppet-test" from "awesome" has, in branch "execute", a file named "hello" with:
"""
Hello
"""
When I successfully run `msync reset --offline`
Then the file "modules/awesome/puppet-test/hello" should not exist

Scenario: Reset to a specified branch
Given a basic setup with a puppet module "puppet-test" from "awesome"
And the global option "branch" sets to "modulesync"
When the puppet module "puppet-test" from "awesome" has a branch named "other-branch"
And the puppet module "puppet-test" from "awesome" has, in branch "other-branch", a file named "hello" with:
"""
Hello
"""
And I successfully run `msync reset`
Then the file "modules/awesome/puppet-test/hello" should not exist
When I successfully run `msync reset --verbose --source-branch origin/other-branch`
And the output should contain "Hard-resetting any local changes to repository in 'modules/awesome/puppet-test' from branch 'origin/other-branch'"
Then the file "modules/awesome/puppet-test/hello" should exist
15 changes: 14 additions & 1 deletion features/step_definitions/git_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,20 @@
end

Given 'a git_base option appended to "modulesync.yml" for local tests' do
File.write "#{Aruba.config.working_directory}/modulesync.yml", "\ngit_base: #{ModuleSync::Faker::PuppetModuleRemoteRepo.git_base}", mode: 'a'
step "the global option 'git_base' sets to '#{ModuleSync::Faker::PuppetModuleRemoteRepo.git_base}'"
end

Given 'the file {string} appended with:' do |filename, content|
File.write filename, "\n#{content}", mode: 'a'
end

Given 'the global option {string} sets to {string}' do |key, value|
steps %(
Given the file "#{Aruba.config.working_directory}/modulesync.yml" appended with:
"""
#{key}: #{value}
"""
)
end

Given 'the puppet module {string} from {string} is read-only' do |name, namespace|
Expand Down
2 changes: 2 additions & 0 deletions features/update.feature
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ Feature: update

Scenario: Setting a directory to unmanaged
Given a basic setup with a puppet module "puppet-apache" from "puppetlabs"
And I successfully run `msync clone`
And a file named "config_defaults.yml" with:
"""
---
Expand Down Expand Up @@ -395,6 +396,7 @@ Feature: update

Scenario: Updating offline
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
And I successfully run `msync clone`
And a file named "config_defaults.yml" with:
"""
---
Expand Down
90 changes: 88 additions & 2 deletions lib/modulesync.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'English'
require 'fileutils'
require 'pathname'

Expand Down Expand Up @@ -108,7 +109,12 @@ def self.manage_file(puppet_module, filename, settings, options)

def self.manage_module(puppet_module, module_files, defaults)
puts "Syncing '#{puppet_module.given_name}'"
puppet_module.repository.prepare_workspace(options[:branch]) unless options[:offline]
# NOTE: #prepare_workspace now supports to execute only offline operations
# but we totally skip the workspace preparation to keep the current behavior
unless options[:offline]
puppet_module.repository.prepare_workspace(branch: options[:branch],
operate_offline: false)
end

module_configs = Util.parse_config puppet_module.path(MODULE_CONF_FILE)
settings = Settings.new(defaults[GLOBAL_DEFAULTS_KEY] || {},
Expand Down Expand Up @@ -164,7 +170,7 @@ def self.update(cli_options)
managed_modules.each do |puppet_module|
manage_module(puppet_module, module_files, defaults)
rescue ModuleSync::Error, Git::GitExecuteError => e
message = e.message || "Error during '#{options[:command]}'"
message = e.message || 'Error during `update`'
$stderr.puts "#{puppet_module.given_name}: #{message}"
exit 1 unless options[:skip_broken]
errors = true
Expand All @@ -177,4 +183,84 @@ def self.update(cli_options)
end
exit 1 if errors && options[:fail_on_warnings]
end

def self.clone(cli_options)
@options = config_defaults.merge(cli_options)

managed_modules.each do |puppet_module|
puppet_module.repository.clone unless puppet_module.repository.cloned?
end
end

def self.execute(cli_options)
@options = config_defaults.merge(cli_options)

errors = {}
managed_modules.each do |puppet_module|
$stdout.puts "#{puppet_module.given_name}:"

puppet_module.repository.clone unless puppet_module.repository.cloned?
puppet_module.repository.switch branch: @options[:branch]

command_args = cli_options[:command_args]
local_script = File.expand_path command_args[0]
command_args[0] = local_script if File.exist?(local_script)

# Remove bundler-related env vars to allow the subprocess to run `bundle`
command_env = ENV.reject { |k, _v| k.match?(/(^BUNDLE|^SOURCE_DATE_EPOCH$|^GEM_|RUBY)/) }

result = system command_env, *command_args, unsetenv_others: true, chdir: puppet_module.working_directory
unless result
message = "Command execution failed ('#{@options[:command_args].join ' '}': #{$CHILD_STATUS})"
raise Thor::Error, message if @options[:fail_fast]

errors.merge!(
puppet_module.given_name => message,
)
$stderr.puts message
end

$stdout.puts ''
end

unless errors.empty?
raise Thor::Error, <<~MSG
Error(s) during `execute` command:
#{errors.map { |name, message| " * #{name}: #{message}" }.join "\n"}
MSG
end

exit 1 unless errors.empty?
end

def self.reset(cli_options)
@options = config_defaults.merge(cli_options)
if @options[:branch].nil?
raise Thor::Error,
"Error: 'branch' option is missing, please set it in configuration or in command line."
end

managed_modules.each do |puppet_module|
puppet_module.repository.reset_workspace(
branch: @options[:branch],
source_branch: @options[:source_branch],
operate_offline: @options[:offline],
)
end
end

def self.push(cli_options)
@options = config_defaults.merge(cli_options)

if @options[:branch].nil?
raise Thor::Error,
"Error: 'branch' option is missing, please set it in configuration or in command line."
end

managed_modules.each do |puppet_module|
puppet_module.repository.push branch: @options[:branch], remote_branch: @options[:remote_branch]
rescue ModuleSync::Error => e
raise Thor::Error, "#{puppet_module.given_name}: #{e.message}"
end
end
end
Loading