Fix smoke-auth in CI, and stop it hiding why it failed #14
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
| # CI: build, the repo's two test tiers, and — only once those pass — the clickd | |
| # container image. `go test ./...` is hermetic (every external service is faked | |
| # in-process), so it runs in the static-checks job; the end-to-end shell suites | |
| # need live Docker Compose stacks, and GitHub's runners ship docker compose, so | |
| # CI runs exactly what a developer runs: make up && make smoke, and | |
| # make up-auth && make smoke-auth. | |
| # | |
| # The image build lives here rather than in a workflow of its own so it can | |
| # depend on those jobs directly (needs:) and build the very commit they tested. | |
| # A separate workflow would have to use workflow_run, which resolves its own | |
| # file from the default branch, checks out the default branch unless told | |
| # otherwise, and never fires at all when CI is skipped — so a tag would silently | |
| # get no image. The CLI release stays separate: release.yml, tag-triggered. | |
| name: ci | |
| on: | |
| # Every push to main runs the full suite, deliberately without a path filter. | |
| # main is what the clickd image is built from below, so "tested" has to mean | |
| # the merge commit itself and not just the pull request that preceded it: a | |
| # squash or rebase can differ from the branch that was reviewed, and a direct | |
| # push to main gets no pull-request run at all. A merged PR therefore runs CI | |
| # twice, which is cheap next to shipping an untested image. | |
| # | |
| # Tags get the same treatment for the same reason: the image a rollout pins | |
| # must come from a commit the suites passed. Note there is deliberately no | |
| # `paths`/`paths-ignore` on push — path filters apply to tag pushes too, so a | |
| # tag whose commit only touched ignored files would silently produce no image. | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| # Docs-only PRs can't affect the binary or the stack, so skip the | |
| # (expensive, multi-arch Docker) smoke suites for them. Scope matters: | |
| # `*.md` is root-only (README/ARCHITECTURE/DESIGN/DEPLOY/AGENTS/CLAUDE — | |
| # pure prose), so | |
| # embedded templates keep running CI — internal/gen/agents.md is go:embed'd | |
| # into the binary and is NOT ignored. docs/** is ignored even though | |
| # docs/site-api.md is embedded there: a content edit still compiles, and a | |
| # rename edits embed.go (a .go file, not ignored), so a build-breaking | |
| # change always still runs CI. | |
| pull_request: | |
| paths-ignore: | |
| - '*.md' | |
| - 'docs/**' | |
| permissions: | |
| contents: read | |
| jobs: | |
| # Arch-agnostic static checks: one runner is enough. | |
| checks: | |
| runs-on: arc-amd64-runners | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| - run: go build ./... | |
| - run: go vet ./... | |
| # The Go unit tests are hermetic (every external service is faked | |
| # in-process), so they belong with the static checks rather than with the | |
| # Docker-bound smoke suites. | |
| - run: go test ./... | |
| - name: gofmt | |
| run: | | |
| out=$(gofmt -l ./cmd ./internal) | |
| if [ -n "$out" ]; then | |
| echo "gofmt needed on:" && echo "$out" | |
| exit 1 | |
| fi | |
| # The smoke suites test the containerized platform itself, so they run on | |
| # both architectures — the compose stack has to work on amd64 and arm64 | |
| # (Graviton) nodes alike. | |
| smoke-open: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runner: [arc-amd64-runners, arc-arm64-runners] | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| - run: make up | |
| - run: make smoke | |
| - name: stack logs | |
| if: failure() | |
| run: docker compose logs --tail 200 | |
| smoke-auth: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runner: [arc-amd64-runners, arc-arm64-runners] | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| # Every curl in the suite maps *.click.localhost to loopback with | |
| # --resolve, but `click login` resolves the OIDC issuer through the system | |
| # resolver — a Go program has no --resolve. macOS maps *.localhost to | |
| # loopback natively and systemd-resolved does the same, so this only bites | |
| # in a bare runner container, where the CLI cannot reach dex at all. | |
| - name: Make the OIDC issuer host resolvable | |
| run: | | |
| if ! grep -q 'dex\.click\.localhost' /etc/hosts; then | |
| echo '127.0.0.1 dex.click.localhost' | tee -a /etc/hosts >/dev/null \ | |
| || echo '127.0.0.1 dex.click.localhost' | sudo tee -a /etc/hosts >/dev/null | |
| fi | |
| getent hosts dex.click.localhost | |
| - run: make up-auth | |
| - run: make smoke-auth | |
| - name: stack logs | |
| if: failure() | |
| run: docker compose -f docker-compose.yml -f docker-compose.auth.yml logs --tail 200 | |
| # Build and push the clickd container image to ECR (infra/clickd) — the | |
| # image the Tanka deployment in closeio-infrastructure pins by tag. | |
| # | |
| # - push to main → infra/clickd:sha-<short-sha> + latest (per-commit image) | |
| # - tag v* → infra/clickd:vX.Y.Z + latest (the tag rollouts pin) | |
| # | |
| # latest always follows the most recent build of either kind. | |
| # | |
| # needs: every test job, so no image ever exists for a commit the suites | |
| # rejected — which matters because the deployment currently tracks latest with | |
| # imagePullPolicy: Always, so a pushed image reaches the platform on the next | |
| # pod restart. The event guard keeps pull requests out of ECR entirely. | |
| # | |
| # Multi-arch (amd64 + arm64): the mgmt clusters have Graviton nodes. The | |
| # Dockerfile cross-compiles in a native build stage, so no emulated Go. | |
| # Runs on the ARC runners, which carry ECR push permissions ambiently — | |
| # same credential model as closeio-infrastructure's workflows. | |
| image: | |
| needs: [checks, smoke-open, smoke-auth] | |
| if: github.event_name == 'push' | |
| runs-on: arc-amd64-runners | |
| # Job-scoped: a superseded image build is cancelled without disturbing the | |
| # test jobs of the run it belongs to. | |
| concurrency: | |
| group: image-${{ github.ref_name || github.run_id }} | |
| cancel-in-progress: true | |
| env: | |
| ECR_IMAGE: 372094135098.dkr.ecr.us-west-2.amazonaws.com/infra/clickd | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup AWS creds | |
| uses: aws-actions/configure-aws-credentials@v6 | |
| with: | |
| aws-region: us-west-2 | |
| - name: Login to AWS ECR | |
| uses: aws-actions/amazon-ecr-login@v2 | |
| with: | |
| mask-password: true | |
| - uses: docker/setup-qemu-action@v4 | |
| - uses: docker/setup-buildx-action@v4 | |
| - name: Compute tags | |
| id: tags | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| tag="$GITHUB_REF_NAME" | |
| else | |
| tag="sha-$(echo "$GITHUB_SHA" | cut -c1-12)" | |
| fi | |
| echo "tags=$ECR_IMAGE:$tag,$ECR_IMAGE:latest" >> "$GITHUB_OUTPUT" | |
| - name: Build and push | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.tags.outputs.tags }} | |
| # Keep the index to exactly the two platform manifests: buildx | |
| # attestations add unknown/unknown entries that older containerd | |
| # versions refuse with "no match for platform in manifest". | |
| provenance: false | |
| sbom: false |