Add manual GitHub Pages republish workflow#212
Conversation
Adds a workflow_dispatch workflow that re-deploys the Sparkle appcast to GitHub Pages with a configurable custom domain. Useful for domain migrations without cutting a new release.
| if [ -f artifacts/appcast.xml ]; then | ||
| echo "Found appcast.xml from release artifacts" | ||
| cp artifacts/appcast.xml appcast.xml | ||
| else |
There was a problem hiding this comment.
The path check looks at
artifacts/appcast.xml, but actions/upload-artifact@v4 preserves the workspace-relative directory structure when uploading. In release.yml, the file is staged at build/appcast.xml, so when gh run download --dir artifacts/ extracts the artifact, the file lands at artifacts/build/appcast.xml — not artifacts/appcast.xml. The condition will always be false and the workflow will always exit with the "No appcast.xml found" error.
| if [ -f artifacts/appcast.xml ]; then | |
| echo "Found appcast.xml from release artifacts" | |
| cp artifacts/appcast.xml appcast.xml | |
| else | |
| if [ -f artifacts/build/appcast.xml ]; then | |
| echo "Found appcast.xml from release artifacts" | |
| cp artifacts/build/appcast.xml appcast.xml | |
| else |
| mkdir -p pages/Cotabby | ||
| cp appcast.xml pages/appcast.xml | ||
| cp appcast.xml pages/Cotabby/appcast.xml |
There was a problem hiding this comment.
The subdirectory name
Cotabby doesn't match the tabby subdirectory that release.yml writes (build/pages/tabby/appcast.xml). Running this workflow would produce a Pages deployment where https://updates.tabbyapp.dev/tabby/appcast.xml no longer exists and a new https://updates.tabbyapp.dev/Cotabby/appcast.xml appears instead — diverging from every prior release deployment.
| mkdir -p pages/Cotabby | |
| cp appcast.xml pages/appcast.xml | |
| cp appcast.xml pages/Cotabby/appcast.xml | |
| mkdir -p pages/tabby | |
| cp appcast.xml pages/appcast.xml | |
| cp appcast.xml pages/tabby/appcast.xml |
| - name: Summary | ||
| run: | | ||
| { | ||
| echo "### Pages Republished" | ||
| echo "| Field | Value |" | ||
| echo "|-------|-------|" | ||
| echo "| Custom domain | ${{ inputs.custom_domain }} |" | ||
| echo "| Appcast URL | https://${{ inputs.custom_domain }}/appcast.xml |" | ||
| echo "| Pages URL | ${{ steps.deploy.outputs.page_url }} |" | ||
| } >> "${GITHUB_STEP_SUMMARY}" |
There was a problem hiding this comment.
${{ inputs.custom_domain }} is expanded directly into the shell script before Bash parses it. Any shell metacharacters in the input (e.g. a value containing "; rm …; #) would be executed. Pass the value through an environment variable instead so Bash never sees it as code.
| - name: Summary | |
| run: | | |
| { | |
| echo "### Pages Republished" | |
| echo "| Field | Value |" | |
| echo "|-------|-------|" | |
| echo "| Custom domain | ${{ inputs.custom_domain }} |" | |
| echo "| Appcast URL | https://${{ inputs.custom_domain }}/appcast.xml |" | |
| echo "| Pages URL | ${{ steps.deploy.outputs.page_url }} |" | |
| } >> "${GITHUB_STEP_SUMMARY}" | |
| - name: Summary | |
| env: | |
| CUSTOM_DOMAIN: ${{ inputs.custom_domain }} | |
| PAGES_URL: ${{ steps.deploy.outputs.page_url }} | |
| run: | | |
| { | |
| echo "### Pages Republished" | |
| echo "| Field | Value |" | |
| echo "|-------|-------|" | |
| echo "| Custom domain | ${CUSTOM_DOMAIN} |" | |
| echo "| Appcast URL | https://${CUSTOM_DOMAIN}/appcast.xml |" | |
| echo "| Pages URL | ${PAGES_URL} |" | |
| } >> "${GITHUB_STEP_SUMMARY}" |
Summary
Adds a
workflow_dispatchworkflow (republish-pages.yml) that re-deploys the Sparkle appcast to GitHub Pages with a configurable custom domain input. This lets us change the Pages CNAME (e.g. fromupdates.tabbyapp.devto a new domain) without cutting a full release.Validation
Workflow syntax validated — uses the same
configure-pages,upload-pages-artifact, anddeploy-pagesactions as the existing release workflow. Cannot be end-to-end tested until merged to a branch with Actions enabled.Linked issues
Refs #202
Risk / rollout notes
appcast.xmlfrom the latest successful release run's artifacts, so at least one prior release must exist.updates.tabbyapp.dev(current production value).Greptile Summary
This PR adds a
workflow_dispatchworkflow (republish-pages.yml) that re-deploys the Sparkle appcast to GitHub Pages without cutting a new release, useful when the Pages custom domain changes.appcast.xmlfrom the latest successfulrelease.ymlrun's artifacts, then prepares and deploys a Pages artifact with a configurable CNAME — but two logic bugs mean every run would fail or produce wrong output: the artifact extraction path check looks atartifacts/appcast.xmlinstead ofartifacts/build/appcast.xml(matching howupload-artifactpreserves thebuild/prefix), and the subdirectory is namedCotabbyinstead oftabby(as used inrelease.yml), which would drop the/tabby/appcast.xmlpath from Pages.inputs.custom_domainvalue is also interpolated directly into shell in the Summary step rather than passed via an environment variable.Confidence Score: 2/5
Not safe to merge as-is — two bugs in the new workflow guarantee it either always errors out or deploys a Pages structure that diverges from every prior release.
The artifact path check (
artifacts/appcast.xml) will never match the actual extracted location (artifacts/build/appcast.xml), so the workflow will always exit with an error and never publish. Additionally, the subdirectory nameCotabbydiffers fromtabbyused by the release workflow; if the path check were fixed, running this workflow would still produce a Pages deployment missing the/tabby/appcast.xmlpath that existing release artifacts establish. Both issues are on the sole code path this workflow exercises..github/workflows/republish-pages.yml — the artifact extraction path and subdirectory name both need correction before this workflow can function correctly.
Security Review
inputs.custom_domain(.github/workflows/republish-pages.yml, Summary step): the user-supplied domain input is expanded directly into the shell script by GitHub Actions template substitution before Bash parses it. A value containing shell metacharacters would be executed as code. Risk is bounded to repository collaborators who can triggerworkflow_dispatch, but the fix (passing the value through anenv:variable) is straightforward.Important Files Changed
Sequence Diagram
sequenceDiagram actor Operator participant GHA as GitHub Actions participant GHAPI as GitHub API participant Pages as GitHub Pages Operator->>GHA: trigger workflow_dispatch (custom_domain input) GHA->>GHAPI: "gh run list (release.yml, status=success, limit=1)" GHAPI-->>GHA: latest release run ID GHA->>GHAPI: gh run download release-artifacts GHAPI-->>GHA: artifact zip (build/appcast.xml inside) Note over GHA: check artifacts/appcast.xml ❌ actual path: artifacts/build/appcast.xml GHA->>GHA: mkdir pages/Cotabby ⚠️ should be pages/tabby GHA->>GHA: write CNAME with custom_domain GHA->>Pages: configure-pages → upload-pages-artifact → deploy-pages Pages-->>GHA: page_url GHA->>GHA: write GITHUB_STEP_SUMMARYReviews (1): Last reviewed commit: "Add manual GitHub Pages republish workfl..." | Re-trigger Greptile