modulesync 2.1.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 +29 -9
- data/.github/workflows/release.yml +7 -7
- data/.gitignore +1 -0
- data/.rubocop.yml +14 -8
- data/.rubocop_todo.yml +25 -17
- data/.simplecov +46 -0
- data/CHANGELOG.md +58 -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 +3 -6
- 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.0'
|
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
|