Skip to content

ci: fall back if e2e clone branch is gone - #767

Open
piotr-iohk wants to merge 9 commits into
masterfrom
cursor/e2e-clone-branch-fallback-2163
Open

piotr-iohk wants to merge 9 commits into
masterfrom
cursor/e2e-clone-branch-fallback-2163

Conversation

@piotr-iohk

@piotr-iohk piotr-iohk commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Twin: bitkit-android#1318

This PR stops Clone E2E tests from hard-failing when determine-e2e-branch resolved a same-named companion branch that is gone by the time actions/checkout runs.

Android already hit this race: after companion cleanup, or on "Re-run failed jobs" that reuse a stale determine output, checkout of synonymdev/bitkit-e2e-tests fails on fetch. Example: https://github.com/synonymdev/bitkit-android/actions/runs/35594055695/job/106339565695. iOS uses the same determine-then-clone pattern in the local, staging, and migration workflows.

Resolve logic now lives in the shared composite action from synonymdev/bitkit-e2e-tests#252, which is merged. Workflows pin resolve-e2e-ref to @main.

Description

  • Resolves the determined e2e ref immediately before each iOS checkout of synonymdev/bitkit-e2e-tests, so a deleted companion branch falls back to main with a ::warning instead of failing clone.
  • Hard-fails with an actionable ::error when a distinguishable explicit e2e_branch input (not main or default-feature-branch) is missing, so a requested custom harness branch is not silently replaced.
  • Calls the shared resolve-e2e-ref composite action from synonymdev/bitkit-e2e-tests#252 in each clone, shard (including macos), and Slack job instead of duplicating the resolve script inline.
  • Keeps one thin resolve-e2e-ref job in the migration workflow so migration-wallet-setup still receives a job-level ref.
  • Pins the action to @main now that e2e#252 is merged.

Out of Scope

  • synonymdev/bitkit-e2e-tests reusable workflows: determine-e2e-branch.yml and migration-wallet-setup.yml are unchanged; iOS only resolves the ref it passes in.
  • Android twin: bitkit-android#1318.

Design

N/A — no UI changes.

Preview

N/A

QA Notes

Manual Tests

N/A

Automated Checks

  • Workflow YAML only. Replaced inline resolve scripts in e2e-tests.yml, e2e-staging.yml, and e2e_migration.yml with the shared composite action from synonymdev/bitkit-e2e-tests#252; parsed all three files after the swap.
  • After merge: a local/staging/migration run whose determined companion branch has been deleted should clone main with a warning; dispatch with a missing custom e2e_branch should still fail.
Open in Web Open in Cursor 

cursoragent and others added 2 commits September 21, 2026 13:01
Resolve the determined bitkit-e2e-tests ref immediately before checkout
so companion cleanup and re-runs do not fail Clone E2E tests. Fall back
to main with a warning unless an explicit custom e2e_branch is missing.

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
Replace duplicated inline resolve-e2e-ref bash in local, staging, and
migration workflows with the composite action from bitkit-e2e-tests#252.

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

@cursor Please add a TEMPORARY file .github/workflows/resolve-e2e-ref-smoke.yml on this PR branch (do not open a new PR). Exact contents:

name: resolve-e2e-ref smoke

on:
  workflow_dispatch:
    inputs:
      e2e_branch:
        description: "E2E branch input (main | default-feature-branch | custom)"
        required: false
        default: "default-feature-branch"
        type: string
      pre_resolve_sleep_seconds:
        description: "Sleep before resolve job (race simulation)"
        required: false
        default: "0"
        type: string

jobs:
  determine:
    uses: synonymdev/bitkit-e2e-tests/.github/workflows/determine-e2e-branch.yml@main
    with:
      app_branch: ${{ github.ref_name }}
      e2e_branch_input: ${{ inputs.e2e_branch }}

  resolve:
    needs: determine
    runs-on: macos-latest
    steps:
      - name: Optional pre-resolve sleep
        if: inputs.pre_resolve_sleep_seconds != '0'
        run: |
          echo "Sleeping ${{ inputs.pre_resolve_sleep_seconds }}s before resolve..."
          sleep "${{ inputs.pre_resolve_sleep_seconds }}"

      - name: Resolve e2e ref
        id: e2e-ref
        uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref
        with:
          selected: ${{ needs.determine.outputs.branch }}
          e2e_branch_input: ${{ inputs.e2e_branch }}

      - name: Checkout e2e tests
        uses: actions/checkout@v4
        with:
          repository: synonymdev/bitkit-e2e-tests
          ref: ${{ steps.e2e-ref.outputs.ref }}
          fetch-depth: 1
          path: e2e-tests

      - name: Confirm checkout
        working-directory: e2e-tests
        run: |
          echo "selected=${{ needs.determine.outputs.branch }}"
          echo "effective=${{ steps.e2e-ref.outputs.ref }}"
          echo "HEAD=$(git rev-parse HEAD)"
          git branch -r || true
          git log -1 --oneline
          echo "PASS"

Commit message: ci: temporary resolve-e2e-ref smoke workflow. Push to this branch only. Stop after the file is on the branch. Use macos-latest for the resolve job (iOS smoke coverage).

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Temporary smoke workflow is on PR #767 (cursor/e2e-clone-branch-fallback-2163).

  • Added .github/workflows/resolve-e2e-ref-smoke.yml with the requested contents
  • Resolve job runs on macos-latest
  • Commit: ci: temporary resolve-e2e-ref smoke workflow (6ed7db41)

No new PR. Dispatch resolve-e2e-ref smoke on this branch when you want to run it. Remove that file before merge.

Open in Web Open in Cursor 

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

@cursor Update the TEMPORARY .github/workflows/resolve-e2e-ref-smoke.yml on this same PR branch (do not open a new PR).

Problem: workflow_dispatch is not registered until the workflow exists on the default branch. Change the smoke so it can run from this PR branch via push/PR.

Replace the file with this exact content (macos-latest for resolve):

name: resolve-e2e-ref smoke

on:
  workflow_dispatch:
    inputs:
      e2e_branch:
        description: "E2E branch input"
        required: false
        default: "default-feature-branch"
        type: string
      pre_resolve_sleep_seconds:
        description: "Sleep before resolve"
        required: false
        default: "0"
        type: string
  push:
    branches:
      - 'cursor/e2e-clone-branch-fallback-2163'
    paths:
      - '.github/workflows/resolve-e2e-ref-smoke.yml'
  pull_request:
    paths:
      - '.github/workflows/resolve-e2e-ref-smoke.yml'

jobs:
  determine:
    uses: synonymdev/bitkit-e2e-tests/.github/workflows/determine-e2e-branch.yml@main
    with:
      app_branch: ${{ github.head_ref || github.ref_name }}
      e2e_branch_input: ${{ inputs.e2e_branch || 'default-feature-branch' }}

  resolve:
    needs: determine
    runs-on: macos-latest
    steps:
      - name: Optional pre-resolve sleep
        if: ${{ (inputs.pre_resolve_sleep_seconds || '0') != '0' }}
        run: |
          echo "Sleeping ${{ inputs.pre_resolve_sleep_seconds }}s before resolve..."
          sleep "${{ inputs.pre_resolve_sleep_seconds }}"

      - name: Resolve e2e ref
        id: e2e-ref
        uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref
        with:
          selected: ${{ needs.determine.outputs.branch }}
          e2e_branch_input: ${{ inputs.e2e_branch || 'default-feature-branch' }}

      - name: Checkout e2e tests
        uses: actions/checkout@v4
        with:
          repository: synonymdev/bitkit-e2e-tests
          ref: ${{ steps.e2e-ref.outputs.ref }}
          fetch-depth: 1
          path: e2e-tests

      - name: Confirm checkout
        working-directory: e2e-tests
        run: |
          echo "selected=${{ needs.determine.outputs.branch }}"
          echo "effective=${{ steps.e2e-ref.outputs.ref }}"
          echo "HEAD=$(git rev-parse HEAD)"
          git branch -r || true
          git log -1 --oneline
          echo "PASS"

Commit message: ci: smoke trigger via push/PR for resolve-e2e-ref. Push to this PR branch only.

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Updated the temporary smoke workflow on PR #767 so it can run from this branch.

.github/workflows/resolve-e2e-ref-smoke.yml now triggers on:

  • push to cursor/e2e-clone-branch-fallback-2163 when that file changes
  • pull_request when that file changes
  • workflow_dispatch (still unused until the file exists on the default branch)

Resolve stays on macos-latest. Commit: ci: smoke trigger via push/PR for resolve-e2e-ref (07f36475). No new PR. This push should start the smoke run.

Open in Web Open in Cursor 

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

@cursor Replace .github/workflows/resolve-e2e-ref-smoke.yml on this PR branch with the following (one push should run Case A+B+C on macos for resolve). Do not open a new PR.

name: resolve-e2e-ref smoke

on:
  push:
    branches:
      - 'cursor/e2e-clone-branch-fallback-2163'
    paths:
      - '.github/workflows/resolve-e2e-ref-smoke.yml'
  pull_request:
    paths:
      - '.github/workflows/resolve-e2e-ref-smoke.yml'
  workflow_dispatch:

jobs:
  determine-A:
    uses: synonymdev/bitkit-e2e-tests/.github/workflows/determine-e2e-branch.yml@main
    with:
      app_branch: ${{ github.head_ref || github.ref_name }}
      e2e_branch_input: main

  resolve-A:
    needs: determine-A
    runs-on: macos-latest
    steps:
      - name: Resolve e2e ref
        id: e2e-ref
        uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref
        with:
          selected: ${{ needs.determine-A.outputs.branch }}
          e2e_branch_input: main
      - name: Checkout e2e tests
        uses: actions/checkout@v4
        with:
          repository: synonymdev/bitkit-e2e-tests
          ref: ${{ steps.e2e-ref.outputs.ref }}
          fetch-depth: 1
          path: e2e-tests
      - name: Confirm checkout
        working-directory: e2e-tests
        run: |
          echo "case=A"
          echo "selected=${{ needs.determine-A.outputs.branch }}"
          echo "effective=${{ steps.e2e-ref.outputs.ref }}"
          echo "HEAD=$(git rev-parse HEAD)"
          git log -1 --oneline
          echo "PASS"

  determine-B:
    uses: synonymdev/bitkit-e2e-tests/.github/workflows/determine-e2e-branch.yml@main
    with:
      app_branch: ${{ github.head_ref || github.ref_name }}
      e2e_branch_input: default-feature-branch

  resolve-B:
    needs: determine-B
    runs-on: macos-latest
    steps:
      - name: Resolve e2e ref
        id: e2e-ref
        uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref
        with:
          selected: ${{ needs.determine-B.outputs.branch }}
          e2e_branch_input: default-feature-branch
      - name: Checkout e2e tests
        uses: actions/checkout@v4
        with:
          repository: synonymdev/bitkit-e2e-tests
          ref: ${{ steps.e2e-ref.outputs.ref }}
          fetch-depth: 1
          path: e2e-tests
      - name: Confirm checkout
        working-directory: e2e-tests
        run: |
          echo "case=B"
          echo "selected=${{ needs.determine-B.outputs.branch }}"
          echo "effective=${{ steps.e2e-ref.outputs.ref }}"
          echo "HEAD=$(git rev-parse HEAD)"
          git log -1 --oneline
          echo "PASS"

  determine-C:
    uses: synonymdev/bitkit-e2e-tests/.github/workflows/determine-e2e-branch.yml@main
    with:
      app_branch: ${{ github.head_ref || github.ref_name }}
      e2e_branch_input: default-feature-branch

  resolve-C:
    needs: determine-C
    runs-on: macos-latest
    steps:
      - name: Pre-resolve sleep for race simulation
        run: |
          echo "Sleeping 90s before resolve (case C race)..."
          sleep 90
      - name: Resolve e2e ref
        id: e2e-ref
        uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref
        with:
          selected: ${{ needs.determine-C.outputs.branch }}
          e2e_branch_input: default-feature-branch
      - name: Checkout e2e tests
        uses: actions/checkout@v4
        with:
          repository: synonymdev/bitkit-e2e-tests
          ref: ${{ steps.e2e-ref.outputs.ref }}
          fetch-depth: 1
          path: e2e-tests
      - name: Confirm checkout
        working-directory: e2e-tests
        run: |
          echo "case=C"
          echo "selected=${{ needs.determine-C.outputs.branch }}"
          echo "effective=${{ steps.e2e-ref.outputs.ref }}"
          echo "HEAD=$(git rev-parse HEAD)"
          git log -1 --oneline
          echo "PASS"

Commit: ci: smoke cases A/B/C for resolve-e2e-ref. Push to this branch only.

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Updated the temporary smoke workflow on PR #767. One push now runs cases A, B, and C on macos-latest.

  • A: e2e_branch_input: main
  • B: e2e_branch_input: default-feature-branch
  • C: same as B, with a 90s pre-resolve sleep

Commit: ci: smoke cases A/B/C for resolve-e2e-ref (f2102534). No new PR. This push should start the smoke run.

Open in Web Open in Cursor 

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

@cursor Replace .github/workflows/resolve-e2e-ref-smoke.yml with Case-C-only (soft-fallback race). Same PR branch, no new PR. Use macos-latest.

name: resolve-e2e-ref smoke

on:
  push:
    branches:
      - 'cursor/e2e-clone-branch-fallback-2163'
    paths:
      - '.github/workflows/resolve-e2e-ref-smoke.yml'
  pull_request:
    paths:
      - '.github/workflows/resolve-e2e-ref-smoke.yml'
  workflow_dispatch:

jobs:
  determine-C:
    uses: synonymdev/bitkit-e2e-tests/.github/workflows/determine-e2e-branch.yml@main
    with:
      app_branch: ${{ github.head_ref || github.ref_name }}
      e2e_branch_input: default-feature-branch

  resolve-C:
    needs: determine-C
    runs-on: macos-latest
    steps:
      - name: Pre-resolve sleep for race simulation
        run: |
          echo "Sleeping 120s before resolve (case C race)..."
          sleep 120
      - name: Resolve e2e ref
        id: e2e-ref
        uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref
        with:
          selected: ${{ needs.determine-C.outputs.branch }}
          e2e_branch_input: default-feature-branch
      - name: Checkout e2e tests
        uses: actions/checkout@v4
        with:
          repository: synonymdev/bitkit-e2e-tests
          ref: ${{ steps.e2e-ref.outputs.ref }}
          fetch-depth: 1
          path: e2e-tests
      - name: Confirm checkout
        working-directory: e2e-tests
        run: |
          echo "case=C"
          echo "selected=${{ needs.determine-C.outputs.branch }}"
          echo "effective=${{ steps.e2e-ref.outputs.ref }}"
          echo "HEAD=$(git rev-parse HEAD)"
          git log -1 --oneline
          echo "PASS"

Commit: ci: smoke case C race only. Push immediately.

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Smoke workflow on PR #767 is now Case C only.

  • e2e_branch_input: default-feature-branch
  • 120s pre-resolve sleep on macos-latest
  • Commit: ci: smoke case C race only (28617169)

Pushed immediately. No new PR. This push should start the smoke run.

Open in Web Open in Cursor 

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

@cursor On this same PR branch, make a tiny no-op edit to .github/workflows/resolve-e2e-ref-smoke.yml: add a comment line # race retry $(date) near the top (after the name) and keep Case-C-only with sleep 120 and macos-latest exactly as-is otherwise. Commit: ci: smoke case C race retry. Push immediately — do not open a new PR.

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Pushed a no-op retry on PR #767.

Added # race retry $(date) after the workflow name. Case C is unchanged: 120s sleep on macos-latest. Commit: ci: smoke case C race retry (d7a6e9ee). No new PR. This push should start the smoke run again.

Open in Web Open in Cursor 

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

@cursor Delete the TEMPORARY file .github/workflows/resolve-e2e-ref-smoke.yml from this PR branch entirely. Commit: ci: remove temporary resolve-e2e-ref smoke. Push to this branch only — do not open a new PR. Stop after the file is gone.

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Removed .github/workflows/resolve-e2e-ref-smoke.yml from PR #767.

Commit: ci: remove temporary resolve-e2e-ref smoke (d8468ddc). Pushed to this branch only. The temporary smoke file is gone.

Open in Web Open in Cursor 

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk

Copy link
Copy Markdown
Collaborator Author

resolve-e2e-ref smoke — iOS PASS (3/3)

Wiring to synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@ci/resolve-e2e-ref validated end-to-end on this branch (macos-latest / macos-26-arm64).

Case Result Notes
A main PASS selected=main → effective=main
B companion PASS selected=companion → effective=companion
C soft fallback PASS selected=companion → warning → effective=main (checkout green, not hard fail)

Runs:

Temporary smoke workflow removed (ci: remove temporary resolve-e2e-ref smoke). Related: e2e-tests #252, android #1318.

Co-authored-by: piotr-iohk <piotr-iohk@users.noreply.github.com>
@piotr-iohk
piotr-iohk marked this pull request as ready for review September 21, 2026 14:16
@greptile-apps

greptile-apps Bot commented Sep 21, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking recommendation to pin the shared resolver action to the reviewed commit SHA.

Findings

  1. P2 Security Mutable Action Reference

Summary

This PR adds a shared E2E-ref resolution step immediately before companion-repository checkouts, allowing deleted automatically selected branches to fall back to main while retaining hard failure for missing explicitly requested branches.

  • Applies the resolver to local, staging, migration, and Slack-report checkouts.
  • Adds a job-level resolved ref for migration wallet preparation.
  • Updates checkout and reporting steps to consume the resolved ref.
  • One non-blocking supply-chain hardening issue remains: the newly executed composite action is referenced through mutable @main.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    D[Determine candidate E2E branch] --> R[Resolve candidate immediately before checkout]
    R -->|Candidate exists| C[Checkout selected E2E ref]
    R -->|Automatic candidate disappeared| M[Warn and select main]
    R -->|Explicit custom branch missing| F[Fail with actionable error]
    M --> C
    C --> T[Run E2E or migration workflow]
    C --> S[Generate Slack summary]
Loading

Reviews (1) · Last reviewed commit: "ci: pin resolve-e2e-ref to main"

Comment thread .github/workflows/e2e-tests.yml
@piotr-iohk
piotr-iohk requested review from a team, ben-kaufman and pwltr and removed request for a team September 21, 2026 16:07

@pwltr pwltr 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.

Requesting changes for two correctness gaps: Git transport failures currently trigger a silent fallback, and the migration wallet setup still reuses a stale ref when failed jobs are retried.

run: echo $E2E_BRANCH
- name: Resolve E2E tests ref
id: e2e-ref
uses: synonymdev/bitkit-e2e-tests/.github/actions/resolve-e2e-ref@main

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.

[P2] Distinguish a missing ref from transport failures. The referenced action runs git ls-remote --exit-code in an elif and sends every nonzero result through the missing-branch path. Exit status 2 means no matching ref, while DNS, authentication, and other transport failures return different statuses. A transient lookup failure can therefore fall back to main and let this workflow pass against a different test harness. Please capture the status, fall back only when it is 2, and fail for other errors. The same issue applies to the other new resolver invocations.

- { name: migration_4-with-sweep, setup_type: sweep }
with:
e2e_branch: ${{ needs.e2e-branch.outputs.branch }}
e2e_branch: ${{ needs.resolve-e2e-ref.outputs.ref }}

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.

[P2] Resolve the ref inside the migration wallet setup workflow. This value comes from a separate successful resolve-e2e-ref job, but a failed-jobs-only rerun does not rerun that successful prerequisite. If the companion branch disappears after resolution and the checkout inside migration-wallet-setup.yml fails, retrying failed jobs reuses this same stale value and fails again. The called workflow checks out inputs.e2e_branch directly, so the resolver needs to run there immediately before checkout (or otherwise be forced to rerun with the failed setup job).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants