mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-09 22:35:56 +05:45
ci: merge gate that tightens once the full suite is approved (#8235)
* ci: post a merge gate status that tightens once the full suite is approved Adds a ci/all-tests-gate commit status driven from CircleCI. A no-requires job posts success at pipeline start, approving the full-suite hold flips it to pending, and all-tasks-passed posts success again once every full job is green. Release pipelines post it from all-tests-succeeded so release PRs are not blocked once the context is required. The reduced suite needs no gate of its own: its jobs are already required individually. * test: find the merge gate by its instance name all-tasks-passed is now an instance of the parameterized post-gate-status job, so the workflow entry is keyed by the job name and carries name:. * ci: never post the default gate success once the full suite is requested full-suite-not-requested waits for the reduced suite and checks the hold first: approved means halt without posting, so the gate goes from unreported straight to pending; anything but on_hold fails the job rather than posting success. all-tasks-passed reaches the reduced suite through full-suite-started, so it keeps a single list, and the test guards the list that gates normal PRs. * ci: retry the gate status post A failed POST leaves the gate at its previous value: green if the pending post fails, stuck if the final success post fails. Retrying transient errors narrows both. --retry-all-errors is not used: the cimg/base curl predates it. * ci: mark the merge gate pending when the bot approves the full suite The bare @RCGitBot please test comment is the usual way to request the full suite. Posting pending from the action right after a successful approval closes the window on that path; a re-comment on an already approved hold posts nothing. Manual approvals in the CircleCI UI keep the window of one container start. * ci: pin the gate's ordering in a test and trim the fan-in list Asserts the state of each gate instance and the requires edges that keep pending after the default success and the final success last. Drops the two reduced-suite jobs all-tasks-passed still listed directly, and lets the hold check log a curl failure instead of a bare exit code.
This commit is contained in:
1 parent
0ab6c0f032
commit
87417b48b2
3 files changed
+104
-34
No files matched your search
@@ -2453,23 +2453,49 @@ jobs:
|
||||
name: Trigger RC App Pipeline
|
||||
command: bundle exec fastlane trigger_bump_sdk_in_rc_mobile_app
|
||||
|
||||
all-tests-succeeded:
|
||||
post-gate-status:
|
||||
parameters:
|
||||
state:
|
||||
type: enum
|
||||
enum: [success, pending]
|
||||
unless_full_suite_approved:
|
||||
type: boolean
|
||||
default: false
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
resource_class: small
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.unless_full_suite_approved >>
|
||||
steps:
|
||||
- run:
|
||||
name: Halt if approve-full-tests was already approved
|
||||
command: |
|
||||
approval=$(curl --fail --silent --show-error --max-time 30 --retry 5 \
|
||||
-H "Circle-Token: ${CIRCLECI_API_TOKEN}" \
|
||||
"https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/job" \
|
||||
| jq -r '.items[] | select(.name == "approve-full-tests") | .status')
|
||||
case "$approval" in
|
||||
success)
|
||||
echo "Full suite already requested, leaving the gate to it"
|
||||
circleci-agent step halt
|
||||
;;
|
||||
on_hold) ;;
|
||||
*)
|
||||
echo "Unexpected approve-full-tests status '${approval}', not posting"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
- run:
|
||||
name: All tests succeeded
|
||||
command: echo "All tests succeeded"
|
||||
|
||||
all-tasks-passed:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
resource_class: small
|
||||
steps:
|
||||
- run:
|
||||
name: All tasks passed
|
||||
command: echo "All tasks passed"
|
||||
name: Post ci/all-tests-gate status (<< parameters.state >>)
|
||||
environment:
|
||||
GATE_STATE: << parameters.state >>
|
||||
command: |
|
||||
curl --fail --silent --show-error --output /dev/null --retry 5 \
|
||||
-X POST "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/statuses/${CIRCLE_SHA1}" \
|
||||
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-d "{\"state\":\"${GATE_STATE}\",\"context\":\"ci/all-tests-gate\",\"target_url\":\"${CIRCLE_BUILD_URL}\"}"
|
||||
|
||||
workflows:
|
||||
record-performance-baselines:
|
||||
@@ -2585,12 +2611,38 @@ workflows:
|
||||
- revenuecat-ads-tests:
|
||||
context:
|
||||
- slack-secrets
|
||||
- post-gate-status:
|
||||
name: full-suite-not-requested
|
||||
state: success
|
||||
unless_full_suite_approved: true
|
||||
requires:
|
||||
- performance-tests
|
||||
- performance-automation-tests
|
||||
- lint
|
||||
- check-api-changes
|
||||
- run-test-ios-27
|
||||
- build-samplecat
|
||||
- build-purchase-tester
|
||||
- pod-lib-lint
|
||||
- run-revenuecat-ui-ios-27
|
||||
- run-revenuecat-ui-ios-26
|
||||
- emerge_purchases_ui_snapshot_tests
|
||||
- binary_size_analysis
|
||||
- build-tv-watch-mac-and-visionos
|
||||
- revenuecat-admob-tests
|
||||
- revenuecat-ads-tests
|
||||
|
||||
# =============================================================
|
||||
# Hold gate for the Full Test Suite
|
||||
# =============================================================
|
||||
- approve-full-tests:
|
||||
type: approval
|
||||
- post-gate-status:
|
||||
name: full-suite-started
|
||||
state: pending
|
||||
requires:
|
||||
- approve-full-tests
|
||||
- full-suite-not-requested
|
||||
|
||||
# =============================================================
|
||||
# Full Test Suite: Gated behind approve-full-tests
|
||||
@@ -2745,22 +2797,11 @@ workflows:
|
||||
# =============================================================
|
||||
# Summary gate: blocks merge until all jobs pass
|
||||
# =============================================================
|
||||
- all-tasks-passed:
|
||||
- post-gate-status:
|
||||
name: all-tasks-passed
|
||||
state: success
|
||||
requires:
|
||||
# Reduced Test Suite
|
||||
- performance-tests
|
||||
- performance-automation-tests
|
||||
- lint
|
||||
- check-api-changes
|
||||
- run-test-ios-27
|
||||
- build-samplecat
|
||||
- build-purchase-tester
|
||||
- pod-lib-lint
|
||||
- run-revenuecat-ui-ios-27
|
||||
- run-revenuecat-ui-ios-26
|
||||
- emerge_purchases_ui_snapshot_tests
|
||||
- binary_size_analysis
|
||||
- build-tv-watch-mac-and-visionos
|
||||
- full-suite-started
|
||||
# Full Test Suite
|
||||
- backend-integration-tests-SK1
|
||||
- backend-integration-tests-SK2
|
||||
@@ -2784,8 +2825,6 @@ workflows:
|
||||
- api-tests
|
||||
- spm-receipt-parser
|
||||
- check-app-extension-safe-api-usage
|
||||
- revenuecat-admob-tests
|
||||
- revenuecat-ads-tests
|
||||
- deploy-purchase-tester
|
||||
- run-workflow-maestro-tests
|
||||
- run-all-maestro-e2e-tests
|
||||
@@ -3136,7 +3175,9 @@ workflows:
|
||||
# =============================================================
|
||||
# All tests gate for release branches
|
||||
# =============================================================
|
||||
- all-tests-succeeded:
|
||||
- post-gate-status:
|
||||
name: all-tests-succeeded
|
||||
state: success
|
||||
requires:
|
||||
- check-api-changes
|
||||
- run-all-maestro-e2e-tests
|
||||
@@ -3192,7 +3233,9 @@ workflows:
|
||||
- all-tests-succeeded
|
||||
<<: *release-branches
|
||||
|
||||
- all-tasks-passed:
|
||||
- post-gate-status:
|
||||
name: all-tasks-passed
|
||||
state: success
|
||||
requires:
|
||||
- revenuecat/tag-current-branch
|
||||
<<: *release-branches
|
||||
@@ -17,6 +17,7 @@ jobs:
|
||||
github.event.comment.author_association == 'MEMBER'
|
||||
permissions:
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
|
||||
steps:
|
||||
# GitHub Actions `issue_comment` workflows always run from the default branch,
|
||||
@@ -24,7 +25,9 @@ jobs:
|
||||
# the hold job in the existing workflow.
|
||||
- name: Get PR branch
|
||||
id: get-branch
|
||||
run: echo "branch=$(gh pr view "$PR_NO" --repo "$REPO" --json headRefName --jq '.headRefName')" >> "$GITHUB_OUTPUT"
|
||||
run: |
|
||||
gh pr view "$PR_NO" --repo "$REPO" --json headRefName,headRefOid \
|
||||
--jq '"branch=\(.headRefName)\nsha=\(.headRefOid)"' >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NO: ${{ github.event.issue.number }}
|
||||
@@ -126,6 +129,18 @@ jobs:
|
||||
fi
|
||||
|
||||
echo "Successfully approved '$APPROVAL_JOB_NAME' in workflow '$WORKFLOW_NAME'"
|
||||
echo "approved=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Mark the merge gate pending
|
||||
if: steps.approve.outputs.approved == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
SHA: ${{ steps.get-branch.outputs.sha }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
gh api "repos/$REPO/statuses/$SHA" \
|
||||
-f state=pending -f context=ci/all-tests-gate -f target_url="$RUN_URL"
|
||||
|
||||
- name: React to comment
|
||||
if: always()
|
||||
|
||||
@@ -72,8 +72,20 @@ class PerformanceBaselineHelperTest < Minitest::Test
|
||||
def test_pr_merge_gate_requires_the_memory_benchmark
|
||||
config = YAML.safe_load(File.read(File.join(ROOT, '.circleci/default_config.yml')), aliases: true)
|
||||
jobs = config.fetch('workflows').fetch('run-all-tests').fetch('jobs')
|
||||
gate = jobs.find { |job| job.is_a?(Hash) && job.key?('all-tasks-passed') }
|
||||
assert_includes gate.fetch('all-tasks-passed').fetch('requires'), 'performance-tests'
|
||||
gate = jobs.find { |job| job.is_a?(Hash) && job.values.first['name'] == 'full-suite-not-requested' }
|
||||
assert_includes gate.values.first.fetch('requires'), 'performance-tests'
|
||||
end
|
||||
|
||||
def test_merge_gate_posts_pending_after_the_default_success_and_success_last
|
||||
config = YAML.safe_load(File.read(File.join(ROOT, '.circleci/default_config.yml')), aliases: true)
|
||||
jobs = config.fetch('workflows').fetch('run-all-tests').fetch('jobs')
|
||||
gates = jobs.select { |job| job.is_a?(Hash) && job.key?('post-gate-status') }.to_h { |job| [job['post-gate-status']['name'], job['post-gate-status']] }
|
||||
assert_equal 'success', gates.fetch('full-suite-not-requested').fetch('state')
|
||||
assert_equal true, gates.fetch('full-suite-not-requested').fetch('unless_full_suite_approved')
|
||||
assert_equal 'pending', gates.fetch('full-suite-started').fetch('state')
|
||||
assert_equal %w[approve-full-tests full-suite-not-requested], gates.fetch('full-suite-started').fetch('requires').sort
|
||||
assert_equal 'success', gates.fetch('all-tasks-passed').fetch('state')
|
||||
assert_includes gates.fetch('all-tasks-passed').fetch('requires'), 'full-suite-started'
|
||||
end
|
||||
|
||||
def test_requested_job_enables_record_and_push_with_boolean_parameters
|
||||
|
||||
Reference in new issue
Block a user