Skip to content

Commit 20d8ae5

Browse files
Copiloteinari
andcommitted
Add test workflow to verify branch check endpoint and PR creation
Co-authored-by: einari <134365+einari@users.noreply.github.com>
1 parent 68c7112 commit 20d8ae5

1 file changed

Lines changed: 181 additions & 0 deletions

File tree

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
name: Test Bootstrap Fix
2+
# Smoke-test for the branch-check and PR-creation fixes in bootstrap-copilot-sync.sh.
3+
# Runs on push to copilot/test-bootstrap-workflow to give live evidence that:
4+
# 1. GET /git/ref/heads/{branch} succeeds with the fine-grained PAT.
5+
# 2. POST /repos/{owner}/{repo}/pulls succeeds (with sleep 5 propagation guard).
6+
#
7+
# This workflow will be deleted once the PR is merged and the bootstrap has been
8+
# validated in production.
9+
10+
on:
11+
push:
12+
branches:
13+
- copilot/test-bootstrap-workflow
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
verify-branch-check-endpoint:
20+
name: Verify Git Data API branch check
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Verify PAT authentication
27+
env:
28+
GH_TOKEN: ${{ secrets.PAT_WORKFLOWS }}
29+
run: |
30+
login=$(gh api /user --jq '.login' 2>/dev/null || true)
31+
if [ -z "$login" ]; then
32+
echo "::error::PAT_WORKFLOWS is not set or cannot authenticate"
33+
exit 1
34+
fi
35+
echo "✓ Authenticated as $login"
36+
37+
- name: Test /git/ref/heads/{branch} endpoint (the NEW branch check)
38+
env:
39+
GH_TOKEN: ${{ secrets.PAT_WORKFLOWS }}
40+
run: |
41+
# This test exercises the EXACT endpoint pattern that was changed.
42+
# We use Cratis/Chronicle (a known repo) and check its default branch.
43+
# If the fine-grained PAT can read this, the propagation poll will work.
44+
45+
echo "--- Testing /git/ref/heads/main on Cratis/Chronicle ---"
46+
result=$(gh api "repos/Cratis/Chronicle/git/ref/heads/main" \
47+
--jq '.object.sha' 2>/dev/null || true)
48+
49+
if [ -n "$result" ]; then
50+
echo "✓ GET /git/ref/heads/main → sha=$result"
51+
echo " The new branch check endpoint works with the fine-grained PAT."
52+
else
53+
echo "::error::GET /git/ref/heads/main returned empty — PAT cannot access this endpoint"
54+
exit 1
55+
fi
56+
57+
echo ""
58+
echo "--- Testing /git/ref/heads/main on Cratis/Fundamentals ---"
59+
result2=$(gh api "repos/Cratis/Fundamentals/git/ref/heads/main" \
60+
--jq '.object.sha' 2>/dev/null || true)
61+
if [ -n "$result2" ]; then
62+
echo "✓ GET /git/ref/heads/main → sha=$result2"
63+
else
64+
echo "::warning::GET /git/ref/heads/main on Fundamentals returned empty"
65+
fi
66+
67+
- name: Test OLD /branches/{branch} endpoint (should fail or be inaccessible)
68+
env:
69+
GH_TOKEN: ${{ secrets.PAT_WORKFLOWS }}
70+
run: |
71+
# This step shows WHY the old endpoint was broken.
72+
# A fine-grained PAT with only Contents:write may return empty here,
73+
# causing the 60-second polling loop to always time out.
74+
75+
echo "--- Testing /branches/main on Cratis/Chronicle ---"
76+
result=$(gh api "repos/Cratis/Chronicle/branches/main" \
77+
--jq '.name' 2>/dev/null || true)
78+
79+
if [ -n "$result" ]; then
80+
echo "ℹ /branches/main returned: name=$result"
81+
echo " This endpoint works for this PAT too."
82+
echo " The issue was likely something else in those runs."
83+
else
84+
echo "✓ /branches/main returned EMPTY — confirmed the old endpoint is broken"
85+
echo " This is why every run timed out: the PAT can read git refs"
86+
echo " but not the higher-level /branches endpoint."
87+
fi
88+
# This step always succeeds — it is diagnostic only.
89+
90+
verify-pr-creation:
91+
name: Verify PR creation works
92+
runs-on: ubuntu-latest
93+
needs: verify-branch-check-endpoint
94+
steps:
95+
- name: Checkout
96+
uses: actions/checkout@v4
97+
98+
- name: Check if add-copilot-sync-workflows branch exists on Chronicle
99+
id: check-branch
100+
env:
101+
GH_TOKEN: ${{ secrets.PAT_WORKFLOWS }}
102+
run: |
103+
# Previous bootstrap runs created the branch but no PR.
104+
# Check if it still exists via the new endpoint pattern.
105+
branch="add-copilot-sync-workflows"
106+
sha=$(gh api "repos/Cratis/Chronicle/git/ref/heads/$branch" \
107+
--jq '.object.sha' 2>/dev/null || true)
108+
109+
if [ -n "$sha" ]; then
110+
echo "✓ Branch $branch exists on Chronicle (sha=$sha)"
111+
echo "branch_exists=true" >> "$GITHUB_OUTPUT"
112+
echo "branch_sha=$sha" >> "$GITHUB_OUTPUT"
113+
else
114+
echo "branch_exists=false" >> "$GITHUB_OUTPUT"
115+
echo "ℹ Branch $branch does not exist on Chronicle (may have been cleaned up)"
116+
fi
117+
118+
- name: Check for existing PR on Chronicle
119+
id: check-pr
120+
if: steps.check-branch.outputs.branch_exists == 'true'
121+
env:
122+
GH_TOKEN: ${{ secrets.PAT_WORKFLOWS }}
123+
run: |
124+
branch="add-copilot-sync-workflows"
125+
pr_num=$(gh api "repos/Cratis/Chronicle/pulls?state=open&head=Cratis:$branch" \
126+
--jq '.[0].number // empty' 2>/dev/null || true)
127+
128+
if [ -n "$pr_num" ]; then
129+
echo "ℹ PR already exists: #$pr_num"
130+
echo "pr_exists=true" >> "$GITHUB_OUTPUT"
131+
echo "pr_number=$pr_num" >> "$GITHUB_OUTPUT"
132+
else
133+
echo "No open PR found for branch $branch"
134+
echo "pr_exists=false" >> "$GITHUB_OUTPUT"
135+
fi
136+
137+
- name: Create PR on Chronicle (proves PR creation works with sleep 5)
138+
if: >-
139+
steps.check-branch.outputs.branch_exists == 'true' &&
140+
steps.check-pr.outputs.pr_exists == 'false'
141+
env:
142+
GH_TOKEN: ${{ secrets.PAT_WORKFLOWS }}
143+
run: |
144+
branch="add-copilot-sync-workflows"
145+
146+
default_branch=$(gh api "repos/Cratis/Chronicle" \
147+
--jq '.default_branch' 2>/dev/null || true)
148+
echo "Default branch: $default_branch"
149+
150+
echo "Sleeping 5s (simulating post-branch-creation propagation guard)..."
151+
sleep 5
152+
153+
pr_response=$(gh api -X POST "repos/Cratis/Chronicle/pulls" \
154+
-f title="Bootstrap Copilot sync workflows" \
155+
-f body="Test PR from bootstrap fix verification." \
156+
-f head="$branch" \
157+
-f base="$default_branch" \
158+
2>/tmp/pr_err || true)
159+
pr_url=$(echo "$pr_response" | jq -r '.html_url // empty' 2>/dev/null || true)
160+
161+
if [ -n "$pr_url" ] && [ "$pr_url" != "null" ]; then
162+
echo "✓ PR created: $pr_url"
163+
echo " PR creation with plain branch name + sleep 5 works."
164+
else
165+
pr_err=$(cat /tmp/pr_err 2>/dev/null || true)
166+
pr_msg=$(echo "$pr_response" | jq -r '.message // empty' 2>/dev/null || true)
167+
pr_errs=$(echo "$pr_response" | jq -r '(.errors // []) | map(.message // .code // "unknown") | join("; ")' 2>/dev/null || true)
168+
echo "::error::PR creation failed"
169+
[ -n "$pr_err" ] && echo " API error: $pr_err"
170+
[ -n "$pr_msg" ] && echo " GitHub message: $pr_msg"
171+
[ -n "$pr_errs" ] && echo " GitHub errors: $pr_errs"
172+
exit 1
173+
fi
174+
175+
- name: Summary when branch does not exist
176+
if: steps.check-branch.outputs.branch_exists != 'true'
177+
run: |
178+
echo "Branch add-copilot-sync-workflows not found on Chronicle."
179+
echo "This likely means it was cleaned up after previous runs."
180+
echo "Run the full bootstrap workflow on main to do a complete end-to-end test."
181+
echo "The branch-check endpoint is verified by the first job."

0 commit comments

Comments
 (0)