fix(ci): sync the server checkout after deployment
All checks were successful
Test and deploy / Verify production build (push) Successful in 4m54s
All checks were successful
Test and deploy / Verify production build (push) Successful in 4m54s
Fast-forward the deployment checkout to the exact healthy image commit while refusing tracked changes, divergence, or an unexpected branch. Ignore release metadata stored beside the checkout.
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -42,3 +42,8 @@ Desktop.ini
|
|||||||
*.temp
|
*.temp
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
|
|
||||||
|
# Server deployment state
|
||||||
|
/.deploy.lock
|
||||||
|
/current
|
||||||
|
/releases/
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ Release manifests are stored in `<DEPLOY_PATH>/releases/<commit-sha>`. Each
|
|||||||
manifest records the immutable image tag and Gitea run number. The `current`
|
manifest records the immutable image tag and Gitea run number. The `current`
|
||||||
symlink is changed only after the new container is healthy. If startup fails,
|
symlink is changed only after the new container is healthy. If startup fails,
|
||||||
the deployment script restarts the previous image without rebuilding it.
|
the deployment script restarts the previous image without rebuilding it.
|
||||||
|
After health succeeds, the Git checkout at `<DEPLOY_PATH>` is fast-forwarded to
|
||||||
|
the exact deployed commit. Deployment refuses to overwrite tracked server-side
|
||||||
|
changes or a checkout that has diverged from `origin/main`.
|
||||||
|
|
||||||
## Gitea Actions setup
|
## Gitea Actions setup
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,40 @@ mkdir -p -- "$releases_dir"
|
|||||||
exec 9>"$deploy_root/.deploy.lock"
|
exec 9>"$deploy_root/.deploy.lock"
|
||||||
flock -x 9
|
flock -x 9
|
||||||
|
|
||||||
|
sync_checkout() {
|
||||||
|
local branch remote_release
|
||||||
|
|
||||||
|
if [[ ! -d "$deploy_root/.git" ]]; then
|
||||||
|
echo "Deployment root is not a Git checkout: $deploy_root" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! git -C "$deploy_root" diff --quiet --ignore-submodules -- \
|
||||||
|
|| ! git -C "$deploy_root" diff --cached --quiet --ignore-submodules --; then
|
||||||
|
echo "Refusing to update a checkout with tracked changes: $deploy_root" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
branch="$(git -C "$deploy_root" symbolic-ref --quiet --short HEAD || true)"
|
||||||
|
if [[ "$branch" != "main" ]]; then
|
||||||
|
echo "Deployment checkout must be on main, not ${branch:-detached HEAD}." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "$deploy_root" fetch --quiet \
|
||||||
|
origin "+refs/heads/main:refs/remotes/origin/main"
|
||||||
|
remote_release="$(git -C "$deploy_root" rev-parse refs/remotes/origin/main)"
|
||||||
|
if [[ "$remote_release" != "$release_id" ]]; then
|
||||||
|
echo "origin/main is $remote_release, expected deployed release $release_id." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "$deploy_root" merge --ff-only --quiet refs/remotes/origin/main
|
||||||
|
if [[ "$(git -C "$deploy_root" rev-parse HEAD)" != "$release_id" ]]; then
|
||||||
|
echo "Checkout did not advance to deployed release $release_id." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
if ! docker image inspect "$image" >/dev/null 2>&1; then
|
if ! docker image inspect "$image" >/dev/null 2>&1; then
|
||||||
echo "Verified runtime image is missing from the production Docker daemon: $image" >&2
|
echo "Verified runtime image is missing from the production Docker daemon: $image" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -63,7 +97,8 @@ if [[ -n "$previous_release" && -f "$previous_release/release.env" ]]; then
|
|||||||
current_sequence="$(sed -n 's/^DEPLOY_SEQUENCE=//p' "$previous_release/release.env")"
|
current_sequence="$(sed -n 's/^DEPLOY_SEQUENCE=//p' "$previous_release/release.env")"
|
||||||
current_release="$(basename "$previous_release")"
|
current_release="$(basename "$previous_release")"
|
||||||
if [[ "$current_release" == "$release_id" ]]; then
|
if [[ "$current_release" == "$release_id" ]]; then
|
||||||
echo "Release is already active: $release_id"
|
sync_checkout
|
||||||
|
echo "Release and server checkout are already active: $release_id"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
if [[ "$current_sequence" =~ ^[1-9][0-9]*$ ]] && (( sequence <= current_sequence )); then
|
if [[ "$current_sequence" =~ ^[1-9][0-9]*$ ]] && (( sequence <= current_sequence )); then
|
||||||
@@ -144,6 +179,10 @@ if activate "$release_dir"; then
|
|||||||
new_link="$deploy_root/.current-$release_id-$$"
|
new_link="$deploy_root/.current-$release_id-$$"
|
||||||
ln -s -- "$release_dir" "$new_link"
|
ln -s -- "$release_dir" "$new_link"
|
||||||
mv -Tf -- "$new_link" "$current_link"
|
mv -Tf -- "$new_link" "$current_link"
|
||||||
|
if ! sync_checkout; then
|
||||||
|
echo "Deployment is healthy, but the server checkout could not be updated." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
echo "Deployment succeeded: $release_id ($image)"
|
echo "Deployment succeeded: $release_id ($image)"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user