create_github_release 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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