chore(desktop): bump to 0.1.1 for re-release with rate-schedule + pro… #331
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" |