| The registry it pushes to is the one it has 627b785 nandi 16h ago | 1 | # The web bundle: built into an image here, served by Modal from that image. |
| 2 | # |
| 3 | # Separate from `build.yml` because it is a different size of thing. That one |
| 4 | # is three suites and a few minutes; this is a Flutter SDK inside a docker |
| 5 | # build, and it only has to happen for what actually gets served — so it runs |
| 6 | # on the default branch and nowhere else. |
| 7 | # |
| 8 | # The split is by what each side has. rickub has a registry, and docker is |
| 9 | # already logged into it before the first step runs, so this builds and |
| 10 | # pushes. Modal has somewhere to run it, so it pulls that exact tag and |
| 11 | # compiles nothing. What ends up on the internet is the commit that was |
| 12 | # built, by construction rather than by care. |
| 13 | # |
| 14 | # See .modal/web/README.md for the two credentials this needs, and |
| 15 | # https://rickub.com/docs/container-registry for why there is no login step. |
| 16 | |
| 17 | name: web |
| 18 | |
| 19 | on: |
| 20 | push: |
| 21 | branches: [main] |
| 22 | workflow_dispatch: |
| 23 | |
| 24 | jobs: |
| 25 | image: |
| 26 | runs-on: ubuntu-latest |
| 27 | # Claims the image name on the first push. Without it the push is denied |
| 28 | # for a name that does not exist yet, which reads as an auth failure. |
| 29 | permissions: |
| 30 | packages: write |
| 31 | outputs: |
| 32 | image: ${{ steps.build.outputs.image }} |
| 33 | steps: |
| 34 | - uses: actions/checkout@v4 |
| 35 | |
| 36 | # `$RICKUB_REGISTRY_HOST` and the token behind it are injected into the |
| 37 | # run; docker is authenticated before this step. A `docker login` here |
| 38 | # would be a second, worse copy of that. |
| 39 | # |
| 40 | # Tagged by the full commit sha and not `latest`: the deploy below |
| 41 | # names the same string, so the thing deployed cannot drift from the |
| 42 | # thing built. `latest` moves too, as a convenience for a human pulling |
| 43 | # it by hand. |
| 44 | - name: Build and push |
| 45 | id: build |
| 46 | run: | |
| 47 | set -euo pipefail |
| 48 | image="$RICKUB_REGISTRY_HOST/${{ github.repository }}-web:${{ github.sha }}" |
| 49 | moving="$RICKUB_REGISTRY_HOST/${{ github.repository }}-web:latest" |
| 50 | docker build -f .modal/web/Dockerfile -t "$image" -t "$moving" . |
| 51 | docker push "$image" |
| 52 | docker push "$moving" |
| 53 | echo "image=$image" >> "$GITHUB_OUTPUT" |
| 54 | |
| 55 | # ...and Modal serves it. |
| 56 | # |
| 57 | # `modal deploy` and not `modal run`: a run is a job that ends, and this is |
| The web container is plain Modal bd10e81 nandi 15h ago | 58 | # a URL that should still be there on the next push. The app is named in |
| 59 | # `.modal/web/app.py` — `modal.App("frq-web")` — so deploying again |
| The registry it pushes to is the one it has 627b785 nandi 16h ago | 60 | # replaces the running one rather than standing a second one beside it. |
| 61 | deploy: |
| 62 | runs-on: ubuntu-latest |
| 63 | needs: [image] |
| 64 | steps: |
| 65 | - uses: actions/checkout@v4 |
| 66 | - uses: actions/setup-python@v5 |
| 67 | with: |
| 68 | python-version: "3.13" |
| 69 | - run: pip install --quiet modal |
| 70 | - name: Deploy |
| 71 | env: |
| 72 | MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }} |
| 73 | MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }} |
| The web container is plain Modal bd10e81 nandi 15h ago | 74 | # The image `app.py` serves. The job above computed the tag; |
| 75 | # passing it forward rather than recomputing it keeps one place |
| 76 | # saying what it is. |
| The registry it pushes to is the one it has 627b785 nandi 16h ago | 77 | FRQ_WEB_IMAGE: ${{ needs.image.outputs.image }} |
| The web container is plain Modal bd10e81 nandi 15h ago | 78 | run: modal deploy .modal/web/app.py |