modulesync 1.2.0 → 2.1.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/.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.
|