modulesync 2.1.1 → 2.3.1
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 +29 -9
- data/.github/workflows/release.yml +5 -6
- data/.gitignore +1 -0
- data/.rubocop.yml +17 -8
- data/.rubocop_todo.yml +25 -17
- data/.simplecov +46 -0
- data/CHANGELOG.md +60 -0
- data/Gemfile +5 -3
- data/LICENSE +173 -12
- data/README.md +30 -0
- 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 +9 -7
- data/lib/modulesync/repository.rb +78 -28
- 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 +9 -5
- data/spec/helpers/faker/puppet_module_remote_repo.rb +16 -1
- data/spec/spec_helper.rb +2 -0
- 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 +96 -14
- 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
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,14 +1,14 @@
|
|
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.1'
|
7
7
|
spec.authors = ['Vox Pupuli']
|
8
8
|
spec.email = ['voxpupuli@groups.io']
|
9
9
|
spec.summary = 'Puppet Module Synchronizer'
|
10
10
|
spec.description = 'Utility to synchronize common files across puppet modules in Github.'
|
11
|
-
spec.homepage = '
|
11
|
+
spec.homepage = 'https://github.com/voxpupuli/modulesync'
|
12
12
|
spec.license = 'Apache-2.0'
|
13
13
|
spec.required_ruby_version = '>= 2.5.0'
|
14
14
|
|
@@ -17,11 +17,15 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
-
spec.add_development_dependency 'aruba', '
|
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 'rubocop', '~> 1.2'
|
26
|
+
spec.add_development_dependency 'rubocop-rake'
|
27
|
+
spec.add_development_dependency 'rubocop-rspec'
|
28
|
+
spec.add_development_dependency 'simplecov'
|
25
29
|
|
26
30
|
spec.add_runtime_dependency 'git', '~>1.7'
|
27
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
@@ -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
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'modulesync/git_service/github'
|
4
|
+
|
5
|
+
describe ModuleSync::GitService::GitHub do
|
6
|
+
context '::open_pull_request' do
|
7
|
+
before(:each) do
|
8
|
+
@client = double()
|
9
|
+
allow(Octokit::Client).to receive(:new).and_return(@client)
|
10
|
+
@it = ModuleSync::GitService::GitHub.new('test', 'https://api.github.com')
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:args) do
|
14
|
+
{
|
15
|
+
repo_path: 'test/modulesync',
|
16
|
+
namespace: 'test',
|
17
|
+
title: 'Test PR is submitted',
|
18
|
+
message: 'Hello world',
|
19
|
+
source_branch: 'test',
|
20
|
+
target_branch: 'master',
|
21
|
+
labels: labels,
|
22
|
+
noop: false,
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:labels) { [] }
|
27
|
+
|
28
|
+
it 'submits PR when --pr is set' do
|
29
|
+
allow(@client).to receive(:pull_requests)
|
30
|
+
.with(args[:repo_path],
|
31
|
+
:state => 'open',
|
32
|
+
:base => 'master',
|
33
|
+
:head => "#{args[:namespace]}:#{args[:source_branch]}"
|
34
|
+
).and_return([])
|
35
|
+
expect(@client).to receive(:create_pull_request)
|
36
|
+
.with(args[:repo_path],
|
37
|
+
'master',
|
38
|
+
args[:source_branch],
|
39
|
+
args[:title],
|
40
|
+
args[:message]
|
41
|
+
).and_return({"html_url" => "http://example.com/pulls/22"})
|
42
|
+
expect { @it.open_pull_request(**args) }.to output(/Submitted PR/).to_stdout
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'skips submitting PR if one has already been issued' do
|
46
|
+
pr = {
|
47
|
+
"title" => "Test title",
|
48
|
+
"html_url" => "https://example.com/pulls/44",
|
49
|
+
"number" => "44"
|
50
|
+
}
|
51
|
+
|
52
|
+
expect(@client).to receive(:pull_requests)
|
53
|
+
.with(args[:repo_path],
|
54
|
+
:state => 'open',
|
55
|
+
:base => 'master',
|
56
|
+
:head => "#{args[:namespace]}:#{args[:source_branch]}"
|
57
|
+
).and_return([pr])
|
58
|
+
expect { @it.open_pull_request(**args) }.to output("Skipped! 1 PRs found for branch 'test'\n").to_stdout
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when labels are set' do
|
62
|
+
let(:labels) { %w{HELLO WORLD} }
|
63
|
+
|
64
|
+
it 'adds labels to PR' do
|
65
|
+
allow(@client).to receive(:create_pull_request).and_return({"html_url" => "http://example.com/pulls/22", "number" => "44"})
|
66
|
+
allow(@client).to receive(:pull_requests)
|
67
|
+
.with(args[:repo_path],
|
68
|
+
:state => 'open',
|
69
|
+
:base => 'master',
|
70
|
+
:head => "#{args[:namespace]}:#{args[:source_branch]}"
|
71
|
+
).and_return([])
|
72
|
+
expect(@client).to receive(:add_labels_to_an_issue)
|
73
|
+
.with(args[:repo_path],
|
74
|
+
"44",
|
75
|
+
["HELLO", "WORLD"]
|
76
|
+
)
|
77
|
+
expect { @it.open_pull_request(**args) }.to output(/Attaching the following labels to PR 44: HELLO, WORLD/).to_stdout
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'modulesync/git_service/gitlab'
|
4
|
+
|
5
|
+
describe ModuleSync::GitService::GitLab do
|
6
|
+
context '::open_pull_request' do
|
7
|
+
before(:each) do
|
8
|
+
@client = double()
|
9
|
+
allow(Gitlab::Client).to receive(:new).and_return(@client)
|
10
|
+
@it = ModuleSync::GitService::GitLab.new('test', 'https://gitlab.com/api/v4')
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:args) do
|
14
|
+
{
|
15
|
+
repo_path: 'test/modulesync',
|
16
|
+
namespace: 'test',
|
17
|
+
title: 'Test MR is submitted',
|
18
|
+
message: 'Hello world',
|
19
|
+
source_branch: 'test',
|
20
|
+
target_branch: 'master',
|
21
|
+
labels: labels,
|
22
|
+
noop: false,
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:labels) { [] }
|
27
|
+
|
28
|
+
it 'submits MR when --pr is set' do
|
29
|
+
allow(@client).to receive(:merge_requests)
|
30
|
+
.with(args[:repo_path],
|
31
|
+
:state => 'opened',
|
32
|
+
:source_branch => args[:source_branch],
|
33
|
+
:target_branch => 'master',
|
34
|
+
).and_return([])
|
35
|
+
|
36
|
+
expect(@client).to receive(:create_merge_request)
|
37
|
+
.with(args[:repo_path],
|
38
|
+
args[:title],
|
39
|
+
:labels => [],
|
40
|
+
:source_branch => args[:source_branch],
|
41
|
+
:target_branch => 'master',
|
42
|
+
).and_return({"html_url" => "http://example.com/pulls/22"})
|
43
|
+
|
44
|
+
expect { @it.open_pull_request(**args) }.to output(/Submitted MR/).to_stdout
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'skips submitting MR if one has already been issued' do
|
48
|
+
mr = {
|
49
|
+
"title" => "Test title",
|
50
|
+
"html_url" => "https://example.com/pulls/44",
|
51
|
+
"iid" => "44"
|
52
|
+
}
|
53
|
+
|
54
|
+
expect(@client).to receive(:merge_requests)
|
55
|
+
.with(args[:repo_path],
|
56
|
+
:state => 'opened',
|
57
|
+
:source_branch => args[:source_branch],
|
58
|
+
:target_branch => 'master',
|
59
|
+
).and_return([mr])
|
60
|
+
|
61
|
+
expect { @it.open_pull_request(**args) }.to output("Skipped! 1 MRs found for branch 'test'\n").to_stdout
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when labels are set' do
|
65
|
+
let(:labels) { %w{HELLO WORLD} }
|
66
|
+
|
67
|
+
it 'adds labels to MR' do
|
68
|
+
mr = double()
|
69
|
+
allow(mr).to receive(:iid).and_return("42")
|
70
|
+
|
71
|
+
expect(@client).to receive(:create_merge_request)
|
72
|
+
.with(args[:repo_path],
|
73
|
+
args[:title],
|
74
|
+
:labels => ["HELLO", "WORLD"],
|
75
|
+
:source_branch => args[:source_branch],
|
76
|
+
:target_branch => 'master',
|
77
|
+
).and_return(mr)
|
78
|
+
|
79
|
+
allow(@client).to receive(:merge_requests)
|
80
|
+
.with(args[:repo_path],
|
81
|
+
:state => 'opened',
|
82
|
+
:source_branch => args[:source_branch],
|
83
|
+
:target_branch => 'master',
|
84
|
+
).and_return([])
|
85
|
+
|
86
|
+
expect { @it.open_pull_request(**args) }.to output(/Attached the following labels to MR 42: HELLO, WORLD/).to_stdout
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|