From 4740fd4f20c9393cb4a5ff8138d7e12114995bca Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Thu, 4 Sep 2025 13:34:39 +0200 Subject: [PATCH 1/8] Initial version --- .github/workflows/ci.yaml | 120 ++++++++++++++++++++++++++++++++-- .github/workflows/release.yml | 58 +++++++++++++++- 2 files changed, 173 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 31c93c96c9..0675c63766 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,6 +12,7 @@ on: - opened # PR was open - reopened # PR was closed and is now open again - ready_for_review # PR was converted from draft to open + - closed # PR was closed concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -108,14 +109,125 @@ jobs: HAPPO_API_KEY: ${{ secrets.HAPPO_API_KEY }} HAPPO_API_SECRET: ${{ secrets.HAPPO_API_SECRET }} - deploy-docs: + deploy-storybook-preview: if: ${{ github.event.pull_request.head.ref != 'changeset-release/master' }} - name: Deploy Picasso docs + name: Deploy Storybook Preview runs-on: ubuntu-latest permissions: - contents: read + contents: write + pull-requests: write + needs: [static-checks] steps: - name: Checkout uses: actions/checkout@v4 - # Some new deployment process is needed here + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.18 + + - name: Install dependencies from cache + uses: ./.github/actions/yarn-install + + - name: Build Storybook + run: yarn build:storybook + + - name: Checkout existing gh-pages content + uses: actions/checkout@v4 + with: + ref: gh-pages + path: gh-pages-content + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Prepare preview deployment + run: | + # Create pr-{number} directory in existing gh-pages content + PR_DIR="gh-pages-content/pr-${{ github.event.pull_request.number }}" + + # Remove existing PR directory if it exists + rm -rf "$PR_DIR" + + # Create new PR directory and copy storybook build + mkdir -p "$PR_DIR" + cp -r build/storybook/* "$PR_DIR/" + + echo "๐Ÿ“‚ Prepared preview in: $PR_DIR" + ls -la "$PR_DIR" + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: gh-pages-content + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + + - name: Comment on PR + uses: actions/github-script@v7 + with: + script: | + const prNumber = '${{ github.event.pull_request.number }}'; + const deployUrl = `https://toptal.github.io/picasso/pr-${prNumber}/`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '๐Ÿ“– **Storybook Preview**\n\n๐Ÿš€ Your Storybook preview is ready: **[View Storybook](' + deployUrl + ')**\n\n๐Ÿ“ Preview URL: `' + deployUrl + '`\n\nThis preview is updated automatically when you push changes to this PR.' + }); + + cleanup-storybook-preview: + if: ${{ github.event.action == 'closed' }} + name: Cleanup Storybook Preview + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + pages: write + id-token: write + steps: + - name: Checkout gh-pages branch + uses: actions/checkout@v4 + with: + ref: gh-pages + path: gh-pages-content + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Remove PR preview directory + run: | + PR_DIR="gh-pages-content/pr-${{ github.event.pull_request.number }}" + if [ -d "$PR_DIR" ]; then + echo "๐Ÿ—‘๏ธ Removing preview directory: $PR_DIR" + rm -rf "$PR_DIR" + echo "Remaining content after cleanup:" + ls -la gh-pages-content/ + else + echo "Preview directory $PR_DIR does not exist" + fi + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: gh-pages-content + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + + - name: Comment cleanup notification + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '๐Ÿ—‘๏ธ **Storybook preview cleaned up**\n\nThe preview deployment has been automatically removed since this PR was closed.' + }); diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a79d7538ec..759ca716c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,6 +16,8 @@ jobs: contents: write issues: write pull-requests: write + pages: write + id-token: write steps: - name: Checkout Repo uses: actions/checkout@v4 @@ -136,7 +138,61 @@ jobs: payload: | text: 'A new PR was merged to Picasso :parrotspin:' - # Implement Storybook deployment here + - name: Build Storybook for Production + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + run: | + yarn build:storybook + echo "๐Ÿ“– Building Storybook for production deployment..." >> $GITHUB_STEP_SUMMARY + + - name: Checkout existing gh-pages content + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + uses: actions/checkout@v4 + with: + ref: gh-pages + path: gh-pages-content + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Prepare production deployment (preserve PR previews) + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + run: | + # Backup PR preview directories + mkdir -p pr-backups + find gh-pages-content -maxdepth 1 -name "pr-*" -type d -exec cp -r {} pr-backups/ \; 2>/dev/null || true + + # Clear gh-pages content but preserve .git + find gh-pages-content -mindepth 1 -not -path "*/\.git*" -exec rm -rf {} + 2>/dev/null || true + + # Copy new production build to root + cp -r build/storybook/* gh-pages-content/ + + # Restore PR preview directories + find pr-backups -maxdepth 1 -name "pr-*" -type d -exec cp -r {} gh-pages-content/ \; 2>/dev/null || true + + echo "๐Ÿ“‚ Production content prepared, PR previews preserved" + echo "Content structure:" + ls -la gh-pages-content/ + + - name: Setup Pages + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + uses: actions/configure-pages@v4 + + - name: Upload artifact + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + uses: actions/upload-pages-artifact@v3 + with: + path: gh-pages-content + + - name: Deploy Production Storybook to GitHub Pages + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + id: storybook-deployment + uses: actions/deploy-pages@v4 + + - name: Storybook Deployment Success + if: ${{ success() && steps.changesets.outputs.published == 'true' }} + run: | + echo "๐Ÿš€ Production Storybook deployed to GitHub Pages!" >> $GITHUB_STEP_SUMMARY + echo "๐Ÿ“– Visit: https://toptal.github.io/picasso/" >> $GITHUB_STEP_SUMMARY + echo "โœ… PR previews preserved during production deployment" >> $GITHUB_STEP_SUMMARY integration-tests: name: Integration Tests From 57d038983df8d33448d571a917cbbdd33a51fcfa Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Thu, 4 Sep 2025 14:08:03 +0200 Subject: [PATCH 2/8] Initial version --- .github/workflows/ci.yaml | 20 ++++++++++++++++++++ .github/workflows/release.yml | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0675c63766..e4249486fd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -133,12 +133,22 @@ jobs: run: yarn build:storybook - name: Checkout existing gh-pages content + id: checkout-gh-pages uses: actions/checkout@v4 + continue-on-error: true with: ref: gh-pages path: gh-pages-content token: ${{ secrets.GITHUB_TOKEN }} + - name: Create gh-pages directory if branch doesn't exist + if: steps.checkout-gh-pages.outcome == 'failure' + run: | + echo "๐Ÿ†• gh-pages branch doesn't exist, creating empty directory structure" + mkdir -p gh-pages-content + echo "# Picasso Storybook" > gh-pages-content/README.md + echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md + - name: Prepare preview deployment run: | # Create pr-{number} directory in existing gh-pages content @@ -191,12 +201,22 @@ jobs: id-token: write steps: - name: Checkout gh-pages branch + id: checkout-gh-pages-cleanup uses: actions/checkout@v4 + continue-on-error: true with: ref: gh-pages path: gh-pages-content token: ${{ secrets.GITHUB_TOKEN }} + - name: Create gh-pages directory if branch doesn't exist + if: steps.checkout-gh-pages-cleanup.outcome == 'failure' + run: | + echo "๐Ÿ†• gh-pages branch doesn't exist, creating empty directory structure" + mkdir -p gh-pages-content + echo "# Picasso Storybook" > gh-pages-content/README.md + echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md + - name: Remove PR preview directory run: | PR_DIR="gh-pages-content/pr-${{ github.event.pull_request.number }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 759ca716c0..0531c7fcde 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -146,12 +146,22 @@ jobs: - name: Checkout existing gh-pages content if: ${{ success() && steps.changesets.outputs.published == 'true' }} + id: checkout-gh-pages-release uses: actions/checkout@v4 + continue-on-error: true with: ref: gh-pages path: gh-pages-content token: ${{ secrets.GITHUB_TOKEN }} + - name: Create gh-pages directory if branch doesn't exist + if: ${{ success() && steps.changesets.outputs.published == 'true' && steps.checkout-gh-pages-release.outcome == 'failure' }} + run: | + echo "๐Ÿ†• gh-pages branch doesn't exist, creating empty directory structure" + mkdir -p gh-pages-content + echo "# Picasso Storybook" > gh-pages-content/README.md + echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md + - name: Prepare production deployment (preserve PR previews) if: ${{ success() && steps.changesets.outputs.published == 'true' }} run: | From dd828856169ae97b8f729ae1d8d784bf8510b769 Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Thu, 4 Sep 2025 14:35:32 +0200 Subject: [PATCH 3/8] Initial version --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e4249486fd..84dfef5d7c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -116,6 +116,8 @@ jobs: permissions: contents: write pull-requests: write + pages: write + id-token: write needs: [static-checks] steps: - name: Checkout From f585d6fe9270d47adb9f78173767ef722909f8cb Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Thu, 4 Sep 2025 16:59:50 +0200 Subject: [PATCH 4/8] Initial version --- .github/workflows/ci.yaml | 6 ++++++ .github/workflows/release.yml | 3 +++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 84dfef5d7c..b511c9bb0f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -113,6 +113,9 @@ jobs: if: ${{ github.event.pull_request.head.ref != 'changeset-release/master' }} name: Deploy Storybook Preview runs-on: ubuntu-latest + concurrency: + group: gh-pages-deployment + cancel-in-progress: false permissions: contents: write pull-requests: write @@ -196,6 +199,9 @@ jobs: if: ${{ github.event.action == 'closed' }} name: Cleanup Storybook Preview runs-on: ubuntu-latest + concurrency: + group: gh-pages-deployment + cancel-in-progress: false permissions: contents: write pull-requests: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0531c7fcde..8f40a37497 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,9 @@ jobs: release: name: Release runs-on: ubuntu-latest + concurrency: + group: gh-pages-deployment + cancel-in-progress: false permissions: contents: write issues: write From a2b7e23d0725eb4ec5b514cd934f1c1f54cbdf06 Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Fri, 5 Sep 2025 10:54:39 +0200 Subject: [PATCH 5/8] Initial version --- .github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b511c9bb0f..49dd4b0e42 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -109,9 +109,9 @@ jobs: HAPPO_API_KEY: ${{ secrets.HAPPO_API_KEY }} HAPPO_API_SECRET: ${{ secrets.HAPPO_API_SECRET }} - deploy-storybook-preview: + deploy-picasso-docs: if: ${{ github.event.pull_request.head.ref != 'changeset-release/master' }} - name: Deploy Storybook Preview + name: Deploy Picasso docs runs-on: ubuntu-latest concurrency: group: gh-pages-deployment @@ -195,7 +195,7 @@ jobs: body: '๐Ÿ“– **Storybook Preview**\n\n๐Ÿš€ Your Storybook preview is ready: **[View Storybook](' + deployUrl + ')**\n\n๐Ÿ“ Preview URL: `' + deployUrl + '`\n\nThis preview is updated automatically when you push changes to this PR.' }); - cleanup-storybook-preview: + cleanup-picasso-docs: if: ${{ github.event.action == 'closed' }} name: Cleanup Storybook Preview runs-on: ubuntu-latest From 188f88e740a1a95fca71c540f153cbeebd9f6717 Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Fri, 5 Sep 2025 11:07:47 +0200 Subject: [PATCH 6/8] Initial version --- .github/workflows/ci.yaml | 29 +++++++++++++++++++---------- .github/workflows/release.yml | 35 +++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 49dd4b0e42..c65804dbd3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -149,15 +149,18 @@ jobs: - name: Create gh-pages directory if branch doesn't exist if: steps.checkout-gh-pages.outcome == 'failure' run: | - echo "๐Ÿ†• gh-pages branch doesn't exist, creating empty directory structure" - mkdir -p gh-pages-content + echo "๐Ÿ†• gh-pages branch doesn't exist, creating organized directory structure" + mkdir -p gh-pages-content/prs echo "# Picasso Storybook" > gh-pages-content/README.md echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md + echo "" >> gh-pages-content/README.md + echo "- Production: Root directory" >> gh-pages-content/README.md + echo "- PR Previews: prs/{number}/" >> gh-pages-content/README.md - name: Prepare preview deployment run: | - # Create pr-{number} directory in existing gh-pages content - PR_DIR="gh-pages-content/pr-${{ github.event.pull_request.number }}" + # Create previews/pr-{number} directory in organized structure + PR_DIR="gh-pages-content/previews/pr-${{ github.event.pull_request.number }}" # Remove existing PR directory if it exists rm -rf "$PR_DIR" @@ -186,7 +189,7 @@ jobs: with: script: | const prNumber = '${{ github.event.pull_request.number }}'; - const deployUrl = `https://toptal.github.io/picasso/pr-${prNumber}/`; + const deployUrl = `https://toptal.github.io/picasso/previews/pr-${prNumber}/`; await github.rest.issues.createComment({ owner: context.repo.owner, @@ -220,19 +223,25 @@ jobs: - name: Create gh-pages directory if branch doesn't exist if: steps.checkout-gh-pages-cleanup.outcome == 'failure' run: | - echo "๐Ÿ†• gh-pages branch doesn't exist, creating empty directory structure" - mkdir -p gh-pages-content + echo "๐Ÿ†• gh-pages branch doesn't exist, creating organized directory structure" + mkdir -p gh-pages-content/prs echo "# Picasso Storybook" > gh-pages-content/README.md echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md + echo "" >> gh-pages-content/README.md + echo "- Production: Root directory" >> gh-pages-content/README.md + echo "- PR Previews: prs/{number}/" >> gh-pages-content/README.md + echo "" >> gh-pages-content/README.md + echo "- Production: Root directory" >> gh-pages-content/README.md + echo "- PR Previews: previews/pr-{number}/" >> gh-pages-content/README.md - name: Remove PR preview directory run: | - PR_DIR="gh-pages-content/pr-${{ github.event.pull_request.number }}" + PR_DIR="gh-pages-content/previews/pr-${{ github.event.pull_request.number }}" if [ -d "$PR_DIR" ]; then echo "๐Ÿ—‘๏ธ Removing preview directory: $PR_DIR" rm -rf "$PR_DIR" - echo "Remaining content after cleanup:" - ls -la gh-pages-content/ + echo "Remaining previews after cleanup:" + ls -la gh-pages-content/previews/ || echo "No previews directory" else echo "Preview directory $PR_DIR does not exist" fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f40a37497..a336ab4bdb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -160,30 +160,41 @@ jobs: - name: Create gh-pages directory if branch doesn't exist if: ${{ success() && steps.changesets.outputs.published == 'true' && steps.checkout-gh-pages-release.outcome == 'failure' }} run: | - echo "๐Ÿ†• gh-pages branch doesn't exist, creating empty directory structure" - mkdir -p gh-pages-content + echo "๐Ÿ†• gh-pages branch doesn't exist, creating organized directory structure" + mkdir -p gh-pages-content/prs echo "# Picasso Storybook" > gh-pages-content/README.md echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md + echo "" >> gh-pages-content/README.md + echo "- Production: Root directory" >> gh-pages-content/README.md + echo "- PR Previews: prs/{number}/" >> gh-pages-content/README.md - name: Prepare production deployment (preserve PR previews) if: ${{ success() && steps.changesets.outputs.published == 'true' }} run: | - # Backup PR preview directories - mkdir -p pr-backups - find gh-pages-content -maxdepth 1 -name "pr-*" -type d -exec cp -r {} pr-backups/ \; 2>/dev/null || true + # Preserve prs directory if it exists + if [ -d "gh-pages-content/prs" ]; then + echo "๐Ÿ“ Backing up prs directory" + mv gh-pages-content/prs ./prs-backup + fi - # Clear gh-pages content but preserve .git - find gh-pages-content -mindepth 1 -not -path "*/\.git*" -exec rm -rf {} + 2>/dev/null || true + # Clear root content but preserve .git and prs + find gh-pages-content -mindepth 1 -maxdepth 1 -not -name ".git" -not -name "prs" -exec rm -rf {} + - # Copy new production build to root + # Deploy production to root + echo "๐Ÿ“ฆ Deploying production Storybook to root" cp -r build/storybook/* gh-pages-content/ - # Restore PR preview directories - find pr-backups -maxdepth 1 -name "pr-*" -type d -exec cp -r {} gh-pages-content/ \; 2>/dev/null || true + # Restore prs + if [ -d "./prs-backup" ]; then + echo "๐Ÿ”„ Restoring prs directory" + mv ./prs-backup gh-pages-content/prs + fi - echo "๐Ÿ“‚ Production content prepared, PR previews preserved" - echo "Content structure:" + echo "๐Ÿ“‚ Production deployment prepared with preserved previews" + echo "Root content:" ls -la gh-pages-content/ + echo "PR previews content:" + ls -la gh-pages-content/prs/ 2>/dev/null || echo "No prs directory" - name: Setup Pages if: ${{ success() && steps.changesets.outputs.published == 'true' }} From 5d7d63d66f8458b0305a80e8ca8ed3e3156b77c4 Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Fri, 5 Sep 2025 11:27:21 +0200 Subject: [PATCH 7/8] Initial version --- .github/workflows/ci.yaml | 77 +---------- .github/workflows/cleanup-previews.yml | 175 +++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 74 deletions(-) create mode 100644 .github/workflows/cleanup-previews.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c65804dbd3..d9b8f5e9c5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -159,8 +159,8 @@ jobs: - name: Prepare preview deployment run: | - # Create previews/pr-{number} directory in organized structure - PR_DIR="gh-pages-content/previews/pr-${{ github.event.pull_request.number }}" + # Create prs/{number} directory in organized structure + PR_DIR="gh-pages-content/prs/${{ github.event.pull_request.number }}" # Remove existing PR directory if it exists rm -rf "$PR_DIR" @@ -189,7 +189,7 @@ jobs: with: script: | const prNumber = '${{ github.event.pull_request.number }}'; - const deployUrl = `https://toptal.github.io/picasso/previews/pr-${prNumber}/`; + const deployUrl = `https://toptal.github.io/picasso/prs/${prNumber}/`; await github.rest.issues.createComment({ owner: context.repo.owner, @@ -197,74 +197,3 @@ jobs: issue_number: context.issue.number, body: '๐Ÿ“– **Storybook Preview**\n\n๐Ÿš€ Your Storybook preview is ready: **[View Storybook](' + deployUrl + ')**\n\n๐Ÿ“ Preview URL: `' + deployUrl + '`\n\nThis preview is updated automatically when you push changes to this PR.' }); - - cleanup-picasso-docs: - if: ${{ github.event.action == 'closed' }} - name: Cleanup Storybook Preview - runs-on: ubuntu-latest - concurrency: - group: gh-pages-deployment - cancel-in-progress: false - permissions: - contents: write - pull-requests: write - pages: write - id-token: write - steps: - - name: Checkout gh-pages branch - id: checkout-gh-pages-cleanup - uses: actions/checkout@v4 - continue-on-error: true - with: - ref: gh-pages - path: gh-pages-content - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Create gh-pages directory if branch doesn't exist - if: steps.checkout-gh-pages-cleanup.outcome == 'failure' - run: | - echo "๐Ÿ†• gh-pages branch doesn't exist, creating organized directory structure" - mkdir -p gh-pages-content/prs - echo "# Picasso Storybook" > gh-pages-content/README.md - echo "This directory contains Storybook deployments for Picasso." >> gh-pages-content/README.md - echo "" >> gh-pages-content/README.md - echo "- Production: Root directory" >> gh-pages-content/README.md - echo "- PR Previews: prs/{number}/" >> gh-pages-content/README.md - echo "" >> gh-pages-content/README.md - echo "- Production: Root directory" >> gh-pages-content/README.md - echo "- PR Previews: previews/pr-{number}/" >> gh-pages-content/README.md - - - name: Remove PR preview directory - run: | - PR_DIR="gh-pages-content/previews/pr-${{ github.event.pull_request.number }}" - if [ -d "$PR_DIR" ]; then - echo "๐Ÿ—‘๏ธ Removing preview directory: $PR_DIR" - rm -rf "$PR_DIR" - echo "Remaining previews after cleanup:" - ls -la gh-pages-content/previews/ || echo "No previews directory" - else - echo "Preview directory $PR_DIR does not exist" - fi - - - name: Setup Pages - uses: actions/configure-pages@v4 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: gh-pages-content - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 - - - name: Comment cleanup notification - uses: actions/github-script@v7 - with: - script: | - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: '๐Ÿ—‘๏ธ **Storybook preview cleaned up**\n\nThe preview deployment has been automatically removed since this PR was closed.' - }); diff --git a/.github/workflows/cleanup-previews.yml b/.github/workflows/cleanup-previews.yml new file mode 100644 index 0000000000..9fc29b9058 --- /dev/null +++ b/.github/workflows/cleanup-previews.yml @@ -0,0 +1,175 @@ +name: Cleanup PR Previews + +on: + # Immediate cleanup when PR closes + pull_request: + types: [closed] + branches: + - master + - 'feature/**' + + # Scheduled garbage collection (runs weekly on Sundays at 2 AM UTC) + schedule: + - cron: '0 2 * * 0' + + # Manual trigger for emergency cleanup + workflow_dispatch: + inputs: + cleanup_mode: + description: 'Cleanup mode' + required: true + default: 'single' + type: choice + options: + - single + - all_closed + - force_all + +concurrency: + group: gh-pages-deployment + cancel-in-progress: false + +jobs: + cleanup-single-pr: + if: ${{ github.event_name == 'pull_request' }} + name: Cleanup Single PR Preview + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + pages: write + id-token: write + steps: + - name: Checkout gh-pages branch + id: checkout-gh-pages + uses: actions/checkout@v4 + continue-on-error: true + with: + ref: gh-pages + path: gh-pages-content + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Remove PR preview directory + if: steps.checkout-gh-pages.outcome == 'success' + run: | + PR_DIR="gh-pages-content/prs/${{ github.event.pull_request.number }}" + if [ -d "$PR_DIR" ]; then + echo "๐Ÿ—‘๏ธ Removing preview directory: $PR_DIR" + rm -rf "$PR_DIR" + echo "โœ… Cleanup successful" + else + echo "โ„น๏ธ Preview directory $PR_DIR does not exist" + fi + + - name: Deploy cleanup to GitHub Pages + if: steps.checkout-gh-pages.outcome == 'success' + uses: actions/upload-pages-artifact@v3 + with: + path: gh-pages-content + + - name: Deploy to GitHub Pages + if: steps.checkout-gh-pages.outcome == 'success' + uses: actions/deploy-pages@v4 + + - name: Comment cleanup notification + if: steps.checkout-gh-pages.outcome == 'success' + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '๐Ÿ—‘๏ธ **Storybook preview cleaned up**\n\nThe preview deployment has been automatically removed since this PR was closed.' + }); + + garbage-collection: + if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + name: Garbage Collection + runs-on: ubuntu-latest + permissions: + contents: write + pages: write + id-token: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Checkout gh-pages branch + id: checkout-gh-pages + uses: actions/checkout@v4 + continue-on-error: true + with: + ref: gh-pages + path: gh-pages-content + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Garbage collect orphaned previews + if: steps.checkout-gh-pages.outcome == 'success' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + + // Get all open PRs + const { data: openPRs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open' + }); + + const openPRNumbers = new Set(openPRs.map(pr => pr.number.toString())); + console.log(`๐Ÿ“Š Found ${openPRNumbers.size} open PRs:`, Array.from(openPRNumbers).join(', ')); + + // Check prs directory + const prsDir = 'gh-pages-content/prs'; + if (!fs.existsSync(prsDir)) { + console.log('โ„น๏ธ No prs directory found'); + return; + } + + const existingPreviews = fs.readdirSync(prsDir); + console.log(`๐Ÿ“ Found ${existingPreviews.length} preview directories:`, existingPreviews.join(', ')); + + let cleanedCount = 0; + for (const prDir of existingPreviews) { + const prNumber = prDir; + + // Skip if PR is still open (unless force mode) + if (openPRNumbers.has(prNumber) && '${{ github.event.inputs.cleanup_mode }}' !== 'force_all') { + console.log(`โญ๏ธ Skipping ${prNumber} (PR still open)`); + continue; + } + + // Remove closed PR preview + const fullPath = path.join(prsDir, prDir); + try { + fs.rmSync(fullPath, { recursive: true, force: true }); + console.log(`๐Ÿ—‘๏ธ Cleaned up preview: ${prNumber}`); + cleanedCount++; + } catch (error) { + console.error(`โŒ Failed to clean ${prNumber}:`, error.message); + } + } + + console.log(`โœ… Garbage collection complete: ${cleanedCount} previews cleaned`); + + // Set output for summary + core.setOutput('cleaned_count', cleanedCount); + core.setOutput('total_found', existingPreviews.length); + + - name: Deploy cleanup to GitHub Pages + if: steps.checkout-gh-pages.outcome == 'success' + uses: actions/upload-pages-artifact@v3 + with: + path: gh-pages-content + + - name: Deploy to GitHub Pages + if: steps.checkout-gh-pages.outcome == 'success' + uses: actions/deploy-pages@v4 + + - name: Summary + run: | + echo "๐Ÿงน **Garbage Collection Summary**" >> $GITHUB_STEP_SUMMARY + echo "- Trigger: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY From 92ca545f1447158ce9cd6cb880dcf07c3972ac94 Mon Sep 17 00:00:00 2001 From: Vedran Ivanac Date: Fri, 5 Sep 2025 11:35:35 +0200 Subject: [PATCH 8/8] Initial version --- .github/workflows/ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d9b8f5e9c5..1222557832 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,6 @@ on: - opened # PR was open - reopened # PR was closed and is now open again - ready_for_review # PR was converted from draft to open - - closed # PR was closed concurrency: group: ${{ github.workflow }}-${{ github.ref }}