fastlane-plugin-wpmreleasetoolkit 12.2.0 → 12.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/buildkite_pipeline_upload_action.rb +7 -4
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_backmerge_pull_request_action.rb +42 -13
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/git_helper.rb +57 -15
- data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd7622da309b11a1d3f03e67692147361bc620cd3b9ecb0fa6d9b923cd5e8c15
|
4
|
+
data.tar.gz: 662c4964c041947dd71506cee2aeb6c01bfaf2ae35281ff41192ab1231c82201
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 891584b03637c76ea99ef7843db8639a8154565efd90e9339167f8edf40d7e24fc53c371c42f8e0de06f32fb6050010288b367920b326d9c34beec60d78fb9b4
|
7
|
+
data.tar.gz: 3e8d0bc1db3db2e76c64ed79285113d63fdad4ffcd08cc7444c741aedf62611a194c47f73ea0c35246320855e5cc3e77e302fbf789c86f3de0378adb4682261e
|
data/README.md
CHANGED
@@ -24,15 +24,17 @@ This guide also includes some tips about configuring your environment and IDE (e
|
|
24
24
|
|
25
25
|
When you need to do a new release of the `release-toolkit`, simply run `rake new_release` and follow the instructions.
|
26
26
|
|
27
|
+
> [!NOTE]
|
27
28
|
> This task will:
|
28
29
|
> - Show you the CHANGELOG/release notes it's about to use for that version
|
29
30
|
> - Deduce which version number to use according to [SemVer](https://semver.org/) rules, and ask you to confirm that version number
|
30
31
|
> - Create a `release/<x.y>` branch, update the version number in all the right places, and create a PR for those changes
|
31
32
|
|
32
|
-
Submit the PR, adding the `Releases` label to it and adding the
|
33
|
+
Submit the PR, adding the `Releases` label to it and adding the `@wordpress-mobile/apps-infrastructure` team as reviewers.
|
33
34
|
|
34
35
|
Once that PR is approved and merged, create a new GitHub Release, copy/pasting the CHANGELOG entries for that GH release's description.
|
35
36
|
|
37
|
+
> [!IMPORTANT]
|
36
38
|
> Publishing the GitHub Release will create the associated tag as well, which will trigger the CI job that will ultimately `gem push` the gem on RubyGems.
|
37
39
|
|
38
40
|
## Security
|
@@ -50,4 +52,4 @@ If you have questions about getting setup or just want to say hi, join the [Word
|
|
50
52
|
|
51
53
|
## License
|
52
54
|
|
53
|
-
Mobile Release Toolkit is an Open Source project covered by the [GNU General Public License version 2](LICENSE).
|
55
|
+
Mobile Release Toolkit is an Open Source project covered by the [GNU General Public License version 2](LICENSE).
|
data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/buildkite_pipeline_upload_action.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
module Fastlane
|
2
2
|
module Actions
|
3
3
|
class BuildkitePipelineUploadAction < Action
|
4
|
-
|
4
|
+
DEFAULT_BUILDKITE_PIPELINE_FOLDER = '.buildkite'.freeze
|
5
|
+
DEFAULT_ENV_FILE = File.join(DEFAULT_BUILDKITE_PIPELINE_FOLDER, 'shared-pipeline-vars').freeze
|
5
6
|
|
6
7
|
def self.run(params)
|
7
8
|
pipeline_file = params[:pipeline_file]
|
9
|
+
pipeline_file = File.join(DEFAULT_BUILDKITE_PIPELINE_FOLDER, pipeline_file) unless File.absolute_path?(pipeline_file)
|
8
10
|
env_file = params[:env_file]
|
9
|
-
|
11
|
+
# Both keys and values need to be passed as strings otherwise Fastlane.sh will fail to parse the command.
|
12
|
+
environment = params[:environment].to_h { |k, v| [k.to_s, v.to_s] }
|
10
13
|
|
11
14
|
UI.user_error!("Pipeline file not found: #{pipeline_file}") unless File.exist?(pipeline_file)
|
12
15
|
UI.user_error!('This action can only be called from a Buildkite CI build') unless ENV['BUILDKITE'] == 'true'
|
13
16
|
|
14
|
-
UI.message
|
17
|
+
UI.message("Adding steps from `#{pipeline_file}` to the current build")
|
15
18
|
|
16
19
|
if env_file && File.exist?(env_file)
|
17
20
|
UI.message(" - Sourcing environment file beforehand: #{env_file}")
|
@@ -31,7 +34,7 @@ module Fastlane
|
|
31
34
|
[
|
32
35
|
FastlaneCore::ConfigItem.new(
|
33
36
|
key: :pipeline_file,
|
34
|
-
description: 'The path to the YAML pipeline file to upload',
|
37
|
+
description: 'The path to the YAML pipeline file to upload. If a relative path is provided, it will be prefixed with the `.buildkite/` folder path. Absolute paths are used as-is',
|
35
38
|
optional: false,
|
36
39
|
type: String
|
37
40
|
),
|
@@ -89,23 +89,33 @@ module Fastlane
|
|
89
89
|
# @return [String] The URL of the created Pull Request, or `nil` if no PR was created.
|
90
90
|
#
|
91
91
|
def self.create_backmerge_pr(token:, repository:, title:, head_branch:, base_branch:, labels:, milestone:, reviewers:, team_reviewers:, intermediate_branch_created_callback:)
|
92
|
-
|
93
|
-
|
94
|
-
|
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.")
|
92
|
+
# Do an early pre-check to see if the PR would be valid, but only if no callback (as a callback might add new commits on intermediate branch)
|
93
|
+
if intermediate_branch_created_callback.nil? && !can_merge?(head_branch, into: base_branch)
|
94
|
+
UI.error("Nothing to merge from #{head_branch} into #{base_branch}. Skipping PR creation.")
|
96
95
|
return nil
|
97
96
|
end
|
98
97
|
|
98
|
+
# Create the intermediate branch
|
99
|
+
intermediate_branch = "merge/#{head_branch.gsub('/', '-')}-into-#{base_branch.gsub('/', '-')}"
|
100
|
+
if Fastlane::Helper::GitHelper.branch_exists_on_remote?(branch_name: intermediate_branch)
|
101
|
+
UI.important("An intermediate branch `#{intermediate_branch}` already exists on the remote. It will be deleted and GitHub will close any associated existing PR.")
|
102
|
+
Fastlane::Helper::GitHelper.delete_remote_branch_if_exists!(intermediate_branch)
|
103
|
+
end
|
104
|
+
Fastlane::Helper::GitHelper.delete_local_branch_if_exists!(intermediate_branch)
|
99
105
|
Fastlane::Helper::GitHelper.create_branch(intermediate_branch)
|
100
106
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
# Call the callback if one was provided to allow the use to add commits on the intermediate branch (e.g. solve conflicts)
|
108
|
+
unless intermediate_branch_created_callback.nil?
|
109
|
+
intermediate_branch_created_callback.call(base_branch, intermediate_branch)
|
110
|
+
# Make sure the callback block didn't switch branches
|
111
|
+
other_action.ensure_git_branch(branch: "^#{intermediate_branch}$")
|
112
|
+
|
113
|
+
# When a callback was provided, do the pre-check about valid PR _only_ at that point, in case the callback added new commits
|
114
|
+
unless can_merge?(intermediate_branch, into: base_branch)
|
115
|
+
UI.error("Nothing to merge from #{intermediate_branch} into #{base_branch}. Skipping PR creation.")
|
116
|
+
Fastlane::Helper::GitHelper.delete_local_branch_if_exists!(intermediate_branch)
|
117
|
+
return nil
|
118
|
+
end
|
109
119
|
end
|
110
120
|
|
111
121
|
other_action.push_to_git_remote(tags: false)
|
@@ -137,6 +147,23 @@ module Fastlane
|
|
137
147
|
)
|
138
148
|
end
|
139
149
|
|
150
|
+
# Determine if a `head->base` PR would be considered valid by GitHub.
|
151
|
+
#
|
152
|
+
# Note that a PR with an empty diff can still be valid (e.g. if you merge a commit and its revert)
|
153
|
+
#
|
154
|
+
# This method returns false mostly when all commits from `head` has already been merged into `base`
|
155
|
+
# and that there are no new commits to merge (in which case GitHub would refuse creating the PR)
|
156
|
+
#
|
157
|
+
# @param head [String] the head reference (commit sha or branch name) we want to merge
|
158
|
+
# @param into [String] the base reference (commit sha or branch name) we want to merge into
|
159
|
+
# @return [Boolean] true if there are commits in `head` that are not yet in `base` and a merge can happen;
|
160
|
+
# false if all commits from `head` are already in `base` and a merge would be rejected
|
161
|
+
#
|
162
|
+
def self.can_merge?(head, into:)
|
163
|
+
merge_base = Fastlane::Helper::GitHelper.find_merge_base(into, head)
|
164
|
+
!Fastlane::Helper::GitHelper.point_to_same_commit?(merge_base, head)
|
165
|
+
end
|
166
|
+
|
140
167
|
def self.description
|
141
168
|
'Creates backmerge PRs for a release branch into target branches'
|
142
169
|
end
|
@@ -200,7 +227,9 @@ module Fastlane
|
|
200
227
|
optional: true,
|
201
228
|
type: Array),
|
202
229
|
FastlaneCore::ConfigItem.new(key: :intermediate_branch_created_callback,
|
203
|
-
description: 'Callback to allow for the caller to perform operations on the intermediate branch
|
230
|
+
description: 'Callback to allow for the caller to perform operations on the intermediate branch (e.g. pushing new commits to pre-solve conflicts) before creating the PR. ' \
|
231
|
+
+ 'The callback receives two parameters: the base (target) branch for the PR and the intermediate branch name that has been created.' \
|
232
|
+
+ 'Note that if you use the callback to add new commits to the intermediate branch, you are responsible for git-pushing them too',
|
204
233
|
optional: true,
|
205
234
|
type: Proc),
|
206
235
|
Fastlane::Helper::GithubHelper.github_token_config_item,
|
@@ -113,11 +113,19 @@ module Fastlane
|
|
113
113
|
|
114
114
|
# Get the SHA of a given git ref. Typically useful to get the SHA of the current HEAD commit.
|
115
115
|
#
|
116
|
-
# @param [String]
|
116
|
+
# @param ref [String]
|
117
|
+
# The git ref (commit, branch name, 'HEAD', …) to resolve as a SHA
|
118
|
+
# @param prepend_origin_if_needed [Boolean]
|
119
|
+
# If true, will retry the rev-parse by prefixing `origin/` to the ref it it failed without it
|
117
120
|
# @return [String] The commit SHA of the ref
|
118
121
|
#
|
119
|
-
def self.get_commit_sha(ref: 'HEAD')
|
120
|
-
Git.open(Dir.pwd)
|
122
|
+
def self.get_commit_sha(ref: 'HEAD', prepend_origin_if_needed: false)
|
123
|
+
repo = Git.open(Dir.pwd)
|
124
|
+
repo.revparse(ref)
|
125
|
+
rescue Git::FailedError
|
126
|
+
raise unless prepend_origin_if_needed
|
127
|
+
|
128
|
+
repo.revparse("origin/#{ref}")
|
121
129
|
end
|
122
130
|
|
123
131
|
# Creates a tag for the given version, and optionally push it to the remote.
|
@@ -170,28 +178,36 @@ module Fastlane
|
|
170
178
|
Action.sh('git', 'fetch', '--tags')
|
171
179
|
end
|
172
180
|
|
181
|
+
# Use `git merge-base` to find as good a common ancestors as possible for a merge
|
182
|
+
#
|
183
|
+
# @param ref1 [String] The first git reference (sha1, ref name…)to find the common ancestor of
|
184
|
+
# @param ref2 [String] The second git reference (sha1, ref name…)to find the common ancestor of
|
185
|
+
# @return [String] The merge-base aka common ancestor for the 2 commits provided
|
186
|
+
# @note If a reference (e.g. branch name) can't be found locally, it will try with the same ref prefixed with `origin/`
|
187
|
+
#
|
188
|
+
def self.find_merge_base(ref1, ref2)
|
189
|
+
git_repo = Git.open(Dir.pwd)
|
190
|
+
# Resolve to shas, mostly so that we can support cases with and without `origin/` explicit prefix on branch names
|
191
|
+
ref1_sha, ref2_sha = [ref1, ref2].map { |ref| get_commit_sha(ref: ref, prepend_origin_if_needed: true) }
|
192
|
+
|
193
|
+
git_repo.merge_base(ref1_sha, ref2_sha)&.first&.sha
|
194
|
+
end
|
195
|
+
|
173
196
|
# Checks if two git references point to the same commit.
|
174
197
|
#
|
175
198
|
# @param ref1 [String] the first git reference to check.
|
176
199
|
# @param ref2 [String] the second git reference to check.
|
177
|
-
# @param remote_name [String] the name of the remote repository to use (default is 'origin').
|
178
|
-
# If nil or empty, no remote prefix will be used.
|
179
200
|
#
|
180
201
|
# @return [Boolean] true if the two references point to the same commit, false otherwise.
|
181
202
|
#
|
182
|
-
def self.point_to_same_commit?(ref1, ref2
|
183
|
-
git_repo = Git.open(Dir.pwd)
|
184
|
-
|
185
|
-
ref1_full = remote_name.to_s.empty? ? ref1 : "#{remote_name}/#{ref1}"
|
186
|
-
ref2_full = remote_name.to_s.empty? ? ref2 : "#{remote_name}/#{ref2}"
|
203
|
+
def self.point_to_same_commit?(ref1, ref2)
|
187
204
|
begin
|
188
|
-
|
189
|
-
|
205
|
+
ref1_sha = get_commit_sha(ref: ref1, prepend_origin_if_needed: true)
|
206
|
+
ref2_sha = get_commit_sha(ref: ref2, prepend_origin_if_needed: true)
|
190
207
|
rescue StandardError => e
|
191
|
-
UI.
|
192
|
-
return false
|
208
|
+
UI.user_error! "Error fetching commits for #{ref1} and/or #{ref2}: #{e.message}"
|
193
209
|
end
|
194
|
-
|
210
|
+
ref1_sha == ref2_sha
|
195
211
|
end
|
196
212
|
|
197
213
|
# Returns the current git branch, or "HEAD" if it's not checked out to any branch
|
@@ -232,6 +248,32 @@ module Fastlane
|
|
232
248
|
!Action.sh('git', 'ls-remote', '--heads', remote_name, branch_name).empty?
|
233
249
|
end
|
234
250
|
|
251
|
+
# Delete a local branch if it exists.
|
252
|
+
#
|
253
|
+
# @param [String] branch_name The name of the local branch to delete.
|
254
|
+
# @return [Boolean] true if the branch was deleted, false if not (e.g. no such local branch existed in the first place)
|
255
|
+
#
|
256
|
+
def self.delete_local_branch_if_exists!(branch_name)
|
257
|
+
git_repo = Git.open(Dir.pwd)
|
258
|
+
return false unless git_repo.is_local_branch?(branch_name)
|
259
|
+
|
260
|
+
git_repo.branch(branch_name).delete
|
261
|
+
true
|
262
|
+
end
|
263
|
+
|
264
|
+
# Delete a remote branch if it exists.
|
265
|
+
#
|
266
|
+
# @param [String] branch_name The name of the remote branch to delete.
|
267
|
+
# @param [String] remote_name The name of the remote to delete the branch from. Defaults to 'origin'
|
268
|
+
# @return [Boolean] true if the branch was deleted, false if not (e.g. no such local branch existed in the first place)
|
269
|
+
#
|
270
|
+
def self.delete_remote_branch_if_exists!(branch_name, remote_name: 'origin')
|
271
|
+
git_repo = Git.open(Dir.pwd)
|
272
|
+
return false unless git_repo.branches.any? { |b| b.remote&.name == remote_name && b.name == branch_name }
|
273
|
+
|
274
|
+
git_repo.push(remote_name, branch_name, delete: true)
|
275
|
+
end
|
276
|
+
|
235
277
|
# Checks whether a given path is ignored by Git, relying on Git's `check-ignore` under the hood.
|
236
278
|
#
|
237
279
|
# @param [String] path The path to check against `.gitignore`
|
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: 12.
|
4
|
+
version: 12.3.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-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|