modulesync 2.2.0 → 2.3.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +18 -3
- data/.github/workflows/release.yml +2 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +14 -8
- data/.rubocop_todo.yml +25 -17
- data/.simplecov +46 -0
- data/CHANGELOG.md +32 -0
- data/Gemfile +1 -1
- data/bin/msync +17 -1
- data/features/cli.feature +12 -6
- data/features/execute.feature +51 -0
- data/features/hook.feature +5 -8
- data/features/push.feature +46 -0
- data/features/reset.feature +57 -0
- data/features/step_definitions/git_steps.rb +29 -1
- data/features/support/env.rb +9 -0
- data/features/update/bump_version.feature +8 -12
- data/features/update/dot_sync.feature +52 -0
- data/features/update/pull_request.feature +180 -0
- data/features/update.feature +74 -103
- data/lib/modulesync/cli/thor.rb +12 -0
- data/lib/modulesync/cli.rb +122 -28
- data/lib/modulesync/git_service/base.rb +63 -0
- data/lib/modulesync/git_service/factory.rb +28 -0
- data/lib/modulesync/{pr → git_service}/github.rb +23 -21
- data/lib/modulesync/git_service/gitlab.rb +62 -0
- data/lib/modulesync/git_service.rb +96 -0
- data/lib/modulesync/hook.rb +11 -13
- data/lib/modulesync/renderer.rb +3 -6
- data/lib/modulesync/repository.rb +71 -25
- data/lib/modulesync/settings.rb +0 -1
- data/lib/modulesync/source_code.rb +28 -2
- data/lib/modulesync/util.rb +4 -4
- data/lib/modulesync.rb +104 -66
- data/modulesync.gemspec +7 -4
- data/spec/helpers/faker/puppet_module_remote_repo.rb +16 -1
- data/spec/spec_helper.rb +1 -23
- data/spec/unit/modulesync/git_service/factory_spec.rb +16 -0
- data/spec/unit/modulesync/git_service/github_spec.rb +81 -0
- data/spec/unit/modulesync/git_service/gitlab_spec.rb +90 -0
- data/spec/unit/modulesync/git_service_spec.rb +201 -0
- data/spec/unit/modulesync/source_code_spec.rb +22 -0
- data/spec/unit/modulesync_spec.rb +0 -12
- metadata +74 -12
- data/lib/modulesync/pr/gitlab.rb +0 -54
- data/spec/unit/modulesync/pr/github_spec.rb +0 -49
- data/spec/unit/modulesync/pr/gitlab_spec.rb +0 -81
@@ -33,10 +33,11 @@ module ModuleSync
|
|
33
33
|
def default_branch
|
34
34
|
symbolic_ref = repo.branches.find { |b| b.full =~ %r{remotes/origin/HEAD} }
|
35
35
|
return unless symbolic_ref
|
36
|
+
|
36
37
|
%r{remotes/origin/HEAD\s+->\s+origin/(?<branch>.+?)$}.match(symbolic_ref.full)[:branch]
|
37
38
|
end
|
38
39
|
|
39
|
-
def
|
40
|
+
def switch(branch:)
|
40
41
|
unless branch
|
41
42
|
branch = default_branch
|
42
43
|
puts "Using repository's default branch: #{branch}"
|
@@ -62,23 +63,50 @@ module ModuleSync
|
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
def cloned?
|
67
|
+
Dir.exist? File.join(@directory, '.git')
|
68
|
+
end
|
69
|
+
|
70
|
+
def clone
|
71
|
+
puts "Cloning from '#{@remote}'"
|
72
|
+
@git = Git.clone(@remote, @directory)
|
73
|
+
end
|
74
|
+
|
75
|
+
def prepare_workspace(branch:, operate_offline:)
|
76
|
+
if cloned?
|
77
|
+
puts "Overriding any local changes to repository in '#{@directory}'"
|
78
|
+
git.fetch 'origin', prune: true unless operate_offline
|
79
|
+
git.reset_hard
|
80
|
+
switch(branch: branch)
|
81
|
+
git.pull('origin', branch) if !operate_offline && remote_branch_exists?(branch)
|
72
82
|
else
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
raise ModuleSync::Error, 'Unable to clone in offline mode.' if operate_offline
|
84
|
+
|
85
|
+
clone
|
86
|
+
switch(branch: branch)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def default_reset_branch(branch)
|
91
|
+
remote_branch_exists?(branch) ? branch : default_branch
|
92
|
+
end
|
93
|
+
|
94
|
+
def reset_workspace(branch:, operate_offline:, source_branch: nil)
|
95
|
+
raise if branch.nil?
|
96
|
+
|
97
|
+
if cloned?
|
98
|
+
source_branch ||= "origin/#{default_reset_branch branch}"
|
99
|
+
puts "Hard-resetting any local changes to repository in '#{@directory}' from branch '#{source_branch}'"
|
100
|
+
switch(branch: branch)
|
101
|
+
git.fetch 'origin', prune: true unless operate_offline
|
102
|
+
|
103
|
+
git.reset_hard source_branch
|
104
|
+
git.clean(d: true, force: true)
|
105
|
+
else
|
106
|
+
raise ModuleSync::Error, 'Unable to clone in offline mode.' if operate_offline
|
107
|
+
|
108
|
+
clone
|
109
|
+
switch(branch: branch)
|
82
110
|
end
|
83
111
|
end
|
84
112
|
|
@@ -102,7 +130,7 @@ module ModuleSync
|
|
102
130
|
files.each do |file|
|
103
131
|
if repo.status.deleted.include?(file)
|
104
132
|
repo.remove(file)
|
105
|
-
elsif File.exist?(
|
133
|
+
elsif File.exist? File.join(@directory, file)
|
106
134
|
repo.add(file)
|
107
135
|
end
|
108
136
|
end
|
@@ -119,9 +147,11 @@ module ModuleSync
|
|
119
147
|
if options[:remote_branch]
|
120
148
|
if remote_branch_differ?(branch, options[:remote_branch])
|
121
149
|
repo.push('origin', "#{branch}:#{options[:remote_branch]}", opts_push)
|
150
|
+
puts "Changes have been pushed to: '#{branch}:#{options[:remote_branch]}'"
|
122
151
|
end
|
123
152
|
else
|
124
153
|
repo.push('origin', branch, opts_push)
|
154
|
+
puts "Changes have been pushed to: '#{branch}'"
|
125
155
|
end
|
126
156
|
rescue Git::GitExecuteError => e
|
127
157
|
raise unless e.message.match?(/working (directory|tree) clean/)
|
@@ -133,11 +163,21 @@ module ModuleSync
|
|
133
163
|
true
|
134
164
|
end
|
135
165
|
|
166
|
+
def push(branch:, remote_branch:, remote_name: 'origin')
|
167
|
+
raise ModuleSync::Error, 'Repository must be locally available before trying to push' unless cloned?
|
168
|
+
|
169
|
+
remote_url = git.remote(remote_name).url
|
170
|
+
remote_branch ||= branch
|
171
|
+
puts "Push branch '#{branch}' to '#{remote_url}' (#{remote_name}/#{remote_branch})"
|
172
|
+
|
173
|
+
git.push(remote_name, "#{branch}:#{remote_branch}", force: true)
|
174
|
+
end
|
175
|
+
|
136
176
|
# Needed because of a bug in the git gem that lists ignored files as
|
137
177
|
# untracked under some circumstances
|
138
178
|
# https://github.com/schacon/ruby-git/issues/130
|
139
179
|
def untracked_unignored_files
|
140
|
-
ignore_path =
|
180
|
+
ignore_path = File.join @directory, '.gitignore'
|
141
181
|
ignored = File.exist?(ignore_path) ? File.read(ignore_path).split : []
|
142
182
|
repo.status.untracked.keep_if { |f, _| ignored.none? { |i| File.fnmatch(i, f) } }
|
143
183
|
end
|
@@ -145,18 +185,24 @@ module ModuleSync
|
|
145
185
|
def show_changes(options)
|
146
186
|
checkout_branch(options[:branch])
|
147
187
|
|
148
|
-
puts 'Files changed:'
|
188
|
+
$stdout.puts 'Files changed:'
|
149
189
|
repo.diff('HEAD', '--').each do |diff|
|
150
|
-
puts diff.patch
|
190
|
+
$stdout.puts diff.patch
|
151
191
|
end
|
152
192
|
|
153
|
-
puts 'Files added:'
|
193
|
+
$stdout.puts 'Files added:'
|
154
194
|
untracked_unignored_files.each_key do |file|
|
155
|
-
puts file
|
195
|
+
$stdout.puts file
|
156
196
|
end
|
157
197
|
|
158
|
-
puts "\n\n"
|
159
|
-
puts '--------------------------------'
|
198
|
+
$stdout.puts "\n\n"
|
199
|
+
$stdout.puts '--------------------------------'
|
200
|
+
|
201
|
+
git.diff('HEAD', '--').any? || untracked_unignored_files.any?
|
202
|
+
end
|
203
|
+
|
204
|
+
def puts(*args)
|
205
|
+
$stdout.puts(*args) if ModuleSync.options[:verbose]
|
160
206
|
end
|
161
207
|
end
|
162
208
|
end
|
data/lib/modulesync/settings.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'modulesync'
|
2
|
+
require 'modulesync/git_service'
|
3
|
+
require 'modulesync/git_service/factory'
|
2
4
|
require 'modulesync/repository'
|
3
5
|
require 'modulesync/util'
|
4
6
|
|
5
7
|
module ModuleSync
|
6
8
|
# Provide methods to retrieve source code attributes
|
7
9
|
class SourceCode
|
8
|
-
attr_reader :given_name
|
9
|
-
attr_reader :options
|
10
|
+
attr_reader :given_name, :options
|
10
11
|
|
11
12
|
def initialize(given_name, options)
|
12
13
|
@options = Util.symbolize_keys(options || {})
|
@@ -47,6 +48,31 @@ module ModuleSync
|
|
47
48
|
File.join(working_directory, *parts)
|
48
49
|
end
|
49
50
|
|
51
|
+
def git_service
|
52
|
+
return nil if git_service_configuration.nil?
|
53
|
+
|
54
|
+
@git_service ||= GitService::Factory.instantiate(**git_service_configuration)
|
55
|
+
end
|
56
|
+
|
57
|
+
def git_service_configuration
|
58
|
+
@git_service_configuration ||= GitService.configuration_for(sourcecode: self)
|
59
|
+
rescue GitService::UnguessableTypeError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def open_pull_request
|
64
|
+
git_service.open_pull_request(
|
65
|
+
repo_path: repository_path,
|
66
|
+
namespace: repository_namespace,
|
67
|
+
title: ModuleSync.options[:pr_title],
|
68
|
+
message: ModuleSync.options[:message],
|
69
|
+
source_branch: ModuleSync.options[:remote_branch] || ModuleSync.options[:branch] || repository.default_branch,
|
70
|
+
target_branch: ModuleSync.options[:pr_target_branch] || repository.default_branch,
|
71
|
+
labels: ModuleSync::Util.parse_list(ModuleSync.options[:pr_labels]),
|
72
|
+
noop: ModuleSync.options[:noop],
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
50
76
|
private
|
51
77
|
|
52
78
|
def _repository_remote
|
data/lib/modulesync/util.rb
CHANGED
@@ -3,9 +3,8 @@ require 'yaml'
|
|
3
3
|
module ModuleSync
|
4
4
|
module Util
|
5
5
|
def self.symbolize_keys(hash)
|
6
|
-
hash.
|
6
|
+
hash.each_with_object({}) do |(k, v), memo|
|
7
7
|
memo[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v
|
8
|
-
memo
|
9
8
|
end
|
10
9
|
end
|
11
10
|
|
@@ -19,9 +18,10 @@ module ModuleSync
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def self.parse_list(option_value)
|
22
|
-
|
21
|
+
case option_value
|
22
|
+
when String
|
23
23
|
option_value.split(',')
|
24
|
-
|
24
|
+
when Array
|
25
25
|
option_value
|
26
26
|
else
|
27
27
|
[]
|
data/lib/modulesync.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'English'
|
1
2
|
require 'fileutils'
|
2
3
|
require 'pathname'
|
3
4
|
|
@@ -18,10 +19,10 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
18
19
|
|
19
20
|
def self.config_defaults
|
20
21
|
{
|
21
|
-
:project_root
|
22
|
+
:project_root => 'modules/',
|
22
23
|
:managed_modules_conf => 'managed_modules.yml',
|
23
|
-
:configs
|
24
|
-
:tag_pattern
|
24
|
+
:configs => '.',
|
25
|
+
:tag_pattern => '%s',
|
25
26
|
}
|
26
27
|
end
|
27
28
|
|
@@ -44,8 +45,8 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
44
45
|
.to_a
|
45
46
|
else
|
46
47
|
$stderr.puts "#{local_template_dir} does not exist." \
|
47
|
-
|
48
|
-
|
48
|
+
' Check that you are working in your module configs directory or' \
|
49
|
+
' that you have passed in the correct directory with -c.'
|
49
50
|
exit 1
|
50
51
|
end
|
51
52
|
end
|
@@ -62,7 +63,7 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
62
63
|
managed_modules = Util.parse_config(config_file)
|
63
64
|
if managed_modules.empty?
|
64
65
|
$stderr.puts "No modules found in #{config_file}." \
|
65
|
-
|
66
|
+
' Check that you specified the right :configs directory and :managed_modules_conf file.'
|
66
67
|
exit 1
|
67
68
|
end
|
68
69
|
managed_modules.select! { |m| m =~ Regexp.new(filter) } unless filter.nil?
|
@@ -82,7 +83,6 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
82
83
|
end
|
83
84
|
|
84
85
|
def self.manage_file(puppet_module, filename, settings, options)
|
85
|
-
namespace = settings.additional_settings[:namespace]
|
86
86
|
module_name = settings.additional_settings[:puppet_module]
|
87
87
|
configs = settings.build_file_configs(filename)
|
88
88
|
target_file = puppet_module.path(filename)
|
@@ -95,12 +95,12 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
95
95
|
# Meta data passed to the template as @metadata[:name]
|
96
96
|
metadata = {
|
97
97
|
:module_name => module_name,
|
98
|
-
:workdir
|
98
|
+
:workdir => puppet_module.working_directory,
|
99
99
|
:target_file => target_file,
|
100
100
|
}
|
101
101
|
template = Renderer.render(erb, configs, metadata)
|
102
102
|
Renderer.sync(template, target_file)
|
103
|
-
rescue StandardError
|
103
|
+
rescue StandardError
|
104
104
|
$stderr.puts "#{puppet_module.given_name}: Error while rendering file: '#{filename}'"
|
105
105
|
raise
|
106
106
|
end
|
@@ -109,7 +109,12 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
109
109
|
|
110
110
|
def self.manage_module(puppet_module, module_files, defaults)
|
111
111
|
puts "Syncing '#{puppet_module.given_name}'"
|
112
|
-
|
112
|
+
# NOTE: #prepare_workspace now supports to execute only offline operations
|
113
|
+
# but we totally skip the workspace preparation to keep the current behavior
|
114
|
+
unless options[:offline]
|
115
|
+
puppet_module.repository.prepare_workspace(branch: options[:branch],
|
116
|
+
operate_offline: false)
|
117
|
+
end
|
113
118
|
|
114
119
|
module_configs = Util.parse_config puppet_module.path(MODULE_CONF_FILE)
|
115
120
|
settings = Settings.new(defaults[GLOBAL_DEFAULTS_KEY] || {},
|
@@ -129,9 +134,8 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
129
134
|
|
130
135
|
if options[:noop]
|
131
136
|
puts "Using no-op. Files in '#{puppet_module.given_name}' may be changed but will not be committed."
|
132
|
-
puppet_module.repository.show_changes(options)
|
133
|
-
options[:pr] &&
|
134
|
-
pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options)
|
137
|
+
changed = puppet_module.repository.show_changes(options)
|
138
|
+
changed && options[:pr] && puppet_module.open_pull_request
|
135
139
|
elsif !options[:offline]
|
136
140
|
pushed = puppet_module.repository.submit_changes(files_to_manage, options)
|
137
141
|
# Only bump/tag if pushing didn't fail (i.e. there were changes)
|
@@ -139,13 +143,13 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
139
143
|
new = puppet_module.bump(options[:message], options[:changelog])
|
140
144
|
puppet_module.repository.tag(new, options[:tag_pattern]) if options[:tag]
|
141
145
|
end
|
142
|
-
pushed && options[:pr] &&
|
143
|
-
pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options)
|
146
|
+
pushed && options[:pr] && puppet_module.open_pull_request
|
144
147
|
end
|
145
148
|
end
|
146
149
|
|
147
150
|
def self.config_path(file, options)
|
148
151
|
return file if Pathname.new(file).absolute?
|
152
|
+
|
149
153
|
File.join(options[:configs], file)
|
150
154
|
end
|
151
155
|
|
@@ -157,15 +161,6 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
157
161
|
@options = config_defaults.merge(cli_options)
|
158
162
|
defaults = Util.parse_config(config_path(CONF_FILE, options))
|
159
163
|
|
160
|
-
if options[:pr]
|
161
|
-
unless options[:branch]
|
162
|
-
$stderr.puts 'A branch must be specified with --branch to use --pr!'
|
163
|
-
raise
|
164
|
-
end
|
165
|
-
|
166
|
-
@pr = create_pr_manager if options[:pr]
|
167
|
-
end
|
168
|
-
|
169
164
|
local_template_dir = config_path(MODULE_FILES_DIR, options)
|
170
165
|
local_files = find_template_files(local_template_dir)
|
171
166
|
module_files = relative_names(local_files, local_template_dir)
|
@@ -173,56 +168,99 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
173
168
|
errors = false
|
174
169
|
# managed_modules is either an array or a hash
|
175
170
|
managed_modules.each do |puppet_module|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
end
|
171
|
+
manage_module(puppet_module, module_files, defaults)
|
172
|
+
rescue ModuleSync::Error, Git::GitExecuteError => e
|
173
|
+
message = e.message || 'Error during `update`'
|
174
|
+
$stderr.puts "#{puppet_module.given_name}: #{message}"
|
175
|
+
exit 1 unless options[:skip_broken]
|
176
|
+
errors = true
|
177
|
+
$stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed"
|
178
|
+
rescue StandardError
|
179
|
+
raise unless options[:skip_broken]
|
180
|
+
|
181
|
+
errors = true
|
182
|
+
$stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed"
|
189
183
|
end
|
190
184
|
exit 1 if errors && options[:fail_on_warnings]
|
191
185
|
end
|
192
186
|
|
193
|
-
def self.
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
if !github_conf.nil?
|
199
|
-
base_url = github_conf[:base_url] || ENV.fetch('GITHUB_BASE_URL', 'https://api.github.com')
|
200
|
-
require 'modulesync/pr/github'
|
201
|
-
ModuleSync::PR::GitHub.new(github_conf[:token], base_url)
|
202
|
-
elsif !gitlab_conf.nil?
|
203
|
-
base_url = gitlab_conf[:base_url] || ENV.fetch('GITLAB_BASE_URL', 'https://gitlab.com/api/v4')
|
204
|
-
require 'modulesync/pr/gitlab'
|
205
|
-
ModuleSync::PR::GitLab.new(gitlab_conf[:token], base_url)
|
206
|
-
elsif @pr.nil?
|
207
|
-
$stderr.puts 'No GitHub or GitLab token specified for --pr!'
|
208
|
-
raise
|
209
|
-
else
|
210
|
-
@pr
|
187
|
+
def self.clone(cli_options)
|
188
|
+
@options = config_defaults.merge(cli_options)
|
189
|
+
|
190
|
+
managed_modules.each do |puppet_module|
|
191
|
+
puppet_module.repository.clone unless puppet_module.repository.cloned?
|
211
192
|
end
|
212
193
|
end
|
213
194
|
|
214
|
-
def self.
|
215
|
-
|
216
|
-
gitlab_token = ENV.fetch('GITLAB_TOKEN', '')
|
195
|
+
def self.execute(cli_options)
|
196
|
+
@options = config_defaults.merge(cli_options)
|
217
197
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
198
|
+
errors = {}
|
199
|
+
managed_modules.each do |puppet_module|
|
200
|
+
$stdout.puts "#{puppet_module.given_name}:"
|
201
|
+
|
202
|
+
puppet_module.repository.clone unless puppet_module.repository.cloned?
|
203
|
+
puppet_module.repository.switch branch: @options[:branch]
|
204
|
+
|
205
|
+
command_args = cli_options[:command_args]
|
206
|
+
local_script = File.expand_path command_args[0]
|
207
|
+
command_args[0] = local_script if File.exist?(local_script)
|
208
|
+
|
209
|
+
# Remove bundler-related env vars to allow the subprocess to run `bundle`
|
210
|
+
command_env = ENV.reject { |k, _v| k.match?(/(^BUNDLE|^SOURCE_DATE_EPOCH$|^GEM_|RUBY)/) }
|
211
|
+
|
212
|
+
result = system command_env, *command_args, unsetenv_others: true, chdir: puppet_module.working_directory
|
213
|
+
unless result
|
214
|
+
message = "Command execution failed ('#{@options[:command_args].join ' '}': #{$CHILD_STATUS})"
|
215
|
+
raise Thor::Error, message if @options[:fail_fast]
|
216
|
+
|
217
|
+
errors.merge!(
|
218
|
+
puppet_module.given_name => message,
|
219
|
+
)
|
220
|
+
$stderr.puts message
|
221
|
+
end
|
222
|
+
|
223
|
+
$stdout.puts ''
|
224
|
+
end
|
225
|
+
|
226
|
+
unless errors.empty?
|
227
|
+
raise Thor::Error, <<~MSG
|
228
|
+
Error(s) during `execute` command:
|
229
|
+
#{errors.map { |name, message| " * #{name}: #{message}" }.join "\n"}
|
230
|
+
MSG
|
231
|
+
end
|
232
|
+
|
233
|
+
exit 1 unless errors.empty?
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.reset(cli_options)
|
237
|
+
@options = config_defaults.merge(cli_options)
|
238
|
+
if @options[:branch].nil?
|
239
|
+
raise Thor::Error,
|
240
|
+
"Error: 'branch' option is missing, please set it in configuration or in command line."
|
241
|
+
end
|
242
|
+
|
243
|
+
managed_modules.each do |puppet_module|
|
244
|
+
puppet_module.repository.reset_workspace(
|
245
|
+
branch: @options[:branch],
|
246
|
+
source_branch: @options[:source_branch],
|
247
|
+
operate_offline: @options[:offline],
|
248
|
+
)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def self.push(cli_options)
|
253
|
+
@options = config_defaults.merge(cli_options)
|
254
|
+
|
255
|
+
if @options[:branch].nil?
|
256
|
+
raise Thor::Error,
|
257
|
+
"Error: 'branch' option is missing, please set it in configuration or in command line."
|
258
|
+
end
|
259
|
+
|
260
|
+
managed_modules.each do |puppet_module|
|
261
|
+
puppet_module.repository.push branch: @options[:branch], remote_branch: @options[:remote_branch]
|
262
|
+
rescue ModuleSync::Error => e
|
263
|
+
raise Thor::Error, "#{puppet_module.given_name}: #{e.message}"
|
226
264
|
end
|
227
265
|
end
|
228
266
|
end
|
data/modulesync.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
lib = File.expand_path('
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = 'modulesync'
|
6
|
-
spec.version = '2.
|
6
|
+
spec.version = '2.3.0'
|
7
7
|
spec.authors = ['Vox Pupuli']
|
8
8
|
spec.email = ['voxpupuli@groups.io']
|
9
9
|
spec.summary = 'Puppet Module Synchronizer'
|
@@ -19,10 +19,13 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_development_dependency 'aruba', '>= 0.14', '< 2'
|
21
21
|
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'cucumber'
|
22
23
|
spec.add_development_dependency 'rake'
|
23
24
|
spec.add_development_dependency 'rspec'
|
24
|
-
spec.add_development_dependency 'rubocop', '~>
|
25
|
-
spec.add_development_dependency '
|
25
|
+
spec.add_development_dependency 'rubocop', '~> 1.2'
|
26
|
+
spec.add_development_dependency 'rubocop-rake'
|
27
|
+
spec.add_development_dependency 'rubocop-rspec'
|
28
|
+
spec.add_development_dependency 'simplecov'
|
26
29
|
|
27
30
|
spec.add_runtime_dependency 'git', '~>1.7'
|
28
31
|
spec.add_runtime_dependency 'gitlab', '~>4.0'
|
@@ -77,6 +77,7 @@ module ModuleSync
|
|
77
77
|
branch ||= default_branch
|
78
78
|
FileUtils.chdir(tmp_repo_dir) do
|
79
79
|
run %W[git checkout #{branch}]
|
80
|
+
run %w[git pull --force --prune]
|
80
81
|
File.write filename, content
|
81
82
|
run %W[git add #{filename}]
|
82
83
|
run %w[git commit --message] << "Add file: '#{filename}'"
|
@@ -94,7 +95,7 @@ module ModuleSync
|
|
94
95
|
def commit_count_by(author, commit = nil)
|
95
96
|
FileUtils.chdir(bare_repo_dir) do
|
96
97
|
commit ||= '--all'
|
97
|
-
stdout = run %W[git rev-list #{
|
98
|
+
stdout = run %W[git rev-list --author #{author} --count #{commit} --]
|
98
99
|
return Integer(stdout)
|
99
100
|
end
|
100
101
|
end
|
@@ -105,6 +106,20 @@ module ModuleSync
|
|
105
106
|
end
|
106
107
|
end
|
107
108
|
|
109
|
+
def delete_branch(branch)
|
110
|
+
FileUtils.chdir(bare_repo_dir) do
|
111
|
+
run %W{git branch -D #{branch}}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def create_branch(branch, from = nil)
|
116
|
+
from ||= default_branch
|
117
|
+
FileUtils.chdir(tmp_repo_dir) do
|
118
|
+
run %W{git branch -c #{from} #{branch}}
|
119
|
+
run %W{git push --set-upstream origin #{branch}}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
108
123
|
def remote_url
|
109
124
|
"file://#{bare_repo_dir}"
|
110
125
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,25 +1,3 @@
|
|
1
|
-
|
2
|
-
require 'simplecov'
|
3
|
-
require 'simplecov-console'
|
4
|
-
require 'codecov'
|
5
|
-
rescue LoadError
|
6
|
-
else
|
7
|
-
SimpleCov.start do
|
8
|
-
track_files 'lib/**/*.rb'
|
9
|
-
|
10
|
-
add_filter '/spec'
|
11
|
-
|
12
|
-
enable_coverage :branch
|
13
|
-
|
14
|
-
# do not track vendored files
|
15
|
-
add_filter '/vendor'
|
16
|
-
add_filter '/.vendor'
|
17
|
-
end
|
18
|
-
|
19
|
-
SimpleCov.formatters = [
|
20
|
-
SimpleCov::Formatter::Console,
|
21
|
-
SimpleCov::Formatter::Codecov,
|
22
|
-
]
|
23
|
-
end
|
1
|
+
require 'simplecov'
|
24
2
|
|
25
3
|
require 'modulesync'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'modulesync'
|
2
|
+
require 'modulesync/git_service/factory'
|
3
|
+
|
4
|
+
describe ModuleSync::GitService::Factory do
|
5
|
+
context 'when instantiate a GitHub service without credentials' do
|
6
|
+
it 'raises an error' do
|
7
|
+
expect { ModuleSync::GitService::Factory.instantiate(type: :github, endpoint: nil, token: nil) }.to raise_error(ModuleSync::GitService::MissingCredentialsError)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'when instantiate a GitLab service without credentials' do
|
12
|
+
it 'raises an error' do
|
13
|
+
expect { ModuleSync::GitService::Factory.instantiate(type: :gitlab, endpoint: nil, token: nil) }.to raise_error(ModuleSync::GitService::MissingCredentialsError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|