Skip to content

chore(desktop): bump to 0.1.1 for re-release with rate-schedule + pro… #331

chore(desktop): bump to 0.1.1 for re-release with rate-schedule + pro…

chore(desktop): bump to 0.1.1 for re-release with rate-schedule + pro… #331

Workflow file for this run

name: CI / CD
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
# Detect whether anything outside docs/README changed. Used to gate the
# publish + deploy jobs so a README-only push doesn't rebuild images
# or redeploy prod.
changes:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- '!README.md'
- '!docs/**'
- '!.github/codeflow-card.svg'
- '!.github/workflows/codeflow-card.yml'
- '!**/*.md'
- '!scripts/launcher/**'
verify:
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- name: Check out repo
uses: actions/checkout@v4
- name: Set up pnpm
uses: pnpm/action-setup@v4
with:
version: 10.30.3
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Generate Prisma client
run: pnpm --filter @bidwright/db db:generate
- name: Typecheck web
run: pnpm --filter @bidwright/web exec tsc --noEmit
- name: Typecheck API
run: pnpm --filter @bidwright/api exec tsc --noEmit
- name: Typecheck worker
run: pnpm --filter @bidwright/worker exec tsc --noEmit
- name: Build API
run: pnpm --filter @bidwright/api build
- name: Build worker
run: pnpm --filter @bidwright/worker build
- name: Build web
run: pnpm --filter @bidwright/web build
- name: Run schedule unit tests
run: pnpm exec tsx --test apps/web/lib/schedule-utils.test.ts
- name: Validate production compose
run: docker compose -f docker-compose.prod.yml config > /dev/null
- name: Validate production registry compose
run: docker compose -f docker-compose.prod-registry.yml config > /dev/null
- name: Validate launcher compose
run: docker compose -f scripts/launcher/docker-compose.yml config > /dev/null
publish:
needs:
- verify
- changes
runs-on: ubuntu-latest
timeout-minutes: 60
if: >
(github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && github.ref == 'refs/heads/main'))
&& needs.changes.outputs.code == 'true'
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- service: api
dockerfile: Dockerfile.api
- service: web
dockerfile: Dockerfile.web
- service: worker
dockerfile: Dockerfile.worker
steps:
- name: Check out repo
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Lowercase repository owner
id: repo
run: echo "owner_lc=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_OUTPUT"
- name: Compute image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ steps.repo.outputs.owner_lc }}/bidwright-${{ matrix.service }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=short
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push ${{ matrix.service }}
uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.service }}
cache-to: type=gha,mode=max,scope=${{ matrix.service }}
provenance: false
deploy:
needs:
- verify
- publish
- changes
# Production lives on the on-prem Dokploy/Docker cluster (project
# "bidwright" at https://cloud.rassaun.com). The deploy job runs on
# a self-hosted, ephemeral GitHub Actions runner that lives ON the
# Dokploy manager node (the "github-runners" Dokploy project, service
# `bidwright-runner`). That runner sits on dokploy-network so it can
# reach dokploy-postgres + the Dokploy API directly by service name.
#
# Why not ubuntu-latest + public webhook?
# Dokploy's deploy command is `docker compose up -d --build
# --remove-orphans` — it does NOT pull new `:latest` digests, so a
# webhook against the public URL with no env change is a no-op.
# We need to bump BIDWRIGHT_TAG in Dokploy's stored env (postgres
# `compose.env` column) so `docker compose` sees the service config
# changed and pulls the new sha-pinned image. The env mutation has
# to happen LAN-side; the runner-on-Dokploy pattern is the cleanest
# path that requires no public-internet-reachable Dokploy API.
#
# Security: PRs from forks NEVER reach this job (it's gated on
# `push && main && ENABLE_SERVER_DEPLOY`). The runner is ephemeral
# (fresh container per job), has no docker.sock mount, no host
# filesystem mount, and only opens network sockets to dokploy-postgres
# + dokploy:3000.
runs-on: [self-hosted, linux, x64, dokploy]
timeout-minutes: 15
environment: production
if: >
(github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' &&
github.ref == 'refs/heads/main' &&
vars.ENABLE_SERVER_DEPLOY == 'true'))
&& needs.changes.outputs.code == 'true'
concurrency:
group: bidwright-production-deploy
cancel-in-progress: false
env:
# The Dokploy compose row name (matches `compose.name` in the
# Dokploy postgres). Distinct from `appName`; this is the
# human-friendly identifier shown in the UI.
COMPOSE_NAME: bidwright
# The .env variable in that compose's stored env whose value
# we bump to the new sha tag.
TAG_ENV_KEY: BIDWRIGHT_TAG
steps:
- name: Install postgres-client + curl in the ephemeral runner
run: |
# Ephemeral runner starts fresh each job; install the two
# binaries the deploy step needs. ~10s.
apt-get update -q
apt-get install -yq --no-install-recommends postgresql-client curl ca-certificates
psql --version
- name: Pin tag in Dokploy env + trigger redeploy
env:
PGPASSWORD: ${{ secrets.DOKPLOY_PG_PASSWORD }}
REFRESH_TOKEN: ${{ secrets.DOKPLOY_REFRESH_TOKEN }}
run: |
set -euo pipefail
SHORT_SHA="${GITHUB_SHA:0:7}"
NEW_TAG="sha-${SHORT_SHA}"
echo "Pinning ${TAG_ENV_KEY}=${NEW_TAG} on Dokploy compose '${COMPOSE_NAME}'…"
# Update the compose's stored env (postgres is the source of truth;
# Dokploy writes it to disk on each deploy). Bare-quotes the
# constants to keep psql/regex sane.
psql -h dokploy-postgres -U dokploy -d dokploy -v ON_ERROR_STOP=1 <<SQL
UPDATE compose
SET env = regexp_replace(env, '${TAG_ENV_KEY}=[^\n]*', '${TAG_ENV_KEY}=${NEW_TAG}')
WHERE name = '${COMPOSE_NAME}';
SELECT
(regexp_match(env, '${TAG_ENV_KEY}=([^\n]+)'))[1] AS confirmed_tag
FROM compose WHERE name = '${COMPOSE_NAME}';
SQL
echo "Triggering Dokploy redeploy…"
# Synchronous: Dokploy waits for compose-up to finish before
# responding. Allow generous time for image pull on first run.
response=$(curl -sf -X GET --max-time 300 \
"http://dokploy:3000/api/deploy/compose/${REFRESH_TOKEN}")
echo "Dokploy response: $response"
echo "::notice title=Deploy complete::Bidwright pinned to ${NEW_TAG} and redeployed. UI: https://cloud.rassaun.com"