Skip to content

Add find_or_create_pull_request action#733

Merged
iangmaia merged 4 commits into
trunkfrom
add/find-or-create-pull-request
Jun 19, 2026
Merged

Add find_or_create_pull_request action#733
iangmaia merged 4 commits into
trunkfrom
add/find-or-create-pull-request

Conversation

@oguzkocer

Copy link
Copy Markdown
Contributor

What does it do?

Adds a generic action that returns the URL of the open Pull Request for a head branch, creating one only if none exists yet. Backed by a new GithubHelper#find_pull_request (list-by-head).

Useful for "rolling" automations (e.g. a daily translations or dependency-update job) that force-push the same head branch each run — GitHub auto-refreshes the existing PR's diff, so a PR only needs to be opened the first time. Token handling uses the standard github_token_config_item, and PR parameters are forwarded to create_pull_request.

Checklist before requesting a review

  • Run bundle exec rubocop to test for code style violations and recommendations.
  • Add Unit Tests (aka specs/*_spec.rb) if applicable.
  • Run bundle exec rspec to run the whole test suite and ensure all your tests pass.
  • Make sure you added an entry in the CHANGELOG.md file to describe your changes under the appropriate existing ### subsection of the existing ## Trunk section.
  • If applicable, add an entry in the MIGRATION.md file to describe how the changes will affect the migration from the previous major version and what the clients will need to change and consider.

Adds a generic action that returns the URL of the open Pull Request for a
head branch, creating one only if none exists yet. Backed by a new
GithubHelper#find_pull_request (list-by-head). Useful for rolling
automations (e.g. a daily translations job) that force-push the same head
branch each run, where GitHub auto-refreshes the existing PR's diff.
@oguzkocer oguzkocer added the enhancement New feature or request label Jun 17, 2026
@oguzkocer oguzkocer marked this pull request as ready for review June 17, 2026 14:26
@oguzkocer oguzkocer requested a review from a team as a code owner June 17, 2026 14:26
@mokagio mokagio requested a review from Copilot June 18, 2026 01:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Fastlane action to de-duplicate “rolling” pull request creation by reusing an existing open PR for a given head branch (and optionally base), backed by a new GithubHelper#find_pull_request helper and accompanying specs.

Changes:

  • Added Fastlane::Actions::FindOrCreatePullRequestAction to find an existing open PR for a head branch or create one and return its URL.
  • Added Fastlane::Helper::GithubHelper#find_pull_request that queries open PRs by qualified head (and optional base).
  • Added/updated RSpec coverage for the new helper method and action behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/github_helper_spec.rb Adds unit tests for GithubHelper#find_pull_request head qualification and filtering behavior.
spec/find_or_create_pull_request_spec.rb Adds unit tests validating “find existing PR vs create PR” behavior and parameter forwarding.
lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb Introduces #find_pull_request helper using Octokit list-by-head (and optional base).
lib/fastlane/plugin/wpmreleasetoolkit/actions/common/find_or_create_pull_request_action.rb New action orchestrating lookup then delegating to Fastlane create_pull_request when needed.
CHANGELOG.md Documents the new action/helper under Trunk “New Features”.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +46
Looks for an open Pull Request whose head is the given branch (optionally targeting a specific base),
and returns its URL if found. Otherwise, creates a new Pull Request and returns its URL.
# @param [String] repository The repository name, including the organization (e.g. `wordpress-mobile/wordpress-ios`)
# @param [String] head The head branch to look for. May be given as `branch` or as the fully-qualified `owner:branch`;
# when unqualified, it is automatically prefixed with the repository's owner.
# @param [String] base The base branch the PR should target. If nil, PRs targeting any base are considered.
- Reword the action's details: base is required (drop 'optionally targeting a
  specific base') to match the required `base` ConfigItem.
- find_pull_request YARD: mark `base` as `[String?]` since it accepts nil.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

end

it 'qualifies an unqualified head with the repository owner and forwards the base' do
expect(client).to receive(:pull_requests).with(test_repo, { state: 'open', head: 'repo-test:my-branch', base: 'trunk' })

@oguzkocer oguzkocer Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude: Leaving this as-is. These tests rely on the instance_double(Octokit::Client, pull_requests: [found_pr], …) default return, so client.pull_requests(...) returns [found_pr] and .first never hits nil (the suite is green — it would raise otherwise). This matches the existing pattern in this file, e.g. expect(client).to receive(:list_milestones) paired with an instance_double default. Adding .and_return onto the expect would also conflict with rubocop's RSpec/StubbedMock.

end

it 'uses an already-qualified head as-is and omits the base when not provided' do
expect(client).to receive(:pull_requests).with(test_repo, { state: 'open', head: 'someone:other-branch' })

@oguzkocer oguzkocer Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude: Leaving this as-is. These tests rely on the instance_double(Octokit::Client, pull_requests: [found_pr], …) default return, so client.pull_requests(...) returns [found_pr] and .first never hits nil (the suite is green — it would raise otherwise). This matches the existing pattern in this file, e.g. expect(client).to receive(:list_milestones) paired with an instance_double default. Adding .and_return onto the expect would also conflict with rubocop's RSpec/StubbedMock.

def self.run(params)
github_helper = Fastlane::Helper::GithubHelper.new(github_token: params[:github_token])

existing_pr = github_helper.find_pull_request(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api_url is used on create_pull_request but not here. I guess we'd need to change the helper for that but it probably makes sense, for consistency?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that adding api_url requires changing a shared helper used across ~14 call sites, and a behavior change for create_release_backmerge_pull_request_action which will now call the custom host for @client.user calls. That, in my opinion, requires its own PR.

Since this PR follows the existing create_release_backmerge_pull_request_action from the repo, I'd prefer to leave that to a follow up if you don't mind.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, makes sense 👍

@oguzkocer oguzkocer requested a review from iangmaia June 18, 2026 23:48
return existing_pr.html_url
end

other_action.create_pull_request(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 nit: this call supports creating drafts, we could forward a draft parameter to allow for creating a draft PR. Not a big deal and we can address it in a follow-up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in dd96bb5.

@iangmaia If that looks good, please feel free to merge the PR, so it doesn't block that PR you mentioned me on.

@iangmaia iangmaia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for implementing this, sounds like a useful addition 👍

Apologies for not already approving it yesterday but I was already at the end of my day.

Allow creating draft PRs by forwarding a draft option to the underlying
create_pull_request action.
@iangmaia iangmaia merged commit de7ff74 into trunk Jun 19, 2026
6 checks passed
@iangmaia iangmaia deleted the add/find-or-create-pull-request branch June 19, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants