Skip to content

refactor: guardrails for branches#3241

Merged
mfranzke merged 1 commit into
mainfrom
refactor-guardrails-for-branches
Jun 22, 2026
Merged

refactor: guardrails for branches#3241
mfranzke merged 1 commit into
mainfrom
refactor-guardrails-for-branches

Conversation

@mfranzke

Copy link
Copy Markdown
Member

Analysis

Root Cause: The cleanup workflow unconditionally deploys

Looking at cleanup.yml:

  1. It checks out the current branch (not gh-pages)
  2. Downloads the gh-pages tarball into ./public
  3. Runs cleanup-gh-pages.js which removes stale dirs from ./public/review/ and ./public/version/
  4. Unconditionally deploys ./public back to gh-pages — regardless of whether the cleanup script actually deleted anything

The peaceiris/actions-gh-pages action with publish_dir: ./public replaces the entire gh-pages branch content with what's in ./public.

Problem 1: ./index.html (root-level files) are lost

The build-gh-page.sh script shows that on a release (RELEASE == "true"), the root of ./public is populated with the build output (mv ./out ./public), and existing review/ and version/ folders are preserved by copying them back in. This is what creates the root index.html.

However, in cleanup.yml, step 1 checks out the repo's default branch (not gh-pages). So the ./public directory is built only from the gh-pages tarball. That tarball should contain index.html. But here's the critical issue:

The cleanup script's deploy result is never checked. The deploy step runs unconditionally. If the tarball download or extraction has any issue (partial download, rate limiting, network error), the deploy will overwrite gh-pages with incomplete content — wiping index.html and anything else that didn't survive.

Problem 2: ./review/main/ is deleted by the cleanup script

This is the primary bug. Look at cleanup-gh-pages.js:

const removeOldFromPath = (isTag, data) => {
  const path = `public/${isTag ? 'version' : 'review'}`;
  // ...
  const dirsToDelete = FS.readdirSync(path).filter(
    (file) => !data.find((branch) => branch.name === file)
  );

It lists all directories under public/review/ and keeps only those whose name matches a branch returned by github.rest.repos.listBranches().

The GitHub API listBranches endpoint is paginated and defaults to 30 results per page. If the repo has more than 30 branches, the main branch might not appear in the first page of results. Since the script doesn't handle pagination, it may not see main in the response, and will delete review/main/.

Even if main does appear, the more fundamental issue is: the script is designed to clean up preview branches for closed PRs. But review/main/ is presumably a permanent deployment of the main branch's build output — it should never be cleaned up.

Solution

Two fixes needed:

  1. Handle pagination (or use paginate) in the API calls
  2. Protect permanent paths (review/main/ and root-level files) from deletion
  3. Only deploy if something changed to avoid unnecessary overwrites

Here's the fix:

Now let's fix the workflow to only deploy when the cleanup actually removed something:

Summary of Changes

Two bugs identified, three fixes applied:

Issue Cause Fix
review/main/ deleted listBranches is paginated (default 30). If main isn't in the first page, the script treats it as stale and deletes it. 1. Use github.paginate() to fetch all branches/tags. 2. Add PROTECTED_DIRS = ['main'] so it's never removed regardless.
index.html disappears The deploy step ran unconditionally — even when nothing was cleaned. Any glitch during tarball download/extraction would overwrite gh-pages with incomplete content. Added if: fromJSON(steps.cleanup.outputs.result).deploy so the deploy only happens when files were actually removed.

The pagination fix ensures accurate branch lookup, the protected list ensures review/main/ survives even edge cases, and the conditional deploy prevents unnecessary (and potentially destructive) overwrites of the gh-pages branch.

@mfranzke mfranzke self-assigned this Jun 22, 2026
@mfranzke
mfranzke requested review from dkolba and nmerget as code owners June 22, 2026 05:50
@github-actions

Copy link
Copy Markdown
Contributor

🔭🐙🐈 Test this branch here: https://db-ui.github.io/elements/review/refactor-guardrails-for-branches

@github-actions github-actions Bot added the cicd Changes inside .github folder label Jun 22, 2026
@mfranzke
mfranzke enabled auto-merge (squash) June 22, 2026 05:51
@mfranzke
mfranzke merged commit bc14054 into main Jun 22, 2026
41 checks passed
@mfranzke
mfranzke deleted the refactor-guardrails-for-branches branch June 22, 2026 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cicd Changes inside .github folder improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants