diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9261a06..3afc472 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,31 +1,77 @@ -name: CI +name: Continuous Integration on: push: branches: [main] + tags: ['v*'] pull_request: + branches: [main] + +env: + REGISTRY: gitea.lucaswinther.info jobs: - test: + lint-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 with: bun-version: latest - - run: bun install --frozen-lockfile - - run: bun test - - run: bunx tsc --noEmit - - run: bun run build + - name: Install dependencies + run: bun install --frozen-lockfile + - name: Typecheck + run: bunx tsc --noEmit + - name: Run test suite + run: bun test + - name: Build app + run: bun run build - docker: + docker-build-and-push: runs-on: ubuntu-latest + needs: [lint-and-test] steps: - uses: actions/checkout@v4 - - run: docker build -t budget2 . - - name: Serve the image and check it responds + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # 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: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ gitea.repository }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=semver,pattern={{version}} + type=sha,prefix=sha- + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: ${{ gitea.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Pull and smoke-test published image + if: gitea.event_name != 'pull_request' + env: + PUBLISHED_TAGS: ${{ steps.meta.outputs.tags }} run: | - docker run -d --rm -p 3000:3000 --name budget2 budget2 + image="$(printf '%s\n' "$PUBLISHED_TAGS" | head -n 1)" + docker pull "$image" + docker run -d --rm -p 3000:3000 --name budget2-ci "$image" + trap 'docker stop budget2-ci' EXIT for i in $(seq 1 30); do if curl -fsS http://localhost:3000/ > /dev/null; then break; fi sleep 1 @@ -33,4 +79,3 @@ jobs: curl -fsS http://localhost:3000/ | grep -q "Budget" curl -fsS http://localhost:3000/sw.js > /dev/null curl -fsS http://localhost:3000/manifest.webmanifest > /dev/null - docker stop budget2 diff --git a/README.md b/README.md index 380805c..56252dd 100755 --- a/README.md +++ b/README.md @@ -15,6 +15,26 @@ bun run build # production build into dist/ ## Self-hosting with Docker +Gitea Actions builds the image on pull requests and publishes it to the Gitea +container registry after the checks pass on `main` and `v*` tags. Published +images are available as `gitea.lucaswinther.info/lucasw89/budget2.0:latest`, +`:main`, `:sha-`, and `:` for version tags. + +Add a repository Actions secret named `REGISTRY_TOKEN` containing a personal +access token with package write permission. The token must belong to the user +who pushes the commit or tag, since the workflow logs in as the triggering +actor. The Gitea runner must have access to a Docker daemon. + +```bash +docker pull gitea.lucaswinther.info/lucasw89/budget2.0:latest +docker run --rm -p 3000:3000 gitea.lucaswinther.info/lucasw89/budget2.0:latest +``` + +For a private package, run `docker login gitea.lucaswinther.info` first with a +Gitea account or token that has package read permission. + +To build locally instead: + ```bash docker build -t budget2 . docker run --rm -p 3000:3000 budget2