Live test: Diffy placeholders, Actions settings, milestones and variables (#56)
After each deploy, the live test checks the importer's Diffy placeholder, the repository Actions settings page, milestones (created closed, refused before an issue edit is saved, shown in the response and the issue filter, the milestone link), case-insensitive repository variable deletes, and that deleting missing organization variables and secrets isn't a 204. Claude-Session: https://claude.ai/code/session_01QMFviVKD61QaDPxdrh7C3f
Canberk Demirci authored · GitHub committed signed1 parent e52c37bcommit 390db27c3d3eb1316f932a77ae5a8f0b6ef72d7eBrowse files
1 file changed+37−1
modified.github/workflows/live-test.yml+37−1View file
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | name: Live test |
| 2 | 2 | |
| 3 | 3 | # End-to-end checks against the real diffinery.com after each deploy: email |
| 4 | -# sending, web UI features (syntax highlighting, settings pages, view transitions), hosted Actions jobs in Cloudflare Containers (with Docker builds and services), the container registry, agent sandboxes, | |
| 4 | +# sending, web UI features (syntax highlighting, settings pages, view transitions, milestones, variables), hosted Actions jobs in Cloudflare Containers (with Docker builds and services), the container registry, agent sandboxes, | |
| 5 | 5 | # webhooks, scheduled workflows, Git LFS, imports from GitHub, that tokens can't mint tokens, and pull requests (test merge commits, pull_request_target and the merge |
| 6 | 6 | # queue). Each run works in a throwaway private repository that it |
| 7 | 7 | # deletes at the end. |
| @@ -298,6 +298,42 @@ | ||
| 298 | 298 | for t in get_organization list_invitations revoke_invitation; do grep -qx "$t" <<<"$tools" || { echo "::error::the MCP server has no $t tool"; exit 1; }; done |
| 299 | 299 | echo "highlighting, Appearance, notification settings link, view transitions, visibility, organization and invitation checks passed" |
| 300 | 300 | |
| 301 | + - name: Diffy placeholders, Actions settings, milestones and variables | |
| 302 | + if: steps.token.outputs.skip != 'true' | |
| 303 | + run: | | |
| 304 | + set -euo pipefail | |
| 305 | + page() { curl -fsS "$DIFFINERY$1" -H "Authorization: Bearer $TOKEN"; } | |
| 306 | + api() { curl -fsS -X "$1" "$DIFFINERY/api/v3$2" -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" ${3:+--data "$3"}; } | |
| 307 | + code() { curl -sS -o /tmp/out -w '%{http_code}' -X "$1" "$DIFFINERY/api/v3$2" -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" ${3:+--data "$3"}; } | |
| 308 | + fail() { echo "::error::$1"; cat /tmp/out 2>/dev/null || true; exit 1; } | |
| 309 | + has() { grep -qF -- "$2" <<<"$1" || fail "$3"; } | |
| 310 | + R="/repos/$OWNER/$REPO" | |
| 311 | + has "$(page /new/import)" 'diffy/hello-world' "the importer's placeholder isn't Diffy" | |
| 312 | + has "$(page "/$OWNER/$REPO/settings/actions")" 'Allow GitHub Actions to create and approve pull requests' "repository settings have no Actions page" | |
| 313 | + # Milestones: created closed, checked before an issue edit is saved, shown in the response, and filterable. | |
| 314 | + [ "$(api POST "$R/milestones" '{"title":"Shipped","state":"closed"}' | jq -r .state)" = closed ] || fail "POST milestones ignored state" | |
| 315 | + ms=$(api POST "$R/milestones" '{"title":"Live v1"}' | jq -r .number) | |
| 316 | + n=$(api POST "$R/issues" '{"title":"Planned"}' | jq -r .number) | |
| 317 | + [ "$(code PATCH "$R/issues/$n" '{"title":"Renamed","milestone":999999}')" = 422 ] || fail "an unknown milestone wasn't refused with 422" | |
| 318 | + [ "$(api GET "$R/issues/$n" | jq -r .title)" = Planned ] || fail "a refused milestone edit saved the title" | |
| 319 | + [ "$(api PATCH "$R/issues/$n" "{\"milestone\":$ms}" | jq -r .milestone.number)" = "$ms" ] || fail "PATCH issue doesn't return the new milestone" | |
| 320 | + [ "$(api GET "$R/issues?milestone=$ms&state=all" | jq -r '[.[].number] | join(",")')" = "$n" ] || fail "issues aren't filtered by milestone" | |
| 321 | + loc=$(curl -sS -o /dev/null -w '%{redirect_url}' "$DIFFINERY/$OWNER/$REPO/milestone/$ms" -H "Authorization: Bearer $TOKEN") | |
| 322 | + has "$loc" "/issues?milestone=$ms" "the milestone link doesn't open its issue list" | |
| 323 | + # Repository variable deletes ignore letter case. | |
| 324 | + [ "$(code PUT "$R/actions/variables/LIVE_CASE" '{"value":"x"}')" = 204 ] || fail "couldn't set a repository variable" | |
| 325 | + [ "$(code DELETE "$R/actions/variables/live_case")" = 204 ] || fail "couldn't delete a repository variable" | |
| 326 | + [ "$(code GET "$R/actions/variables/LIVE_CASE")" = 404 ] || fail "deleting a variable in lower case left it in place" | |
| 327 | + org=$(page /api/v3/user/orgs | jq -r '.[0].login // empty') | |
| 328 | + if [ -n "$org" ]; then | |
| 329 | + # Deleting an organization variable or secret that doesn't exist is a 404 (403 for someone who isn't an admin). | |
| 330 | + for path in variables secrets; do | |
| 331 | + c=$(code DELETE "/orgs/$org/actions/$path/LIVE_NEVER_SET_$GITHUB_RUN_ID") | |
| 332 | + case "$c" in 404|403) ;; *) fail "DELETE of a missing organization $path entry got $c" ;; esac | |
| 333 | + done | |
| 334 | + fi | |
| 335 | + echo "Diffy placeholders, Actions settings page, milestone and variable checks passed" | |
| 336 | + | |
| 301 | 337 | - name: Hosted Actions jobs (and Docker) run in Cloudflare Containers |
| 302 | 338 | if: steps.token.outputs.skip != 'true' |
| 303 | 339 | run: | |