From 261676d9f1547e2f77d961a4f8f48476234f7c3f Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Thu, 27 Aug 2026 16:13:01 +0100 Subject: [PATCH] Run all Bitrise jobs for manual branch builds Assisted-By: devx/68f42277-9354-4f9c-8a96-afcc8732a061 --- e2e/BITRISE.md | 8 ++++-- e2e/bitrise.yml | 4 +-- e2e/scripts/bitrise_ci_helpers | 18 ++++++++++---- e2e/test/bitrise_ci_helpers_test.rb | 38 +++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/e2e/BITRISE.md b/e2e/BITRISE.md index a04d91997..d008d43e8 100644 --- a/e2e/BITRISE.md +++ b/e2e/BITRISE.md @@ -40,7 +40,7 @@ Validate the configuration locally with: bitrise validate -c e2e/bitrise.yml ``` -## PR trigger +## PR and manual runs The `e2e` pipeline defines a target-based pull request trigger in `e2e/bitrise.yml`. The trigger uses Bitrise `changed_files.regex` as a coarse source-tree gate for Checkout Kit platform, protocol, shared filter, package, and E2E paths. Target-based triggers are defined on each pipeline so one pull request can start both `e2e` and `ci-ios`; the legacy project-level `trigger_map` starts only its first match and must not be restored. Bitrise does not support the same named include/exclude filter objects as GitHub Actions, so `platforms` level filtering is enforced by `e2e/config/matrix.yml` and `e2e/scripts/e2e_matrix_to_browserstack_run_plan` after the pipeline starts (essentially fulfilling the same need that `dorny/paths-filter` holds in GitHub Actions). @@ -52,6 +52,8 @@ For example, editing `platforms/react-native/README.md` matches the coarse `chan The GitHub checks are kept non-blocking while the suite stabilizes; they become merge-blocking only once the "Checkout Kit E2E" check is marked required in branch protection. +A manually started pipeline has no pull request file list, so it selects every application in the E2E matrix. Choose the branch and `e2e` pipeline from the Bitrise **Start build** page to run the complete E2E suite against that branch. No push trigger is configured, so merging to `main` does not automatically start this pipeline. + ## The `ci-ios` pipeline `ci-ios` is the second pipeline in `e2e/bitrise.yml`. It runs the four macOS jobs that used to run on GitHub Actions: the Swift package tests, the Swift sample build and test, the React Native iOS sample build, and the React Native iOS tests. It is separate from `e2e` rather than a set of extra workflows inside it, because Bitrise reports one status per pipeline: sharing one would tie a merge gate to the BrowserStack device flake that the E2E checks deliberately keep non-blocking. @@ -64,6 +66,8 @@ Selection happens inside the pipeline instead. The Linux `ci-ios-plan` workflow This is the same two-layer idea as `e2e` — a cheap first pass, then a precise runtime decision — with the first layer set to "always". +A manually started `ci-ios` pipeline selects all four macOS jobs. Choose the branch and `ci-ios` pipeline from the Bitrise **Start build** page to verify the complete iOS build and test suite. Like `e2e`, `ci-ios` has no push trigger and does not run automatically after a merge to `main`. + ### The check is self-posted `ci-ios-report` runs with `should_always_run: workflow` and posts the `Checkout Kit iOS` Check Run itself, through `e2e/scripts/report_ios_ci_results`. Bitrise's own pipeline status cannot tell the two kinds of not-run apart: @@ -202,7 +206,7 @@ Do not pass storefront tokens or customer data through BrowserStack Maestro envi ## GitHub reporting -The `e2e-report` workflow creates commit statuses, Check Runs, and sticky PR comments using the short-lived token generated by the Bitrise GitHub App. +For pull request builds, the `e2e-report` workflow creates commit statuses, Check Runs, and sticky PR comments using the short-lived token generated by the Bitrise GitHub App. Manual branch builds have no pull request to update, so both E2E and iOS reporting workflows skip GitHub reporting without requiring a token. The Bitrise project has **Project settings > Repository > Extend GitHub App permissions to builds** enabled. Bitrise exposes the build-scoped GitHub App token as `GIT_HTTP_PASSWORD`; the report workflow maps it to `GITHUB_TOKEN` before running `e2e/scripts/report_e2e_results`. diff --git a/e2e/bitrise.yml b/e2e/bitrise.yml index 397bfa175..776fba8ce 100644 --- a/e2e/bitrise.yml +++ b/e2e/bitrise.yml @@ -276,7 +276,7 @@ workflows: - content: |- set -euo pipefail source e2e/scripts/bitrise_ci_helpers - e2e_log "Fetching pull request changed files" + e2e_log "Selecting files for the iOS CI run plan" changed_files="$(e2e_changed_files_file)" ruby e2e/scripts/ios_ci_run_plan validate --changed-files-file "$changed_files" e2e_log "Asserting the pipeline can run every selected job" @@ -479,7 +479,7 @@ workflows: - content: |- set -euo pipefail source e2e/scripts/bitrise_ci_helpers - e2e_log "Fetching pull request changed files" + e2e_log "Selecting files for the E2E run plan" changed_files="$(e2e_changed_files_file)" ruby e2e/scripts/e2e_matrix_to_browserstack_run_plan validate --changed-files-file "$changed_files" e2e_log "Asserting the pipeline can build every selected target" diff --git a/e2e/scripts/bitrise_ci_helpers b/e2e/scripts/bitrise_ci_helpers index c4083e4ba..d16db21ce 100755 --- a/e2e/scripts/bitrise_ci_helpers +++ b/e2e/scripts/bitrise_ci_helpers @@ -21,21 +21,24 @@ e2e_deploy_dir() { printf '%s\n' "$dir" } +e2e_has_pull_request() { + [ -n "${BITRISE_PULL_REQUEST:-}" ] && [ "$BITRISE_PULL_REQUEST" != "false" ] && [ "$BITRISE_PULL_REQUEST" != "0" ] +} + # Writes the changed file list and prints its path. Two gates read it — the E2E matrix # and the iOS CI run plan — and a second copy of this derivation would let them select # different work from the same commit. # # PR builds: the checkout is a shallow merge commit, so the GitHub API is the -# authoritative source for the PR's changed files. Non-PR runs (manual, scheduled, -# local) fall back to diffing the branch against its base with a three-dot range -# (changes since the merge-base, not tip-to-tip). +# authoritative source for the PR's changed files. Non-PR runs select every tracked +# file so manually starting a pipeline against a branch runs every applicable job. e2e_changed_files_file() { local changed_files changed_files="$(mktemp "${TMPDIR:-/tmp}/checkout-kit-changed-files.XXXXXX")" - if [ -n "${BITRISE_PULL_REQUEST:-}" ]; then + if e2e_has_pull_request; then ruby e2e/scripts/github_pr_changed_files > "$changed_files" else - git diff --name-only "${BITRISE_GIT_BRANCH_DEST:-origin/main}...HEAD" > "$changed_files" + git ls-files > "$changed_files" fi printf '%s\n' "$changed_files" } @@ -58,6 +61,11 @@ e2e_branch_bitrise_config() { } e2e_export_github_token() { + if ! e2e_has_pull_request; then + e2e_log "No pull request associated with this build; skipping GitHub reporting configuration" + return + fi + e2e_log "Checking GitHub reporting configuration" if [ -z "${GITHUB_TOKEN:-}" ]; then : "${GIT_HTTP_PASSWORD:?GITHUB_TOKEN or Bitrise GitHub App GIT_HTTP_PASSWORD is required. Enable Project settings > Repository > Extend GitHub App permissions to builds.}" diff --git a/e2e/test/bitrise_ci_helpers_test.rb b/e2e/test/bitrise_ci_helpers_test.rb index 1c00fb74c..5f0688d74 100644 --- a/e2e/test/bitrise_ci_helpers_test.rb +++ b/e2e/test/bitrise_ci_helpers_test.rb @@ -24,6 +24,44 @@ def test_changed_files_are_written_to_a_temporary_file end end + def test_non_pr_build_treats_every_tracked_file_as_changed + Dir.mktmpdir do |directory| + output, error, status = run_helper( + 'changed_files="$(e2e_changed_files_file)"; cat "$changed_files"', + "TMPDIR" => directory, + "BITRISE_DEPLOY_DIR" => File.join(directory, "deploy") + ) + + assert status.success?, error + assert_equal `git ls-files`.lines.sort, output.lines.sort + end + end + + def test_false_pull_request_value_treats_every_tracked_file_as_changed + Dir.mktmpdir do |directory| + output, error, status = run_helper( + 'changed_files="$(e2e_changed_files_file)"; cat "$changed_files"', + "TMPDIR" => directory, + "BITRISE_DEPLOY_DIR" => File.join(directory, "deploy"), + "BITRISE_PULL_REQUEST" => "false" + ) + + assert status.success?, error + assert_equal `git ls-files`.lines.sort, output.lines.sort + end + end + + def test_non_pr_build_does_not_require_a_github_token + Dir.mktmpdir do |directory| + _output, error, status = run_helper( + "e2e_export_github_token", + "BITRISE_DEPLOY_DIR" => directory + ) + + assert status.success?, error + end + end + def test_pr_build_fails_when_branch_head_config_cannot_be_read Dir.mktmpdir do |directory| _output, error, status = run_helper(