modulesync 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|