fastlane-plugin-wpmreleasetoolkit 11.0.2 → 11.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_backmerge_pull_request_action.rb +215 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_localize_helper.rb +80 -21
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/git_helper.rb +26 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f9d86b44058a8ff2f28f2c56bdb81230395e36eac41f6e4d0761140f9694177
|
4
|
+
data.tar.gz: cc234c6029919a63d4d9ed2114d390bb58ad79e67f7ae1650e94b23cfac92bc9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2e86d40c624300445ddc600e19b8b16a560e86725c82344719bbbadb69ad0c1552fff4f951cdb5411d892973fa37b524b47bcc99b0d14a23bff56607d44f676
|
7
|
+
data.tar.gz: faf08e93483cced02d83d705b9cff2843e07244c708312bdf8dfb86131b2990d4e5ba94397aa71aadd8a3cb6d485da2007b5743950e15486ff81243f8a956b35
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../../helper/github_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class CreateReleaseBackmergePullRequestAction < Action
|
7
|
+
DEFAULT_BRANCH = 'trunk'.freeze
|
8
|
+
|
9
|
+
def self.run(params)
|
10
|
+
token = params[:github_token]
|
11
|
+
repository = params[:repository]
|
12
|
+
source_branch = params[:source_branch]
|
13
|
+
default_branch = params[:default_branch]
|
14
|
+
target_branches = params[:target_branches]
|
15
|
+
labels = params[:labels]
|
16
|
+
milestone_title = params[:milestone_title]
|
17
|
+
reviewers = params[:reviewers]
|
18
|
+
team_reviewers = params[:team_reviewers]
|
19
|
+
intermediate_branch_created_callback = params[:intermediate_branch_created_callback]
|
20
|
+
|
21
|
+
if target_branches.include?(source_branch)
|
22
|
+
UI.user_error!('`target_branches` must not contain `source_branch`')
|
23
|
+
end
|
24
|
+
|
25
|
+
github_helper = Fastlane::Helper::GithubHelper.new(github_token: params[:github_token])
|
26
|
+
target_milestone = milestone_title.nil? ? nil : github_helper.get_milestone(repository, milestone_title)
|
27
|
+
|
28
|
+
final_target_branches = if target_branches.empty?
|
29
|
+
unless source_branch.start_with?('release/')
|
30
|
+
UI.user_error!('`source_branch` must start with `release/`')
|
31
|
+
end
|
32
|
+
|
33
|
+
determine_target_branches(source_release_version: source_branch.delete('release/'), default_branch: default_branch)
|
34
|
+
else
|
35
|
+
target_branches
|
36
|
+
end
|
37
|
+
|
38
|
+
final_target_branches.map do |target_branch|
|
39
|
+
Fastlane::Helper::GitHelper.checkout_and_pull(source_branch)
|
40
|
+
|
41
|
+
create_backmerge_pr(
|
42
|
+
token: token,
|
43
|
+
repository: repository,
|
44
|
+
title: "Merge #{source_branch} into #{target_branch}",
|
45
|
+
head_branch: source_branch,
|
46
|
+
base_branch: target_branch,
|
47
|
+
labels: labels,
|
48
|
+
milestone: target_milestone&.number,
|
49
|
+
reviewers: reviewers,
|
50
|
+
team_reviewers: team_reviewers,
|
51
|
+
intermediate_branch_created_callback: intermediate_branch_created_callback
|
52
|
+
)
|
53
|
+
end.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
# Determines the target branches for a release version.
|
57
|
+
#
|
58
|
+
# @param source_release_version [String] the source release version to compare against other release branches.
|
59
|
+
# @param default_branch [String] the default branch to use if no target branches are found.
|
60
|
+
# @return [Array<String>] the list of target branches greater than the release version.
|
61
|
+
def self.determine_target_branches(source_release_version:, default_branch:)
|
62
|
+
release_branches = Actions.sh('git', 'branch', '-r', '-l', 'origin/release/*').strip.split("\n")
|
63
|
+
|
64
|
+
all_release_branches_versions = release_branches
|
65
|
+
.map { |branch| branch.match(%r{origin/release/([0-9.]*)})&.captures&.first }
|
66
|
+
.compact
|
67
|
+
|
68
|
+
target_branches = all_release_branches_versions.select { |branch| Gem::Version.new(branch) > Gem::Version.new(source_release_version) }
|
69
|
+
.map { |v| "release/#{v}" }
|
70
|
+
target_branches = [default_branch] if target_branches.empty?
|
71
|
+
|
72
|
+
target_branches
|
73
|
+
end
|
74
|
+
|
75
|
+
# Creates a backmerge pull request using the `create_pull_request` Fastlane Action.
|
76
|
+
#
|
77
|
+
# @param token [String] the GitHub token for authentication.
|
78
|
+
# @param repository [String] the repository where the pull request will be created.
|
79
|
+
# @param title [String] the title of the pull request.
|
80
|
+
# @param head_branch [String] the source branch for the pull request.
|
81
|
+
# @param base_branch [String] the target branch for the pull request.
|
82
|
+
# @param labels [Array<String>] the labels to add to the pull request.
|
83
|
+
# @param milestone [String] the milestone to associate with the pull request.
|
84
|
+
# @param reviewers [Array<String>] the individual reviewers for the pull request.
|
85
|
+
# @param team_reviewers [Array<String>] the team reviewers for the pull request.
|
86
|
+
# @param intermediate_branch_created_callback [Proc] A callback to call after having created the intermediate branch
|
87
|
+
# to allow the caller to e.g. add new commits on it before the PR is created. The callback takes two parameters: the base branch and the intermediate branch
|
88
|
+
#
|
89
|
+
# @return [String] The URL of the created Pull Request, or `nil` if no PR was created.
|
90
|
+
#
|
91
|
+
def self.create_backmerge_pr(token:, repository:, title:, head_branch:, base_branch:, labels:, milestone:, reviewers:, team_reviewers:, intermediate_branch_created_callback:)
|
92
|
+
intermediate_branch = "merge/#{head_branch.gsub('/', '-')}-into-#{base_branch.gsub('/', '-')}"
|
93
|
+
|
94
|
+
if Fastlane::Helper::GitHelper.branch_exists_on_remote?(branch_name: intermediate_branch)
|
95
|
+
UI.user_error!("The intermediate branch `#{intermediate_branch}` already exists. Please check if there is an existing Pull Request that needs to be merged or closed first, or delete the branch.")
|
96
|
+
return nil
|
97
|
+
end
|
98
|
+
|
99
|
+
Fastlane::Helper::GitHelper.create_branch(intermediate_branch)
|
100
|
+
|
101
|
+
intermediate_branch_created_callback&.call(base_branch, intermediate_branch)
|
102
|
+
|
103
|
+
# if there's a callback, make sure it didn't switch branches
|
104
|
+
other_action.ensure_git_branch(branch: "^#{intermediate_branch}/") unless intermediate_branch_created_callback.nil?
|
105
|
+
|
106
|
+
if Fastlane::Helper::GitHelper.point_to_same_commit?(base_branch, head_branch)
|
107
|
+
UI.error("No differences between #{head_branch} and #{base_branch}. Skipping PR creation.")
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
|
111
|
+
other_action.push_to_git_remote(tags: false)
|
112
|
+
|
113
|
+
pr_body = <<~BODY
|
114
|
+
Merging `#{head_branch}` into `#{base_branch}`.
|
115
|
+
|
116
|
+
Via intermediate branch `#{intermediate_branch}`, to help fix conflicts if any:
|
117
|
+
```
|
118
|
+
#{head_branch.rjust(40)} ----o-- - - -
|
119
|
+
#{' ' * 40} \\
|
120
|
+
#{intermediate_branch.rjust(40)} `---.
|
121
|
+
#{' ' * 40} \\
|
122
|
+
#{base_branch.rjust(40)} ------------x- - -
|
123
|
+
```
|
124
|
+
BODY
|
125
|
+
|
126
|
+
other_action.create_pull_request(
|
127
|
+
api_token: token,
|
128
|
+
repo: repository,
|
129
|
+
title: title,
|
130
|
+
body: pr_body,
|
131
|
+
head: intermediate_branch,
|
132
|
+
base: base_branch,
|
133
|
+
labels: labels,
|
134
|
+
milestone: milestone,
|
135
|
+
reviewers: reviewers,
|
136
|
+
team_reviewers: team_reviewers
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.description
|
141
|
+
'Creates backmerge PRs for a release branch into target branches'
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.authors
|
145
|
+
['Automattic']
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.return_type
|
149
|
+
:array_of_strings
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.return_value
|
153
|
+
'The list of the created backmerge Pull Request URLs'
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.details
|
157
|
+
<<~DETAILS
|
158
|
+
This action creates backmerge Pull Requests from a release branch into one or more target branches.
|
159
|
+
|
160
|
+
It can be used to ensure that changes from a release branch are merged back into other branches, such as newer release branches or the main development branch (e.g., `trunk`).
|
161
|
+
DETAILS
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.available_options
|
165
|
+
[
|
166
|
+
FastlaneCore::ConfigItem.new(key: :repository,
|
167
|
+
env_name: 'GHHELPER_REPOSITORY',
|
168
|
+
description: 'The remote path of the GH repository on which we work',
|
169
|
+
optional: false,
|
170
|
+
type: String),
|
171
|
+
FastlaneCore::ConfigItem.new(key: :source_branch,
|
172
|
+
description: 'The source branch to create a backmerge PR from, in the format `release/x.y.z`',
|
173
|
+
optional: false,
|
174
|
+
type: String),
|
175
|
+
FastlaneCore::ConfigItem.new(key: :default_branch,
|
176
|
+
description: 'The default branch to target if no newer release branches exist',
|
177
|
+
optional: true,
|
178
|
+
default_value: DEFAULT_BRANCH,
|
179
|
+
type: String),
|
180
|
+
FastlaneCore::ConfigItem.new(key: :target_branches,
|
181
|
+
description: 'Array of target branches for the backmerge. If empty, the action will determine target branches by finding all `release/x.y.z` branches with a `x.y.z` version greater than the version in source branch\'s name. If none are found, it will target `default_branch`', # rubocop:disable Layout/LineLength
|
182
|
+
optional: true,
|
183
|
+
default_value: [],
|
184
|
+
type: Array),
|
185
|
+
FastlaneCore::ConfigItem.new(key: :labels,
|
186
|
+
description: 'The labels that should be assigned to the backmerge PRs',
|
187
|
+
optional: true,
|
188
|
+
default_value: [],
|
189
|
+
type: Array),
|
190
|
+
FastlaneCore::ConfigItem.new(key: :milestone_title,
|
191
|
+
description: 'The title of the milestone to assign to the created PRs',
|
192
|
+
optional: true,
|
193
|
+
type: String),
|
194
|
+
FastlaneCore::ConfigItem.new(key: :reviewers,
|
195
|
+
description: 'An array of GitHub users that will be assigned to the pull request',
|
196
|
+
optional: true,
|
197
|
+
type: Array),
|
198
|
+
FastlaneCore::ConfigItem.new(key: :team_reviewers,
|
199
|
+
description: 'An array of GitHub team slugs that will be assigned to the pull request',
|
200
|
+
optional: true,
|
201
|
+
type: Array),
|
202
|
+
FastlaneCore::ConfigItem.new(key: :intermediate_branch_created_callback,
|
203
|
+
description: 'Callback to allow for the caller to perform operations on the intermediate branch before pushing. The call back receives two parameters: the base (target) branch for the PR and the intermediate branch name',
|
204
|
+
optional: true,
|
205
|
+
type: Proc),
|
206
|
+
Fastlane::Helper::GithubHelper.github_token_config_item,
|
207
|
+
]
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.is_supported?(platform)
|
211
|
+
true
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -152,6 +152,13 @@ module Fastlane
|
|
152
152
|
(added_count + updated_count) != 0
|
153
153
|
end
|
154
154
|
|
155
|
+
########
|
156
|
+
# @!group Verify diff of library vs main strings matches
|
157
|
+
#
|
158
|
+
# @note This set of methods is used by `an_validate_lib_strings_action`
|
159
|
+
# (which doesn't seem to be used by any of our Android projects nowadays?)
|
160
|
+
########
|
161
|
+
|
155
162
|
def self.verify_diff(diff_string, main_strings, lib_strings, library)
|
156
163
|
return unless diff_string.start_with?('name=')
|
157
164
|
|
@@ -198,6 +205,8 @@ module Fastlane
|
|
198
205
|
end
|
199
206
|
end
|
200
207
|
|
208
|
+
# @!endgroup
|
209
|
+
|
201
210
|
########
|
202
211
|
# @!group Downloading translations from GlotPress
|
203
212
|
########
|
@@ -223,7 +232,7 @@ module Fastlane
|
|
223
232
|
#
|
224
233
|
# @param [String] res_dir The relative path to the `…/src/main/res` directory.
|
225
234
|
# @param [String] glotpress_project_url The base URL to the glotpress project to download the strings from.
|
226
|
-
# @param [Hash{
|
235
|
+
# @param [Hash{Symbol=>String}, Array] glotpress_filters
|
227
236
|
# The filters to apply when exporting strings from GlotPress.
|
228
237
|
# Typical examples include `{ status: 'current' }` or `{ status: 'review' }`.
|
229
238
|
# If an array of Hashes is provided instead of a single Hash, this method will perform as many
|
@@ -235,10 +244,8 @@ module Fastlane
|
|
235
244
|
def self.download_from_glotpress(res_dir:, glotpress_project_url:, locales_map:, glotpress_filters: { status: 'current' })
|
236
245
|
glotpress_filters = [glotpress_filters] unless glotpress_filters.is_a?(Array)
|
237
246
|
|
238
|
-
attributes_to_copy = %w[formatted] # Attributes that we want to replicate into translated `string.xml` files
|
239
247
|
orig_file = File.join(res_dir, 'values', 'strings.xml')
|
240
248
|
orig_xml = File.open(orig_file) { |f| Nokogiri::XML(f, nil, Encoding::UTF_8.to_s) }
|
241
|
-
orig_attributes = orig_xml.xpath('//string').to_h { |tag| [tag['name'], tag.attributes.select { |k, _| attributes_to_copy.include?(k) }] }
|
242
249
|
|
243
250
|
locales_map.each do |lang_codes|
|
244
251
|
all_xml_documents = glotpress_filters.map do |filters|
|
@@ -250,13 +257,7 @@ module Fastlane
|
|
250
257
|
# Merge all XMLs together
|
251
258
|
merged_xml = merge_xml_documents(all_xml_documents)
|
252
259
|
|
253
|
-
|
254
|
-
merged_xml.xpath('//string').each do |string_tag|
|
255
|
-
apply_substitutions(string_tag)
|
256
|
-
orig_attributes[string_tag['name']]&.each { |k, v| string_tag[k] = v }
|
257
|
-
quick_lint(string_tag, lang_codes[:android])
|
258
|
-
end
|
259
|
-
merged_xml.xpath('//string-array/item').each { |item_tag| apply_substitutions(item_tag) }
|
260
|
+
post_process_xml!(merged_xml, locale_code: lang_codes[:android], original_xml: orig_xml)
|
260
261
|
|
261
262
|
# Save
|
262
263
|
lang_dir = File.join(res_dir, "values-#{lang_codes[:android]}")
|
@@ -266,8 +267,10 @@ module Fastlane
|
|
266
267
|
end
|
267
268
|
end
|
268
269
|
|
270
|
+
# @!endgroup
|
271
|
+
|
269
272
|
#####################
|
270
|
-
# Private Helpers
|
273
|
+
# @!group Private Helpers
|
271
274
|
#####################
|
272
275
|
|
273
276
|
# Downloads the export from GlotPress for a given locale and given filters
|
@@ -276,7 +279,7 @@ module Fastlane
|
|
276
279
|
# @param [String] locale The GlotPress locale code to download strings for.
|
277
280
|
# @param [Hash{Symbol=>String}] filters The hash of filters to apply when exporting from GlotPress.
|
278
281
|
# Typical examples include `{ status: 'current' }` or `{ status: 'review' }`.
|
279
|
-
# @return [Nokogiri::XML] the download XML document, parsed as a Nokogiri::XML object
|
282
|
+
# @return [Nokogiri::XML::Document] the download XML document, parsed as a Nokogiri::XML object
|
280
283
|
#
|
281
284
|
def self.download_glotpress_export_file(project_url:, locale:, filters:)
|
282
285
|
query_params = filters.transform_keys { |k| "filters[#{k}]" }.merge(format: 'android')
|
@@ -297,6 +300,9 @@ module Fastlane
|
|
297
300
|
|
298
301
|
# Merge multiple Nokogiri::XML `strings.xml` documents together
|
299
302
|
#
|
303
|
+
# Used especially when we provided multiple GlotPress filters to `download_from_glotpress`,
|
304
|
+
# as in this case we'd trigger one export per filter, then merge the result in a single XML
|
305
|
+
#
|
300
306
|
# @param [Array<Nokogiri::XML::Document>] all_xmls Array of the Nokogiri XML documents to merge together
|
301
307
|
# @return [Nokogiri::XML::Document] The merged document.
|
302
308
|
#
|
@@ -323,11 +329,53 @@ module Fastlane
|
|
323
329
|
end
|
324
330
|
private_class_method :merge_xml_documents
|
325
331
|
|
326
|
-
#
|
332
|
+
# Process a downloaded XML (in-place), to apply the following
|
333
|
+
# - replicate attributes from the nodes of the original XML (`translatable`, `tools:ignore`, …) to the translated XML
|
334
|
+
# - text substitutions for common special characters
|
335
|
+
# - quick-lint string by searching for common issue patterns (using `%%` in a `formatted=false` string, etc)
|
336
|
+
#
|
337
|
+
# @param [Nokogiri::XML::Document] translated_xml The downloaded XML to post-process
|
338
|
+
# @param [String] locale_code The android locale code associated with the translated_xml
|
339
|
+
# @param [Nokogiri::XML::Document] original_xml The original `values/strings.xml` to use as reference
|
340
|
+
#
|
341
|
+
def self.post_process_xml!(translated_xml, locale_code:, original_xml:)
|
342
|
+
copy_orig_attributes = lambda do |node, xpath|
|
343
|
+
orig_attributes = original_xml.xpath(xpath)&.first&.attribute_nodes&.to_h do |attr|
|
344
|
+
[[attr.namespace&.prefix, attr.name].compact.join(':'), attr.value]
|
345
|
+
end
|
346
|
+
orig_attributes&.each { |k, v| node[k] = v unless k == 'name' }
|
347
|
+
end
|
348
|
+
|
349
|
+
# 1. Replicate namespaces on the document (especially `xmlns:tools` if present)
|
350
|
+
original_xml.namespaces.each { |k, v| translated_xml.root&.add_namespace(k.delete_prefix('xmlns:'), v) }
|
351
|
+
# 2. Replicate attributes on any node with `@name` attribute (`string`, `string-array`, `plurals`)
|
352
|
+
translated_xml.xpath('//*[@name]').each do |node|
|
353
|
+
copy_orig_attributes.call(node, "//#{node.name}[@name = '#{node['name']}']")
|
354
|
+
end
|
355
|
+
# 3. Process copies for `string` nodes
|
356
|
+
translated_xml.xpath('//string[@name]').each do |string_node|
|
357
|
+
apply_substitutions!(string_node)
|
358
|
+
quick_lint(string_node, locale_code)
|
359
|
+
end
|
360
|
+
# 4. Process copies for `string-array/item` nodes
|
361
|
+
translated_xml.xpath('//string-array[@name]/item').each do |item_node|
|
362
|
+
apply_substitutions!(item_node)
|
363
|
+
quick_lint(item_node, locale_code)
|
364
|
+
end
|
365
|
+
# 5. Replicate attributes + Process copies for `plurals/item` nodes
|
366
|
+
translated_xml.xpath('//plurals[@name]/item[@quantity]').each do |item_node|
|
367
|
+
copy_orig_attributes.call(item_node, "//plurals[@name = '#{item_node.parent['name']}']/item[@quantity = '#{item_node['quantity']}']")
|
368
|
+
apply_substitutions!(item_node)
|
369
|
+
quick_lint(item_node, locale_code)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
private_class_method :post_process_xml!
|
373
|
+
|
374
|
+
# Apply some common text substitutions to tag contents, like `... => …` or en-dash instead of regular dash for ranges of numbers
|
327
375
|
#
|
328
376
|
# @param [Nokogiri::XML::Node] tag The XML tag/node to apply substitutions to
|
329
377
|
#
|
330
|
-
def self.apply_substitutions(tag)
|
378
|
+
def self.apply_substitutions!(tag)
|
331
379
|
tag.content = tag.content.gsub('...', '…')
|
332
380
|
|
333
381
|
# Typography en-dash
|
@@ -339,17 +387,28 @@ module Fastlane
|
|
339
387
|
is_negative_number ? str : "#{match[1]}\u{2013}#{match[2]}"
|
340
388
|
end
|
341
389
|
end
|
342
|
-
private_class_method :apply_substitutions
|
390
|
+
private_class_method :apply_substitutions!
|
343
391
|
|
344
|
-
# Perform some quick basic checks about an individual `<string>` tag and print warnings accordingly
|
392
|
+
# Perform some quick basic checks about an individual `<string>` tag and print warnings accordingly:
|
393
|
+
# - detect the use of `%%` in the string even if `formatted=false` is set
|
394
|
+
# - detect the presence of `\@string/` in translated XML, which suggests the original key that referenced `@string/…` did not set `translatable=false`
|
395
|
+
# and thus that `@string/…` copy was sent to GlotPress for translation, then escaped during exporting it back.
|
345
396
|
#
|
346
|
-
# @param [Nokogiri::XML::Node]
|
397
|
+
# @param [Nokogiri::XML::Node] node The XML tag/node to check the content of
|
347
398
|
# @param [String] lang The language we are currently processing. Used for providing context during logging / warning message
|
348
399
|
#
|
349
|
-
def self.quick_lint(
|
350
|
-
|
351
|
-
|
352
|
-
|
400
|
+
def self.quick_lint(node, lang)
|
401
|
+
named_node = node.has_attribute?('name') ? node : node.parent
|
402
|
+
if named_node['formatted'] == 'false' && node.content.include?('%%')
|
403
|
+
UI.important "Warning: [#{lang}] translation for '#{named_node['name']}' has attribute formatted=false, but still contains escaped '%%' in translation."
|
404
|
+
end
|
405
|
+
# rubocop:disable Style/GuardClause
|
406
|
+
if node.content.include?('\\@string/')
|
407
|
+
UI.important "Warning: [#{lang}] exported translation for '#{named_node['name']}' contains `\\@string/`. This is a sign that this entry was not marked as `translatable=false` " \
|
408
|
+
+ 'in the original `values/strings.xml`, and was thus sent to GlotPress, which added the backslash when exporting it back.'
|
409
|
+
node.content = node.content.gsub('\\@string/', '@string/')
|
410
|
+
end
|
411
|
+
# rubocop:enable Style/GuardClause
|
353
412
|
end
|
354
413
|
private_class_method :quick_lint
|
355
414
|
|
@@ -179,6 +179,21 @@ module Fastlane
|
|
179
179
|
Action.sh('git', 'fetch', '--tags')
|
180
180
|
end
|
181
181
|
|
182
|
+
# Checks if two git references point to the same commit.
|
183
|
+
#
|
184
|
+
# @param ref1 [String] the first git reference to check.
|
185
|
+
# @param ref2 [String] the second git reference to check.
|
186
|
+
#
|
187
|
+
# @return [Boolean] true if the two references point to the same commit, false otherwise.
|
188
|
+
#
|
189
|
+
def self.point_to_same_commit?(ref1, ref2)
|
190
|
+
git_repo = Git.open(Dir.pwd)
|
191
|
+
ref1_commit = git_repo.gcommit(ref1)
|
192
|
+
ref2_commit = git_repo.gcommit(ref2)
|
193
|
+
|
194
|
+
ref1_commit.sha == ref2_commit.sha
|
195
|
+
end
|
196
|
+
|
182
197
|
# Returns the current git branch, or "HEAD" if it's not checked out to any branch
|
183
198
|
# Can NOT be replaced using the environment variables such as `GIT_BRANCH` or `BUILDKITE_BRANCH`
|
184
199
|
#
|
@@ -206,6 +221,17 @@ module Fastlane
|
|
206
221
|
!Action.sh('git', 'branch', '--list', branch_name).empty?
|
207
222
|
end
|
208
223
|
|
224
|
+
# Checks if a branch exists on the repository's remote.
|
225
|
+
#
|
226
|
+
# @param branch_name [String] the name of the branch to check.
|
227
|
+
# @param remote_name [String] the name of the remote repository (default is 'origin').
|
228
|
+
#
|
229
|
+
# @return [Boolean] true if the branch exists on remote, false otherwise.
|
230
|
+
#
|
231
|
+
def self.branch_exists_on_remote?(branch_name:, remote_name: 'origin')
|
232
|
+
!Action.sh('git', 'ls-remote', '--heads', remote_name, branch_name).empty?
|
233
|
+
end
|
234
|
+
|
209
235
|
# Ensure that we are on the expected branch, and abort if not.
|
210
236
|
#
|
211
237
|
# @param [String] branch_name The name of the branch we expect to be on
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-wpmreleasetoolkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 11.0
|
4
|
+
version: 11.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Automattic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -449,6 +449,7 @@ files:
|
|
449
449
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/copy_branch_protection_action.rb
|
450
450
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_new_milestone_action.rb
|
451
451
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_action.rb
|
452
|
+
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_backmerge_pull_request_action.rb
|
452
453
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/extract_release_notes_for_version_action.rb
|
453
454
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/find_previous_tag.rb
|
454
455
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/common/firebase_login.rb
|