Skip to content

deploy-docs.sh: root deploy deletes every archived documentation version (/v0.1/ is already 404) #3

Description

@projectious

Summary

scripts/deploy-docs.sh clears the gh-pages root with a blanket delete that also removes the vX.Y/ archive directories. Any deploy of the latest docs therefore destroys the documentation for every previously released version.

This is not hypothetical — the Releases dropdown on the live site already links to a 404.

Evidence

hugo.yaml advertises a v0.1 entry in the version menu:

  versions:
    - version: "main"
      kind: latest
      url: "https://projectious-work.github.io/kubeclaw/"
    - version: "v0.1"
      url: "https://projectious-work.github.io/kubeclaw/v0.1/"

But that URL is gone, and no version directory exists on the branch:

$ curl -o /dev/null -w '%{http_code}' https://projectious-work.github.io/kubeclaw/
200
$ curl -o /dev/null -w '%{http_code}' https://projectious-work.github.io/kubeclaw/v0.1/
404

$ git ls-tree --name-only origin/gh-pages | grep -cE '^v[0-9]'
0

Root cause

if [[ "${DOCS_VERSION}" == "main" ]]; then
find "${WORKTREE_DIR}" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
cp -R "${BUILD_DIR}/." "${WORKTREE_DIR}/"

if [[ "${DOCS_VERSION}" == "main" ]]; then
  find "${WORKTREE_DIR}" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
  cp -R "${BUILD_DIR}/." "${WORKTREE_DIR}/"

The find excludes only .git. Everything else at the top level is removed — including v0.1/, v0.2/, and so on. Those directories are separate published sites living alongside the latest build, not stale output from the previous build.

Why this is easy to miss

If a release publishes the archive first and the root second:

DOCS_VERSION=v1.0.0 ./scripts/deploy-docs.sh   # creates /v1.0.0/
DOCS_VERSION=main   ./scripts/deploy-docs.sh   # deletes /v1.0.0/

…the release deletes its own archive seconds after creating it. The deploy output shows a wall of delete mode 100644 v1.0.0/... lines, which reads like routine churn unless you are looking for it. Both commands succeed and exit 0.

Suggested fix

Exclude semver-named directories from the root clean:

if [[ "${DOCS_VERSION}" == "main" ]]; then
  # Clear the root, but KEEP archived version directories — they are separate
  # published sites, not stale build output from this deploy.
  find "${WORKTREE_DIR}" -mindepth 1 -maxdepth 1 \
    ! -name .git \
    ! -regex '.*/v[0-9]+\.[0-9]+\(\.[0-9]+\)?\(-[0-9A-Za-z.-]+\)?$' \
    -exec rm -rf {} +
  cp -R "${BUILD_DIR}/." "${WORKTREE_DIR}/"

The pattern matches both v0.1 and v1.0.0, plus pre-release suffixes such as v1.2.3-rc.1. Verified against a fixture containing .git, v1.0.0, v1.2.3-rc.1, and ordinary build directories: only .git and the two version directories survive.

Restoring /v0.1/ needs a one-off DOCS_VERSION=v0.1 ./scripts/deploy-docs.sh from the v0.1 tag after the fix lands, since the previous contents are only recoverable from gh-pages history.

Context

Found while adapting this deployment pattern for projectious-work/brand — the docs setup there is closely modelled on kubeclaw's, and it hit exactly this on its first release. Fixed downstream in scripts/deploy-docs.sh; reporting upstream since the defect originates here.

Everything else in the deploy script — the worktree handling, the orphan-branch bootstrap, the .nojekyll write, the no-op short-circuit — worked exactly as intended.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions