paperclip/.github/workflows/storybook-deploy.yml

170 lines
6.9 KiB
YAML

name: Storybook Deploy
on:
workflow_dispatch:
inputs:
branch:
description: "Repository branch to publish (empty uses the selected workflow branch)"
type: string
default: ""
# Also exposed by Storybook Visual, which is already available on master.
workflow_call:
inputs:
branch:
type: string
default: ""
permissions:
contents: read
jobs:
authorize:
name: Authorize Storybook publisher
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
sha: ${{ steps.source.outputs.sha }}
branch: ${{ steps.source.outputs.branch }}
branch_key: ${{ steps.source.outputs.branch_key }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Require CODEOWNER initiator and rerunner
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const authorize = require('./.github/scripts/authorize-storybook-deploy.cjs');
await authorize({ github, context });
- name: Pin requested repository branch
id: source
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
SOURCE_BRANCH: ${{ inputs.branch }}
STORYBOOK_S3_BUCKET: ${{ vars.STORYBOOK_S3_BUCKET }}
STORYBOOK_PUBLIC_BASE_URL: ${{ vars.STORYBOOK_PUBLIC_BASE_URL }}
with:
script: |
const branch = process.env.SOURCE_BRANCH || context.ref.slice('refs/heads/'.length);
const { data } = await github.rest.git.getRef({ ...context.repo, ref: `heads/${branch}` });
if (data.ref !== `refs/heads/${branch}` || data.object.type !== 'commit') {
throw new Error('Select an existing branch in this repository.');
}
// With no source override, preserve the exact dispatched commit.
const sha = process.env.SOURCE_BRANCH ? data.object.sha : context.sha;
const { storybookDestination } = require('./.github/scripts/storybook-destination.cjs');
const destination = storybookDestination({ branch, sha,
runId: context.runId, runAttempt: process.env.GITHUB_RUN_ATTEMPT,
bucket: process.env.STORYBOOK_S3_BUCKET, baseUrl: process.env.STORYBOOK_PUBLIC_BASE_URL });
core.setOutput('sha', sha);
core.setOutput('branch_key', destination.branchKey);
core.setOutput('branch', branch);
build:
name: Build selected branch Storybook
permissions: {}
needs: authorize
runs-on: ubuntu-latest
timeout-minutes: 25
outputs:
artifact_name: ${{ steps.artifact.outputs.name }}
env:
STORYBOOK_DISABLE_TELEMETRY: "1"
steps:
- name: Download public source without repository credentials
env:
SOURCE_SHA: ${{ needs.authorize.outputs.sha }}
run: |
[[ "$SOURCE_SHA" =~ ^[a-f0-9]{40}$ ]]
curl --fail --silent --show-error --location --retry 3 \
"https://codeload.github.com/paperclipai/paperclip/tar.gz/$SOURCE_SHA" \
--output "$RUNNER_TEMP/source.tar.gz"
tar -xzf "$RUNNER_TEMP/source.tar.gz" --strip-components=1
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
with:
version: 9.15.4
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24
package-manager-cache: false
- run: pnpm install --frozen-lockfile --ignore-scripts
- run: pnpm build-storybook
- name: Record source and validate output
id: artifact
env:
SOURCE_SHA: ${{ needs.authorize.outputs.sha }}
SOURCE_BRANCH: ${{ needs.authorize.outputs.branch }}
run: |
test -s ui/storybook-static/index.html
test -s ui/storybook-static/iframe.html
test -s ui/storybook-static/index.json
jq -n --arg sha "$SOURCE_SHA" --arg branch "$SOURCE_BRANCH" \
'{sha: $sha, branch: $branch}' > ui/storybook-static/deployment.json
echo "name=storybook-deploy-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_OUTPUT"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ${{ steps.artifact.outputs.name }}
path: ui/storybook-static
if-no-files-found: error
retention-days: 7
deploy:
name: Publish branch Storybook to S3
needs: [authorize, build]
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: storybook-deploy-${{ needs.authorize.outputs.branch_key }}
cancel-in-progress: false
permissions:
contents: read
id-token: write
environment:
name: storybook-deploy
url: ${{ steps.deployment.outputs.url }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
sparse-checkout: .github/scripts
- name: Recheck CODEOWNER access before publishing
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const authorize = require('./.github/scripts/authorize-storybook-deploy.cjs');
await authorize({ github, context });
- name: Download the successful build artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ${{ needs.build.outputs.artifact_name }}
path: storybook-static
- name: Assume the Storybook-only uploader role
uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6
with:
role-to-assume: ${{ vars.STORYBOOK_AWS_ROLE_ARN }}
aws-region: ${{ vars.STORYBOOK_AWS_REGION }}
role-duration-seconds: 900
- name: Publish this branch preview
id: deployment
env:
SOURCE_SHA: ${{ needs.authorize.outputs.sha }}
SOURCE_BRANCH: ${{ needs.authorize.outputs.branch }}
STORYBOOK_S3_BUCKET: ${{ vars.STORYBOOK_S3_BUCKET }}
STORYBOOK_PUBLIC_BASE_URL: ${{ vars.STORYBOOK_PUBLIC_BASE_URL }}
run: node .github/scripts/publish-storybook.cjs
- name: Verify public build and stable branch URL
env:
BUILD_URL: ${{ steps.deployment.outputs.build_url }}
BRANCH_URL: ${{ steps.deployment.outputs.url }}
SOURCE_SHA: ${{ needs.authorize.outputs.sha }}
run: node .github/scripts/verify-storybook.cjs
- name: Upload deployment links
if: ${{ !cancelled() && steps.deployment.outcome == 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: storybook-deployment-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ steps.deployment.outputs.report_path }}
if-no-files-found: error
retention-days: 30