From a22c41c950de0cdb118667a973b24377c75e252a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Dec 2025 17:06:52 +0000 Subject: [PATCH 1/4] Simplify user setup by moving checkout and mode detection into action - Action now handles checkout with fetch-depth: 0 internally - Auto-detects mode (squash-merge vs conflict-resolved) from event context - Removes need for users to specify mode or pr-branch inputs - Simplifies workflow to just trigger + single action call - E2e tests now copy workflow from repo and sed the action reference - E2e tests verify repo is clean and commit exists on origin before running --- .github/workflows/update-pr-stack.yml | 26 +------- action.yml | 42 +++++++++---- tests/test_e2e.sh | 86 +++++++++++---------------- 3 files changed, 67 insertions(+), 87 deletions(-) diff --git a/.github/workflows/update-pr-stack.yml b/.github/workflows/update-pr-stack.yml index bb3b17b..660ca9c 100644 --- a/.github/workflows/update-pr-stack.yml +++ b/.github/workflows/update-pr-stack.yml @@ -7,35 +7,11 @@ on: permissions: contents: write pull-requests: write - repository-projects: read # See https://github.com/cli/cli/discussions/5307 jobs: update-pr-stack: - if: github.event.action == 'closed' && github.event.pull_request.merged == true && github.event.pull_request.merge_commit_sha != '' runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Update PR stack - uses: ./ - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - - continue-after-conflict-resolution: - if: github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'autorestack-needs-conflict-resolution') - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Continue PR stack update after conflict resolution - uses: ./ + - uses: Phlogistique/autorestack-action@main with: github-token: ${{ secrets.GITHUB_TOKEN }} - mode: conflict-resolved - pr-branch: ${{ github.event.pull_request.head.ref }} diff --git a/action.yml b/action.yml index 0d40ef5..d4845f9 100644 --- a/action.yml +++ b/action.yml @@ -7,19 +7,17 @@ inputs: description: 'GitHub token for API access' required: true default: ${{ github.token }} - mode: - description: 'Action mode: squash-merge (after PR merge) or conflict-resolved (after manual resolution)' - required: false - default: 'squash-merge' - pr-branch: - description: 'The PR branch that was pushed (required for conflict-resolved mode)' - required: false - default: '' runs: using: 'composite' steps: - - name: Update PR stack + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ inputs.github-token }} + + - name: Detect mode and update PR stack shell: bash env: GITHUB_TOKEN: ${{ inputs.github-token }} @@ -27,12 +25,32 @@ runs: GIT_AUTHOR_EMAIL: github-actions@github.com GIT_COMMITTER_NAME: github-actions GIT_COMMITTER_EMAIL: github-actions@github.com - ACTION_MODE: ${{ inputs.mode }} + # Context for mode detection + EVENT_ACTION: ${{ github.event.action }} + PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} + PR_MERGED: ${{ github.event.pull_request.merged }} + MERGE_COMMIT_SHA: ${{ github.event.pull_request.merge_commit_sha }} + # Variables for squash-merge mode SQUASH_COMMIT: ${{ github.event.pull_request.merge_commit_sha }} MERGED_BRANCH: ${{ github.event.pull_request.head.ref }} TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} - PR_BRANCH: ${{ inputs.pr-branch }} - run: ${{ github.action_path }}/update-pr-stack.sh + # Variables for conflict-resolved mode + PR_BRANCH: ${{ github.event.pull_request.head.ref }} + run: | + # Auto-detect mode based on event context + if [[ "$EVENT_ACTION" == "closed" && "$PR_MERGED" == "true" && -n "$MERGE_COMMIT_SHA" ]]; then + echo "Detected squash-merge mode" + export ACTION_MODE="squash-merge" + elif [[ "$EVENT_ACTION" == "synchronize" && "$PR_LABELS" == *"autorestack-needs-conflict-resolution"* ]]; then + echo "Detected conflict-resolved mode" + export ACTION_MODE="conflict-resolved" + else + echo "Event does not match any action trigger (action=$EVENT_ACTION, merged=$PR_MERGED, labels=$PR_LABELS)" + echo "Nothing to do." + exit 0 + fi + + ${{ github.action_path }}/update-pr-stack.sh branding: icon: 'git-pull-request' diff --git a/tests/test_e2e.sh b/tests/test_e2e.sh index e4fc8f1..379a8e4 100755 --- a/tests/test_e2e.sh +++ b/tests/test_e2e.sh @@ -372,6 +372,34 @@ wait_for_workflow() { # --- Test Execution --- echo >&2 "--- Starting E2E Test ---" +# 0. Sanity checks - ensure we're testing committed code +echo >&2 "0. Running sanity checks..." + +# Check that the working directory is clean +if ! git -C "$PROJECT_ROOT" diff --quiet HEAD 2>/dev/null; then + echo >&2 "ERROR: Repository has uncommitted changes." + echo >&2 "Please commit your changes before running e2e tests." + echo >&2 "This ensures we test exactly what will be deployed." + git -C "$PROJECT_ROOT" status --short >&2 + exit 1 +fi + +# Get the current commit SHA from the action repo +ACTION_REPO_COMMIT=$(git -C "$PROJECT_ROOT" rev-parse HEAD) +echo >&2 "Testing commit: $ACTION_REPO_COMMIT" + +# Check that the current commit exists on origin +if ! git -C "$PROJECT_ROOT" fetch origin --quiet 2>/dev/null; then + echo >&2 "WARNING: Could not fetch from origin, skipping remote check" +elif ! git -C "$PROJECT_ROOT" branch -r --contains "$ACTION_REPO_COMMIT" 2>/dev/null | grep -q .; then + echo >&2 "ERROR: Current commit $ACTION_REPO_COMMIT does not exist on origin." + echo >&2 "Please push your changes before running e2e tests." + echo >&2 "This ensures the workflow can reference the action at this commit." + exit 1 +fi + +echo >&2 "✅ Sanity checks passed" + # 1. Setup local repository echo >&2 "1. Setting up local test repository..." TEST_DIR=$(mktemp -d) @@ -400,57 +428,15 @@ cp "$PROJECT_ROOT/action.yml" . cp "$PROJECT_ROOT/update-pr-stack.sh" . cp "$PROJECT_ROOT/command_utils.sh" . -# Create workflow file pointing to the local action -echo >&2 "Creating workflow file..." +# Copy workflow file from the repo and modify it to use local action +echo >&2 "Copying workflow file from repo..." mkdir -p .github/workflows -cat > .github/workflows/"$WORKFLOW_FILE" <&2 "Modified workflow to use local action (./)" log_cmd git add action.yml update-pr-stack.sh command_utils.sh .github/workflows/"$WORKFLOW_FILE" log_cmd git commit -m "Add action and workflow files" From 548c3438081161889599d176a41ace37660065a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Dec 2025 17:42:21 +0000 Subject: [PATCH 2/4] Fix e2e tests to use remote action at current SHA instead of local copy --- tests/test_e2e.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/test_e2e.sh b/tests/test_e2e.sh index 379a8e4..24896c8 100755 --- a/tests/test_e2e.sh +++ b/tests/test_e2e.sh @@ -422,23 +422,17 @@ log_cmd git add file.txt log_cmd git commit -m "Initial commit" INITIAL_COMMIT_SHA=$(git rev-parse HEAD) -# Copy action files -echo >&2 "Copying action files..." -cp "$PROJECT_ROOT/action.yml" . -cp "$PROJECT_ROOT/update-pr-stack.sh" . -cp "$PROJECT_ROOT/command_utils.sh" . - -# Copy workflow file from the repo and modify it to use local action +# Copy workflow file from the repo and modify it to use the current commit SHA +# This tests the actual deployed action, not a local copy echo >&2 "Copying workflow file from repo..." mkdir -p .github/workflows cp "$PROJECT_ROOT/.github/workflows/$WORKFLOW_FILE" .github/workflows/ -# Replace the remote action reference with local action for testing -# This ensures e2e tests validate the same workflow users would copy -sed -i 's|uses: Phlogistique/autorestack-action@main|uses: ./|g' .github/workflows/"$WORKFLOW_FILE" -echo >&2 "Modified workflow to use local action (./)" +# Replace @main with the current commit SHA to test exactly what we pushed +sed -i "s|uses: Phlogistique/autorestack-action@main|uses: Phlogistique/autorestack-action@$ACTION_REPO_COMMIT|g" .github/workflows/"$WORKFLOW_FILE" +echo >&2 "Modified workflow to use action at commit $ACTION_REPO_COMMIT" -log_cmd git add action.yml update-pr-stack.sh command_utils.sh .github/workflows/"$WORKFLOW_FILE" +log_cmd git add .github/workflows/"$WORKFLOW_FILE" log_cmd git commit -m "Add action and workflow files" ACTION_COMMIT_SHA=$(git rev-parse HEAD) From 876a9ea2651900e39ecac0159053569dc57bfac0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Dec 2025 17:53:06 +0000 Subject: [PATCH 3/4] Fix e2e test job detection and bash glob pattern for label matching --- action.yml | 2 +- tests/test_e2e.sh | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/action.yml b/action.yml index d4845f9..53c4f6f 100644 --- a/action.yml +++ b/action.yml @@ -41,7 +41,7 @@ runs: if [[ "$EVENT_ACTION" == "closed" && "$PR_MERGED" == "true" && -n "$MERGE_COMMIT_SHA" ]]; then echo "Detected squash-merge mode" export ACTION_MODE="squash-merge" - elif [[ "$EVENT_ACTION" == "synchronize" && "$PR_LABELS" == *"autorestack-needs-conflict-resolution"* ]]; then + elif [[ "$EVENT_ACTION" == "synchronize" && "$PR_LABELS" == *autorestack-needs-conflict-resolution* ]]; then echo "Detected conflict-resolved mode" export ACTION_MODE="conflict-resolved" else diff --git a/tests/test_e2e.sh b/tests/test_e2e.sh index 24896c8..6e20dcd 100755 --- a/tests/test_e2e.sh +++ b/tests/test_e2e.sh @@ -210,16 +210,14 @@ wait_for_synchronize_workflow() { echo >&2 "Found candidate run IDs: $candidate_run_ids. Checking runs..." for run_id in $candidate_run_ids; do echo >&2 "Checking candidate run ID: $run_id" - run_info=$(log_cmd gh run view "$run_id" --repo "$REPO_FULL_NAME" --json headBranch,jobs || echo "{}") + run_info=$(log_cmd gh run view "$run_id" --repo "$REPO_FULL_NAME" --json headBranch || echo "{}") run_head_branch=$(echo "$run_info" | jq -r '.headBranch // ""') - # Check if this run has the continue-after-conflict-resolution job - has_continue_job=$(echo "$run_info" | jq -r '.jobs[] | select(.name == "continue-after-conflict-resolution") | .name' || echo "") - echo >&2 " Run head branch: $run_head_branch, has continue job: $has_continue_job" + echo >&2 " Run head branch: $run_head_branch" - if [[ "$run_head_branch" == "$branch_name" && -n "$has_continue_job" ]]; then - echo >&2 "Found matching workflow run ID: $run_id (synchronize with continue job)" + if [[ "$run_head_branch" == "$branch_name" ]]; then + echo >&2 "Found matching workflow run ID: $run_id (branch matches)" target_run_id="$run_id" break fi From 8c6f13ec6d2cd8f3e1a7bcb4592a33908aaf72e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Dec 2025 19:48:49 +0000 Subject: [PATCH 4/4] Skip checkout when no action needed to avoid wasteful git operations --- action.yml | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/action.yml b/action.yml index 53c4f6f..aab3651 100644 --- a/action.yml +++ b/action.yml @@ -11,13 +11,33 @@ inputs: runs: using: 'composite' steps: + - name: Check if action should run + id: check + shell: bash + env: + EVENT_ACTION: ${{ github.event.action }} + PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} + PR_MERGED: ${{ github.event.pull_request.merged }} + MERGE_COMMIT_SHA: ${{ github.event.pull_request.merge_commit_sha }} + run: | + if [[ "$EVENT_ACTION" == "closed" && "$PR_MERGED" == "true" && -n "$MERGE_COMMIT_SHA" ]]; then + echo "mode=squash-merge" >> $GITHUB_OUTPUT + elif [[ "$EVENT_ACTION" == "synchronize" && "$PR_LABELS" == *autorestack-needs-conflict-resolution* ]]; then + echo "mode=conflict-resolved" >> $GITHUB_OUTPUT + else + echo "Event does not match any action trigger (action=$EVENT_ACTION, merged=$PR_MERGED, labels=$PR_LABELS)" + echo "mode=skip" >> $GITHUB_OUTPUT + fi + - name: Checkout repository + if: steps.check.outputs.mode != 'skip' uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ inputs.github-token }} - - name: Detect mode and update PR stack + - name: Update PR stack + if: steps.check.outputs.mode != 'skip' shell: bash env: GITHUB_TOKEN: ${{ inputs.github-token }} @@ -25,31 +45,13 @@ runs: GIT_AUTHOR_EMAIL: github-actions@github.com GIT_COMMITTER_NAME: github-actions GIT_COMMITTER_EMAIL: github-actions@github.com - # Context for mode detection - EVENT_ACTION: ${{ github.event.action }} - PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }} - PR_MERGED: ${{ github.event.pull_request.merged }} - MERGE_COMMIT_SHA: ${{ github.event.pull_request.merge_commit_sha }} - # Variables for squash-merge mode + ACTION_MODE: ${{ steps.check.outputs.mode }} SQUASH_COMMIT: ${{ github.event.pull_request.merge_commit_sha }} MERGED_BRANCH: ${{ github.event.pull_request.head.ref }} TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} - # Variables for conflict-resolved mode PR_BRANCH: ${{ github.event.pull_request.head.ref }} run: | - # Auto-detect mode based on event context - if [[ "$EVENT_ACTION" == "closed" && "$PR_MERGED" == "true" && -n "$MERGE_COMMIT_SHA" ]]; then - echo "Detected squash-merge mode" - export ACTION_MODE="squash-merge" - elif [[ "$EVENT_ACTION" == "synchronize" && "$PR_LABELS" == *autorestack-needs-conflict-resolution* ]]; then - echo "Detected conflict-resolved mode" - export ACTION_MODE="conflict-resolved" - else - echo "Event does not match any action trigger (action=$EVENT_ACTION, merged=$PR_MERGED, labels=$PR_LABELS)" - echo "Nothing to do." - exit 0 - fi - + echo "Running in $ACTION_MODE mode" ${{ github.action_path }}/update-pr-stack.sh branding: