chore(release): 3.8.0 #15
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
| # GitHub Actions equivalent of the .gitlab-ci.yml `turboops-build` + `deploy-*` | |
| # jobs — for repos hosted on (or mirrored to) GitHub. | |
| # | |
| # Flow, mirroring GitLab's stage order (test -> turboops-build -> deploy): | |
| # 1. `test` runs the full suite via .github/workflows/test.yml | |
| # 2. `build-push` builds both images and pushes them to the TurboOps registry | |
| # 3. `deploy` rolls the matching TurboOps stage | |
| # | |
| # A red test therefore blocks the deploy — `needs:` is the GitHub equivalent of | |
| # GitLab's sequential stages. Branch -> stage: `dev` -> the `dev` stage, | |
| # `main` -> the `production` stage. | |
| # | |
| # Setup (once per repo), same two values as the GitLab CI/CD variables: | |
| # - Repository variable `TURBOOPS_PROJECT` (the project slug; a secret of the | |
| # same name also works and takes over when the variable is unset) | |
| # - Repository secret `TURBOOPS_TOKEN` | |
| # - `.turboops.json` committed in the repo root | |
| # Run `lt deployment create` to generate the file and print the setup checklist. | |
| name: Deploy | |
| on: | |
| push: | |
| branches: [dev, main] | |
| # A newer push supersedes an in-flight deploy of the same branch, but never | |
| # cancels a deploy that is already rolling out. | |
| concurrency: | |
| group: deploy-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| # Gate: run the deploy pipeline only when TurboOps is actually configured | |
| # (TURBOOPS_PROJECT via repo variable or secret, plus the TURBOOPS_TOKEN | |
| # secret). This keeps the workflow inert in the lt-monorepo TEMPLATE itself — | |
| # no TurboOps project exists there, so a push is just a push — while every | |
| # generated project (which sets both via `lt deployment create`) still runs | |
| # the full test -> build-push -> deploy pipeline. Without this the template's | |
| # own pushes failed the pipeline on every commit at the TurboOps guard. | |
| guard: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| configured: ${{ steps.check.outputs.configured }} | |
| steps: | |
| - id: check | |
| env: | |
| HAS_PROJECT: ${{ vars.TURBOOPS_PROJECT != '' || secrets.TURBOOPS_PROJECT != '' }} | |
| HAS_TOKEN: ${{ secrets.TURBOOPS_TOKEN != '' }} | |
| run: | | |
| if [ "$HAS_PROJECT" = "true" ] && [ "$HAS_TOKEN" = "true" ]; then | |
| echo "configured=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "configured=false" >> "$GITHUB_OUTPUT" | |
| echo "TurboOps not configured (TURBOOPS_PROJECT / TURBOOPS_TOKEN unset) — skipping deploy. Expected in the lt-monorepo template." | |
| fi | |
| test: | |
| needs: guard | |
| if: ${{ needs.guard.outputs.configured == 'true' }} | |
| uses: ./.github/workflows/test.yml | |
| build-push: | |
| needs: [guard, test] | |
| if: ${{ needs.guard.outputs.configured == 'true' }} | |
| runs-on: ubuntu-latest | |
| env: | |
| # IMAGE_TAG is the commit SHA — baked into both images as | |
| # APP_VERSION_COMMIT (see docker-compose.yml) and the exact tag the | |
| # TurboOps stage rolls out. | |
| IMAGE_TAG: ${{ github.sha }} | |
| TURBOOPS_PROJECT: ${{ vars.TURBOOPS_PROJECT || secrets.TURBOOPS_PROJECT }} | |
| TURBOOPS_TOKEN: ${{ secrets.TURBOOPS_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Verify TurboOps setup | |
| run: sh scripts/turboops-guard.sh | |
| - name: Log in to the TurboOps registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: registry.turbo-ops.de | |
| username: ${{ env.TURBOOPS_PROJECT }} | |
| password: ${{ env.TURBOOPS_TOKEN }} | |
| - name: Build and push images | |
| env: | |
| IMAGE_NAME: registry.turbo-ops.de/${{ env.TURBOOPS_PROJECT }} | |
| run: | | |
| # Both images read the commit at runtime from a runner-stage ENV, so no build | |
| # layer depends on it and both stay cacheable. An earlier `--no-cache app` | |
| # blamed BuildKit for baking a stale commit — a misdiagnosis; an in-scope ARG | |
| # always invalidates the layers that follow it. The real cause was that | |
| # `pnpm --filter app` matched nothing and exits 0, so the build silently | |
| # never ran and the image shipped the `.output` from the build context. | |
| docker compose -f docker-compose.yml build api app | |
| docker compose -f docker-compose.yml push api app | |
| deploy: | |
| needs: [guard, build-push] | |
| if: ${{ needs.guard.outputs.configured == 'true' }} | |
| runs-on: ubuntu-latest | |
| env: | |
| TURBOOPS_PROJECT: ${{ vars.TURBOOPS_PROJECT || secrets.TURBOOPS_PROJECT }} | |
| TURBOOPS_TOKEN: ${{ secrets.TURBOOPS_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| - name: Verify TurboOps setup | |
| run: sh scripts/turboops-guard.sh | |
| # Pinned to the major: an unpinned global install would let a breaking 2.x | |
| # release take down every deployment without a repo change. | |
| - name: Install the TurboOps CLI | |
| run: npm install -g @turboops/cli@^1 | |
| - name: Roll the stage | |
| # `--compose` forces the compose upload independent of project.detectedConfig; | |
| # without it a freshly created project can fall into the broken single-service | |
| # fallback (registry/<slug>-<name> with a dash instead of the pushed | |
| # registry/<slug>/<name> with a slash) → "not found in registry". | |
| run: | | |
| turbo config set token "$TURBOOPS_TOKEN" | |
| turbo deploy ${{ github.ref_name == 'main' && 'production' || 'dev' }} --compose docker-compose.yml --wait |