From 51c92ea9275afb6fc022c9d5f18396110f2e2884 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Sun, 6 Sep 2026 20:44:09 +0200 Subject: [PATCH] ci: create GitHub Actions workflow for testing and multi-arch Docker publishing --- .github/workflows/ci.yml | 87 +++++++++++++++++++++++++++++++++++++++ tests/ci-workflow.test.ts | 55 +++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 tests/ci-workflow.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9877f8b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,87 @@ +name: CI + +on: + push: + branches: + - main + tags: + - 'v*.*.*' + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + test: + name: Test & Lint + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.14 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Type check + run: bun run typecheck + + - name: Run test suite + run: bun test + + docker: + name: Build & Publish Docker Image + needs: test + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + flavor: | + latest=auto + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix=sha- + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + + - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/tests/ci-workflow.test.ts b/tests/ci-workflow.test.ts new file mode 100644 index 0000000..7fb3892 --- /dev/null +++ b/tests/ci-workflow.test.ts @@ -0,0 +1,55 @@ +import { describe, test, expect } from "bun:test"; +import { existsSync, readFileSync } from "node:fs"; +import { resolve } from "node:path"; + +const ROOT_DIR = resolve(import.meta.dir, ".."); +const WORKFLOW_PATH = resolve(ROOT_DIR, ".github/workflows/ci.yml"); + +describe("GitHub Actions CI Workflow", () => { + test("ci.yml exists and has proper triggers and permissions", () => { + expect(existsSync(WORKFLOW_PATH)).toBe(true); + + const content = readFileSync(WORKFLOW_PATH, "utf-8"); + + // Triggers + expect(content).toContain("pull_request:"); + expect(content).toContain("push:"); + expect(content).toContain("workflow_dispatch:"); + expect(content).toContain("- main"); + expect(content).toContain("- 'v*.*.*'"); + + // Permissions + expect(content).toContain("permissions:"); + expect(content).toContain("contents: read"); + expect(content).toContain("packages: write"); + }); + + test("ci.yml defines test job with Bun 1.3.14 and strict checks", () => { + const content = readFileSync(WORKFLOW_PATH, "utf-8"); + + expect(content).toContain("test:"); + expect(content).toContain("runs-on: ubuntu-latest"); + expect(content).toContain("oven-sh/setup-bun@v2"); + expect(content).toContain("bun-version: 1.3.14"); + expect(content).toContain("bun install --frozen-lockfile"); + expect(content).toContain("bun run typecheck"); + expect(content).toContain("bun test"); + }); + + test("ci.yml defines docker job with multi-arch buildx and ghcr publishing", () => { + const content = readFileSync(WORKFLOW_PATH, "utf-8"); + + expect(content).toContain("docker:"); + expect(content).toContain("needs: test"); + expect(content).toContain("docker/setup-qemu-action@v3"); + expect(content).toContain("docker/setup-buildx-action@v3"); + expect(content).toContain("docker/metadata-action@v5"); + expect(content).toContain("ghcr.io/${{ github.repository }}"); + expect(content).toContain("docker/login-action@v3"); + expect(content).toContain("registry: ghcr.io"); + expect(content).toContain("docker/build-push-action@v6"); + expect(content).toContain("platforms: linux/amd64,linux/arm64"); + expect(content).toContain("push: ${{ github.event_name != 'pull_request' }}"); + expect(content).toContain("type=gha"); + }); +});