jamesfredley opened a new pull request, #98:
URL: https://github.com/apache/grails-github-actions/pull/98

   ## What
   
   Makes the `deploy-github-pages` action safe when multiple documentation 
deploys publish concurrently. Today, when several release/snapshot builds push 
to the documentation branch at the same time, their pushes race: a rejected 
push runs a plain `git pull --rebase`, which stops on a merge conflict in the 
shared folders and - under `set -e` - kills the whole job. Concurrent releases 
therefore fail (observed in `apache/grails-core` doc publishing).
   
   ## Why it happens
   
   Different releases never collide on their specific `X.X.X` folders, but they 
all write the shared paths: `latest`, the generic `X.X.x`, the root 
`index.html`, and the `snapshot` folder. A concurrent deploy that lands first 
advances the branch, our push is rejected, and the naive rebase conflicts on 
those shared paths and aborts.
   
   ## The fix
   
   In `deploy-github-pages/entrypoint.sh`, the push-retry loop is now 
concurrency-safe:
   
   - **Rebase with `-X theirs` + backoff.** The deploy commit is replayed onto 
the remote so a concurrent deploy's independent version folders are preserved, 
and shared-folder file-content conflicts auto-resolve in favour of this deploy. 
Retries use bounded backoff with jitter.
   - **Reconcile owned paths.** After the rebase, purge-owned folders 
(`PURGE_EXISTING=true`) are restored wholesale from this deploy's commit (clean 
last-writer-wins), so a shared folder never becomes a union of both deploys' 
files. Merge-mode folders (`PURGE_EXISTING=false`) are deliberately left to the 
`-X theirs` merge so a concurrent deploy's independent changes survive.
   - **`latest` is highest-version-wins.** A lower release replayed after a 
concurrent higher release yields `latest` back to the remote instead of 
overwriting it with older docs.
   - **Modify/delete conflicts resolved.** `-X theirs` cannot auto-resolve a 
modify/delete conflict (a file this deploy purges that a concurrent deploy 
modified). Instead of aborting and re-hitting the same conflict until attempts 
are exhausted, the rebase is now driven to completion deterministically.
   
   ## Tests
   
   Adds a Testcontainers regression test to `DeployGithubPagesSpec` that lands 
a concurrent deploy modifying a file this deploy purges (a real modify/delete 
conflict) and asserts the retry recovers cleanly - the deploy's own content 
wins and the stale file is removed. All existing deploy tests pass.
   
   ## Note / follow-up
   
   `apache/grails-static-website` exhibits the **same class** of race, but in a 
separate Gradle publish task (`:publishMainSite` pushing to 
`apache/grails-website` `asf-site-production`), which lives outside this 
repository. That will need a separate follow-up fix in that project - it is not 
addressed here.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to