create_github_release 0.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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.markdownlint.yml +25 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +20 -0
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +31 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +64 -0
  10. data/Rakefile +85 -0
  11. data/create_github_release.gemspec +49 -0
  12. data/exe/create-github-release +22 -0
  13. data/lib/create_github_release/assertion_base.rb +62 -0
  14. data/lib/create_github_release/assertions/bundle_is_up_to_date.rb +73 -0
  15. data/lib/create_github_release/assertions/changelog_docker_container_exists.rb +73 -0
  16. data/lib/create_github_release/assertions/docker_is_running.rb +42 -0
  17. data/lib/create_github_release/assertions/gh_command_exists.rb +42 -0
  18. data/lib/create_github_release/assertions/git_command_exists.rb +42 -0
  19. data/lib/create_github_release/assertions/in_git_repo.rb +44 -0
  20. data/lib/create_github_release/assertions/in_repo_root_directory.rb +47 -0
  21. data/lib/create_github_release/assertions/local_and_remote_on_same_commit.rb +45 -0
  22. data/lib/create_github_release/assertions/local_release_branch_does_not_exist.rb +43 -0
  23. data/lib/create_github_release/assertions/local_release_tag_does_not_exist.rb +45 -0
  24. data/lib/create_github_release/assertions/no_staged_changes.rb +46 -0
  25. data/lib/create_github_release/assertions/no_uncommitted_changes.rb +46 -0
  26. data/lib/create_github_release/assertions/on_default_branch.rb +44 -0
  27. data/lib/create_github_release/assertions/remote_release_branch_does_not_exist.rb +43 -0
  28. data/lib/create_github_release/assertions/remote_release_tag_does_not_exist.rb +43 -0
  29. data/lib/create_github_release/assertions.rb +25 -0
  30. data/lib/create_github_release/changelog.rb +372 -0
  31. data/lib/create_github_release/command_line_parser.rb +137 -0
  32. data/lib/create_github_release/options.rb +397 -0
  33. data/lib/create_github_release/release.rb +82 -0
  34. data/lib/create_github_release/release_assertions.rb +86 -0
  35. data/lib/create_github_release/release_tasks.rb +78 -0
  36. data/lib/create_github_release/task_base.rb +62 -0
  37. data/lib/create_github_release/tasks/commit_release.rb +42 -0
  38. data/lib/create_github_release/tasks/create_github_release.rb +106 -0
  39. data/lib/create_github_release/tasks/create_release_branch.rb +42 -0
  40. data/lib/create_github_release/tasks/create_release_pull_request.rb +107 -0
  41. data/lib/create_github_release/tasks/create_release_tag.rb +42 -0
  42. data/lib/create_github_release/tasks/push_release.rb +42 -0
  43. data/lib/create_github_release/tasks/update_changelog.rb +126 -0
  44. data/lib/create_github_release/tasks/update_version.rb +46 -0
  45. data/lib/create_github_release/tasks.rb +18 -0
  46. data/lib/create_github_release/version.rb +6 -0
  47. data/lib/create_github_release.rb +21 -0
  48. metadata +235 -0
@@ -0,0 +1,397 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bump'
4
+ require 'uri'
5
+
6
+ module CreateGithubRelease
7
+ # Captures the options for this script
8
+ #
9
+ # @api public
10
+ #
11
+ class Options
12
+ # Initialize a new instance of Options
13
+ #
14
+ # @example Without a block
15
+ # options = Options.new
16
+ # options.release_type = 'minor'
17
+ #
18
+ # @example With a block
19
+ # options = Options.new do |o|
20
+ # o.release_type = 'minor'
21
+ # end
22
+ #
23
+ # @yield [self] an initialization block
24
+ # @yieldparam self [Options] the instance being initialized
25
+ # @yieldreturn [void] the return value is ignored
26
+ #
27
+ def initialize
28
+ yield self if block_given?
29
+ end
30
+
31
+ # @!attribute [rw] branch
32
+ #
33
+ # The release branch based on the `next_tag`
34
+ #
35
+ # @example By default, `branch` is based on the tag
36
+ # options = Options.new
37
+ # options.tag = 'v1.2.3'
38
+ # options.branch # => 'release-v1.2.3'
39
+ #
40
+ # @example `branch` can be set explicitly
41
+ # options = Options.new
42
+ # options.branch = 'prod-v9.9.9'
43
+ # options.branch # => 'prod-v9.9.9'
44
+ #
45
+ # @return [String] the release branch
46
+ #
47
+ def branch
48
+ @branch ||= "release-#{tag}"
49
+ end
50
+
51
+ # @!attribute [rw] current_tag
52
+ #
53
+ # The git tag of the previous release
54
+ #
55
+ # @example By default, `current_tag` is based on `current_version`
56
+ # options = Options.new
57
+ # options.current_version = '0.1.0'
58
+ # options.current_tag # => 'v0.1.0'
59
+ #
60
+ # @example `current_tag` can be set explicitly
61
+ # options = Options.new
62
+ # options.current_tag = 'v9.9.9'
63
+ # options.current_tag # => 'v9.9.9'
64
+ #
65
+ # @return [String] the current tag
66
+ #
67
+ def current_tag
68
+ @current_tag ||= "v#{current_version}"
69
+ end
70
+
71
+ # @!attribute [rw] current_version
72
+ #
73
+ # The current version of the project's gem as determined by `Bump::Bump.current`
74
+ #
75
+ # @example By default, `current_version` is based on `Bump::Bump.current`
76
+ # options = Options.new
77
+ # options.current_version # => 'v0.1.0'
78
+ #
79
+ # @example `current_version` can be set explicitly
80
+ # options = Options.new
81
+ # options.current_version = '9.9.9'
82
+ # options.current_version # => '9.9.9'
83
+ #
84
+ # @return [String] the current version
85
+ #
86
+ def current_version
87
+ @current_version ||= Bump::Bump.current
88
+ end
89
+
90
+ def current_version=(current_version)
91
+ self.current_tag = self.next_version = nil
92
+ @current_version = current_version
93
+ end
94
+
95
+ # @!attribute [rw] default_branch
96
+ #
97
+ # The default branch of the remote repository
98
+ #
99
+ # This is the default branch as reported by the `HEAD branch` returned by
100
+ # `git remote show #{remote}`.
101
+ #
102
+ # Uses the value of `remote` to determine the remote repository to query.
103
+ #
104
+ # @example By default, `default_branch` is based on `git remote show`
105
+ # options = Options.new
106
+ # options.default_branch # => 'main'
107
+ #
108
+ # @example `default_branch` can be set explicitly
109
+ # options = Options.new
110
+ # options.default_branch = 'master'
111
+ # options.current_version # => 'master'
112
+ #
113
+ # @return [String] the default branch of the remote repository
114
+ #
115
+ def default_branch
116
+ @default_branch ||= `git remote show '#{remote}'`.match(/HEAD branch: (.*?)$/)[1]
117
+ end
118
+
119
+ # @!attribute [rw] next_tag
120
+ #
121
+ # The tag to use for the next release based on `next_version`
122
+ #
123
+ # @example By default, `next_tag` is based on `next_version`
124
+ # options = Options.new
125
+ # options.next_version = '0.2.0'
126
+ # options.next_tag # => 'v0.2.0 '
127
+ #
128
+ # @example `next_tag` can be set explicitly
129
+ # options = Options.new
130
+ # options.next_tag = 'v9.9.9'
131
+ # options.next_tag # => 'v9.9.9'
132
+ #
133
+ # @return [String] the tag to use for the next release
134
+ #
135
+ def next_tag
136
+ @next_tag ||= "v#{next_version}"
137
+ end
138
+
139
+ def next_tag=(next_tag)
140
+ self.branch = self.release_url = nil
141
+ @next_tag = next_tag
142
+ end
143
+
144
+ alias tag next_tag
145
+ alias tag= next_tag=
146
+
147
+ # @!attribute [rw] next_version
148
+ #
149
+ # The version of the next release
150
+ #
151
+ # Both `release_type` and `current_version` are used to determine the next
152
+ # version using `Bump::Bump.next_version(release_type, current_version)`.
153
+ #
154
+ # @example `next_version` is determined by `release_type` and `current_version`
155
+ # options = Options.new
156
+ # options.release_type = 'major'
157
+ # options.current_version = '0.1.0'
158
+ # options.next_version # => '2.0.0'
159
+ #
160
+ # @example `next_version` can be set explicitly
161
+ # options = Options.new
162
+ # options.next_version = '9.9.9'
163
+ # options.next_version # => '9.9.9'
164
+ #
165
+ # @return [String] the version of the next release
166
+ #
167
+ def next_version
168
+ @next_version ||= Bump::Bump.next_version(release_type, current_version)
169
+ end
170
+
171
+ def next_version=(next_version)
172
+ self.tag = nil
173
+ @next_version = next_version
174
+ end
175
+
176
+ # Valid values for the `release_type` attribute
177
+ #
178
+ VALID_RELEASE_TYPES = %w[major minor patch].freeze
179
+
180
+ # @!attribute [rw] release_type
181
+ #
182
+ # The type of release to make: major, minor, or patch
183
+ #
184
+ # This is passed to `Bump` when determining the next version. `release_type`
185
+ # must be set before it is read.
186
+ #
187
+ # Reading this attribute when it has not been explicitly set will raise a RuntimeError.
188
+ # Writing anything by major, minor, or path will raise an ArgumentError.
189
+ #
190
+ # @example `release_type` can be set explicitly
191
+ # options = Options.new
192
+ # options.release_type = 'major'
193
+ # options.release_type # => 'major'
194
+ #
195
+ # @return [String] the release type
196
+ #
197
+ def release_type
198
+ raise 'release_type not set. Must be major, minor, or patch' if @release_type.nil?
199
+
200
+ @release_type
201
+ end
202
+
203
+ def release_type=(release_type)
204
+ unless VALID_RELEASE_TYPES.include?(release_type)
205
+ raise(ArgumentError, "Invalid release_type #{release_type}: must be major, minor, or patch")
206
+ end
207
+
208
+ self.next_version = nil
209
+ @release_type = release_type
210
+ end
211
+
212
+ # @!attribute [rw] quiet
213
+ #
214
+ # Run the script without no or minimal output
215
+ #
216
+ # @example By default, `quiet` is false
217
+ # options = Options.new
218
+ # options.quiet # => false
219
+ #
220
+ # @example `quiet` can be set explicitly
221
+ # options = Options.new
222
+ # options.quiet = true
223
+ # options.quiet # => true
224
+ #
225
+ # @return [Boolean] the quiet flag
226
+ #
227
+ def quiet
228
+ @quiet = false unless instance_variable_defined?(:@quiet)
229
+ @quiet
230
+ end
231
+
232
+ # @!attribute [rw] release_url
233
+ #
234
+ # The address of the GitHub release notes for the next release
235
+ #
236
+ # `remote_url` and `next_tag` are used to determine the release URL.
237
+ #
238
+ # @example Given the remote_url is https://github.com/user/repo.git and `next_tag` is v0.2.0
239
+ # options = Options.new
240
+ # options.release_url # => https://github.com/user/repo/releases/tag/v1.0.0
241
+ #
242
+ # @example `release_url` can be set explicitly
243
+ # options = Options.new
244
+ # options.release_url = "https://github.com/user/repo/releases/tag/v9.9.9"
245
+ # options.release_url # => "https://github.com/user/repo/releases/tag/v9.9.9"
246
+ #
247
+ # @return [String] the address of the GitHub release notes for the next release
248
+ #
249
+ def release_url
250
+ @release_url ||= begin
251
+ url = remote_url.to_s.sub(/\.git$/, '')
252
+ "#{url}/releases/tag/#{next_tag}"
253
+ end
254
+ end
255
+
256
+ # @!attribute [rw] remote
257
+ #
258
+ # The Git remote to use to get the remote repository URL
259
+ #
260
+ # The default is 'origin'.
261
+ #
262
+ # @example The default `remote`` is origin
263
+ # options = Options.new
264
+ # options.remote # => "origin"
265
+ #
266
+ # @example `remote` can be set explicitly
267
+ # options = Options.new
268
+ # options.remote = 'upstream'
269
+ # options.remote # => "upstream"
270
+ #
271
+ # @return [String] the address of the GitHub release notes for the next release
272
+ #
273
+ def remote
274
+ @remote ||= 'origin'
275
+ end
276
+
277
+ def remote=(remote)
278
+ self.default_branch = self.remote_url = nil
279
+ @remote = remote
280
+ end
281
+
282
+ # @!attribute [rw] remote_url
283
+ #
284
+ # The URL of the remote repository
285
+ #
286
+ # Uses the value of `remote` to determine the remote repository URL. This is
287
+ # the URL reported by `git remote get-url #{remote}`.
288
+ #
289
+ # @example
290
+ # options = Options.new
291
+ # options.remote_url # => "https://github.com/user/repo.git"
292
+ #
293
+ # @example Using a different `remote`
294
+ # options = Options.new
295
+ # options.remote = 'upstream'
296
+ # options.remote_url # => "https://github.com/another_user/upstream_repo.git"
297
+ #
298
+ # @return [URI] the URL of the remote repository
299
+ #
300
+ def remote_url
301
+ @remote_url ||= URI.parse(`git remote get-url '#{remote}'`.chomp)
302
+ end
303
+
304
+ def remote_url=(remote_url)
305
+ self.remote_base_url = self.remote_repository = self.release_url = nil
306
+
307
+ @remote_url = remote_url.nil? || remote_url.is_a?(URI) ? remote_url : URI.parse(remote_url)
308
+ end
309
+
310
+ # @!attribute [rw] remote_base_url
311
+ #
312
+ # The base URL of the remote repository
313
+ #
314
+ # This is the part of the `remote_url` excluding the path.
315
+ #
316
+ # @example Given the `remote_url` is https://github.com/user/repo.git
317
+ # options = Options.new
318
+ # options.remote_base_url # => "https://github.com/"
319
+ #
320
+ # @example `remote_base_url` can be set explicitly
321
+ # options = Options.new
322
+ # options.remote_base_url = 'https://gitlab.com/'
323
+ # options.remote_base_url # => "https://gitlab.com/"
324
+ #
325
+ # @return [String] the bsae URL of the remote repository
326
+ #
327
+ def remote_base_url
328
+ @remote_base_url ||= remote_url.to_s[0..-remote_url.path.length]
329
+ end
330
+
331
+ # @!attribute [rw] remote_repository
332
+ #
333
+ # The user and repository name of the remote repository
334
+ #
335
+ # This is the extracted from the `remote_url`.
336
+ #
337
+ # @example Given the `remote_url` is https://github.com/user/repo.git
338
+ # options = Options.new
339
+ # options.remote_repository # => "user/repo"
340
+ #
341
+ # @example `remote_repository` can be set explicitly
342
+ # options = Options.new
343
+ # options.remote_repository = 'foo/bar'
344
+ # options.remote_repository # => "foo/bar"
345
+ #
346
+ # @return [String] the bsae URL of the remote repository
347
+ #
348
+ def remote_repository
349
+ @remote_repository ||= remote_url.path.sub(%r{^/}, '').sub(/\.git$/, '')
350
+ end
351
+
352
+ attr_writer :branch, :current_tag, :default_branch, :quiet, :remote_base_url, :remote_repository, :release_url
353
+
354
+ # Returns a string representation of the options
355
+ #
356
+ # @example
357
+ # # Given that:
358
+ # # * the remote is 'origin'
359
+ # # * the url of origin is 'http://githib.com/main-branch/create_github_release.git'
360
+ # # * the default branch is 'main'
361
+ # # * the current version is '0.1.0'
362
+ # options = Options.new { |o| o.release_type = 'major' }
363
+ # puts options.to_s
364
+ # branch='release-v1.0.0'
365
+ # current_tag='v0.1.0'
366
+ # current_version='0.1.0'
367
+ # default_branch='main'
368
+ # next_tag='v1.0.0'
369
+ # next_version='1.0.0'
370
+ # quiet=false
371
+ # release_type='major'
372
+ # remote='origin'
373
+ # remote_url='https://github.com/main-branch/create_github_release.git'
374
+ # remote_base_url='https://github.com/'
375
+ # remote_repository='main-branch/create_github_release'
376
+ #
377
+ # @return [String] a string representation of the options
378
+ #
379
+ def to_s
380
+ <<~OUTPUT
381
+ branch='#{branch}'
382
+ current_tag='#{current_tag}'
383
+ current_version='#{current_version}'
384
+ default_branch='#{default_branch}'
385
+ next_tag='#{next_tag}'
386
+ next_version='#{next_version}'
387
+ quiet=#{quiet}
388
+ release_type='#{release_type}'
389
+ remote='#{remote}'
390
+ remote_url='#{remote_url}'
391
+ remote_base_url='#{remote_base_url}'
392
+ remote_repository='#{remote_repository}'
393
+ tag='#{tag}'
394
+ OUTPUT
395
+ end
396
+ end
397
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CreateGithubRelease
4
+ # The release information needed to generate a changelog
5
+ #
6
+ # @api public
7
+ #
8
+ class Release
9
+ # Create a new release object
10
+ #
11
+ # @example
12
+ # tag = 'v0.1.1'
13
+ # date = Date.new(2022, 11, 7)
14
+ # description = <<~DESCRIPTION
15
+ # * e718690 Release v0.1.1 (#3)
16
+ # * a92453c Bug fix (#2)
17
+ # DESCRIPTION
18
+ #
19
+ # release = CreateGithubRelease::Release.new(tag, date, description)
20
+ # release.tag # => 'v0.1.1'
21
+ # release.date # => #<Date: 2022-11-07 ((2459773j,0s,0n),+0s,2299161j)>
22
+ # release.description # => "* e718690 Release v0.1.1 (#3)\n* a92453c Bug fix (#2)\n"
23
+ #
24
+ # @param tag [String] The tag of the release
25
+ # @param date [Date] The date of the release
26
+ # @param description [String] The description of the release (usually a bullet list of changes)
27
+ #
28
+ def initialize(tag, date, description)
29
+ @tag = tag
30
+ @date = date
31
+ @description = description
32
+ end
33
+
34
+ # The Git release tag
35
+ #
36
+ # @example
37
+ # tag = 'v0.1.1'
38
+ # date = Date.new(2022, 11, 7)
39
+ # description = <<~DESCRIPTION
40
+ # * e718690 Release v0.1.1 (#3)
41
+ # * a92453c Bug fix (#2)
42
+ # DESCRIPTION
43
+ #
44
+ # release = CreateGithubRelease::Release.new(tag, date, description)
45
+ # release.tag # => 'v0.1.1'
46
+ #
47
+ # @return [String] The Git release tag
48
+ attr_reader :tag
49
+
50
+ # The date the release tag was created
51
+ #
52
+ # @example
53
+ # tag = 'v0.1.1'
54
+ # date = Date.new(2022, 11, 7)
55
+ # description = <<~DESCRIPTION
56
+ # * e718690 Release v0.1.1 (#3)
57
+ # * a92453c Bug fix (#2)
58
+ # DESCRIPTION
59
+ #
60
+ # release = CreateGithubRelease::Release.new(tag, date, description)
61
+ # release.date # => #<Date: 2022-11-07 ((2459773j,0s,0n),+0s,2299161j)>
62
+ #
63
+ # @return [Date] The date the release tag was created
64
+ attr_reader :date
65
+
66
+ # The description of the release
67
+ #
68
+ # @example
69
+ # tag = 'v0.1.1'
70
+ # date = Date.new(2022, 11, 7)
71
+ # description = <<~DESCRIPTION
72
+ # * e718690 Release v0.1.1 (#3)
73
+ # * a92453c Bug fix (#2)
74
+ # DESCRIPTION
75
+ #
76
+ # release = CreateGithubRelease::Release.new(tag, date, description)
77
+ # release.description # => "* e718690 Release v0.1.1 (#3)\n* a92453c Bug fix (#2)\n"
78
+ #
79
+ # @return [String] The description of the release
80
+ attr_reader :description
81
+ end
82
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'create_github_release/assertions'
4
+
5
+ module CreateGithubRelease
6
+ # Assertions that must be true for a new Github release to be created
7
+ #
8
+ # @example
9
+ # require 'create_github_release'
10
+ #
11
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
12
+ # assertions = CreateGithubRelease::ReleaseAssertions.new(options)
13
+ # assertions.options # => #<CreateGithubRelease::Options:0x00007f9b0a0b0a00>
14
+ #
15
+ # @api public
16
+ #
17
+ class ReleaseAssertions
18
+ # The options used in the assertions
19
+ #
20
+ # @example
21
+ # require 'create_github_release'
22
+ #
23
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
24
+ # assertions = CreateGithubRelease::ReleaseAssertions.new(options)
25
+ # assertions.options # => #<CreateGithubRelease::Options:0x00007f9b0a0b0a00>
26
+ #
27
+ # @return [CreateGithubRelease::Options]
28
+ attr_reader :options
29
+
30
+ # Create a new instance of ReleaseAssertions
31
+ #
32
+ # @example
33
+ # require 'create_github_release'
34
+ #
35
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
36
+ # assertions = CreateGithubRelease::ReleaseAssertions.new(options)
37
+ # assertions.make_assertions
38
+ #
39
+ def initialize(options)
40
+ @options = options
41
+ end
42
+
43
+ # The assertions that must be true for a new Github release to be created
44
+ #
45
+ # The assertions are run in the order they are defined in this array.
46
+ #
47
+ # @return [Array<Class>] The assertions that must be true for a new Github release to be created
48
+ #
49
+ ASSERTIONS = [
50
+ CreateGithubRelease::Assertions::GitCommandExists,
51
+ CreateGithubRelease::Assertions::BundleIsUpToDate,
52
+ CreateGithubRelease::Assertions::InGitRepo,
53
+ CreateGithubRelease::Assertions::InRepoRootDirectory,
54
+ CreateGithubRelease::Assertions::OnDefaultBranch,
55
+ CreateGithubRelease::Assertions::NoUncommittedChanges,
56
+ CreateGithubRelease::Assertions::NoStagedChanges,
57
+ CreateGithubRelease::Assertions::LocalAndRemoteOnSameCommit,
58
+ CreateGithubRelease::Assertions::LocalReleaseTagDoesNotExist,
59
+ CreateGithubRelease::Assertions::RemoteReleaseTagDoesNotExist,
60
+ CreateGithubRelease::Assertions::LocalReleaseBranchDoesNotExist,
61
+ CreateGithubRelease::Assertions::RemoteReleaseBranchDoesNotExist,
62
+ CreateGithubRelease::Assertions::DockerIsRunning,
63
+ CreateGithubRelease::Assertions::ChangelogDockerContainerExists,
64
+ CreateGithubRelease::Assertions::GhCommandExists
65
+ ].freeze
66
+
67
+ # Run all assertions
68
+ #
69
+ # @example
70
+ # require 'create_github_release'
71
+ #
72
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
73
+ # assertions = CreateGithubRelease::ReleaseAssertions.new(options)
74
+ # assertions.make_assertions
75
+ #
76
+ # @return [void]
77
+ #
78
+ # @raise [SystemExit] if any assertion fails
79
+ #
80
+ def make_assertions
81
+ ASSERTIONS.each do |assertion_class|
82
+ assertion_class.new(options).assert
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'create_github_release/tasks'
4
+
5
+ module CreateGithubRelease
6
+ # Tasks that must be run to create a new Github release.
7
+ #
8
+ # @example
9
+ # require 'create_github_release'
10
+ #
11
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
12
+ # tasks = CreateGithubRelease::ReleaseTasks.new(options)
13
+ # tasks.run
14
+ #
15
+ # @api public
16
+ #
17
+ class ReleaseTasks
18
+ # The options used to create the Github release
19
+ #
20
+ # @example
21
+ # require 'create_github_release'
22
+ #
23
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
24
+ # tasks = CreateGithubRelease::ReleaseTasks.new(options)
25
+ # tasks.options # => #<CreateGithubRelease::Options:0x00007f9b0a0b0a00>
26
+ #
27
+ # @return [CreateGithubRelease::Options]
28
+ attr_reader :options
29
+
30
+ # Create a new instance of ReleaseTasks
31
+ #
32
+ # @example
33
+ # require 'create_github_release'
34
+ #
35
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
36
+ # tasks = CreateGithubRelease::ReleaseTasks.new(options)
37
+ # tasks.run
38
+ #
39
+ def initialize(options)
40
+ @options = options
41
+ end
42
+ # The tasks that will be run to create a new Github release
43
+ #
44
+ # The tasks are run in the order they are defined in this array.
45
+ #
46
+ # @return [Array<Class>] The tasks that will be run to create a new Github release
47
+ #
48
+ TASKS = [
49
+ CreateGithubRelease::Tasks::CreateReleaseTag,
50
+ CreateGithubRelease::Tasks::CreateReleaseBranch,
51
+ CreateGithubRelease::Tasks::UpdateVersion,
52
+ CreateGithubRelease::Tasks::UpdateChangelog,
53
+ CreateGithubRelease::Tasks::CommitRelease,
54
+ CreateGithubRelease::Tasks::PushRelease,
55
+ CreateGithubRelease::Tasks::CreateGithubRelease,
56
+ CreateGithubRelease::Tasks::CreateReleasePullRequest
57
+ ].freeze
58
+
59
+ # Run all tasks to create a new Github release
60
+ #
61
+ # @example
62
+ # require 'create_github_release'
63
+ #
64
+ # options = CreateGithubRelease::Options.new { |o| o.release_type = 'major' }
65
+ # tasks = CreateGithubRelease::ReleaseTasks.new(options)
66
+ # tasks.run
67
+ #
68
+ # @return [void]
69
+ #
70
+ # @raise [SystemExit] if any task fails
71
+ #
72
+ def run
73
+ TASKS.each do |task_class|
74
+ task_class.new(options).run
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CreateGithubRelease
4
+ # Base class for tasks
5
+ #
6
+ # All tasks must inherit from this class.
7
+ # It holds the options and knows how to print, puts and error while respecting the `quiet` flag.
8
+ #
9
+ # @api private
10
+ #
11
+ class TaskBase
12
+ # Create a new tasks object and save the given `options`
13
+ # @param options [CreateGithubRelease::Options] the options
14
+ # @api private
15
+ def initialize(options)
16
+ @options = options
17
+ end
18
+
19
+ # This method must be overriden by a subclass
20
+ #
21
+ # The subclass is expected to call `error` if the task fails.
22
+ #
23
+ # @return [void]
24
+ #
25
+ # @api private
26
+ def run
27
+ raise NotImplementedError
28
+ end
29
+
30
+ # @!attribute [r] options
31
+ #
32
+ # The options passed to the task object
33
+ # @return [CreateGithubRelease::Options] the options
34
+ # @api private
35
+ attr_reader :options
36
+
37
+ # Calls `Kernel.print` if the `quiet` flag is not set in the `options`
38
+ # @param args [Array] the arguments to pass to `Kernel.print`
39
+ # @return [void]
40
+ # @api private
41
+ def print(*args)
42
+ super unless options.quiet
43
+ end
44
+
45
+ # Calls `Kernel.puts` if the `quiet` flag is not set in the `options`
46
+ # @param args [Array] the arguments to pass to `Kernel.puts`
47
+ # @return [void]
48
+ # @api private
49
+ def puts(*args)
50
+ super unless options.quiet
51
+ end
52
+
53
+ # Writes a message to stderr and exits with exitcode 1
54
+ # @param message [String] the message to write to stderr
55
+ # @return [void]
56
+ # @api private
57
+ def error(message)
58
+ warn "ERROR: #{message}"
59
+ exit 1
60
+ end
61
+ end
62
+ end