From 7a3c92b22c87fa525a6d3688b7c2ea45ef9e8f17 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 15:40:58 -0700 Subject: [PATCH 1/8] Updated ci workflow --- .github/workflows/ci.yml | 152 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9701d96..981c46a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,13 +8,56 @@ on: types: [opened, reopened, synchronize] jobs: + meta: + name: Generate and check metadata + runs-on: ubuntu-latest + outputs: + environment: ${{ steps.environment.outputs.environment }} + labels: ${{ steps.meta.outputs.labels }} + tag: ${{ steps.meta.outputs.tags }} + tag_names: ${{ steps.meta.outputs.tag_names }} + tag_exists: ${{ steps.check-image.outputs.tag_exists }} + json: ${{ steps.meta.outputs.json }} + version: ${{ steps.meta.outputs.version }} + steps: + - name: Set environment variable based on branch + id: environment + run: | + if [[ "${{ github.ref_name }}" == "main" ]]; then + echo "environment=main" >> "$GITHUB_OUTPUT" + elif [[ "${{ github.ref_name }}" == "dev" ]]; then + echo "environment=dev" >> "$GITHUB_OUTPUT" + fi + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ vars.REGISTRY_IMAGE }} + tags: | + type=sha,format=long + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Check if image exists already + id: check-image + run: | + if docker manifest inspect ${{ steps.meta.outputs.tags }} > /dev/null 2>&1; then + echo "tag_exists=true" >> "$GITHUB_OUTPUT" + else + echo "tag_exists=false" >> "$GITHUB_OUTPUT" + fi + test: name: Test + needs: meta runs-on: ubuntu-latest - container: node:24.14.1-trixie + if: ${{ needs.meta.outputs.tag_exists == 'false' }} + container: node:22.19.0-bookworm services: db: - image: postgres:18.3 + image: postgres:17.6 env: POSTGRES_PASSWORD: postgres minio: @@ -29,11 +72,106 @@ jobs: cache: 'npm' - name: Install Dependencies run: npm ci - - name: Generate Prisma client - run: npm run prisma:generate -w server - env: - DATABASE_URL: postgresql://postgres:postgres@db:5432/app + - name: Generate Prisma client and compile forms + run: npm run prisma:generate -w server && npm run build:forms -w server - name: Run ESLint - run: npm run lint + run: npm run lint:check - name: Run Tests run: cp server/example.env server/.env && npm test + + build: + name: Build Image + needs: [ meta, test ] + strategy: + fail-fast: false + matrix: + runner: + - ubuntu-24.04 + - ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + if: ${{ github.ref_name == 'dev' || github.ref_name == 'main' }} + steps: + - name: Prepare + run: | + if [[ ${{ matrix.runner }} == "ubuntu-24.04-arm" ]]; then + platform=linux/arm64 + else + platform=linux/amd64 + fi + echo "PLATFORM=${platform}" >> $GITHUB_ENV + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + - name: Set up docker buildx + uses: docker/setup-buildx-action@v3 + - name: Login to docker hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + platforms: ${{ env.PLATFORM }} + labels: ${{ needs.meta.outputs.labels }} + tags: ${{ vars.REGISTRY_IMAGE }} + outputs: type=image,push-by-digest=true,name-canonical=true,push=true + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: [ meta, build ] + env: + DOCKER_METADATA_OUTPUT_VERSION: ${{ needs.meta.outputs.version }} + DOCKER_METADATA_OUTPUT_TAGS: ${{ needs.meta.outputs.tag }} + DOCKER_METADATA_OUTPUT_TAG_NAMES: ${{ needs.meta.outputs.tag_names }} + DOCKER_METADATA_OUTPUT_LABELS: ${{ needs.meta.outputs.labels }} + DOCKER_METADATA_OUTPUT_JSON: ${{ needs.meta.outputs.json }} + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Create manifest list and push + working-directory: ${{ runner.temp }}/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ vars.REGISTRY_IMAGE }}@sha256:%s ' *) + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ needs.meta.outputs.tag }} + + deploy: + name: Deploy + needs: [ meta, merge ] + if: | + always() + && (needs.meta.outputs.tag_exists == 'true' || needs.merge.result == 'success') + runs-on: ubuntu-latest + environment: ${{ needs.meta.outputs.environment }} + steps: + - name: Push to dokku + uses: dokku/github-action@master + with: + git_remote_url: ${{ vars.DOKKU_GIT_REMOTE_URL }} + ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} + deploy_docker_image: ${{ needs.meta.outputs.tag }} From 7bd262442b2a021748598f1116a16b614bb8f9c9 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 15:43:21 -0700 Subject: [PATCH 2/8] Fix ci.yml --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 981c46a..c60243f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,12 +72,14 @@ jobs: cache: 'npm' - name: Install Dependencies run: npm ci - - name: Generate Prisma client and compile forms - run: npm run prisma:generate -w server && npm run build:forms -w server + - name: Generate Prisma client + run: npm run prisma:generate -w server - name: Run ESLint run: npm run lint:check - name: Run Tests run: cp server/example.env server/.env && npm test + - name: Build client + run: npm run build -w client build: name: Build Image From 34269c57ced34c103e305bfb67778abe4560bbc0 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 15:46:48 -0700 Subject: [PATCH 3/8] Update actions, add DATABASE_URL placeholder for prisma generate --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c60243f..32a42d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,13 +30,13 @@ jobs: fi - name: Docker meta id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: ${{ vars.REGISTRY_IMAGE }} tags: | type=sha,format=long - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -64,16 +64,16 @@ jobs: image: minio/minio:RELEASE.2025-09-07T16-13-09Z steps: - name: Check out repository code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up npm cache - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: 'npm' - name: Install Dependencies run: npm ci - name: Generate Prisma client - run: npm run prisma:generate -w server + run: DATABASE_URL=test npm run prisma:generate -w server - name: Run ESLint run: npm run lint:check - name: Run Tests From 20d92bb6098fd97cf2d329b3323aa5195d502588 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 15:49:55 -0700 Subject: [PATCH 4/8] Add lint:check --- client/package.json | 1 + package.json | 1 + server/package.json | 1 + 3 files changed, 3 insertions(+) diff --git a/client/package.json b/client/package.json index e44a698..1b95a47 100644 --- a/client/package.json +++ b/client/package.json @@ -9,6 +9,7 @@ "build:client": "vite build --outDir dist/client", "build:server": "vite build --ssr src/entry-server.jsx --outDir dist/server", "lint": "eslint --fix", + "lint:check": "eslint", "preview": "vite preview", "test": "" }, diff --git a/package.json b/package.json index 0c53328..48502b3 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "dev": "cp -n server/example.env server/.env; cp server/.env client/.env; nf -j Procfile.dev start", "lint": "npm run lint --workspaces", + "lint:check": "npm run lint:check --workspaces", "test": "npm test --workspaces" }, "devDependencies": { diff --git a/server/package.json b/server/package.json index 002f5f5..fbd9184 100644 --- a/server/package.json +++ b/server/package.json @@ -9,6 +9,7 @@ "scripts": { "dev": "prisma migrate deploy; prisma db push --accept-data-loss; npm run prisma:generate; fastify start -w -l info -P app.js", "lint": "eslint --fix", + "lint:check": "eslint", "pretest": "eslint", "prisma:generate": "prisma generate; tsc", "prisma:studio": "prisma studio", From bd982cb2febac79a75df3737e6b0c0b971126759 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 18:15:30 -0700 Subject: [PATCH 5/8] Test build in PR branch --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32a42d6..5f28569 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: - ubuntu-24.04 - ubuntu-24.04-arm runs-on: ${{ matrix.runner }} - if: ${{ github.ref_name == 'dev' || github.ref_name == 'main' }} + # if: ${{ github.ref_name == 'dev' || github.ref_name == 'main' }} steps: - name: Prepare run: | From 4dde830afdd3b51bcc0bc1fa7285e2cad88b430c Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 18:22:43 -0700 Subject: [PATCH 6/8] Skip deploy step if no DOKKU URL set --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f28569..38d9167 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,6 +168,7 @@ jobs: if: | always() && (needs.meta.outputs.tag_exists == 'true' || needs.merge.result == 'success') + && ${{ vars.DOKKU_GIT_REMOTE_URL != '' }} runs-on: ubuntu-latest environment: ${{ needs.meta.outputs.environment }} steps: From b614bd1cf406093a38d365590aa18afada1dd6ae Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 18:28:30 -0700 Subject: [PATCH 7/8] Adjust conditional syntax --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38d9167..f358b3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,9 +166,9 @@ jobs: name: Deploy needs: [ meta, merge ] if: | - always() + ${{ always() && (needs.meta.outputs.tag_exists == 'true' || needs.merge.result == 'success') - && ${{ vars.DOKKU_GIT_REMOTE_URL != '' }} + && vars.DOKKU_GIT_REMOTE_URL != '' }} runs-on: ubuntu-latest environment: ${{ needs.meta.outputs.environment }} steps: From 9a6c8ba04ceaa237ee05daba4a3e44ed4336e14a Mon Sep 17 00:00:00 2001 From: Francis Li Date: Thu, 18 Jun 2026 18:34:01 -0700 Subject: [PATCH 8/8] Restore build/deploy to only dev/main branches --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f358b3e..fd664b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: - ubuntu-24.04 - ubuntu-24.04-arm runs-on: ${{ matrix.runner }} - # if: ${{ github.ref_name == 'dev' || github.ref_name == 'main' }} + if: ${{ github.ref_name == 'dev' || github.ref_name == 'main' }} steps: - name: Prepare run: |