Skip to content

Comments

Require PR approval for release tagging + auto-merge release PR after deploy#6243

Open
ajpallares wants to merge 12 commits intopallares/change-ci-structure-for-PRsfrom
pallares/auto-merge-release-pr
Open

Require PR approval for release tagging + auto-merge release PR after deploy#6243
ajpallares wants to merge 12 commits intopallares/change-ci-structure-for-PRsfrom
pallares/auto-merge-release-pr

Conversation

@ajpallares
Copy link
Contributor

@ajpallares ajpallares commented Feb 10, 2026

Motivation

Building on the CI restructuring of #6241, the release workflow still requires manual PR merging after deploy and does not verify that the release PR has been approved before tagging. This change automates the release PR merge via GitHub auto-merge and adds safeguards to the tagging and post-release flow.

Description

Release PR auto-merge:

  • automatic_bump now sets enable_auto_merge: true, leveraging the new plugin option (fastlane-plugin-revenuecat_internal#112) so release PRs are created with GitHub auto-merge enabled. Once required checks pass, the PR merges automatically.

PR approval check before tagging:

  • tag-release-branch now runs a new check_release_pr_approved Fastlane lane before tagging. It uses the check_pr_approved plugin action (fastlane-plugin-revenuecat_internal#111) to verify the PR is approved by an org member with write permissions. Fails immediately if not approved.

New release-or-main workflow jobs (release branches only):

  • all-tests-succeeded: intermediate gate requiring all test jobs. Replaces all-tasks-passed as the prerequisite for approve-release.
  • wait-for-release-to-finish: polls the GitHub Releases API (every 30s, up to 2h) until the release created by deploy-tag exists. Orchestrated via a new wait_for_release_to_finish Fastlane lane.
  • all-tasks-passed: final gate requiring wait-for-release-to-finish. This is the required GitHub status check — when it passes, auto-merge kicks in and merges the release PR into main.

deploy-tag workflow reordering:

  • make-release (creates the GitHub release) now runs last, after push-revenuecatui-pod, deploy-to-spm, docs-deploy, and deploy-purchase-tester. Those jobs only need the git tag, not the GitHub release.

Note

Medium Risk
Changes the release CI orchestration and gating logic (tagging/holds/status checks), which can block or prematurely advance releases if misconfigured. The new GitHub polling step also adds dependency on API auth/rate limits and could introduce timeouts.

Overview
Tightens the release pipeline by blocking release tagging unless the release PR is approved: tag-release-branch now runs fastlane run validate_pr_approved before tagging.

Automates the release PR completion path by enabling GitHub auto-merge for automatic_bump PRs (enable_auto_merge: true passed through bump) and by adding a new wait_for_release_to_finish Fastlane lane/job that polls the GitHub Releases API; release-or-main now uses all-tests-succeeded as an intermediate gate, waits for the GitHub release to exist, and only then runs the final required status check (all-tasks-passed).

Reorders the deploy-tag workflow so make-release (GitHub release creation) runs after pod/SPM/docs/purchase-tester deploy jobs, and updates naming/holds accordingly.

Written by Cursor Bugbot for commit 2678a09. This will update automatically on new commits. Configure here.

@ajpallares ajpallares requested a review from a team as a code owner February 10, 2026 16:57
@ajpallares ajpallares changed the title Require PR approval for release tagging + auto-merge release PR after… Require PR approval for release tagging + auto-merge release PR after deploy Feb 10, 2026
@claude
Copy link

claude bot commented Feb 10, 2026

Code review

Found 2 issues that need to be addressed:


Issue 1: Missing Content-Type header in get_pr_review_decision (Critical)

Location:

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "bearer #{token}"
request.body = {
query: "{ repository(owner: \"RevenueCat\", name: \"#{REPO_NAME}\") { pullRequest(number: #{pr_number}) { reviewDecision } } }"
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }

The get_pr_review_decision function sends a POST request to the GitHub GraphQL API without setting the Content-Type: application/json header.

Ruby's Net::HTTP::Post does not automatically set Content-Type when .body is assigned directly. The GitHub GraphQL API requires this header to parse the JSON request body. Without it, the API will not process the query correctly, causing .dig("data", "repository", "pullRequest", "reviewDecision") to return nil, which falls back to "NONE". This will make the check_release_pr_approved lane always report the PR as unapproved, blocking all releases.

Other API calls in this file correctly set the Content-Type header (see

# Make request
headers = {"Circle-Token": circle_token, "Content-Type": "application/json", "Accept": "application/json"}
data = {
).

Suggested fix - Add this line after line 2377:

request["Content-Type"] = "application/json"

Issue 2: Missing Content-Type header in merge_pr

Location:

request = Net::HTTP::Put.new(uri)
request["Authorization"] = "token #{token}"
request.body = { merge_method: merge_method }.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }

The merge_pr function sends a PUT request to the GitHub REST API with a JSON body but without setting Content-Type: application/json.

Without this header, the GitHub API will not parse the JSON body correctly, causing the merge_method: "squash" parameter to be ignored. The merge would either fail or default to a regular merge commit instead of the intended squash merge.

Suggested fix - Add this line after line 2394:

request["Content-Type"] = "application/json"

Both issues follow the same pattern: JSON is being sent in the request body (.to_json) but the Content-Type header is not set, which prevents the GitHub API from parsing the body correctly.

Copy link
Member

@rickvdl rickvdl left a comment

Choose a reason for hiding this comment

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

Nice work! I think this makes sense

Copy link
Contributor

@tonidero tonidero left a comment

Choose a reason for hiding this comment

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

I think if we just move to use fastlane's github_action it would be simpler? Other than that, looks good to me!

- install-rubydocker-dependencies
- run:
name: Merge release PR
command: bundle exec fastlane merge_release_pr
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder how this will work in case the branch is not up to date with main... It might not work correctly right? I guess it would fail in that case, and we would need human intervention, which is not too bad I guess, so let's try with this! 👍

ajpallares and others added 10 commits February 12, 2026 17:57
…o-merge-release-pr

# Conflicts:
#	.circleci/config.yml
- Add `all-tests-succeeded` and `wait-for-release-to-finish` jobs
- Rename summary gate to `all-tasks-passed`, requiring release completion
- Reorder deploy-tag: deployment jobs run first, `make-release` last
- Remove `merge-release-pr` job (auto-merge handles it)
- Add `approve-release` hold gate before tagging release branches
- Use `check_pr_approved` plugin action for PR approval verification
- Enable auto-merge on release PRs via `enable_auto_merge` option
- Use "Reduced Test Suite" / "Full Test Suite" naming in run-all-tests
- Rename `ci` workflow to `release-or-main`

Co-authored-by: Cursor <cursoragent@cursor.com>
…already depends on all-tests-succeeded transitively.
…o-merge-release-pr

# Conflicts:
#	.circleci/config.yml
#	fastlane/Fastfile
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

command: |
echo "Verifying that the release PR has been approved by an org member with write permissions."
echo "This check prevents tagging a release before the PR is properly reviewed."
bundle exec fastlane run validate_pr_approved
Copy link

Choose a reason for hiding this comment

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

Wrong Fastlane PR approval action name

High Severity

The new “Check Release PR is approved” step runs bundle exec fastlane run validate_pr_approved, but this identifier does not appear anywhere else in the repo and doesn’t match the described check_pr_approved/check_release_pr_approved flow. This likely makes tag-release-branch fail before tagging, blocking releases.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants