Copilot commented on code in PR #98:
URL:
https://github.com/apache/grails-github-actions/pull/98#discussion_r3522465273
##########
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:
In reconcile_owned_paths, yielding "latest" to FETCH_HEAD ignores failures
from `git checkout` / `git add` (`|| true`). If either command fails (e.g.,
unexpected repo state, missing ref/path), the action can silently commit a
deletion of the latest docs and push it. It’s safer to fail the job rather than
publish an incomplete docs tree.
##########
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:
Similarly for OWNED_KEEP_PATHS, ignoring failures from `git checkout` / `git
add` can result in silently pushing an unexpected state (e.g., missing
index.html) if the restore fails. These operations should be expected to
succeed and should fail the job if they don’t.
##########
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:
Owned-path reconciliation currently ignores failures from `git checkout` /
`git add` (`|| true`). If restoring an owned folder from DEPLOY_COMMIT fails
for any reason, this can silently commit the folder’s removal and publish
broken documentation. Since these paths are expected to exist in DEPLOY_COMMIT,
letting the job fail is safer than masking the error.
--
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]