fastlane-plugin-wpmreleasetoolkit 12.2.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24ece3855d069cb67f8e0a3eca97e11f14af1361ce2c00084289a21b23b99b10
4
- data.tar.gz: 7fda68ae30e60082db9276f89649dcea58d279be623f1ecd6ea96eddf47394cc
3
+ metadata.gz: bd7622da309b11a1d3f03e67692147361bc620cd3b9ecb0fa6d9b923cd5e8c15
4
+ data.tar.gz: 662c4964c041947dd71506cee2aeb6c01bfaf2ae35281ff41192ab1231c82201
5
5
  SHA512:
6
- metadata.gz: 351386b21f54221ebd0b821caaa9bf1b3a2584c4d14d292e4d5a607ab1ef421443df685d25c464da00dc9a6d5abe7b4934a670afa092b9a04776f504f457eba6
7
- data.tar.gz: 5ac9f250c4baef6cab62e214b94ead03fd6ecd5c5618a37f62ed230963c34c7d04951db78b3382e4d0abfa8510d1a571e8a12ca8d0df42d814d5cbe9a51c7679
6
+ metadata.gz: 891584b03637c76ea99ef7843db8639a8154565efd90e9339167f8edf40d7e24fc53c371c42f8e0de06f32fb6050010288b367920b326d9c34beec60d78fb9b4
7
+ data.tar.gz: 3e8d0bc1db3db2e76c64ed79285113d63fdad4ffcd08cc7444c741aedf62611a194c47f73ea0c35246320855e5cc3e77e302fbf789c86f3de0378adb4682261e
@@ -1,17 +1,20 @@
1
1
  module Fastlane
2
2
  module Actions
3
3
  class BuildkitePipelineUploadAction < Action
4
- DEFAULT_ENV_FILE = File.join('.buildkite', 'shared-pipeline-vars').freeze
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
- environment = params[:environment]
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 "Adding steps from `#{pipeline_file}` to the current build"
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,24 +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
- intermediate_branch = "merge/#{head_branch.gsub('/', '-')}-into-#{base_branch.gsub('/', '-')}"
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.")
95
+ return nil
96
+ end
93
97
 
98
+ # Create the intermediate branch
99
+ intermediate_branch = "merge/#{head_branch.gsub('/', '-')}-into-#{base_branch.gsub('/', '-')}"
94
100
  if Fastlane::Helper::GitHelper.branch_exists_on_remote?(branch_name: intermediate_branch)
95
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.")
96
102
  Fastlane::Helper::GitHelper.delete_remote_branch_if_exists!(intermediate_branch)
97
103
  end
98
-
99
104
  Fastlane::Helper::GitHelper.delete_local_branch_if_exists!(intermediate_branch)
100
105
  Fastlane::Helper::GitHelper.create_branch(intermediate_branch)
101
106
 
102
- intermediate_branch_created_callback&.call(base_branch, intermediate_branch)
103
-
104
- # if there's a callback, make sure it didn't switch branches
105
- other_action.ensure_git_branch(branch: "^#{intermediate_branch}/") unless intermediate_branch_created_callback.nil?
106
-
107
- if Fastlane::Helper::GitHelper.point_to_same_commit?(base_branch, head_branch)
108
- UI.error("No differences between #{head_branch} and #{base_branch}. Skipping PR creation.")
109
- return nil
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
110
119
  end
111
120
 
112
121
  other_action.push_to_git_remote(tags: false)
@@ -138,6 +147,23 @@ module Fastlane
138
147
  )
139
148
  end
140
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
+
141
167
  def self.description
142
168
  'Creates backmerge PRs for a release branch into target branches'
143
169
  end
@@ -201,7 +227,9 @@ module Fastlane
201
227
  optional: true,
202
228
  type: Array),
203
229
  FastlaneCore::ConfigItem.new(key: :intermediate_branch_created_callback,
204
- 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',
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',
205
233
  optional: true,
206
234
  type: Proc),
207
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] ref The git ref (commit, branch name, 'HEAD', …) to resolve as a SHA
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).revparse(ref)
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, remote_name: 'origin')
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
- ref1_commit = git_repo.gcommit(ref1_full)
189
- ref2_commit = git_repo.gcommit(ref2_full)
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.error "Error fetching commits for #{ref1_full} and #{ref2_full}: #{e.message}"
192
- return false
208
+ UI.user_error! "Error fetching commits for #{ref1} and/or #{ref2}: #{e.message}"
193
209
  end
194
- ref1_commit.sha == ref2_commit.sha
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Fastlane
4
4
  module Wpmreleasetoolkit
5
- VERSION = '12.2.1'
5
+ VERSION = '12.3.0'
6
6
  end
7
7
  end
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.2.1
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-10-18 00:00:00.000000000 Z
11
+ date: 2024-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport