Skip to content

build(deps): switch package manager to pnpm #61

build(deps): switch package manager to pnpm

build(deps): switch package manager to pnpm #61

Workflow file for this run

name: Preview deployment
# Since 2025-12-08 `pull_request_target` always takes the workflow file and the checked-out commit
# from the default branch, whatever the pull request targets. Pull-request code therefore never runs
# on this runner, which holds the Coolify webhook secret.
on:
pull_request_target:
types: [labeled, synchronize, reopened, ready_for_review]
permissions: {}
jobs:
deploy:
name: "Preview / Deploy"
if: >-
vars.COOLIFY_URL != '' &&
vars.COOLIFY_APP_UUID != '' &&
vars.COOLIFY_PREVIEW_URL_TEMPLATE != '' &&
(github.event.label.name == 'preview' ||
contains(github.event.pull_request.labels.*.name, 'preview'))
runs-on: ubuntu-latest
permissions:
attestations: read
contents: read
deployments: write
packages: read
pull-requests: write
# Longer than the budgets inside the scripts (image wait, deploy, reachability), so a run that
# exceeds them reports a deployment status instead of being cancelled without one.
timeout-minutes: 40
concurrency:
group: hephaestus-preview-admission
cancel-in-progress: false
env:
COOLIFY_URL: ${{ vars.COOLIFY_URL }}
COOLIFY_APP_UUID: ${{ vars.COOLIFY_APP_UUID }}
COOLIFY_PREVIEW_URL_TEMPLATE: ${{ vars.COOLIFY_PREVIEW_URL_TEMPLATE }}
PREVIEW_MAX_ACTIVE: ${{ vars.PREVIEW_MAX_ACTIVE }}
steps:
- name: Load the trusted preview controller
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
persist-credentials: false
sparse-checkout: |
.github/actions/setup-node-pnpm
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
scripts
- name: Set up the repository's Node.js and pnpm versions
uses: ./.github/actions/setup-node-pnpm
- name: Resolve the pull request head
id: context
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const controller = await import(`${process.env.GITHUB_WORKSPACE}/scripts/preview-controller.ts`);
await controller.resolve({ github, context, core });
- name: Explain why the preview did not deploy
if: steps.context.outputs.announce == 'true'
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: app-preview
number: ${{ steps.context.outputs.pr_number }}
message: |
## 🚧 App Preview
Not deployed: ${{ steps.context.outputs.reason }}
<sub>Remove the `preview` label to opt out.</sub>
- name: Wait for CI to publish this commit's signed images
if: steps.context.outputs.eligible == 'true'
env:
GHCR_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
run: node scripts/coolify-preview.ts images
- name: Recheck opt-in and head before queueing
id: recheck
if: steps.context.outputs.eligible == 'true'
env:
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const controller = await import(`${process.env.GITHUB_WORKSPACE}/scripts/preview-controller.ts`);
await controller.recheck({ github, context, core });
- name: Reserve the native GitHub deployment
id: github_deployment
if: steps.recheck.outputs.proceed == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
ENVIRONMENT: ${{ steps.context.outputs.environment }}
PREVIEW_URL: ${{ steps.context.outputs.preview_url }}
SOURCE_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
with:
script: |
const controller = await import(`${process.env.GITHUB_WORKSPACE}/scripts/preview-controller.ts`);
await controller.create({ github, context, core });
- name: Announce the deployment
if: steps.github_deployment.outputs.deployment_id != ''
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: app-preview
number: ${{ steps.context.outputs.pr_number }}
message: |
## 🚧 App Preview
Deploying `${{ steps.context.outputs.head_sha }}`…
<sub>Runs the images CI published for this commit. Updates on every commit. Remove the `preview` label to tear it down.</sub>
- name: Queue the exact commit through Coolify's signed PR webhook
id: queue
if: steps.recheck.outputs.proceed == 'true'
env:
COOLIFY_TOKEN: ${{ secrets.COOLIFY_PREVIEW_READ_TOKEN }}
COOLIFY_WEBHOOK_SECRET: ${{ secrets.COOLIFY_PREVIEW_WEBHOOK_SECRET }}
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
PR_URL: ${{ steps.context.outputs.pr_url }}
PR_TITLE: ${{ steps.context.outputs.pr_title }}
AUTHOR_ASSOCIATION: ${{ steps.context.outputs.author_association }}
HEAD_REF: ${{ steps.context.outputs.head_ref }}
BASE_REF: ${{ steps.context.outputs.base_ref }}
run: node scripts/coolify-preview.ts queue
- name: Wait for Coolify and verify the preview
id: wait
if: steps.queue.outputs.deployment_uuid != ''
env:
COOLIFY_TOKEN: ${{ secrets.COOLIFY_PREVIEW_READ_TOKEN }}
DEPLOYMENT_UUID: ${{ steps.queue.outputs.deployment_uuid }}
EXPECTED_SHA: ${{ steps.context.outputs.head_sha }}
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
PREVIEW_URL: ${{ steps.context.outputs.preview_url }}
run: node scripts/coolify-preview.ts wait
- name: Finalize the GitHub deployment
id: finalize
if: always() && steps.github_deployment.outputs.deployment_id != ''
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
DEPLOYMENT_ID: ${{ steps.github_deployment.outputs.deployment_id }}
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
ENVIRONMENT: ${{ steps.context.outputs.environment }}
PREVIEW_URL: ${{ steps.context.outputs.preview_url }}
SOURCE_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
FINAL_STATE: ${{ steps.wait.outputs.state || 'error' }}
DESCRIPTION: ${{ steps.wait.outputs.description || 'Preview workflow stopped unexpectedly.' }}
LOG_URL: ${{ steps.wait.outputs.log_url || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}
with:
script: |
const controller = await import(`${process.env.GITHUB_WORKSPACE}/scripts/preview-controller.ts`);
await controller.finalize({ github, context, core });
- name: Publish the preview link
if: steps.finalize.outputs.final_state == 'success'
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: app-preview
number: ${{ steps.context.outputs.pr_number }}
message: |
## 🚀 App Preview
🔗 **[Open preview](${{ steps.context.outputs.preview_url }})**
<sub>Preview for commit ${{ steps.context.outputs.head_sha }}. Updates on every commit. Remove the `preview` label to tear it down.</sub>
# An opted-in pull request must not learn about a red preview only from the Actions tab.
- name: Report a failed preview
if: >-
always() &&
steps.context.outputs.eligible == 'true' &&
steps.recheck.outputs.opted_out != 'true' &&
steps.wait.outputs.state != 'success'
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: app-preview
number: ${{ steps.context.outputs.pr_number }}
message: |
## ❌ App Preview
${{ steps.wait.outputs.description || 'CI did not publish images for this commit in time, or the preview could not be prepared.' }}
🔎 **[Deployment log](${{ steps.wait.outputs.log_url || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }})**
<sub>The next commit retries automatically.</sub>
- name: Fail when the preview failed
if: steps.queue.outputs.deployment_uuid != '' && steps.wait.outputs.state != 'success'
env:
FINAL_STATE: ${{ steps.wait.outputs.state || 'error' }}
run: |
echo "::error::Preview deployment ended in state ${FINAL_STATE}."
exit 1