|
38 | 38 | - name: Test |
39 | 39 | run: | |
40 | 40 | pixi run -e all pytest |
| 41 | +
|
| 42 | + dockerize: |
| 43 | + name: Build Docker image and push to GHCR |
| 44 | + runs-on: ubuntu-latest |
| 45 | + permissions: |
| 46 | + contents: read |
| 47 | + packages: write |
| 48 | + steps: |
| 49 | + - name: Checkout |
| 50 | + uses: actions/checkout@v6 |
| 51 | + with: |
| 52 | + fetch-depth: 0 |
| 53 | + - name: Set up Node |
| 54 | + uses: actions/setup-node@v4 |
| 55 | + with: |
| 56 | + node-version: '20' |
| 57 | + cache: 'npm' |
| 58 | + - name: Build frontend bundle |
| 59 | + # Dockerfile copies src/ which must contain the built frontend at |
| 60 | + # src/bowser/dist/. That directory is gitignored, so it has to be |
| 61 | + # produced on the runner before `docker build` is invoked. |
| 62 | + run: | |
| 63 | + npm ci |
| 64 | + npm run build |
| 65 | + - name: Set up Python |
| 66 | + uses: actions/setup-python@v6 |
| 67 | + with: |
| 68 | + python-version: '3.11' |
| 69 | + - name: Compute version from setuptools_scm |
| 70 | + run: | |
| 71 | + pip install setuptools_scm |
| 72 | + version=$(python -m setuptools_scm) |
| 73 | + # BOWSER_VERSION stays PEP 440 (keeps '+') — used for the build arg |
| 74 | + # so setuptools_scm can read it back inside the image. |
| 75 | + # BOWSER_IMAGE_TAG sanitizes '+' to '-' because Docker tags forbid '+'. |
| 76 | + echo "BOWSER_VERSION=${version}" >> "$GITHUB_ENV" |
| 77 | + echo "BOWSER_IMAGE_TAG=${version//+/-}" >> "$GITHUB_ENV" |
| 78 | + - name: Set up Docker Buildx |
| 79 | + uses: docker/setup-buildx-action@v3 |
| 80 | + - name: Login to GitHub Container Registry |
| 81 | + if: github.event_name != 'pull_request' |
| 82 | + uses: docker/login-action@v4 |
| 83 | + with: |
| 84 | + registry: ghcr.io |
| 85 | + username: ${{ github.actor }} |
| 86 | + password: ${{ secrets.GITHUB_TOKEN }} |
| 87 | + - name: Build, tag, and push image to GHCR |
| 88 | + uses: docker/build-push-action@v7 |
| 89 | + with: |
| 90 | + context: . |
| 91 | + file: ./Dockerfile |
| 92 | + push: ${{ github.event_name != 'pull_request' }} |
| 93 | + build-args: | |
| 94 | + VERSION=${{ env.BOWSER_VERSION }} |
| 95 | + tags: | |
| 96 | + ghcr.io/${{ github.repository }}:${{ env.BOWSER_IMAGE_TAG }} |
| 97 | + labels: | |
| 98 | + org.opencontainers.image.version=${{ env.BOWSER_VERSION }} |
| 99 | + org.opencontainers.image.revision=${{ github.sha }} |
| 100 | + org.opencontainers.image.created=${{ github.event.head_commit.timestamp }} |
| 101 | + # GHA-cache layers across runs — biggest win is the pixi conda solve |
| 102 | + # in stage 1, which otherwise re-runs from scratch each build. |
| 103 | + cache-from: type=gha |
| 104 | + cache-to: type=gha,mode=max |
| 105 | + - name: Add develop tag (main branch only) |
| 106 | + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' |
| 107 | + uses: akhilerm/tag-push-action@v2.2.0 |
| 108 | + with: |
| 109 | + src: ghcr.io/${{ github.repository }}:${{ env.BOWSER_IMAGE_TAG }} |
| 110 | + dst: ghcr.io/${{ github.repository }}:develop |
| 111 | + - name: Add latest tag (release tags only) |
| 112 | + if: startsWith(github.ref, 'refs/tags/v') |
| 113 | + uses: akhilerm/tag-push-action@v2.2.0 |
| 114 | + with: |
| 115 | + src: ghcr.io/${{ github.repository }}:${{ env.BOWSER_IMAGE_TAG }} |
| 116 | + dst: ghcr.io/${{ github.repository }}:latest |
0 commit comments