diff --git a/.github/workflows/ci.yml b/.gitea/workflows/ci.yml similarity index 53% rename from .github/workflows/ci.yml rename to .gitea/workflows/ci.yml index 84194a2..24f3208 100644 --- a/.github/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,19 +1,15 @@ -name: CI +name: Continuous Integration on: push: - branches: - - main - tags: - - 'v*.*.*' + branches: [main] + tags: ['v*'] pull_request: - branches: - - main + branches: [main] workflow_dispatch: -permissions: - contents: read - packages: write +env: + REGISTRY: gitea.lucaswinther.info jobs: test: @@ -26,7 +22,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.14 + bun-version: 1.4.4 - name: Install dependencies run: bun install --frozen-lockfile @@ -39,7 +35,7 @@ jobs: env: SKIP_DOCKER_TESTS: "true" - docker: + docker-build-and-push: name: Build & Publish Docker Image needs: test runs-on: ubuntu-latest @@ -47,46 +43,34 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Lowercase image name - run: echo "IMAGE_NAME=ghcr.io/$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV" - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Docker metadata + # Gitea's job token cannot publish packages; use a package-write PAT. + - name: Log in to Gitea Container Registry + if: gitea.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: lucasw89 + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.IMAGE_NAME }} - flavor: | - latest=auto + images: ${{ env.REGISTRY }}/lucasw89/openproject-mcp tags: | + type=raw,value=latest,enable={{is_default_branch}} 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' }} + push: ${{ gitea.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/Dockerfile b/Dockerfile index 2975cb8..8b276e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Dependency resolution and production prune -FROM oven/bun:1-slim AS builder +FROM oven/bun:1.4.4-slim AS builder WORKDIR /app # Copy dependency manifests @@ -9,7 +9,7 @@ COPY package.json bun.lock ./ RUN bun install --frozen-lockfile --production # Stage 2: Minimal runtime image -FROM oven/bun:1-slim AS runner +FROM oven/bun:1.4.4-slim AS runner WORKDIR /app ENV NODE_ENV=production diff --git a/tests/ci-workflow.test.ts b/tests/ci-workflow.test.ts index 1b87383..bce5ada 100644 --- a/tests/ci-workflow.test.ts +++ b/tests/ci-workflow.test.ts @@ -3,10 +3,10 @@ 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"); +const WORKFLOW_PATH = resolve(ROOT_DIR, ".gitea/workflows/ci.yml"); -describe("GitHub Actions CI Workflow", () => { - test("ci.yml exists and has proper triggers and permissions", () => { +describe("Gitea Actions CI Workflow", () => { + test("ci.yml exists and has proper triggers", () => { expect(existsSync(WORKFLOW_PATH)).toBe(true); const content = readFileSync(WORKFLOW_PATH, "utf-8"); @@ -15,42 +15,35 @@ describe("GitHub Actions CI Workflow", () => { 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"); + expect(content).toContain("branches: [main]"); + expect(content).toContain("tags: ['v*']"); }); - test("ci.yml defines test job with Bun 1.3.14 and strict checks", () => { + test("ci.yml defines test job with Bun 1.4.4 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-version: 1.4.4"); 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", () => { + test("ci.yml defines docker-build-and-push job with buildx and Gitea registry publishing", () => { const content = readFileSync(WORKFLOW_PATH, "utf-8"); - expect(content).toContain("docker:"); + expect(content).toContain("docker-build-and-push:"); 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("IMAGE_NAME=ghcr.io/$(echo \"${{ github.repository }}\" | tr '[:upper:]' '[:lower:]')"); - expect(content).toContain("images: ${{ env.IMAGE_NAME }}"); + expect(content).toContain("images: ${{ env.REGISTRY }}/lucasw89/openproject-mcp"); expect(content).toContain("docker/login-action@v3"); - expect(content).toContain("registry: ghcr.io"); + expect(content).toContain("registry: ${{ env.REGISTRY }}"); + expect(content).toContain("username: lucasw89"); + expect(content).toContain("password: ${{ secrets.REGISTRY_TOKEN }}"); 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"); + expect(content).toContain("push: ${{ gitea.event_name != 'pull_request' }}"); }); }); diff --git a/tests/docker.test.ts b/tests/docker.test.ts index a54d62d..4b428b4 100644 --- a/tests/docker.test.ts +++ b/tests/docker.test.ts @@ -10,8 +10,8 @@ describe("Docker Container Packaging", () => { expect(existsSync(dockerfilePath)).toBe(true); const content = readFileSync(dockerfilePath, "utf-8"); - expect(content).toContain("FROM oven/bun:1-slim AS builder"); - expect(content).toContain("FROM oven/bun:1-slim AS runner"); + expect(content).toContain("FROM oven/bun:1.4.4-slim AS builder"); + expect(content).toContain("FROM oven/bun:1.4.4-slim AS runner"); expect(content).toContain("bun install --frozen-lockfile --production"); expect(content).toContain("USER bun"); expect(content).toContain('ENTRYPOINT ["bun", "run", "src/index.ts"]');