create_github_release 1.1.0 → 1.2.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/.yardopts +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +156 -38
- data/Rakefile +6 -6
- data/create_github_release.gemspec +3 -3
- data/exe/create-github-release +1 -1
- data/lib/create_github_release/assertions/bundle_is_up_to_date.rb +1 -1
- data/lib/create_github_release/assertions/gh_authenticated.rb +1 -1
- data/lib/create_github_release/assertions/gh_command_exists.rb +1 -1
- data/lib/create_github_release/assertions/git_command_exists.rb +1 -1
- data/lib/create_github_release/assertions/in_git_repo.rb +1 -1
- data/lib/create_github_release/assertions/in_repo_root_directory.rb +1 -1
- data/lib/create_github_release/assertions/local_and_remote_on_same_commit.rb +1 -1
- data/lib/create_github_release/assertions/local_release_branch_does_not_exist.rb +1 -1
- data/lib/create_github_release/assertions/no_staged_changes.rb +1 -1
- data/lib/create_github_release/assertions/no_uncommitted_changes.rb +1 -1
- data/lib/create_github_release/assertions/on_default_branch.rb +1 -1
- data/lib/create_github_release/assertions/remote_release_branch_does_not_exist.rb +1 -1
- data/lib/create_github_release/assertions/remote_release_tag_does_not_exist.rb +1 -1
- data/lib/create_github_release/command_line/options.rb +151 -0
- data/lib/create_github_release/command_line/parser.rb +253 -0
- data/lib/create_github_release/command_line/validations.rb +293 -0
- data/lib/create_github_release/command_line/validator.rb +93 -0
- data/lib/create_github_release/command_line.rb +43 -0
- data/lib/create_github_release/project.rb +115 -55
- data/lib/create_github_release/release_assertions.rb +1 -1
- data/lib/create_github_release/release_tasks.rb +1 -1
- data/lib/create_github_release/tasks/commit_release.rb +1 -1
- data/lib/create_github_release/tasks/create_github_release.rb +1 -1
- data/lib/create_github_release/tasks/create_release_branch.rb +1 -1
- data/lib/create_github_release/tasks/create_release_pull_request.rb +1 -1
- data/lib/create_github_release/tasks/create_release_tag.rb +1 -1
- data/lib/create_github_release/tasks/push_release.rb +1 -1
- data/lib/create_github_release/tasks/update_changelog.rb +1 -1
- data/lib/create_github_release/tasks/update_version.rb +1 -1
- data/lib/create_github_release/version.rb +1 -1
- data/lib/create_github_release.rb +1 -2
- metadata +10 -34
- data/lib/create_github_release/command_line_options.rb +0 -378
- data/lib/create_github_release/command_line_parser.rb +0 -229
@@ -0,0 +1,253 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
require 'optparse'
|
5
|
+
require 'create_github_release/command_line/options'
|
6
|
+
|
7
|
+
module CreateGithubRelease
|
8
|
+
module CommandLine
|
9
|
+
# rubocop:disable Metrics/ClassLength
|
10
|
+
|
11
|
+
# Parses the options for this script
|
12
|
+
#
|
13
|
+
# @example Specify the release type
|
14
|
+
# options = CommandLineParser.new.parse('major')
|
15
|
+
# options.valid? # => true
|
16
|
+
# options.release_type # => "major"
|
17
|
+
# options.quiet # => false
|
18
|
+
#
|
19
|
+
# @example Specify the release type and the quiet option
|
20
|
+
# parser = CommandLineParser.new
|
21
|
+
# args = %w[minor --quiet]
|
22
|
+
# options = parser.parse(*args)
|
23
|
+
# options.release_type # => "minor"
|
24
|
+
# options.quiet # => true
|
25
|
+
#
|
26
|
+
# @example Show the command line help
|
27
|
+
# CommandLineParser.new.parse('--help')
|
28
|
+
# parser.parse('--help')
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
#
|
32
|
+
class Parser
|
33
|
+
# Create a new command line parser
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# parser = CommandLineParser.new
|
37
|
+
#
|
38
|
+
def initialize
|
39
|
+
@option_parser = OptionParser.new
|
40
|
+
define_options
|
41
|
+
@options = CreateGithubRelease::CommandLine::Options.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# Parse the command line arguements returning the options
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# parser = CommandLineParser.new
|
48
|
+
# options = parser.parse(['major'])
|
49
|
+
#
|
50
|
+
# @param args [Array<String>] the command line arguments
|
51
|
+
#
|
52
|
+
# @return [CreateGithubRelease::CommandLine::Options] the options
|
53
|
+
#
|
54
|
+
def parse(*args)
|
55
|
+
begin
|
56
|
+
option_parser.parse!(remaining_args = args.dup)
|
57
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
58
|
+
report_errors(e.message)
|
59
|
+
end
|
60
|
+
parse_remaining_args(remaining_args)
|
61
|
+
# puts options unless options.quiet
|
62
|
+
report_errors(*options.errors) unless options.valid?
|
63
|
+
options
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# @!attribute [rw] options
|
69
|
+
#
|
70
|
+
# The options to used for the create-github-release script
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# parser = CommandLineParser.new
|
74
|
+
# parser.parse(['major'])
|
75
|
+
# options = parser.options
|
76
|
+
# options.release_type # => 'major'
|
77
|
+
#
|
78
|
+
# @return [CreateGithubRelease::CommandLine::Options] the options
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
#
|
82
|
+
attr_reader :options
|
83
|
+
|
84
|
+
# @!attribute [rw] option_parser
|
85
|
+
#
|
86
|
+
# The option parser
|
87
|
+
#
|
88
|
+
# @return [OptionParser] the option parser
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
#
|
92
|
+
attr_reader :option_parser
|
93
|
+
|
94
|
+
# Parse non-option arguments (the release type)
|
95
|
+
# @return [void]
|
96
|
+
# @api private
|
97
|
+
def parse_remaining_args(remaining_args)
|
98
|
+
options.release_type = remaining_args.shift || nil
|
99
|
+
report_errors('Too many args') unless remaining_args.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
# An error message constructed from the given errors array
|
103
|
+
# @return [String]
|
104
|
+
# @api private
|
105
|
+
def error_message(errors)
|
106
|
+
<<~MESSAGE
|
107
|
+
#{errors.map { |e| "ERROR: #{e}" }.join("\n")}
|
108
|
+
|
109
|
+
Use --help for usage
|
110
|
+
MESSAGE
|
111
|
+
end
|
112
|
+
|
113
|
+
# Output an error message and useage to stderr and exit
|
114
|
+
# @return [void]
|
115
|
+
# @api private
|
116
|
+
def report_errors(*errors)
|
117
|
+
warn error_message(errors)
|
118
|
+
exit 1
|
119
|
+
end
|
120
|
+
|
121
|
+
# The command line template as a string
|
122
|
+
# @return [String]
|
123
|
+
# @api private
|
124
|
+
def command_template
|
125
|
+
<<~COMMAND
|
126
|
+
#{File.basename($PROGRAM_NAME)} --help | RELEASE_TYPE [options]
|
127
|
+
COMMAND
|
128
|
+
end
|
129
|
+
|
130
|
+
# Define the options for OptionParser
|
131
|
+
# @return [void]
|
132
|
+
# @api private
|
133
|
+
def define_options
|
134
|
+
# @sg-ignore
|
135
|
+
option_parser.banner = "Usage:\n#{command_template}"
|
136
|
+
option_parser.separator ''
|
137
|
+
option_parser.separator "RELEASE_TYPE must be 'major', 'minor', 'patch', 'pre', 'release', or 'first'"
|
138
|
+
option_parser.separator ''
|
139
|
+
option_parser.separator 'Options:'
|
140
|
+
%i[
|
141
|
+
define_help_option define_default_branch_option define_release_branch_option define_pre_option
|
142
|
+
define_pre_type_option define_remote_option define_last_release_version_option
|
143
|
+
define_next_release_version_option define_changelog_path_option define_quiet_option define_verbose_option
|
144
|
+
].each { |m| send(m) }
|
145
|
+
end
|
146
|
+
|
147
|
+
# Define the pre option
|
148
|
+
# @return [void]
|
149
|
+
# @api private
|
150
|
+
def define_pre_option
|
151
|
+
option_parser.on('-p', '--pre', 'Create a pre-release') do |pre|
|
152
|
+
options.pre = pre
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Define the pre-type option
|
157
|
+
# @return [void]
|
158
|
+
# @api private
|
159
|
+
def define_pre_type_option
|
160
|
+
description = 'Type of pre-release to create (e.g. alpha, beta, etc.)'
|
161
|
+
option_parser.on('-t', '--pre-type=TYPE', description) do |pre_type|
|
162
|
+
options.pre_type = pre_type
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Define the quiet option
|
167
|
+
# @return [void]
|
168
|
+
# @api private
|
169
|
+
def define_quiet_option
|
170
|
+
option_parser.on('-q', '--[no-]quiet', 'Do not show output') do |quiet|
|
171
|
+
options.quiet = quiet
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Define the verbose option
|
176
|
+
# @return [void]
|
177
|
+
# @api private
|
178
|
+
def define_verbose_option
|
179
|
+
option_parser.on('-v', '--[no-]verbose', 'Show extra output') do |verbose|
|
180
|
+
options.verbose = verbose
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Define the help option
|
185
|
+
# @return [void]
|
186
|
+
# @api private
|
187
|
+
def define_help_option
|
188
|
+
option_parser.on_tail('-h', '--help', 'Show this message') do
|
189
|
+
puts option_parser
|
190
|
+
exit 0
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Define the default_branch option which requires a value
|
195
|
+
# @return [void]
|
196
|
+
# @api private
|
197
|
+
def define_default_branch_option
|
198
|
+
option_parser.on('--default-branch=BRANCH_NAME', 'Override the default branch') do |name|
|
199
|
+
options.default_branch = name
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Define the release_branch option which requires a value
|
204
|
+
# @return [void]
|
205
|
+
# @api private
|
206
|
+
def define_release_branch_option
|
207
|
+
option_parser.on('--release-branch=BRANCH_NAME', 'Override the release branch to create') do |name|
|
208
|
+
options.release_branch = name
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Define the remote option which requires a value
|
213
|
+
# @return [void]
|
214
|
+
# @api private
|
215
|
+
def define_remote_option
|
216
|
+
option_parser.on('--remote=REMOTE_NAME', "Use this remote name instead of 'origin'") do |name|
|
217
|
+
options.remote = name
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Define the last_release_version option which requires a value
|
222
|
+
# @return [void]
|
223
|
+
# @api private
|
224
|
+
def define_last_release_version_option
|
225
|
+
option_parser.on('--last-release-version=VERSION', 'Use this version instead `semverify current`') do |version|
|
226
|
+
options.last_release_version = version
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Define the next_release_version option which requires a value
|
231
|
+
# @return [void]
|
232
|
+
# @api private
|
233
|
+
def define_next_release_version_option
|
234
|
+
option_parser.on(
|
235
|
+
'--next-release-version=VERSION',
|
236
|
+
'Use this version instead `semverify next-RELEASE_TYPE`'
|
237
|
+
) do |version|
|
238
|
+
options.next_release_version = version
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Define the changelog_path option which requires a value
|
243
|
+
# @return [void]
|
244
|
+
# @api private
|
245
|
+
def define_changelog_path_option
|
246
|
+
option_parser.on('--changelog-path=PATH', 'Use this file instead of CHANGELOG.md') do |name|
|
247
|
+
options.changelog_path = name
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
# rubocop:enable Metrics/ClassLength
|
252
|
+
end
|
253
|
+
end
|
@@ -0,0 +1,293 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CreateGithubRelease
|
4
|
+
module CommandLine
|
5
|
+
# Module containing all option validations
|
6
|
+
#
|
7
|
+
# All validation classes must inherit from `CreateGithubRelease::Validations::Base`
|
8
|
+
# and implement the `#valid?` and `#error` methods.
|
9
|
+
#
|
10
|
+
# All validation classes must be named `Validate*` and must be defined in the
|
11
|
+
# `CreateGithubRelease::Validations` namespace. Classes that follow this convention
|
12
|
+
# are automatically run by `CreateGithubRelease::CommandLine::OptionsValidator`.
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
module Validations
|
17
|
+
# All validation classes inherit this classes initializer and options reader
|
18
|
+
# @api public
|
19
|
+
class Base
|
20
|
+
# Create a new validation object with the given options
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# class ValidatePreFlag < Base
|
24
|
+
# def validate
|
25
|
+
# options.pre == false || %w[major minor patch].include?(options.release_type)
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @param options [CreateGithubRelease::CommandLine::Options] the options to validate
|
30
|
+
#
|
31
|
+
def initialize(options)
|
32
|
+
@options = options
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# The options to validate
|
38
|
+
# @return [CreateGithubRelease::CommandLine::Options]
|
39
|
+
# @api private
|
40
|
+
attr_reader :options
|
41
|
+
|
42
|
+
# Returns `true` if the given version is a valid gem version
|
43
|
+
# @return [Boolean]
|
44
|
+
# @api private
|
45
|
+
def valid_gem_version?(version)
|
46
|
+
Gem::Version.new(version)
|
47
|
+
true
|
48
|
+
rescue ArgumentError
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
# `true` if the given name is a valid git reference
|
53
|
+
# @return [Boolean]
|
54
|
+
# @api private
|
55
|
+
def valid_reference?(name)
|
56
|
+
VALID_REF_PATTERN.match?(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns `true` if the given path is a valid path
|
60
|
+
# @param path [String] the path to validate
|
61
|
+
# @return [Boolean]
|
62
|
+
# @api private
|
63
|
+
def valid_path?(path)
|
64
|
+
File.expand_path(path)
|
65
|
+
true
|
66
|
+
rescue ArgumentError
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Validate that `pre` is unset or is set with the appropriate release types
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
class ValidatePreFlag < Base
|
75
|
+
# Returns `true` if valid
|
76
|
+
# @return [Boolean]
|
77
|
+
# @api private
|
78
|
+
def valid?
|
79
|
+
options.pre == false || %w[major minor patch].include?(options.release_type)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Called when valid? is `false` to return the error messages
|
83
|
+
# @return [String, Array<String>]
|
84
|
+
# @api private
|
85
|
+
def error
|
86
|
+
'--pre can only be given with a release type of major, minor, or patch'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Validate if pre_type is nil or releast_type is 'pre' or the pre flag is set
|
91
|
+
# @api private
|
92
|
+
#
|
93
|
+
class ValidatePreType < Base
|
94
|
+
# Returns `true` if valid
|
95
|
+
# @return [Boolean]
|
96
|
+
# @api private
|
97
|
+
def valid?
|
98
|
+
options.pre_type.nil? ||
|
99
|
+
options.release_type == 'pre' ||
|
100
|
+
(%w[major minor patch].include?(options.release_type) && options.pre == true)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Called when valid? is `false` to return the error messages
|
104
|
+
# @return [String, Array<String>]
|
105
|
+
# @api private
|
106
|
+
def error
|
107
|
+
if %w[major minor patch pre].include?(options.release_type)
|
108
|
+
'--pre must be given when --pre-type is given'
|
109
|
+
else
|
110
|
+
'--pre-type can only be given with a release type of major, minor, patch, or pre'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Validate that the quiet flag is true or false
|
116
|
+
# @api private
|
117
|
+
class ValidateQuiet < Base
|
118
|
+
# Returns `true` if valid
|
119
|
+
# @return [Boolean]
|
120
|
+
# @api private
|
121
|
+
def valid?
|
122
|
+
options.quiet == true || options.quiet == false
|
123
|
+
end
|
124
|
+
|
125
|
+
# Called when valid? is `false` to return the error messages
|
126
|
+
# @return [String, Array<String>]
|
127
|
+
# @api private
|
128
|
+
def error
|
129
|
+
'quiet must be either true or false'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Validate that the verbose flag is true or false
|
134
|
+
# @api private
|
135
|
+
class ValidateVerbose < Base
|
136
|
+
# Returns `true` if the `#verbose` is `true` or `false` and `false` otherwise
|
137
|
+
# @return [Boolean]
|
138
|
+
# @api private
|
139
|
+
def valid?
|
140
|
+
options.verbose == true || options.verbose == false
|
141
|
+
end
|
142
|
+
|
143
|
+
# Called when valid? is `false` to return the error messages
|
144
|
+
# @return [String, Array<String>]
|
145
|
+
# @api private
|
146
|
+
def error
|
147
|
+
'verbose must be either true or false'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Validate that either quiet or verbose is given, but not both
|
152
|
+
# @api private
|
153
|
+
class ValidateOnlyQuietOrVerbose < Base
|
154
|
+
# Returns `true` if at most only one of `#quiet` or `#verbose` is `true`
|
155
|
+
# @return [Boolean]
|
156
|
+
# @api private
|
157
|
+
def valid? = !options.quiet || !options.verbose
|
158
|
+
|
159
|
+
# Called when valid? is `false` to return the error messages
|
160
|
+
# @return [String, Array<String>]
|
161
|
+
# @api private
|
162
|
+
def error = '--quiet and --verbose cannot be used together'
|
163
|
+
end
|
164
|
+
|
165
|
+
# Validates that a release type is given
|
166
|
+
# @api private
|
167
|
+
class ValidateReleaseTypeGiven < Base
|
168
|
+
# Returns `true` if the `#release_type` is not nil
|
169
|
+
# @return [Boolean]
|
170
|
+
# @api private
|
171
|
+
def valid? = !options.release_type.nil?
|
172
|
+
|
173
|
+
# Called when valid? is `false` to return the error messages
|
174
|
+
# @return [String, Array<String>]
|
175
|
+
# @api private
|
176
|
+
def error
|
177
|
+
valid_release_types = "'#{VALID_RELEASE_TYPES.join("', '")}'"
|
178
|
+
"RELEASE_TYPE must be given. Must be one of #{valid_release_types}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Validates that the given release type is valid
|
183
|
+
# @api private
|
184
|
+
class ValidateReleaseType < Base
|
185
|
+
# Returns `true` if the `#release_type` is nil or a valid release type
|
186
|
+
# @return [Boolean]
|
187
|
+
# @api private
|
188
|
+
def valid? = options.release_type.nil? || VALID_RELEASE_TYPES.include?(options.release_type)
|
189
|
+
|
190
|
+
# Called when valid? is `false` to return the error messages
|
191
|
+
# @return [String, Array<String>]
|
192
|
+
# @api private
|
193
|
+
def error
|
194
|
+
valid_release_types = "'#{VALID_RELEASE_TYPES.join("', '")}'"
|
195
|
+
"RELEASE_TYPE '#{options.release_type}' is not valid. Must be one of #{valid_release_types}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Validates the default branch (if given) a valid Git reference
|
200
|
+
# @api private
|
201
|
+
class ValidateDefaultBranch < Base
|
202
|
+
# Returns `true` if the `#default_branch` is nil or is a valid git reference
|
203
|
+
# @return [Boolean]
|
204
|
+
# @api private
|
205
|
+
def valid? = options.default_branch.nil? || valid_reference?(options.default_branch)
|
206
|
+
|
207
|
+
# Called when valid? is `false` to return the error messages
|
208
|
+
# @return [String, Array<String>]
|
209
|
+
# @api private
|
210
|
+
def error = "--default-branch='#{options.default_branch}' is not valid"
|
211
|
+
end
|
212
|
+
|
213
|
+
# Validates the release branch (if given) a valid Git reference
|
214
|
+
# @api private
|
215
|
+
class ValidateReleaseBranch < Base
|
216
|
+
# Returns `true` if the `#release_branch` is nil or is a valid git reference
|
217
|
+
# @return [Boolean]
|
218
|
+
# @api private
|
219
|
+
def valid? = options.release_branch.nil? || valid_reference?(options.release_branch)
|
220
|
+
|
221
|
+
# Called when valid? is `false` to return the error messages
|
222
|
+
# @return [String, Array<String>]
|
223
|
+
# @api private
|
224
|
+
def error = "--release-branch='#{options.release_branch}' is not valid"
|
225
|
+
end
|
226
|
+
|
227
|
+
# Validate that the remote (if given) is a valid Git reference
|
228
|
+
# @api private
|
229
|
+
class ValidateRemote < Base
|
230
|
+
# Returns `true` if the `#remote` is nil or is a valid git reference
|
231
|
+
# @return [Boolean]
|
232
|
+
# @api private
|
233
|
+
def valid? = options.remote.nil? || valid_reference?(options.remote)
|
234
|
+
|
235
|
+
# Called when valid? is `false` to return the error messages
|
236
|
+
# @return [String, Array<String>]
|
237
|
+
# @api private
|
238
|
+
def error = "--remote='#{options.remote}' is not valid"
|
239
|
+
end
|
240
|
+
|
241
|
+
# Validate that the last release version (if given) is a valid gem version
|
242
|
+
# @api private
|
243
|
+
class ValidateLastReleaseVersion < Base
|
244
|
+
# Returns `true` if the `#last_release_version` is nil or is a valid gem version
|
245
|
+
# @return [Boolean]
|
246
|
+
# @api private
|
247
|
+
def valid? = options.last_release_version.nil? || valid_gem_version?(options.last_release_version)
|
248
|
+
|
249
|
+
# Called when valid? is `false` to return the error messages
|
250
|
+
# @return [String, Array<String>]
|
251
|
+
# @api private
|
252
|
+
def error = "--last-release-version='#{options.last_release_version}' is not valid"
|
253
|
+
end
|
254
|
+
|
255
|
+
# Validate that the next release version (if given) is a valid gem version
|
256
|
+
# @api private
|
257
|
+
class ValidateNextReleaseVersion < Base
|
258
|
+
# Returns `true` if the `#next_release_version` is nil or is a valid gem version
|
259
|
+
# @return [Boolean]
|
260
|
+
# @api private
|
261
|
+
def valid? = options.next_release_version.nil? || valid_gem_version?(options.next_release_version)
|
262
|
+
|
263
|
+
# Called when valid? is `false` to return the error messages
|
264
|
+
# @return [String, Array<String>]
|
265
|
+
# @api private
|
266
|
+
def error = "--next-release-version='#{options.next_release_version}' is not valid"
|
267
|
+
end
|
268
|
+
|
269
|
+
# Validate that the change log path (if given) is a valid path
|
270
|
+
# @api private
|
271
|
+
class ValidateChangelogPath < Base
|
272
|
+
# Returns `true` if `#changelog_path` is nil or is a valid regular file path
|
273
|
+
# @return [Boolean]
|
274
|
+
# @api private
|
275
|
+
def valid?
|
276
|
+
options.changelog_path.nil? ||
|
277
|
+
(valid_path?(options.changelog_path) && File.file?(File.expand_path(options.changelog_path)))
|
278
|
+
end
|
279
|
+
|
280
|
+
# Called when valid? is `false` to return the error messages
|
281
|
+
# @return [String, Array<String>]
|
282
|
+
# @api private
|
283
|
+
def error
|
284
|
+
if valid_path?(options.changelog_path)
|
285
|
+
"The change log path '#{options.changelog_path}' is not a regular file"
|
286
|
+
else
|
287
|
+
"The change log path '#{options.changelog_path}' is not a valid path"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'validations'
|
4
|
+
|
5
|
+
module CreateGithubRelease
|
6
|
+
module CommandLine
|
7
|
+
# Validates a set of options after the options have been fully initialized
|
8
|
+
# @api private
|
9
|
+
class Validator
|
10
|
+
# Create a new instance of this class
|
11
|
+
# @param options [CreateGithubRelease::CommandLine::Options] the options to validate
|
12
|
+
# @api private
|
13
|
+
def initialize(options)
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns `true` if all options are valid and `false` otherwise
|
18
|
+
#
|
19
|
+
# * If the options are valid, returns `true` clears the `#errors` array
|
20
|
+
# * If the options are not valid, returns `false` and populates the `#errors` array
|
21
|
+
#
|
22
|
+
# @example when all options are valid
|
23
|
+
# options = CreateGithubRelease::CommandLine::Options.new
|
24
|
+
# options.release_type = 'major'
|
25
|
+
# options.valid? #=> true
|
26
|
+
# options.errors #=> []
|
27
|
+
#
|
28
|
+
# @example when one or more options are not valid
|
29
|
+
# options = CreateGithubRelease::CommandLine::Options.new
|
30
|
+
# options.release_type #=> nil
|
31
|
+
# options.valid? #=> false
|
32
|
+
# options.errors #=> ["--release-type must be given and be one of 'major', 'minor', 'patch'"]
|
33
|
+
#
|
34
|
+
# @return [Boolean]
|
35
|
+
#
|
36
|
+
def valid?
|
37
|
+
@errors = []
|
38
|
+
validation_classes.each do |validation_class|
|
39
|
+
validation = validation_class.new(options)
|
40
|
+
@errors << validation.error unless validation.valid?
|
41
|
+
end
|
42
|
+
@errors.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns an array of error messages
|
46
|
+
#
|
47
|
+
# * If the options are valid, returns an empty array
|
48
|
+
# * If the options are not valid, returns an array of error messages
|
49
|
+
#
|
50
|
+
# @example when all options are valid
|
51
|
+
# options = CreateGithubRelease::CommandLine::Options.new
|
52
|
+
# options.release_type = 'major'
|
53
|
+
# options.valid? #=> true
|
54
|
+
# options.errors #=> []
|
55
|
+
#
|
56
|
+
# @example when one or more options are not valid
|
57
|
+
# options = CreateGithubRelease::CommandLine::Options.new
|
58
|
+
# options.release_type #=> nil
|
59
|
+
# options.quiet = options.verbose = true
|
60
|
+
# options.valid? #=> false
|
61
|
+
# options.errors #=> [
|
62
|
+
# "Both --quiet and --verbose cannot be given",
|
63
|
+
# "--release-type must be given and be one of 'major', 'minor', 'patch'"
|
64
|
+
# ]
|
65
|
+
#
|
66
|
+
# @return [Array<String>] an array of error messages
|
67
|
+
#
|
68
|
+
def errors
|
69
|
+
valid?
|
70
|
+
@errors
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# The options to validate
|
76
|
+
# @return [CreateGithubRelease::CommandLine::Options]
|
77
|
+
# @api private
|
78
|
+
attr_reader :options
|
79
|
+
|
80
|
+
# Returns an array of validation classes
|
81
|
+
# @return [Array<CreateGithubRelease::Validations::Base>]
|
82
|
+
# @api private
|
83
|
+
def validation_classes
|
84
|
+
[].tap do |validation_classes|
|
85
|
+
CreateGithubRelease::CommandLine::Validations.constants.each do |constant_name|
|
86
|
+
constant = Validations.const_get(constant_name)
|
87
|
+
validation_classes << constant if constant.is_a?(Class) && constant_name.to_s.start_with?('Validate')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CreateGithubRelease
|
4
|
+
# This module has all the classes and modules for the command line interface
|
5
|
+
#
|
6
|
+
# The Parser class is the main interface. It parses and validates the command line
|
7
|
+
# arguments and returns an instance of the Options class.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# parser = CreateGithubRelease::CommandLine::Parser.new
|
11
|
+
# options = parser.parse(*ARGV)
|
12
|
+
# if !option.valid?
|
13
|
+
# puts options.errors
|
14
|
+
# exit 1
|
15
|
+
# end
|
16
|
+
# # ... do something with the options
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
#
|
20
|
+
module CommandLine
|
21
|
+
# An array of the valid release types
|
22
|
+
# @return [Array<String>]
|
23
|
+
# @api private
|
24
|
+
VALID_RELEASE_TYPES = %w[major minor patch pre release first].freeze
|
25
|
+
|
26
|
+
# Regex pattern for a [valid git reference](https://git-scm.com/docs/git-check-ref-format)
|
27
|
+
# @return [Regexp]
|
28
|
+
# @api private
|
29
|
+
VALID_REF_PATTERN = /^(?:(?:[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)|(?:[a-zA-Z0-9-]+))$/
|
30
|
+
|
31
|
+
# An array of the allowed options that can be passed to `.new`
|
32
|
+
# @return [Array<Symbol>]
|
33
|
+
ALLOWED_OPTIONS = %i[
|
34
|
+
release_type pre pre_type default_branch release_branch remote last_release_version
|
35
|
+
next_release_version changelog_path quiet verbose
|
36
|
+
].freeze
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
require_relative 'command_line/options'
|
41
|
+
require_relative 'command_line/parser'
|
42
|
+
require_relative 'command_line/validations'
|
43
|
+
require_relative 'command_line/validator'
|