Merge pull request #117 from MacNite/claude/food-search-ranking-6sxrgf #128
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: Publish image | |
| on: | |
| push: | |
| branches: ["main"] | |
| tags: ["v*.*.*"] | |
| workflow_dispatch: | |
| inputs: | |
| platforms: | |
| description: Platforms to build | |
| required: false | |
| default: linux/amd64 | |
| type: choice | |
| options: | |
| - linux/amd64 | |
| - linux/amd64,linux/arm64 | |
| # GITHUB_TOKEN needs write access to the container registry; nothing else. | |
| permissions: | |
| contents: read | |
| packages: write | |
| # A newer push to the same branch supersedes an image that has not been | |
| # published yet. Release-tag builds are kept independent from branch builds. | |
| concurrency: | |
| group: publish-image-${{ github.ref }} | |
| cancel-in-progress: ${{ github.ref == 'refs/heads/main' }} | |
| env: | |
| REGISTRY: ghcr.io | |
| # Lowercased below: GHCR rejects uppercase characters in an image name. | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| # A broken image must never reach the registry, so the fast checks run first. | |
| verify: | |
| runs-on: ubuntu-latest | |
| env: | |
| APP_SECRET: ci-only-secret-value-at-least-32-characters | |
| # Prisma requires the variable to exist; nothing connects during these checks. | |
| DATABASE_URL: postgresql://nutricore:nutricore@127.0.0.1:5432/nutricore?schema=public | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - run: npm ci | |
| - run: npx prisma generate | |
| - run: npm run lint | |
| - run: npm run typecheck | |
| - run: npm test | |
| publish: | |
| needs: verify | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Lowercase the image name | |
| id: image | |
| run: echo "name=${IMAGE_NAME,,}" >> "$GITHUB_OUTPUT" | |
| - name: Select platforms | |
| id: platforms | |
| run: | | |
| # Emulated arm64 builds are slow, so they are reserved for releases | |
| # and for an explicit manual run. | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "list=${{ inputs.platforms }}" >> "$GITHUB_OUTPUT" | |
| elif [ "${{ startsWith(github.ref, 'refs/tags/v') }}" = "true" ]; then | |
| echo "list=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "list=linux/amd64" >> "$GITHUB_OUTPUT" | |
| fi | |
| - uses: docker/setup-qemu-action@v3 | |
| if: contains(steps.platforms.outputs.list, 'arm64') | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Derive tags and labels | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }} | |
| type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }} | |
| type=sha,format=short | |
| type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }} | |
| labels: | | |
| org.opencontainers.image.title=NutriCore | |
| org.opencontainers.image.description=Privacy-first, self-hosted nutrition tracking | |
| org.opencontainers.image.licenses=NOASSERTION | |
| - name: Build and push | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: ${{ steps.platforms.outputs.list }} | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| provenance: mode=max | |
| sbom: true | |
| # The migration runner, from the same Dockerfile's `migrate` stage. It is | |
| # a separate image on purpose: it is the only one carrying the Prisma CLI, | |
| # it runs as a one-shot service and exits, and keeping it apart is what | |
| # lets the long-running image drop the CLI and its transitive packages. | |
| # Tagged in lockstep with the app image so a pinned version resolves to a | |
| # matching pair. | |
| - name: Derive migrate tags and labels | |
| id: meta-migrate | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}-migrate | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }} | |
| type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }} | |
| type=sha,format=short | |
| type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }} | |
| labels: | | |
| org.opencontainers.image.title=NutriCore migrations | |
| org.opencontainers.image.description=One-shot Prisma migration runner for NutriCore | |
| org.opencontainers.image.licenses=NOASSERTION | |
| - name: Build and push the migration runner | |
| id: build-migrate | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| target: migrate | |
| platforms: ${{ steps.platforms.outputs.list }} | |
| push: true | |
| tags: ${{ steps.meta-migrate.outputs.tags }} | |
| labels: ${{ steps.meta-migrate.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| provenance: mode=max | |
| sbom: true | |
| - name: Summarise | |
| run: | | |
| { | |
| echo "### Image published" | |
| echo | |
| echo "**Digest:** \`${{ steps.build.outputs.digest }}\`" | |
| echo "**Platforms:** \`${{ steps.platforms.outputs.list }}\`" | |
| echo | |
| echo "Tags:" | |
| echo '```' | |
| echo "${{ steps.meta.outputs.tags }}" | |
| echo '```' | |
| echo | |
| echo "### Migration runner published" | |
| echo | |
| echo "**Digest:** \`${{ steps.build-migrate.outputs.digest }}\`" | |
| echo | |
| echo "Tags:" | |
| echo '```' | |
| echo "${{ steps.meta-migrate.outputs.tags }}" | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" |