Skip to content
This repository was archived by the owner on Sep 16, 2026. It is now read-only.
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
87 changes: 0 additions & 87 deletions .github/workflows/main.yml

This file was deleted.

59 changes: 47 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
name: Release

# npm Trusted Publishing (OIDC) for @uinaf/attach-cli + uinaf-releaser.
# Worker deploy stays in main.yml — never needs: [release].
# The file name is load-bearing: the trusted publisher binds this package's
# OIDC identity to `.github/workflows/release.yml` plus the `release`
# environment. So the publish job stays here, and everything else that runs on
# a push to main came to it.
#
# `deploy` and `release` are siblings, both on `needs: [verify, scan]`.
# Never make deploy `needs: [release]`. attach.uinaf.dev must keep shipping
# when publication fails.
#
# First-time bootstrap (human, once): manual npm publish of @uinaf/attach-cli,
# then `npm trust github …` — see docs/releasing.md. CI owns every later release.
Expand All @@ -12,37 +19,65 @@ on:

permissions: {}

concurrency:
group: main-${{ github.repository }}
cancel-in-progress: false

jobs:
# One verify and one secret scan for the whole push pipeline. These used to
# live here and in main.yml, on the same trigger, so every push to main ran
# the entire gate twice: two verifies and eight scan jobs per commit.
verify:
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
permissions:
contents: read
uses: ./.github/workflows/verify.yml

scan:
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
permissions:
contents: read
uses: uinaf/.github/.github/workflows/scan.yml@main

deploy:
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
needs: [verify, scan]
runs-on: ubuntu-24.04
timeout-minutes: 10
timeout-minutes: 20
permissions:
contents: read
environment:
name: production
url: https://attach.uinaf.dev
concurrency:
group: verify-release-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: deploy-${{ github.repository }}-production
cancel-in-progress: false
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0

- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
with:
standalone: true

- uses: voidzero-dev/setup-vp@313600b80b104eadebb9111787d37a2e83e014ca # v1.17.0
with:
node-version-file: ".node-version"
cache: true
cache: false
run-install: |
- args: ["--frozen-lockfile"]
- run: pnpm exec vp run ready

scan:
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
permissions:
contents: read
uses: uinaf/.github/.github/workflows/scan.yml@main
- name: Deploy Worker
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_D1_DATABASE_ID: ${{ vars.CLOUDFLARE_D1_DATABASE_ID }}
ALLOWED_GITHUB_USER_IDS: ${{ vars.ALLOWED_GITHUB_USER_IDS }}
ATTACH_PUBLIC_BASE: ${{ vars.ATTACH_PUBLIC_BASE }}
run: |
pnpm exec vp run -t @uinaf/attach-web#build
node apps/api/scripts/deploy.ts

release:
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
merge_group:
# release.yml calls this for pushes to main. One definition serves every
# trigger; a second copy is how the gate drifts from the gate that guards
# the branch it ships from.
workflow_call:
workflow_dispatch:

permissions:
contents: read

concurrency:
# `github.workflow` and `github.ref` resolve to the caller's, so a called run
# groups under its caller and never collides with a PR run.
group: verify-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# A superseded pull request run is waste. A superseded push to main is not:
# it is the run whose result the release and deploy jobs need.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
Comment on lines +20 to +22

jobs:
verify:
Expand Down
2 changes: 1 addition & 1 deletion docs/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Production Worker deploys from CI, not from a laptop.

Push to `main` → `.github/workflows/main.yml` → GitHub Environment `production`
Push to `main` → `.github/workflows/release.yml` → GitHub Environment `production`
→ `apps/api/scripts/deploy.ts` (build landing assets, dry-run the Worker,
validate R2 lifecycle, D1 migrate, deploy). The dry run and lifecycle gate must
pass before production D1 is mutated.
Expand Down
8 changes: 4 additions & 4 deletions docs/releasing.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Releasing

| Workflow | On push to `main` |
| ------------------------------- | -------------------------------------------------------------------------- |
| `.github/workflows/main.yml` | verify → secret scan → Worker deploy (`production`) |
| `.github/workflows/release.yml` | verify → secret scan → npm + Homebrew (`release`, OIDC + `uinaf-releaser`) |
One workflow runs on push to `main`. `.github/workflows/release.yml` runs a
single `verify` and a single `scan`, then `deploy` (Worker, `production`) and
`release` (npm + Homebrew, `release`, OIDC + `uinaf-releaser`) as siblings, both
on `needs: [verify, scan]`.

Worker deploy stays independent of npm. Do not make deploy `needs: [release]`.

Expand Down