modulesync 1.2.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.config/cucumber.yml +1 -0
- data/.github/workflows/ci.yml +29 -0
- data/.github/workflows/release.yml +30 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +8 -1
- data/.rubocop_todo.yml +16 -35
- data/CHANGELOG.md +82 -1
- data/Gemfile +5 -1
- data/HISTORY.md +227 -0
- data/README.md +29 -6
- data/Rakefile +24 -0
- data/features/cli.feature +14 -6
- data/features/hook.feature +3 -5
- data/features/step_definitions/git_steps.rb +73 -35
- data/features/support/env.rb +4 -0
- data/features/update.feature +163 -341
- data/features/update/bad_context.feature +26 -0
- data/features/update/bump_version.feature +87 -0
- data/lib/modulesync.rb +92 -51
- data/lib/modulesync/cli.rb +10 -4
- data/lib/modulesync/cli/thor.rb +24 -0
- data/lib/modulesync/pr/github.rb +25 -9
- data/lib/modulesync/pr/gitlab.rb +27 -13
- data/lib/modulesync/puppet_module.rb +37 -0
- data/lib/modulesync/repository.rb +158 -0
- data/lib/modulesync/source_code.rb +57 -0
- data/lib/modulesync/util.rb +4 -1
- data/lib/monkey_patches.rb +9 -48
- data/modulesync.gemspec +4 -4
- data/spec/helpers/faker.rb +14 -0
- data/spec/helpers/faker/puppet_module_remote_repo.rb +146 -0
- data/spec/unit/modulesync_spec.rb +7 -3
- metadata +30 -10
- data/.travis.yml +0 -27
- data/lib/modulesync/git.rb +0 -194
@@ -0,0 +1,26 @@
|
|
1
|
+
Feature: Run `msync update` without a good context
|
2
|
+
|
3
|
+
Scenario: Run `msync update` without any module
|
4
|
+
Given a directory named "moduleroot"
|
5
|
+
When I run `msync update --message "In a bad context"`
|
6
|
+
Then the exit status should be 1
|
7
|
+
And the stderr should contain:
|
8
|
+
"""
|
9
|
+
No modules found
|
10
|
+
"""
|
11
|
+
|
12
|
+
Scenario: Run `msync update` without the "moduleroot" directory
|
13
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
14
|
+
When I run `msync update --message "In a bad context"`
|
15
|
+
Then the exit status should be 1
|
16
|
+
And the stderr should contain "moduleroot"
|
17
|
+
|
18
|
+
Scenario: Run `msync update` without commit message
|
19
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
20
|
+
And a directory named "moduleroot"
|
21
|
+
When I run `msync update`
|
22
|
+
Then the exit status should be 1
|
23
|
+
And the stderr should contain:
|
24
|
+
"""
|
25
|
+
No value provided for required option "--message"
|
26
|
+
"""
|
@@ -0,0 +1,87 @@
|
|
1
|
+
Feature: Bump a new version after an update
|
2
|
+
Scenario: Bump the module version, update changelog and tag it after an update that produces changes
|
3
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
4
|
+
And the puppet module "puppet-test" from "fakenamespace" has a file named "CHANGELOG.md" with:
|
5
|
+
"""
|
6
|
+
## 1965-04-14 - Release 0.4.2
|
7
|
+
"""
|
8
|
+
And a file named "config_defaults.yml" with:
|
9
|
+
"""
|
10
|
+
---
|
11
|
+
new-file:
|
12
|
+
content: aruba
|
13
|
+
"""
|
14
|
+
And a directory named "moduleroot"
|
15
|
+
And a file named "moduleroot/new-file.erb" with:
|
16
|
+
"""
|
17
|
+
<%= @configs['content'] %>
|
18
|
+
"""
|
19
|
+
When I run `msync update --message "Add new-file" --bump --changelog --tag`
|
20
|
+
Then the exit status should be 0
|
21
|
+
And the file named "modules/fakenamespace/puppet-test/new-file" should contain "aruba"
|
22
|
+
And the stdout should contain:
|
23
|
+
"""
|
24
|
+
Bumped to version 0.4.3
|
25
|
+
"""
|
26
|
+
And the stdout should contain:
|
27
|
+
"""
|
28
|
+
Tagging with 0.4.3
|
29
|
+
"""
|
30
|
+
And the file named "modules/fakenamespace/puppet-test/CHANGELOG.md" should contain "0.4.3"
|
31
|
+
And the puppet module "puppet-test" from "fakenamespace" should have 2 commits made by "Aruba"
|
32
|
+
And the puppet module "puppet-test" from "fakenamespace" should have a tag named "0.4.3"
|
33
|
+
|
34
|
+
Scenario: Bump the module version after an update that produces changes
|
35
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
36
|
+
And a file named "config_defaults.yml" with:
|
37
|
+
"""
|
38
|
+
---
|
39
|
+
new-file:
|
40
|
+
content: aruba
|
41
|
+
"""
|
42
|
+
And a directory named "moduleroot"
|
43
|
+
And a file named "moduleroot/new-file.erb" with:
|
44
|
+
"""
|
45
|
+
<%= @configs['content'] %>
|
46
|
+
"""
|
47
|
+
When I run `msync update --message "Add new-file" --bump`
|
48
|
+
Then the exit status should be 0
|
49
|
+
And the file named "modules/fakenamespace/puppet-test/new-file" should contain "aruba"
|
50
|
+
And the stdout should contain:
|
51
|
+
"""
|
52
|
+
Bumped to version 0.4.3
|
53
|
+
"""
|
54
|
+
And the puppet module "puppet-test" from "fakenamespace" should have 2 commits made by "Aruba"
|
55
|
+
And the puppet module "puppet-test" from "fakenamespace" should not have a tag named "0.4.3"
|
56
|
+
|
57
|
+
Scenario: Bump the module version with changelog update when no CHANGELOG.md is available
|
58
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
59
|
+
And a file named "config_defaults.yml" with:
|
60
|
+
"""
|
61
|
+
---
|
62
|
+
new-file:
|
63
|
+
content: aruba
|
64
|
+
"""
|
65
|
+
And a directory named "moduleroot"
|
66
|
+
And a file named "moduleroot/new-file.erb" with:
|
67
|
+
"""
|
68
|
+
<%= @configs['content'] %>
|
69
|
+
"""
|
70
|
+
When I run `msync update --message "Add new-file" --bump --changelog`
|
71
|
+
Then the exit status should be 0
|
72
|
+
And the file named "modules/fakenamespace/puppet-test/new-file" should contain "aruba"
|
73
|
+
And the stdout should contain:
|
74
|
+
"""
|
75
|
+
Bumped to version 0.4.3
|
76
|
+
No CHANGELOG.md file found, not updating.
|
77
|
+
"""
|
78
|
+
And the file named "modules/fakenamespace/puppet-test/CHANGELOG.md" should not exist
|
79
|
+
And the puppet module "puppet-test" from "fakenamespace" should have 2 commits made by "Aruba"
|
80
|
+
|
81
|
+
Scenario: Dont bump the module version after an update that produces no changes
|
82
|
+
Given a basic setup with a puppet module "puppet-test" from "fakenamespace"
|
83
|
+
And a directory named "moduleroot"
|
84
|
+
When I run `msync update --message "Add new-file" --bump --tag`
|
85
|
+
Then the exit status should be 0
|
86
|
+
And the puppet module "puppet-test" from "fakenamespace" should have no commits made by "Aruba"
|
87
|
+
And the puppet module "puppet-test" from "fakenamespace" should not have a tag named "0.4.3"
|
data/lib/modulesync.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'pathname'
|
3
|
+
|
3
4
|
require 'modulesync/cli'
|
4
5
|
require 'modulesync/constants'
|
5
|
-
require 'modulesync/git'
|
6
6
|
require 'modulesync/hook'
|
7
|
+
require 'modulesync/puppet_module'
|
7
8
|
require 'modulesync/renderer'
|
8
9
|
require 'modulesync/settings'
|
9
10
|
require 'modulesync/util'
|
11
|
+
|
10
12
|
require 'monkey_patches'
|
11
13
|
|
12
14
|
module ModuleSync # rubocop:disable Metrics/ModuleLength
|
15
|
+
class Error < StandardError; end
|
16
|
+
|
13
17
|
include Constants
|
14
18
|
|
15
19
|
def self.config_defaults
|
@@ -21,12 +25,12 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
21
25
|
}
|
22
26
|
end
|
23
27
|
|
24
|
-
def self.
|
25
|
-
|
28
|
+
def self.options
|
29
|
+
@options
|
26
30
|
end
|
27
31
|
|
28
|
-
def self.
|
29
|
-
File.join(
|
32
|
+
def self.local_file(config_path, file)
|
33
|
+
File.join(config_path, MODULE_FILES_DIR, file)
|
30
34
|
end
|
31
35
|
|
32
36
|
# List all template files.
|
@@ -39,10 +43,10 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
39
43
|
.collect { |p| p.chomp('.erb') }
|
40
44
|
.to_a
|
41
45
|
else
|
42
|
-
$
|
46
|
+
$stderr.puts "#{local_template_dir} does not exist." \
|
43
47
|
' Check that you are working in your module configs directory or' \
|
44
48
|
' that you have passed in the correct directory with -c.'
|
45
|
-
exit
|
49
|
+
exit 1
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
@@ -50,21 +54,20 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
50
54
|
file_list.map { |file| file.sub(/#{path}/, '') }
|
51
55
|
end
|
52
56
|
|
53
|
-
def self.managed_modules
|
57
|
+
def self.managed_modules
|
58
|
+
config_file = config_path(options[:managed_modules_conf], options)
|
59
|
+
filter = options[:filter]
|
60
|
+
negative_filter = options[:negative_filter]
|
61
|
+
|
54
62
|
managed_modules = Util.parse_config(config_file)
|
55
63
|
if managed_modules.empty?
|
56
|
-
$
|
64
|
+
$stderr.puts "No modules found in #{config_file}." \
|
57
65
|
' Check that you specified the right :configs directory and :managed_modules_conf file.'
|
58
|
-
exit
|
66
|
+
exit 1
|
59
67
|
end
|
60
68
|
managed_modules.select! { |m| m =~ Regexp.new(filter) } unless filter.nil?
|
61
69
|
managed_modules.reject! { |m| m =~ Regexp.new(negative_filter) } unless negative_filter.nil?
|
62
|
-
managed_modules
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.module_name(module_name, default_namespace)
|
66
|
-
return [default_namespace, module_name] unless module_name.include?('/')
|
67
|
-
ns, mod = module_name.split('/')
|
70
|
+
managed_modules.map { |given_name, options| PuppetModule.new(given_name, options) }
|
68
71
|
end
|
69
72
|
|
70
73
|
def self.hook(options)
|
@@ -78,11 +81,11 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
78
81
|
end
|
79
82
|
end
|
80
83
|
|
81
|
-
def self.manage_file(filename, settings, options)
|
84
|
+
def self.manage_file(puppet_module, filename, settings, options)
|
82
85
|
namespace = settings.additional_settings[:namespace]
|
83
86
|
module_name = settings.additional_settings[:puppet_module]
|
84
87
|
configs = settings.build_file_configs(filename)
|
85
|
-
target_file =
|
88
|
+
target_file = puppet_module.path(filename)
|
86
89
|
if configs['delete']
|
87
90
|
Renderer.remove(target_file)
|
88
91
|
else
|
@@ -92,51 +95,68 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
92
95
|
# Meta data passed to the template as @metadata[:name]
|
93
96
|
metadata = {
|
94
97
|
:module_name => module_name,
|
95
|
-
:workdir =>
|
98
|
+
:workdir => puppet_module.working_directory,
|
96
99
|
:target_file => target_file,
|
97
100
|
}
|
98
101
|
template = Renderer.render(erb, configs, metadata)
|
99
102
|
Renderer.sync(template, target_file)
|
100
|
-
rescue
|
101
|
-
$stderr.puts "Error while rendering #{filename}"
|
103
|
+
rescue StandardError => e
|
104
|
+
$stderr.puts "#{puppet_module.given_name}: Error while rendering file: '#{filename}'"
|
102
105
|
raise
|
103
106
|
end
|
104
107
|
end
|
105
108
|
end
|
106
109
|
|
107
|
-
def self.manage_module(puppet_module, module_files,
|
108
|
-
|
109
|
-
|
110
|
-
unless options[:offline]
|
111
|
-
Git.pull(options[:git_base], git_repo, options[:branch], options[:project_root], module_options || {})
|
112
|
-
end
|
110
|
+
def self.manage_module(puppet_module, module_files, defaults)
|
111
|
+
puts "Syncing '#{puppet_module.given_name}'"
|
112
|
+
puppet_module.repository.prepare_workspace(options[:branch]) unless options[:offline]
|
113
113
|
|
114
|
-
module_configs = Util.parse_config(
|
114
|
+
module_configs = Util.parse_config puppet_module.path(MODULE_CONF_FILE)
|
115
115
|
settings = Settings.new(defaults[GLOBAL_DEFAULTS_KEY] || {},
|
116
116
|
defaults,
|
117
117
|
module_configs[GLOBAL_DEFAULTS_KEY] || {},
|
118
118
|
module_configs,
|
119
|
-
:puppet_module =>
|
119
|
+
:puppet_module => puppet_module.repository_name,
|
120
120
|
:git_base => options[:git_base],
|
121
|
-
:namespace =>
|
121
|
+
:namespace => puppet_module.repository_namespace)
|
122
|
+
|
122
123
|
settings.unmanaged_files(module_files).each do |filename|
|
123
|
-
$stdout.puts "Not managing #{filename} in #{
|
124
|
+
$stdout.puts "Not managing '#{filename}' in '#{puppet_module.given_name}'"
|
124
125
|
end
|
125
126
|
|
126
127
|
files_to_manage = settings.managed_files(module_files)
|
127
|
-
files_to_manage.each { |filename| manage_file(filename, settings, options) }
|
128
|
+
files_to_manage.each { |filename| manage_file(puppet_module, filename, settings, options) }
|
128
129
|
|
129
130
|
if options[:noop]
|
130
|
-
|
131
|
+
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)
|
131
135
|
elsif !options[:offline]
|
132
|
-
pushed =
|
133
|
-
|
136
|
+
pushed = puppet_module.repository.submit_changes(files_to_manage, options)
|
137
|
+
# Only bump/tag if pushing didn't fail (i.e. there were changes)
|
138
|
+
if pushed && options[:bump]
|
139
|
+
new = puppet_module.bump(options[:message], options[:changelog])
|
140
|
+
puppet_module.repository.tag(new, options[:tag_pattern]) if options[:tag]
|
141
|
+
end
|
142
|
+
pushed && options[:pr] && \
|
143
|
+
pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options)
|
134
144
|
end
|
135
145
|
end
|
136
146
|
|
137
|
-
def self.
|
138
|
-
|
139
|
-
|
147
|
+
def self.config_path(file, options)
|
148
|
+
return file if Pathname.new(file).absolute?
|
149
|
+
File.join(options[:configs], file)
|
150
|
+
end
|
151
|
+
|
152
|
+
def config_path(file, options)
|
153
|
+
self.class.config_path(file, options)
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.update(cli_options)
|
157
|
+
@options = config_defaults.merge(cli_options)
|
158
|
+
defaults = Util.parse_config(config_path(CONF_FILE, options))
|
159
|
+
|
140
160
|
if options[:pr]
|
141
161
|
unless options[:branch]
|
142
162
|
$stderr.puts 'A branch must be specified with --branch to use --pr!'
|
@@ -146,29 +166,51 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
146
166
|
@pr = create_pr_manager if options[:pr]
|
147
167
|
end
|
148
168
|
|
149
|
-
local_template_dir =
|
169
|
+
local_template_dir = config_path(MODULE_FILES_DIR, options)
|
150
170
|
local_files = find_template_files(local_template_dir)
|
151
171
|
module_files = relative_names(local_files, local_template_dir)
|
152
172
|
|
153
|
-
managed_modules = self.managed_modules(File.join(options[:configs], options[:managed_modules_conf]),
|
154
|
-
options[:filter],
|
155
|
-
options[:negative_filter])
|
156
|
-
|
157
173
|
errors = false
|
158
174
|
# managed_modules is either an array or a hash
|
159
|
-
managed_modules.each do |puppet_module
|
175
|
+
managed_modules.each do |puppet_module|
|
160
176
|
begin
|
161
|
-
manage_module(puppet_module, module_files,
|
162
|
-
rescue
|
163
|
-
|
177
|
+
manage_module(puppet_module, module_files, defaults)
|
178
|
+
rescue ModuleSync::Error, Git::GitExecuteError => e
|
179
|
+
message = e.message || "Error during '#{options[:command]}'"
|
180
|
+
$stderr.puts "#{puppet_module.given_name}: #{message}"
|
181
|
+
exit 1 unless options[:skip_broken]
|
182
|
+
errors = true
|
183
|
+
$stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed"
|
184
|
+
rescue StandardError => e
|
164
185
|
raise unless options[:skip_broken]
|
165
186
|
errors = true
|
166
|
-
$stdout.puts "Skipping #{puppet_module} as update process failed"
|
187
|
+
$stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed"
|
167
188
|
end
|
168
189
|
end
|
169
190
|
exit 1 if errors && options[:fail_on_warnings]
|
170
191
|
end
|
171
192
|
|
193
|
+
def self.pr(puppet_module)
|
194
|
+
module_options = puppet_module.options
|
195
|
+
github_conf = module_options[:github]
|
196
|
+
gitlab_conf = module_options[:gitlab]
|
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
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
172
214
|
def self.create_pr_manager
|
173
215
|
github_token = ENV.fetch('GITHUB_TOKEN', '')
|
174
216
|
gitlab_token = ENV.fetch('GITLAB_TOKEN', '')
|
@@ -177,11 +219,10 @@ module ModuleSync # rubocop:disable Metrics/ModuleLength
|
|
177
219
|
require 'modulesync/pr/github'
|
178
220
|
ModuleSync::PR::GitHub.new(github_token, ENV.fetch('GITHUB_BASE_URL', 'https://api.github.com'))
|
179
221
|
elsif !gitlab_token.empty?
|
180
|
-
require 'modulesync/pr/
|
222
|
+
require 'modulesync/pr/gitlab'
|
181
223
|
ModuleSync::PR::GitLab.new(gitlab_token, ENV.fetch('GITLAB_BASE_URL', 'https://gitlab.com/api/v4'))
|
182
224
|
else
|
183
|
-
|
184
|
-
raise
|
225
|
+
warn '--pr specified without environment variables GITHUB_TOKEN or GITLAB_TOKEN'
|
185
226
|
end
|
186
227
|
end
|
187
228
|
end
|
data/lib/modulesync/cli.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'thor'
|
2
|
+
|
2
3
|
require 'modulesync'
|
4
|
+
require 'modulesync/cli/thor'
|
3
5
|
require 'modulesync/constants'
|
4
6
|
require 'modulesync/util'
|
5
7
|
|
6
8
|
module ModuleSync
|
7
|
-
|
9
|
+
module CLI
|
8
10
|
def self.defaults
|
9
11
|
@defaults ||= Util.symbolize_keys(Util.parse_config(Constants::MODULESYNC_CONF_FILE))
|
10
12
|
end
|
@@ -36,15 +38,14 @@ module ModuleSync
|
|
36
38
|
class Base < Thor
|
37
39
|
class_option :project_root,
|
38
40
|
:aliases => '-c',
|
39
|
-
:desc => 'Path used by git to clone modules into.
|
41
|
+
:desc => 'Path used by git to clone modules into.',
|
40
42
|
:default => CLI.defaults[:project_root] || 'modules'
|
41
43
|
class_option :git_base,
|
42
44
|
:desc => 'Specify the base part of a git URL to pull from',
|
43
45
|
:default => CLI.defaults[:git_base] || 'git@github.com:'
|
44
46
|
class_option :namespace,
|
45
47
|
:aliases => '-n',
|
46
|
-
:desc => 'Remote github namespace (user or organization) to clone from and push to.'
|
47
|
-
' Defaults to puppetlabs',
|
48
|
+
:desc => 'Remote github namespace (user or organization) to clone from and push to.',
|
48
49
|
:default => CLI.defaults[:namespace] || 'puppetlabs'
|
49
50
|
class_option :filter,
|
50
51
|
:aliases => '-f',
|
@@ -67,6 +68,8 @@ module ModuleSync
|
|
67
68
|
:aliases => '-c',
|
68
69
|
:desc => 'The local directory or remote repository to define the list of managed modules,' \
|
69
70
|
' the file templates, and the default values for template variables.'
|
71
|
+
option :managed_modules_conf,
|
72
|
+
:desc => 'The file name to define the list of managed modules'
|
70
73
|
option :remote_branch,
|
71
74
|
:aliases => '-r',
|
72
75
|
:desc => 'Remote branch name to push the changes to. Defaults to the branch name.',
|
@@ -99,6 +102,9 @@ module ModuleSync
|
|
99
102
|
:type => :array,
|
100
103
|
:desc => 'Labels to add to the pull/merge request',
|
101
104
|
:default => CLI.defaults[:pr_labels] || []
|
105
|
+
option :pr_target_branch,
|
106
|
+
:desc => 'Target branch for the pull/merge request',
|
107
|
+
:default => CLI.defaults[:pr_target_branch] || 'master'
|
102
108
|
option :offline,
|
103
109
|
:type => :boolean,
|
104
110
|
:desc => 'Do not run any Git commands. Allows the user to manage Git outside of ModuleSync.',
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'modulesync/cli'
|
3
|
+
|
4
|
+
module ModuleSync
|
5
|
+
module CLI
|
6
|
+
# Workaround some, still unfixed, Thor behaviors
|
7
|
+
#
|
8
|
+
# This class extends ::Thor class to
|
9
|
+
# - exit with status code sets to `1` on Thor failure (e.g. missing required option)
|
10
|
+
# - exit with status code sets to `1` when user calls `msync` (or a subcommand) without required arguments
|
11
|
+
class Thor < ::Thor
|
12
|
+
desc '_invalid_command_call', 'Invalid command', hide: true
|
13
|
+
def _invalid_command_call
|
14
|
+
self.class.new.help
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
default_task :_invalid_command_call
|
18
|
+
|
19
|
+
def self.exit_on_failure?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/modulesync/pr/github.rb
CHANGED
@@ -15,20 +15,36 @@ module ModuleSync
|
|
15
15
|
|
16
16
|
def manage(namespace, module_name, options)
|
17
17
|
repo_path = File.join(namespace, module_name)
|
18
|
-
|
18
|
+
branch = options[:remote_branch] || options[:branch]
|
19
|
+
head = "#{namespace}:#{branch}"
|
20
|
+
target_branch = options[:pr_target_branch] || 'master'
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
if options[:noop]
|
23
|
+
$stdout.puts \
|
24
|
+
"Using no-op. Would submit PR '#{options[:pr_title]}' to #{repo_path} " \
|
25
|
+
"- merges #{branch} into #{target_branch}"
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
pull_requests = @api.pull_requests(repo_path,
|
30
|
+
:state => 'open',
|
31
|
+
:base => target_branch,
|
32
|
+
:head => head)
|
33
|
+
unless pull_requests.empty?
|
25
34
|
# Skip creating the PR if it exists already.
|
26
|
-
$stdout.puts "Skipped! #{pull_requests.length} PRs found for branch #{
|
35
|
+
$stdout.puts "Skipped! #{pull_requests.length} PRs found for branch #{branch}"
|
36
|
+
return
|
27
37
|
end
|
28
38
|
|
29
|
-
# PR labels can either be a list in the YAML file or they can pass in a comma
|
30
|
-
# separated list via the command line argument.
|
31
39
|
pr_labels = ModuleSync::Util.parse_list(options[:pr_labels])
|
40
|
+
pr = @api.create_pull_request(repo_path,
|
41
|
+
target_branch,
|
42
|
+
branch,
|
43
|
+
options[:pr_title],
|
44
|
+
options[:message])
|
45
|
+
$stdout.puts \
|
46
|
+
"Submitted PR '#{options[:pr_title]}' to #{repo_path} " \
|
47
|
+
"- merges #{branch} into #{target_branch}"
|
32
48
|
|
33
49
|
# We only assign labels to the PR if we've discovered a list > 1. The labels MUST
|
34
50
|
# already exist. We DO NOT create missing labels.
|