Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 34 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,40 +144,48 @@ jobs:
run: pnpm turbo test --force
env: ${{ matrix.env }}

publishDocs:
name: Publish Docs to Cloudflare Pages
build_docs:
name: 'Build: Docs'
runs-on: ubuntu-latest
timeout-minutes: 15
needs:
- install_dependencies
permissions:
contents: read
deployments: write
pull-requests: write
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.UX_OSS_CLOUDFLARE_API_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: TurboRepo local server
uses: felixmosh/turborepo-gh-artifacts@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: ./.github/actions/pnpm
- run: pnpm build:docs
- name: Publish to Cloudflare Pages
id: publishStep
# skip (rather than fail) when the Cloudflare secrets are not
# configured, e.g. on forks or PRs from forks
if: env.CLOUDFLARE_API_TOKEN != ''
uses: cloudflare/pages-action@v1
- uses: actions/upload-artifact@v4
with:
name: docs-app-dist
if-no-files-found: error
path: |
./docs-app/dist/**/*
!node_modules/
!./**/node_modules/

deploy_docs:
name: 'Deploy: Production'
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [build_docs]
permissions:
contents: read
deployments: write
steps:
- uses: actions/download-artifact@v4
with:
apiToken: ${{ secrets.UX_OSS_CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.UX_OSS_CLOUDFLARE_ACCOUNT_ID }}
projectName: ember-headless-form
directory: ./docs-app/dist
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
- uses: marocchino/sticky-pull-request-comment@v2
if: env.CLOUDFLARE_API_TOKEN != '' && github.event_name == 'pull_request'
name: docs-app-dist
path: docs-app-dist
- name: Publish
uses: cloudflare/wrangler-action@v4
with:
message: |+
## Preview URLs
Env: ${{ steps.publishStep.outputs.environment }}
Docs: ${{ steps.publishStep.outputs.url }}
# # api docs: ${{ steps.publishStep.outputs.url }}/api/modules.html
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy ./docs-app-dist/ --project-name=ue-form
161 changes: 161 additions & 0 deletions .github/workflows/deploy-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Because C.I. jobs could expose secrets to malicious pull requests,
# GitHub prevents (by default) exposing action secrets to pull requests
# from forks.
#
# This is great, however, the jobs that use the secrets are still useful on
# pull requests.
#
# To run a _trusted_ workflow, we can trigger it from an event from an _untrusted_
# workflow. This keeps the secrets out of reach from the fork, but still allows
# us to keep the utility of pull request preview deploys.
# Normally, this _trusted_ behavior is offloaded to Cloudflare, Netlify, Vercel, etc
# -- their own workers are trusted and can push comments / updates to pull requests.
#
# To be *most* secure, you'd need to build all the artifacts in the PR,
# then upload them to then be downloaded in the trusted workflows.
# Trusted workflows should not run any scripts from a PR, as malicious
# submitters may tweak the build scripts.
# Since all build artifacts are for the web browser, and not executed in
# node-space, we can be reasonably confident that downloading and deploying
# those artifacts does not compromise our secrets.
#
# More information here:
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
name: Deploy Preview

# read-write repo token
# access to secrets
on:
workflow_dispatch:
inputs:
prNum:
description: 'PR #'
required: true
type: string

workflow_run:
workflows: ['CI']
types:
# as early as possible
- requested

concurrency:
group: deploy-preview-${{ github.event.workflow_run.pull_requests[0].number || github.event.inputs.prNum || github.ref }}
cancel-in-progress: true

env:
TURBO_API: http://127.0.0.1:9080
TURBO_TOKEN: this-is-not-a-secret
TURBO_TEAM: myself

jobs:
determinePR:
# this job gates the others -- if the workflow_run request did not come from a PR,
# exit as early as possible
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request' || github.event.inputs.prNum
outputs:
number: ${{ steps.pr-info.outputs.number }}
branch: ${{ steps.pr-info.outputs.branch }}
repo: ${{ steps.pr-info.outputs.repo }}
steps:
- id: pr-info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ -n "${{ github.event.inputs.prNum }}" ]; then
PR_NUM="${{ github.event.inputs.prNum }}"
PR_JSON=$(gh pr view "$PR_NUM" --repo "${{ github.repository }}" --json headRefName,headRepository,headRepositoryOwner)
BRANCH=$(echo "$PR_JSON" | jq -r '.headRefName')
REPO=$(echo "$PR_JSON" | jq -r '.headRepositoryOwner.login + "/" + .headRepository.name')
else
# For fork PRs, pull_requests[] is empty, so look up by SHA
PR_NUM="${{ github.event.workflow_run.pull_requests[0].number }}"
if [ -z "$PR_NUM" ]; then
HEAD_SHA="${{ github.event.workflow_run.head_sha }}"
PR_NUM=$(gh pr list --repo "${{ github.repository }}" --json number,headRefOid \
--jq ".[] | select(.headRefOid == \"$HEAD_SHA\") | .number")
fi
BRANCH="${{ github.event.workflow_run.head_branch }}"
REPO="${{ github.event.workflow_run.head_repository.full_name }}"
fi

echo "number=$PR_NUM" >> "$GITHUB_OUTPUT"
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
echo "repo=${REPO:-${{ github.repository }}}" >> "$GITHUB_OUTPUT"

# This is the only job that needs access to the source code
Build:
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [determinePR]
steps:
- uses: actions/checkout@v4
with:
repository: ${{ needs.determinePR.outputs.repo }}
ref: ${{ needs.determinePR.outputs.branch }}
persist-credentials: false
- name: TurboRepo local server
uses: felixmosh/turborepo-gh-artifacts@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: wyvox/action-setup-pnpm@v4
with:
node-version: 24
# a real (pnpm-run) build so pnpm re-syncs the injected
# workspace-package copies created by the install above
- run: pnpm build:packages --force
- run: pnpm build:docs
- uses: actions/upload-artifact@v4
with:
name: deploy-prep-dist
if-no-files-found: error
path: |
./docs-app/dist/**/*
!node_modules/
!./**/node_modules/

#################################################################
# For the rest:
# Does not checkout code, has access to secrets
#################################################################

DeployPreview_Docs:
name: 'Deploy: Preview'
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [Build, determinePR]
permissions:
contents: read
deployments: write
outputs:
docsUrl: ${{ steps.deploy.outputs.deployment-url }}
steps:
- uses: actions/download-artifact@v4
with:
name: deploy-prep-dist
path: deploy-prep-dist
- id: deploy
uses: cloudflare/wrangler-action@v4
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy ./deploy-prep-dist/ --project-name=ue-form --branch=${{ needs.determinePR.outputs.branch }}

PostComment:
name: Post Preview URL as comment to PR
runs-on: ubuntu-latest
needs: [DeployPreview_Docs, determinePR]
permissions:
pull-requests: write
steps:
- uses: marocchino/sticky-pull-request-comment@v3
with:
header: preview-urls
number: ${{ needs.determinePR.outputs.number }}
message: |+
| Project | Preview URL |
| ------- | ----------- |
| Docs | ${{ needs.DeployPreview_Docs.outputs.docsUrl }} |

[Logs](https://github.com/universal-ember/form/actions/runs/${{ github.run_id }})
Loading