From c2b20f310f567188d1a206ee778ce332e213a952 Mon Sep 17 00:00:00 2001 From: delisma Date: Sat, 14 Feb 2026 06:12:11 -0500 Subject: [PATCH] chores: Update jekyll.yml pr-preview.yml --- .github/workflows/cleanup-previews.yml | 161 +++++++++++++++++++++++++ .github/workflows/jekyll.yml | 35 ++---- .github/workflows/pr-preview.yml | 30 ++++- 3 files changed, 200 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/cleanup-previews.yml diff --git a/.github/workflows/cleanup-previews.yml b/.github/workflows/cleanup-previews.yml new file mode 100644 index 000000000..9edc5aa29 --- /dev/null +++ b/.github/workflows/cleanup-previews.yml @@ -0,0 +1,161 @@ +name: Cleanup Stale PR Previews + +on: + schedule: + # Run every day at 2:00 AM UTC + - cron: '0 2 * * *' + workflow_dispatch: # Allow manual trigger + +permissions: + contents: write + pull-requests: read + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Checkout gh-pages branch + uses: actions/checkout@v4 + with: + ref: gh-pages + fetch-depth: 0 + + - name: Clean up stale preview directories + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + const { execSync } = require('child_process'); + + // Configuration + const RETENTION_DAYS = 7; // Keep previews for PRs closed within this many days + + // Helper function to safely extract error information + function extractErrorInfo(error) { + const status = (typeof error === 'object' && error !== null && 'status' in error) + ? error.status + : undefined; + const message = (typeof error === 'object' && error !== null && 'message' in error && typeof error.message === 'string') + ? error.message + : String(error); + return { status, message }; + } + + // Get all open and recently closed PRs (with pagination) + const openPRs = await github.paginate(github.rest.pulls.list, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100 + }); + + const closedPRs = await github.paginate(github.rest.pulls.list, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'closed', + per_page: 100, + sort: 'updated', + direction: 'desc' + }); + + // Keep previews for open PRs and PRs closed in the last N days + const retentionMs = RETENTION_DAYS * 24 * 60 * 60 * 1000; + const cutoffDate = new Date(Date.now() - retentionMs); + const activePRNumbers = new Set([ + ...openPRs.map(pr => pr.number), + ...closedPRs + .filter(pr => pr.closed_at && new Date(pr.closed_at) > cutoffDate) + .map(pr => pr.number) + ]); + + console.log(`Retention period: ${RETENTION_DAYS} days`); + console.log(`Active PR numbers to keep: ${Array.from(activePRNumbers).join(', ')}`); + + // Check if pr-preview directory exists + const previewDir = 'pr-preview'; + if (!fs.existsSync(previewDir)) { + console.log('No pr-preview directory found, nothing to clean up'); + return; + } + + // List all preview directories + const previewDirs = fs.readdirSync(previewDir) + .filter(dir => dir.startsWith('pr-')) + .map(dir => { + const match = dir.match(/^pr-(\d+)$/); + return match ? { dir, prNumber: parseInt(match[1]) } : null; + }) + .filter(x => x !== null); + + console.log(`Found ${previewDirs.length} preview directories`); + + // Identify stale directories + const staleDirectories = previewDirs.filter( + ({ prNumber }) => !activePRNumbers.has(prNumber) + ); + + if (staleDirectories.length === 0) { + console.log('No stale preview directories to remove'); + return; + } + + console.log(`Found ${staleDirectories.length} stale preview directories to remove:`); + staleDirectories.forEach(({ dir, prNumber }) => { + console.log(` - ${dir} (PR #${prNumber})`); + }); + + // Remove stale directories + staleDirectories.forEach(({ dir }) => { + const dirPath = path.join(previewDir, dir); + try { + fs.rmSync(dirPath, { recursive: true, force: true }); + console.log(`Removed: ${dirPath}`); + } catch (error) { + const { message } = extractErrorInfo(error); + console.error(`Failed to remove preview directory: ${dirPath}`, message); + throw error; + } + }); + + // Commit and push changes + try { + execSync('git config --local user.name "github-actions[bot]"', { stdio: 'inherit' }); + execSync('git config --local user.email "github-actions[bot]@users.noreply.github.com"', { stdio: 'inherit' }); + console.log('Git config set successfully'); + } catch (error) { + const { message } = extractErrorInfo(error); + console.error('Failed to configure git:', message); + throw error; + } + + try { + execSync('git add pr-preview', { stdio: 'inherit' }); + console.log('Changes staged successfully'); + } catch (error) { + const { message } = extractErrorInfo(error); + console.error('Failed to stage changes:', message); + throw error; + } + + try { + execSync(`git commit -m "chore: cleanup ${staleDirectories.length} stale PR preview(s)"`, { stdio: 'inherit' }); + console.log('Changes committed successfully'); + } catch (error) { + const { message } = extractErrorInfo(error); + if (message && message.includes('nothing to commit')) { + console.log('No changes to commit'); + return; + } + console.error('Failed to commit changes:', message); + throw error; + } + + try { + execSync('git push', { stdio: 'inherit' }); + console.log('Changes pushed successfully'); + } catch (error) { + const { message } = extractErrorInfo(error); + console.error('Failed to push changes:', message); + throw error; + } diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml index 167b18b5b..058443d3a 100644 --- a/.github/workflows/jekyll.yml +++ b/.github/workflows/jekyll.yml @@ -16,18 +16,18 @@ on: # Sets permissions of the GITHUB_TOKEN to allow pushing to gh-pages permissions: - contents: read + contents: write pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: - group: "pages" + group: 'production-deploy' cancel-in-progress: false jobs: - build: + build_and_deploy: runs-on: ubuntu-latest steps: - name: Checkout @@ -40,28 +40,19 @@ jobs: bundler-cache: true cache-version: 0 - - name: Setup Pages - id: pages - uses: actions/configure-pages@v5 - - name: Build with Jekyll # Outputs to the './_site' directory by default run: bundle exec jekyll build env: JEKYLL_ENV: production - - name: Upload artifact - # Automatically uploads an artifact from the './_site' directory by default - uses: actions/upload-pages-artifact@v3 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + - name: Deploy to gh-pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./_site + # keep_files is intentionally set to true so that existing content (including PR preview directories) + # is not deleted on each deploy. Old preview directories are periodically cleaned up by + # .github/workflows/cleanup-previews.yml to prevent unbounded growth of the gh-pages branch. + keep_files: true + publish_branch: gh-pages diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index 20565e799..cfeb614f3 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -6,7 +6,7 @@ on: - opened - reopened - synchronize -# - closed + - closed # Sets permissions of the GITHUB_TOKEN to allow pushing to gh-pages permissions: @@ -14,7 +14,7 @@ permissions: pull-requests: write concurrency: - group: preview-${{ github.ref }} + group: preview-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: @@ -142,8 +142,30 @@ jobs: currentBody = currentBody.substring(0, markerIndex).trim(); } - const previewSection = `## Alternate language PR\n${alternateLangLink}\n\n---\n\n## 🚀 PR Preview\n\n| Name | Link(s) |\n|------|----------|\n| **Latest commit** | [${context.payload.pull_request.head.sha.substring(0, 7)}](${commitUrl}) |\n| **Page preview** | ${previewLinks} |${otherFilesContent ? `\n| **Other changed files** | ${otherFilesContent} |` : ''}\n\n---\n*Preview updates automatically with each commit*`; - + const otherFilesRow = otherFilesContent + ? `| **Other changed files** | ${otherFilesContent} |` + : null; + + const previewLines = [ + '', + '## Alternate language PR', + alternateLangLink, + '', + '---', + '', + '## 🚀 PR Preview', + '', + '| Name | Link(s) |', + '|------|----------|', + `| **Latest commit** | [${context.payload.pull_request.head.sha.substring(0, 7)}](${commitUrl}) |`, + `| **Page preview** | ${previewLinks} |`, + ...(otherFilesRow ? [otherFilesRow] : []), + '', + '---', + '*Preview updates automatically with each commit*', + ]; + + const previewSection = previewLines.join('\n'); // Update PR description await github.rest.pulls.update({ owner: context.repo.owner,