toys-release 0.3.2 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7e7c3ea9f175113e9565cc7b9f017eff5de24c8366b946323203d86b6d1935d
4
- data.tar.gz: '08c8a4a8f7d65c865fce847b7ad1ef8cdd47a840348c0deada8ead48dde96bf3'
3
+ metadata.gz: 760890033dfab6a454ca2364d28dc335c787576328b7899f11ce7886129bc820
4
+ data.tar.gz: 5c1c8178fd9313d1359c7c4044240c6be7cc0cc76911d2750eb1420b66bea185
5
5
  SHA512:
6
- metadata.gz: bcec75c6c50f5415356ce4b329b4c04fbeff104f271d9fa56e4d6bf937743828d26e133ce2328294a20472de58130f92cf8cd364c995d3e933819c666137be1d
7
- data.tar.gz: b8c669b5f75f25894f8489776f422c4cbb1c7453d77ba79d9aa2fb05a32ced2e94799b1fc480f4c89c7c89818b2c7334a3dc3e522bb91d5f862336365ed8724f
6
+ metadata.gz: b06f2e581a8474075ed3ea105935644c47a500ad7d0aadf0cd88f82ecf1464939cc5f4136c90fb30d8bfb5e7439dc4857fee1c2fc92296ab66e5b77b68079dda
7
+ data.tar.gz: d672e7c98230a13e14c33d9781b433f7f6cd12bf9e9ea6bc2fd55ce163401ed6a098ac6839cda3d8bebb7a79b60aa2a9532e75c401433337fb688b4492b2663d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Release History
2
2
 
3
+ ### v0.5.0 / 2026-01-27
4
+
5
+ * BREAKING CHANGE: Disabled GitHub check validation by default, because GitHub started adding hidden checks we can't account for
6
+ * ADDED: Support for updating release pull requests when new commits are added
7
+ * ADDED: Multiple release pull requests are now allowed as long as they don't release any of the same components
8
+ * FIXED: Use v6 of the checkout action
9
+ * FIXED: Disabled GitHub check validation by default, because GitHub started adding hidden checks we can't account for
10
+ * FIXED: Reverting a commit that itself does a revert does the right thing
11
+ * FIXED: Fixed error when requesting a release from a branch with a slash in the name
12
+ * FIXED: Updated some outdated GitHub API usage
13
+
14
+ ### v0.4.0 / 2026-01-06
15
+
16
+ * ADDED: Actions workflows use Ruby 4.0 and Toys 0.19 or later
17
+ * FIXED: Output formatting in setup utilities is more consistent
18
+
3
19
  ### v0.3.2 / 2025-12-25
4
20
 
5
21
  * DOCS: Some formatting fixes in the user guide
data/README.md CHANGED
@@ -75,7 +75,7 @@ For more information on the underlying Toys framework, see the
75
75
 
76
76
  ## License
77
77
 
78
- Copyright 2025 Daniel Azuma and the Toys contributors
78
+ Copyright 2025-2026 Daniel Azuma and the Toys contributors
79
79
 
80
80
  Permission is hereby granted, free of charge, to any person obtaining a copy
81
81
  of this software and associated documentation files (the "Software"), to deal
data/docs/guide.md CHANGED
@@ -927,8 +927,8 @@ required. The rest are optional.
927
927
  * **required_checks**: *regexp/boolean* (optional) --
928
928
  Identifies which GitHub checks must pass as a prerequisite for a release.
929
929
  If a string is provided, it is interpreted as a Ruby regexp (PCRE) and
930
- identifies the check names. A boolean value of *true* (the default) means
931
- all checks must pass. A boolean value of *false* disables checking.
930
+ identifies the check names. A boolean value of *true* means all checks must
931
+ pass. A boolean value of *false* (the default) disables checking.
932
932
 
933
933
  * **required_checks_timeout**: *integer* (optional) --
934
934
  The time to wait, in seconds, for required checks to pass during release
@@ -6,6 +6,6 @@ module Toys
6
6
  # Current version of the Toys release system.
7
7
  # @return [String]
8
8
  #
9
- VERSION = "0.3.2"
9
+ VERSION = "0.5.0"
10
10
  end
11
11
  end
@@ -13,7 +13,7 @@ jobs:
13
13
  release-process-request:
14
14
  if: ${{ github.repository == '<%= @settings.repo_path %>' }}
15
15
  env:
16
- ruby_version: "3.4"
16
+ ruby_version: "4.0"
17
17
  runs-on: ubuntu-latest
18
18
  steps:
19
19
  - name: Install Ruby ${{ env.ruby_version }}
@@ -21,7 +21,7 @@ jobs:
21
21
  with:
22
22
  ruby-version: ${{ env.ruby_version }}
23
23
  - name: Checkout repo
24
- uses: actions/checkout@v5
24
+ uses: actions/checkout@v6
25
25
  - name: Install Toys
26
26
  run: "gem install --no-document toys"
27
27
  - name: Process release request
@@ -2,8 +2,8 @@ name: "[release hook] Update open releases"
2
2
 
3
3
  on:
4
4
  push:
5
- branches:
6
- - <%= @settings.main_branch %>
5
+ branches-ignore:
6
+ - "<%= @settings.release_branch_prefix %>/**"
7
7
 
8
8
  permissions:
9
9
  contents: write # required for pushing changes
@@ -13,7 +13,7 @@ jobs:
13
13
  release-update-open-requests:
14
14
  if: ${{ github.repository == '<%= @settings.repo_path %>' }}
15
15
  env:
16
- ruby_version: "3.4"
16
+ ruby_version: "4.0"
17
17
  runs-on: ubuntu-latest
18
18
  steps:
19
19
  - name: Install Ruby ${{ env.ruby_version }}
@@ -21,7 +21,7 @@ jobs:
21
21
  with:
22
22
  ruby-version: ${{ env.ruby_version }}
23
23
  - name: Checkout repo
24
- uses: actions/checkout@v5
24
+ uses: actions/checkout@v6
25
25
  - name: Install Toys
26
26
  run: "gem install --no-document toys"
27
27
  - name: Update open releases
@@ -23,7 +23,7 @@ jobs:
23
23
  release-perform:
24
24
  if: ${{ github.repository == '<%= @settings.repo_path %>' }}
25
25
  env:
26
- ruby_version: "3.4"
26
+ ruby_version: "4.0"
27
27
  runs-on: ubuntu-latest
28
28
  steps:
29
29
  - name: Install Ruby ${{ env.ruby_version }}
@@ -31,7 +31,7 @@ jobs:
31
31
  with:
32
32
  ruby-version: ${{ env.ruby_version }}
33
33
  - name: Checkout repo
34
- uses: actions/checkout@v5
34
+ uses: actions/checkout@v6
35
35
  - name: Install Toys
36
36
  run: "gem install --no-document toys"
37
37
  - name: Perform release
@@ -16,7 +16,7 @@ jobs:
16
16
  release-request:
17
17
  if: ${{ github.repository == '<%= @settings.repo_path %>' }}
18
18
  env:
19
- ruby_version: "3.4"
19
+ ruby_version: "4.0"
20
20
  runs-on: ubuntu-latest
21
21
  steps:
22
22
  - name: Install Ruby ${{ env.ruby_version }}
@@ -24,7 +24,7 @@ jobs:
24
24
  with:
25
25
  ruby-version: ${{ env.ruby_version }}
26
26
  - name: Checkout repo
27
- uses: actions/checkout@v5
27
+ uses: actions/checkout@v6
28
28
  - name: Install Toys
29
29
  run: "gem install --no-document toys"
30
30
  - name: Open release pull request
@@ -20,7 +20,7 @@ jobs:
20
20
  release-retry:
21
21
  if: ${{ github.repository == '<%= @settings.repo_path %>' }}
22
22
  env:
23
- ruby_version: "3.4"
23
+ ruby_version: "4.0"
24
24
  runs-on: ubuntu-latest
25
25
  steps:
26
26
  - name: Install Ruby ${{ env.ruby_version }}
@@ -28,7 +28,7 @@ jobs:
28
28
  with:
29
29
  ruby-version: ${{ env.ruby_version }}
30
30
  - name: Checkout repo
31
- uses: actions/checkout@v5
31
+ uses: actions/checkout@v6
32
32
  - name: Install Toys
33
33
  run: "gem install --no-document toys"
34
34
  - name: Retry release
@@ -23,21 +23,21 @@ module Toys
23
23
  @semver = Semver::NONE
24
24
  @change_groups = nil
25
25
  @inputs = []
26
+ @significant_shas = nil
26
27
  end
27
28
 
28
29
  ##
29
30
  # Add a commit.
30
31
  #
31
- # @param sha [String] The SHA for the commit.
32
- # @param message [String] The commit message.
32
+ # @param commit [Toys::Release::CommitInfo] The commit.
33
33
  #
34
- def add_message(sha, message)
34
+ def add_commit(commit)
35
35
  raise "ChangeSet locked" if finished?
36
- lines = message.split("\n")
36
+ lines = commit.message.split("\n")
37
37
  return if lines.empty?
38
- input = Input.new(sha)
38
+ input = Input.new(commit.sha)
39
39
  lines.each { |line| analyze_line(line, input) }
40
- @inputs << input
40
+ @inputs << input if input.significant?
41
41
  self
42
42
  end
43
43
 
@@ -52,6 +52,7 @@ module Toys
52
52
  @commit_tags.each do |tag_info|
53
53
  tag_info.all_headers.each { |header| change_groups[header] = Group.new(header) }
54
54
  end
55
+ apply_reverts
55
56
  @inputs.each do |input|
56
57
  @semver = input.semver if input.semver > @semver
57
58
  input.changes.each do |(header, change)|
@@ -60,9 +61,10 @@ module Toys
60
61
  change_groups[:breaking].add(input.breaks)
61
62
  end
62
63
  @change_groups = change_groups.values.find_all { |group| !group.empty? }
63
- if @change_groups.empty? && @semver != Semver::NONE
64
+ if @change_groups.empty? && @semver.significant?
64
65
  @change_groups << Group.new(nil).add(@no_significant_updates_notice)
65
66
  end
67
+ @significant_shas = @inputs.map(&:sha)
66
68
  @inputs = nil
67
69
  self
68
70
  end
@@ -88,12 +90,19 @@ module Toys
88
90
  end
89
91
 
90
92
  ##
91
- # @return [boolean] Whether this change set is empty.
93
+ # @return [boolean] Whether this change set is empty. Valid only after
94
+ # the change set is finished.
92
95
  #
93
96
  def empty?
94
- @change_groups.empty?
97
+ @change_groups&.empty?
95
98
  end
96
99
 
100
+ ##
101
+ # @return [Array<String>] All significant SHAs. Valid only after the
102
+ # change set is finished.
103
+ #
104
+ attr_reader :significant_shas
105
+
97
106
  ##
98
107
  # @return [Integer] The semver change.
99
108
  #
@@ -185,13 +194,22 @@ module Toys
185
194
  when /^semver-change$/i
186
195
  input.apply_semver_change(match[:content].split.first)
187
196
  when /^revert-commit$/i
188
- @inputs.delete_if { |elem| elem.sha.start_with?(match[:content].split.first) }
197
+ input.add_revert(match[:content].split.first)
189
198
  else
190
199
  tag_info = @commit_tags.find { |tag| tag.tag == match[:tag] }
191
200
  input.apply_commit(tag_info, match[:scope], match[:bang], match[:content])
192
201
  end
193
202
  end
194
203
 
204
+ def apply_reverts
205
+ reverts = []
206
+ @inputs.reverse_each do |input|
207
+ next if reverts.any? { |revert_sha| input.sha.start_with?(revert_sha) }
208
+ reverts += input.reverts
209
+ end
210
+ @inputs.delete_if { |input| reverts.any? { |revert_sha| input.sha.start_with?(revert_sha) } }
211
+ end
212
+
195
213
  ##
196
214
  # @private
197
215
  # Analyzed commit info
@@ -204,6 +222,7 @@ module Toys
204
222
  @breaks = []
205
223
  @semver = Semver::NONE
206
224
  @semver_locked = false
225
+ @reverts = []
207
226
  end
208
227
 
209
228
  attr_reader :sha
@@ -211,6 +230,12 @@ module Toys
211
230
  attr_reader :breaks
212
231
  attr_reader :semver
213
232
  attr_reader :semver_locked
233
+ attr_reader :reverts
234
+
235
+ # @private
236
+ def significant?
237
+ @semver.significant? || !reverts.empty? || !changes.empty? || !breaks.empty?
238
+ end
214
239
 
215
240
  # @private
216
241
  def apply_breaking_change(value)
@@ -245,6 +270,11 @@ module Toys
245
270
  self
246
271
  end
247
272
 
273
+ # @private
274
+ def add_revert(sha)
275
+ @reverts << sha
276
+ end
277
+
248
278
  private
249
279
 
250
280
  def normalize_description(description, delete_pr_number: false)
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toys
4
+ module Release
5
+ ##
6
+ # Represents info about a commit
7
+ #
8
+ class CommitInfo
9
+ ##
10
+ # Create a new CommitInfo
11
+ #
12
+ # @param environment_utils [Toys::Release::EnvironmentUtils]
13
+ # @param sha [String]
14
+ #
15
+ def initialize(environment_utils, sha, message: nil)
16
+ @utils = environment_utils
17
+ @sha = sha
18
+ @message = message
19
+ @parent_sha = nil
20
+ @modified_paths = nil
21
+ end
22
+
23
+ ##
24
+ # @return [String] The SHA of this commit
25
+ #
26
+ attr_reader :sha
27
+
28
+ ##
29
+ # @return [boolean] Whether this commit is valid.
30
+ #
31
+ def exist?
32
+ !message.empty?
33
+ end
34
+
35
+ ##
36
+ # @return [String] The commit message, or the empty string if this commit
37
+ # does not exist.
38
+ #
39
+ def message
40
+ @message ||= begin
41
+ git_cmd = ["git", "log", sha, "--max-count=1", "--format=%B"]
42
+ result = @utils.exec(git_cmd, out: :capture, err: :null)
43
+ result.success? ? result.captured_out.strip : ""
44
+ end
45
+ end
46
+
47
+ ##
48
+ # @return [String] The SHA of this commit's parent, for diffs, or the
49
+ # empty string if this commit does not exist.
50
+ #
51
+ def parent_sha
52
+ @parent_sha ||=
53
+ if exist?
54
+ result = @utils.exec(["git", "rev-parse", "#{sha}^"], out: :capture, err: :null)
55
+ if result.success?
56
+ result.captured_out.strip
57
+ else
58
+ @utils.capture(["git", "hash-object", "-t", "tree", "--stdin"], e: true, in: :null).strip
59
+ end
60
+ else
61
+ ""
62
+ end
63
+ end
64
+
65
+ ##
66
+ # @return [Array<String>] A list of paths modified by this commit, or the
67
+ # empty array if this commit does not exist.
68
+ #
69
+ def modified_paths
70
+ @modified_paths ||=
71
+ if exist?
72
+ git_cmd = ["git", "diff", "--name-only", "#{parent_sha}..#{sha}"]
73
+ @utils.capture(git_cmd, e: true).split("\n").sort
74
+ else
75
+ []
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -13,13 +13,13 @@ module Toys
13
13
  ##
14
14
  # Constructor
15
15
  #
16
- # @param repo_settings [Toys::Release::RepoSettings] the repo settings
16
+ # @param repository [Toys::Release::Repository] the repository
17
17
  # @param name [String] The component name
18
18
  # @param environment_utils [Toys::Release::EnvironmentUtils] env utils
19
19
  #
20
- def initialize(repo_settings, name, environment_utils)
21
- @repo_settings = repo_settings
22
- @settings = repo_settings.component_settings(name)
20
+ def initialize(repository, name, environment_utils)
21
+ @repository = repository
22
+ @settings = repository.settings.component_settings(name)
23
23
  @utils = environment_utils
24
24
  @changelog_file = ChangelogFile.new(changelog_path(from: :absolute), @utils)
25
25
  @version_rb_file = VersionRbFile.new(version_rb_path(from: :absolute), @utils, @settings.version_constant)
@@ -245,23 +245,27 @@ module Toys
245
245
  end
246
246
 
247
247
  ##
248
- # Returns a list of commit messages, since the given committish, that are
249
- # relevant to this component.
248
+ # Returns a changeset with the changes, from the given commit range, that
249
+ # are relevant to this component.
250
250
  #
251
+ # @param commits [Array<Toys::Release::CommitInfo>,nil] Commits to add.
252
+ # If not provided, uses `from` and `to` to get commits.
251
253
  # @param from [String,nil] The starting point, defaults to the last
252
- # release tag. Set to nil explicitly to use the first commit.
254
+ # release tag. Set to nil explicitly to search the full history of
255
+ # the `to` commit.
253
256
  # @param to [String] The endpoint. Defaults to HEAD.
254
- # @return [ChangeSet]
255
257
  #
256
- def make_change_set(from: :default, to: nil)
257
- to ||= "HEAD"
258
- from = latest_tag(ref: to) if from == :default
259
- commits = from ? "#{from}..#{to}" : to
258
+ # @return [Toys::Release::ChangeSet]
259
+ #
260
+ def make_change_set(commits: nil, from: :default, to: nil)
261
+ commits ||= begin
262
+ to ||= "HEAD"
263
+ from = latest_tag(ref: to) if from == :default
264
+ @repository.commit_info_sequence(from: from, to: to)
265
+ end
260
266
  changeset = ChangeSet.new(@settings)
261
- shas = @utils.capture(["git", "log", commits, "--format=%H"], e: true).split("\n")
262
- shas.reverse_each do |sha|
263
- message = touched_message(sha)
264
- changeset.add_message(sha, message) if message
267
+ commits.each do |commit|
268
+ changeset.add_commit(commit) if touched?(commit)
265
269
  end
266
270
  changeset.finish
267
271
  end
@@ -280,33 +284,20 @@ module Toys
280
284
  end
281
285
 
282
286
  ##
283
- # Checks if the given sha touches this component. If so, returns the
284
- # commit message, otherwise returns nil.
287
+ # Checks if the given commit touches this component.
285
288
  #
286
- # @return [String] if the given commit touches this component
287
- # @return [nil] if the given commit does not touch this component
289
+ # @param commit [Toys::Release::CommitInfo] A commit to check
290
+ # @return [boolean] Whether the given commit touches this component
288
291
  #
289
- def touched_message(sha)
292
+ def touched?(commit)
290
293
  dir = settings.directory
291
294
  dir = "#{dir}/" unless dir.end_with?("/")
292
295
 
293
- message = @utils.capture(["git", "log", sha, "--max-count=1", "--format=%B"], e: true)
294
- return message if dir == "./" || /(^|\n)touch-component: #{name}(\s|$)/i.match?(message)
295
-
296
- result = @utils.exec(["git", "rev-parse", "#{sha}^"], out: :capture, err: :null)
297
- parent_sha =
298
- if result.success?
299
- result.captured_out.strip
300
- else
301
- @utils.capture(["git", "hash-object", "-t", "tree", "--stdin"], in: :null).strip
302
- end
303
- files = @utils.capture(["git", "diff", "--name-only", "#{parent_sha}..#{sha}"], e: true)
304
- files.split("\n").each do |file|
305
- return message if (file.start_with?(dir) ||
306
- settings.include_globs.any? { |pattern| ::File.fnmatch?(pattern, file) }) &&
307
- settings.exclude_globs.none? { |pattern| ::File.fnmatch?(pattern, file) }
296
+ return true if dir == "./" || /(^|\n)touch-component: #{name}(\s|$)/i.match?(commit.message)
297
+ commit.modified_paths.any? do |file|
298
+ (file.start_with?(dir) || settings.include_globs.any? { |pattern| ::File.fnmatch?(pattern, file) }) &&
299
+ settings.exclude_globs.none? { |pattern| ::File.fnmatch?(pattern, file) }
308
300
  end
309
- nil
310
301
  end
311
302
 
312
303
  # @private
@@ -106,31 +106,88 @@ module Toys
106
106
  resource["merged_at"] ? true : false
107
107
  end
108
108
 
109
+ ##
110
+ # @return [String] The pull request description text
111
+ #
112
+ def description
113
+ resource["body"].to_s
114
+ end
115
+
116
+ ##
117
+ # Attempt to parse metadata from the pull request description.
118
+ #
119
+ # @return [Hash,nil] The metadata hash, or nil if not found.
120
+ #
121
+ def release_metadata
122
+ unless defined?(@release_metadata)
123
+ match = /```\n# release_metadata(?:\s[^\n]*)?\n(\{\n(?:[^\n]*\n)+\}\n)```\n/.match(description)
124
+ @release_metadata = begin
125
+ match ? ::JSON.parse(match[1]) : nil
126
+ rescue ::JSON::ParserError
127
+ nil
128
+ end
129
+ end
130
+ @release_metadata
131
+ end
132
+
133
+ ##
134
+ # The request components hash from the release metadata.
135
+ #
136
+ # @return [Hash{String=>(String,nil)},nil] The arguments, or nil if not found.
137
+ #
138
+ def requested_components
139
+ metadata = release_metadata
140
+ metadata ? metadata["requested_components"] : nil
141
+ end
142
+
143
+ ##
144
+ # The request sha from the release metadata.
145
+ #
146
+ # @return [String,nil] The SHA, or nil if not found
147
+ #
148
+ def release_request_sha
149
+ metadata = release_metadata
150
+ metadata ? metadata["request_sha"] : nil
151
+ end
152
+
109
153
  ##
110
154
  # Perform various updates to a pull request
111
155
  #
112
156
  # @param labels [String,Array<String>,nil] One or more release-related
113
157
  # labels that should be applied. All existing release-related labels
114
- # are replaced with this list. Optional; no label updates are applied
115
- # if not present.
116
- # @param state [String,nil] New pull request state. Optional; the state is
117
- # not modified if not present.
158
+ # are replaced with this list. Optional; if not present, no label
159
+ # updates are applied.
160
+ # @param state [String,nil] New pull request state. Optional; if not
161
+ # present, the state is not modified.
162
+ # @param title [String,nil] New pull request title. Optional; if not
163
+ # present, the title is not modified.
164
+ # @param body [String,nil] New pull request body. Optional; if not
165
+ # present, the body is not modified.
118
166
  # @return [self]
119
167
  #
120
- def update(labels: nil, state: nil)
121
- body = {}
122
- body[:state] = state if state && self.state != state
168
+ def update(labels: nil, state: nil, title: nil, body: nil)
169
+ content = {}
170
+ content[:state] = state if state && self.state != state
171
+ content[:body] = body if body
172
+ content[:title] = title if title
123
173
  if labels
124
174
  labels = Array(labels)
125
175
  release_labels, other_labels = self.labels.partition do |label|
126
176
  repository.release_related_label?(label)
127
177
  end
128
- body[:labels] = other_labels + labels unless release_labels.sort == labels.sort
178
+ content[:labels] = other_labels + labels unless release_labels.sort == labels.sort
129
179
  end
130
- unless body.empty?
131
- cmd = ["gh", "api", "-XPATCH", "repos/#{repository.settings.repo_path}/issues/#{number}",
132
- "--input", "-", "-H", "Accept: application/vnd.github.v3+json"]
133
- repository.utils.exec(cmd, in: [:string, ::JSON.dump(body)], out: :null, e: true)
180
+ unless content.empty?
181
+ cmd = [
182
+ "gh", "api",
183
+ "--method", "PATCH",
184
+ "repos/#{repository.settings.repo_path}/issues/#{number}",
185
+ "-H", "Accept: application/vnd.github+json",
186
+ "-H", "X-GitHub-Api-Version: 2022-11-28",
187
+ "--input", "-"
188
+ ]
189
+ # TODO: Update the resource in this object
190
+ repository.utils.exec(cmd, in: [:string, ::JSON.dump(content)], out: :null, e: true)
134
191
  end
135
192
  self
136
193
  end
@@ -142,9 +199,16 @@ module Toys
142
199
  # @return [self]
143
200
  #
144
201
  def add_comment(message)
145
- cmd = ["gh", "api", "repos/#{repository.settings.repo_path}/issues/#{number}/comments",
146
- "--input", "-", "-H", "Accept: application/vnd.github.v3+json"]
147
- repository.utils.exec(cmd, in: [:string, ::JSON.dump(body: message)], out: :null, e: true)
202
+ content = {body: message}
203
+ cmd = [
204
+ "gh", "api",
205
+ "--method", "POST",
206
+ "repos/#{repository.settings.repo_path}/issues/#{number}/comments",
207
+ "-H", "Accept: application/vnd.github+json",
208
+ "-H", "X-GitHub-Api-Version: 2022-11-28",
209
+ "--input", "-"
210
+ ]
211
+ repository.utils.exec(cmd, in: [:string, ::JSON.dump(content)], out: :null, e: true)
148
212
  self
149
213
  end
150
214
  end
@@ -644,6 +644,11 @@ module Toys
644
644
  #
645
645
  attr_reader :gh_pages_enabled
646
646
 
647
+ ##
648
+ # @return [boolean] Whether commits update existing release requests
649
+ #
650
+ attr_reader :update_existing_requests
651
+
647
652
  ##
648
653
  # @return [Array<CommitTagSettings>] The conventional commit types
649
654
  # recognized as release-triggering, along with information on the
@@ -926,6 +931,7 @@ module Toys
926
931
  @signoff_commits = info.delete("signoff_commits") ? true : false
927
932
  @gh_pages_enabled = info.delete("gh_pages_enabled") ? true : false
928
933
  @enable_release_automation = info.delete("enable_release_automation") != false
934
+ @update_existing_requests = info.delete("update_existing_requests") ? true : false
929
935
  @release_branch_prefix = info.delete("release_branch_prefix") || "release"
930
936
  @git_user_name = info.delete("git_user_name")
931
937
  @git_user_email = info.delete("git_user_email")
@@ -935,7 +941,7 @@ module Toys
935
941
  required_checks = info.delete("required_checks")
936
942
  @required_checks_regexp =
937
943
  case required_checks
938
- when false
944
+ when false, nil
939
945
  nil
940
946
  when true
941
947
  //