jamesfredley commented on code in PR #98:
URL:
https://github.com/apache/grails-github-actions/pull/98#discussion_r3522495907
##########
deploy-github-pages/entrypoint.sh:
##########
@@ -130,6 +139,140 @@ is_highest_version() {
return 0
}
+# Paths this deploy owns. Populated by publish_artifacts and used to reconcile
the
+# working tree after rebasing onto a concurrent deploy (see
reconcile_owned_paths).
+# OWNED_PURGE_PATHS - folders this deploy replaces wholesale
(PURGE_EXISTING=true):
+# on retry, strip anything a concurrent deploy left
there and
+# restore exactly this deploy's content (clean
last-writer-wins).
+# OWNED_KEEP_PATHS - single files this deploy owns outright (e.g. the root
+# index.html): on retry, re-assert just that file. Merged
+# folders (PURGE_EXISTING=false) are intentionally NOT
listed
+# here - the "-X theirs" rebase already gives correct
merge
+# semantics, and re-asserting them would clobber a
concurrent
+# deploy's independent changes.
+OWNED_PURGE_PATHS=()
+OWNED_KEEP_PATHS=()
+
+# If this release publishes the shared "latest" folder, remember its path and
this
+# release's generic (X.X.x) version. "latest" must always hold the HIGHEST
released
+# version, but is_highest_version is evaluated against the checkout taken
before a
+# concurrent higher release may have landed. reconcile_owned_paths re-checks
these
+# against the rebased tree so a lower release retried after a higher one does
not
+# overwrite "latest" with older docs. Empty unless this deploy published
"latest".
+LATEST_OWNED_PATH=""
+LATEST_GENERIC_VERSION=""
+
+# After a push is rejected we rebase this deploy's commit onto the concurrent
deploy
+# with "-X theirs", which wins FILE-LEVEL conflicts but cannot remove files
the other
+# deploy ADDED to a folder we own. Re-assert our owned paths from our original
commit
+# so shared folders (latest, X.X.x, ...) end up as a clean last-writer-wins
instead of
+# a union of both deploys' files. Everything the other deploy published
independently
+# (its own version folders) is untouched and preserved.
+reconcile_owned_paths() {
+ local p changed=false
+
+ # "latest" must hold the HIGHEST released version. If a concurrent, higher
+ # release landed first (its X.X.x folder is now in the just-rebased tree) and
+ # THIS is a lower release, do not overwrite "latest" with our older docs:
+ # restore it to the remote's (higher) content and drop it from our owned set.
+ # Re-run is_highest_version from within TARGET_FOLDER, where the version
folders
+ # actually live, against the merged tree. Same-minor patches compare equal,
so
+ # they still fall through to last-writer-wins, which is fine.
+ if [ -n "${LATEST_OWNED_PATH}" ] && [ -n "${LATEST_GENERIC_VERSION}" ]; then
+ if ! ( cd "${TARGET_FOLDER}" && is_highest_version
"${LATEST_GENERIC_VERSION}" ); then
+ echo "A concurrent higher release now owns ${LATEST_OWNED_PATH};
yielding it to the remote."
+ # Strip our rebased copy first so files that exist ONLY in our (lower)
+ # version are removed - otherwise the checkout below would leave them and
+ # "latest" would become a union of both releases instead of exactly the
+ # remote's higher version. FETCH_HEAD is the remote tip fetched by the
+ # preceding `git pull --rebase`, i.e. the concurrent deploy we rebased
onto.
+ git rm -rf --ignore-unmatch --quiet -- "${LATEST_OWNED_PATH}" >/dev/null
2>&1 || true
+ git checkout FETCH_HEAD -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true
+ git add -A -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true
Review Comment:
Good catch - addressed in b170851.
The `latest` yield restore is no longer masked. It now only runs `git
checkout FETCH_HEAD -- <path>` + `git add -A` when the remote actually
publishes that path, guarded by `git ls-tree -r FETCH_HEAD -- <path>`:
```sh
git rm -rf --ignore-unmatch --quiet -- "${LATEST_OWNED_PATH}" >/dev/null
2>&1 || true
local remote_latest
remote_latest="$(git ls-tree -r FETCH_HEAD -- "${LATEST_OWNED_PATH}")"
if [ -n "${remote_latest}" ]; then
git checkout FETCH_HEAD -- "${LATEST_OWNED_PATH}"
git add -A -- "${LATEST_OWNED_PATH}"
fi
```
If the remote genuinely lacks the path (e.g. a higher release that skipped
`latest`), the preceding `git rm --ignore-unmatch` already staged the deletion
and we skip the restore - which also avoids aborting on a now-absent pathspec.
The `git ls-tree` check is unmasked, so an invalid `FETCH_HEAD` exits non-zero
and fails the job under `set -e` rather than being mistaken for "path absent".
A checkout failure on a path the remote does have also aborts.
##########
deploy-github-pages/entrypoint.sh:
##########
@@ -130,6 +139,140 @@ is_highest_version() {
return 0
}
+# Paths this deploy owns. Populated by publish_artifacts and used to reconcile
the
+# working tree after rebasing onto a concurrent deploy (see
reconcile_owned_paths).
+# OWNED_PURGE_PATHS - folders this deploy replaces wholesale
(PURGE_EXISTING=true):
+# on retry, strip anything a concurrent deploy left
there and
+# restore exactly this deploy's content (clean
last-writer-wins).
+# OWNED_KEEP_PATHS - single files this deploy owns outright (e.g. the root
+# index.html): on retry, re-assert just that file. Merged
+# folders (PURGE_EXISTING=false) are intentionally NOT
listed
+# here - the "-X theirs" rebase already gives correct
merge
+# semantics, and re-asserting them would clobber a
concurrent
+# deploy's independent changes.
+OWNED_PURGE_PATHS=()
+OWNED_KEEP_PATHS=()
+
+# If this release publishes the shared "latest" folder, remember its path and
this
+# release's generic (X.X.x) version. "latest" must always hold the HIGHEST
released
+# version, but is_highest_version is evaluated against the checkout taken
before a
+# concurrent higher release may have landed. reconcile_owned_paths re-checks
these
+# against the rebased tree so a lower release retried after a higher one does
not
+# overwrite "latest" with older docs. Empty unless this deploy published
"latest".
+LATEST_OWNED_PATH=""
+LATEST_GENERIC_VERSION=""
+
+# After a push is rejected we rebase this deploy's commit onto the concurrent
deploy
+# with "-X theirs", which wins FILE-LEVEL conflicts but cannot remove files
the other
+# deploy ADDED to a folder we own. Re-assert our owned paths from our original
commit
+# so shared folders (latest, X.X.x, ...) end up as a clean last-writer-wins
instead of
+# a union of both deploys' files. Everything the other deploy published
independently
+# (its own version folders) is untouched and preserved.
+reconcile_owned_paths() {
+ local p changed=false
+
+ # "latest" must hold the HIGHEST released version. If a concurrent, higher
+ # release landed first (its X.X.x folder is now in the just-rebased tree) and
+ # THIS is a lower release, do not overwrite "latest" with our older docs:
+ # restore it to the remote's (higher) content and drop it from our owned set.
+ # Re-run is_highest_version from within TARGET_FOLDER, where the version
folders
+ # actually live, against the merged tree. Same-minor patches compare equal,
so
+ # they still fall through to last-writer-wins, which is fine.
+ if [ -n "${LATEST_OWNED_PATH}" ] && [ -n "${LATEST_GENERIC_VERSION}" ]; then
+ if ! ( cd "${TARGET_FOLDER}" && is_highest_version
"${LATEST_GENERIC_VERSION}" ); then
+ echo "A concurrent higher release now owns ${LATEST_OWNED_PATH};
yielding it to the remote."
+ # Strip our rebased copy first so files that exist ONLY in our (lower)
+ # version are removed - otherwise the checkout below would leave them and
+ # "latest" would become a union of both releases instead of exactly the
+ # remote's higher version. FETCH_HEAD is the remote tip fetched by the
+ # preceding `git pull --rebase`, i.e. the concurrent deploy we rebased
onto.
+ git rm -rf --ignore-unmatch --quiet -- "${LATEST_OWNED_PATH}" >/dev/null
2>&1 || true
+ git checkout FETCH_HEAD -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true
+ git add -A -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true
+ local kept=() x
+ for x in "${OWNED_PURGE_PATHS[@]}"; do
+ [ "$x" = "${LATEST_OWNED_PATH}" ] || kept+=("$x")
+ done
+ OWNED_PURGE_PATHS=("${kept[@]}")
+ changed=true
+ fi
+ fi
+
+ for p in "${OWNED_PURGE_PATHS[@]}"; do
+ git rm -rf --ignore-unmatch --quiet -- "$p" >/dev/null 2>&1 || true
+ git checkout "$DEPLOY_COMMIT" -- "$p" >/dev/null 2>&1 || true
+ git add -A -- "$p" >/dev/null 2>&1 || true
+ changed=true
Review Comment:
Addressed in b170851. Removed the `|| true` (and output suppression) from
the owned-purge restore:
```sh
git rm -rf --ignore-unmatch --quiet -- "$p" >/dev/null 2>&1 || true
git checkout "$DEPLOY_COMMIT" -- "$p"
git add -A -- "$p"
```
These paths are always present in `DEPLOY_COMMIT` (this deploy published
them), so a `git checkout`/`git add` failure signals a genuinely broken state.
It now fails the job under `set -e` instead of silently committing the folder's
removal and publishing broken docs. Only the best-effort pre-clean `git rm
--ignore-unmatch` stays lenient, since `--ignore-unmatch` already handles the
expected "not present" case.
##########
deploy-github-pages/entrypoint.sh:
##########
@@ -130,6 +139,140 @@ is_highest_version() {
return 0
}
+# Paths this deploy owns. Populated by publish_artifacts and used to reconcile
the
+# working tree after rebasing onto a concurrent deploy (see
reconcile_owned_paths).
+# OWNED_PURGE_PATHS - folders this deploy replaces wholesale
(PURGE_EXISTING=true):
+# on retry, strip anything a concurrent deploy left
there and
+# restore exactly this deploy's content (clean
last-writer-wins).
+# OWNED_KEEP_PATHS - single files this deploy owns outright (e.g. the root
+# index.html): on retry, re-assert just that file. Merged
+# folders (PURGE_EXISTING=false) are intentionally NOT
listed
+# here - the "-X theirs" rebase already gives correct
merge
+# semantics, and re-asserting them would clobber a
concurrent
+# deploy's independent changes.
+OWNED_PURGE_PATHS=()
+OWNED_KEEP_PATHS=()
+
+# If this release publishes the shared "latest" folder, remember its path and
this
+# release's generic (X.X.x) version. "latest" must always hold the HIGHEST
released
+# version, but is_highest_version is evaluated against the checkout taken
before a
+# concurrent higher release may have landed. reconcile_owned_paths re-checks
these
+# against the rebased tree so a lower release retried after a higher one does
not
+# overwrite "latest" with older docs. Empty unless this deploy published
"latest".
+LATEST_OWNED_PATH=""
+LATEST_GENERIC_VERSION=""
+
+# After a push is rejected we rebase this deploy's commit onto the concurrent
deploy
+# with "-X theirs", which wins FILE-LEVEL conflicts but cannot remove files
the other
+# deploy ADDED to a folder we own. Re-assert our owned paths from our original
commit
+# so shared folders (latest, X.X.x, ...) end up as a clean last-writer-wins
instead of
+# a union of both deploys' files. Everything the other deploy published
independently
+# (its own version folders) is untouched and preserved.
+reconcile_owned_paths() {
+ local p changed=false
+
+ # "latest" must hold the HIGHEST released version. If a concurrent, higher
+ # release landed first (its X.X.x folder is now in the just-rebased tree) and
+ # THIS is a lower release, do not overwrite "latest" with our older docs:
+ # restore it to the remote's (higher) content and drop it from our owned set.
+ # Re-run is_highest_version from within TARGET_FOLDER, where the version
folders
+ # actually live, against the merged tree. Same-minor patches compare equal,
so
+ # they still fall through to last-writer-wins, which is fine.
+ if [ -n "${LATEST_OWNED_PATH}" ] && [ -n "${LATEST_GENERIC_VERSION}" ]; then
+ if ! ( cd "${TARGET_FOLDER}" && is_highest_version
"${LATEST_GENERIC_VERSION}" ); then
+ echo "A concurrent higher release now owns ${LATEST_OWNED_PATH};
yielding it to the remote."
+ # Strip our rebased copy first so files that exist ONLY in our (lower)
+ # version are removed - otherwise the checkout below would leave them and
+ # "latest" would become a union of both releases instead of exactly the
+ # remote's higher version. FETCH_HEAD is the remote tip fetched by the
+ # preceding `git pull --rebase`, i.e. the concurrent deploy we rebased
onto.
+ git rm -rf --ignore-unmatch --quiet -- "${LATEST_OWNED_PATH}" >/dev/null
2>&1 || true
+ git checkout FETCH_HEAD -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true
+ git add -A -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true
+ local kept=() x
+ for x in "${OWNED_PURGE_PATHS[@]}"; do
+ [ "$x" = "${LATEST_OWNED_PATH}" ] || kept+=("$x")
+ done
+ OWNED_PURGE_PATHS=("${kept[@]}")
+ changed=true
+ fi
+ fi
+
+ for p in "${OWNED_PURGE_PATHS[@]}"; do
+ git rm -rf --ignore-unmatch --quiet -- "$p" >/dev/null 2>&1 || true
+ git checkout "$DEPLOY_COMMIT" -- "$p" >/dev/null 2>&1 || true
+ git add -A -- "$p" >/dev/null 2>&1 || true
+ changed=true
+ done
+ for p in "${OWNED_KEEP_PATHS[@]}"; do
+ git checkout "$DEPLOY_COMMIT" -- "$p" >/dev/null 2>&1 || true
+ git add -A -- "$p" >/dev/null 2>&1 || true
+ changed=true
Review Comment:
Addressed in b170851. Same fail-safe applied to the `OWNED_KEEP_PATHS`
restore:
```sh
git checkout "$DEPLOY_COMMIT" -- "$p"
git add -A -- "$p"
```
The `|| true` and output suppression are removed, so if restoring an owned
file (e.g. the root `index.html`) fails, the job fails under `set -e` rather
than silently pushing a missing file. These paths always exist in
`DEPLOY_COMMIT`, so a failure here is a genuinely broken state.
--
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]