From 3e2a3d92c0cbffb621c7834e75df472e06018b7d Mon Sep 17 00:00:00 2001 From: nicodes Date: Thu, 8 Oct 2026 04:52:24 +0200 Subject: [PATCH] build: standardize Termcade CLI and SDK profile gates --- .github/actions/build/action.yml | 35 ++---------------------- .github/actions/test/action.yml | 44 ++----------------------------- .github/workflows/ci.yml | 7 +++-- .github/workflows/release-sdk.yml | 7 +++-- .github/workflows/release.yml | 7 +++-- .gitignore | 3 +++ .mise.toml | 5 ++++ Makefile | 26 ++++++++++++++++++ engineering-profile.json | 36 +++++++++++++++++++++++++ go.work.sum | 2 ++ mise.toml | 2 -- scripts/build.sh | 29 ++++++++++++++++++++ scripts/lint.sh | 13 +++++++++ scripts/test.sh | 4 +++ 14 files changed, 131 insertions(+), 89 deletions(-) create mode 100644 .mise.toml create mode 100644 Makefile create mode 100644 engineering-profile.json delete mode 100644 mise.toml create mode 100644 scripts/build.sh create mode 100644 scripts/lint.sh create mode 100644 scripts/test.sh diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index a2ef413..827919c 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -19,39 +19,8 @@ inputs: runs: using: composite steps: - - name: Cross-compile + - name: Cross-compile and checksum every release platform shell: bash env: VERSION: ${{ inputs.version }} - run: | - set -euo pipefail - if [[ "$VERSION" != dev && ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Unsupported version string: $VERSION" >&2 - exit 1 - fi - mkdir -p dist - # linux/386 and friends excluded on purpose: wazero's compiler backend - # covers amd64/arm64, and everything else falls back to the - # interpreter — playable, but not something worth publishing. - for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64; do - GOOS="${target%/*}"; GOARCH="${target#*/}" - bin=termcade - [ "$GOOS" = windows ] && bin=termcade.exe - CGO_ENABLED=0 GOOS="$GOOS" GOARCH="$GOARCH" \ - go build -trimpath -ldflags "-s -w -X main.version=$VERSION" \ - -o "dist/$bin" . - name="termcade_$(echo "$GOOS" | sed 's/./\U&/')_${GOARCH}" - case "$GOARCH" in amd64) name="termcade_$(echo "$GOOS" | sed 's/./\U&/')_x86_64";; esac - if [ "$GOOS" = windows ]; then - (cd dist && zip -q "${name}.zip" "$bin" && rm "$bin") - else - tar -czf "dist/${name}.tar.gz" -C dist "$bin" && rm "dist/$bin" - fi - done - - - name: Checksums - shell: bash - run: | - set -euo pipefail - (cd dist && sha256sum *.tar.gz *.zip > checksums.txt) - cat dist/checksums.txt + run: make build diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index c3f871f..f39c486 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -13,46 +13,6 @@ description: > runs: using: composite steps: - # Cheapest first, and the one most likely to be the only thing wrong. - - name: Go formatting + - name: Formatting, vet, race and independent consumer checks shell: bash - run: | - unformatted="$(gofmt -l .)" - if [ -n "$unformatted" ]; then - echo "::error::gofmt would change these files:" - echo "$unformatted" - exit 1 - fi - - - name: Go vet - shell: bash - run: | - go vet ./... - go vet ./sdk/... - - # -race because the shell runs marketplace commands as goroutines feeding - # messages back into the model, which is exactly the shape that fails only - # under load. -count=1 because a cached PASS from an earlier run is not - # evidence about this one — the plugin suite builds and executes wasm from - # the working tree. - # - # Both workspace modules in one invocation: the arcade and the sdk release - # together or not at all. - - name: Go tests - shell: bash - run: go test -race -count=1 -timeout 10m ./... ./sdk/... - - # Everything above runs inside go.work, where ./sdk satisfies the arcade's - # dependency on it — so the version in go.mod is never consulted and can - # be wrong without anything noticing. That is exactly how v0.0.3 shipped - # using sdk.ASCII while requiring an sdk release that predated it: green - # locally, green here, and broken for every `go run …@latest` on earth. - # - # GOWORK=off resolves the dependency the way a stranger's toolchain will. - # It is the only check in this file that tests the module rather than the - # code, and it belongs in the shared action so a release cannot skip it. - - name: Build as a consumer would - shell: bash - run: | - GOWORK=off go build ./... - GOWORK=off go vet ./... + run: make lint test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c81d41c..b7a1daa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,10 +28,9 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 - with: - go-version-file: go.mod - cache-dependency-path: go.sum + - uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1 + - name: Install pinned build and validation tools + run: make install # Built first: a compile error should fail before a test suite spends # minutes reaching the same conclusion more slowly. This is the order diff --git a/.github/workflows/release-sdk.yml b/.github/workflows/release-sdk.yml index 6ac0bae..8db0bd7 100644 --- a/.github/workflows/release-sdk.yml +++ b/.github/workflows/release-sdk.yml @@ -70,10 +70,9 @@ jobs: fi echo "tag=$tag" >> "$GITHUB_OUTPUT" - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 - with: - go-version-file: go.mod - cache-dependency-path: go.sum + - uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1 + - name: Install pinned build and validation tools + run: make install # The release gate is the same suite CI runs; the SDK never releases # from a commit the arcade's tests wouldn't pass. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a01a7b2..df05655 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,10 +75,9 @@ jobs: echo "version=$version" >> "$GITHUB_OUTPUT" echo "tag=$tag" >> "$GITHUB_OUTPUT" - - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 - with: - go-version-file: go.mod - cache-dependency-path: go.sum + - uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1 + - name: Install pinned build and validation tools + run: make install # The same steps CI runs, from the same definition. Running them again # against this exact commit is not redundant: CI passing on this SHA diff --git a/.gitignore b/.gitignore index be8c8d6..c90a82d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ games/*/build/ # output — regenerate with `go generate ./internal/starter`. !internal/starter/packs/*.tcade game.wasm + +.artifacts/ +__pycache__/ diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..0662628 --- /dev/null +++ b/.mise.toml @@ -0,0 +1,5 @@ +[tools] +go = "1.27.1" +python = "3.13.11" +actionlint = "1.7.12" +shellcheck = "0.11.0" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62a0ca5 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +SHELL := /bin/bash +.SHELLFLAGS := -eu -o pipefail -c +.DEFAULT_GOAL := help +.NOTPARALLEL: +VERSION ?= dev +.PHONY: help install lint test build check dev stop clean +help: + @echo 'make check: complete five-platform archive build, lint and race/consumer checks' +install: + mise trust .mise.toml + mise install go python actionlint shellcheck + mise exec -- go mod download + cd sdk && mise exec -- go mod download +lint: + mise exec -- bash scripts/lint.sh + mise exec -- actionlint + mise exec -- shellcheck scripts/*.sh .github/scripts/*.sh +test: + mise exec -- bash scripts/test.sh +build: + mise exec -- env VERSION="$(VERSION)" bash scripts/build.sh +check: build lint test +dev stop: + @echo '$@: unsupported: interactive arcade sessions require caller-owned terminal and account configuration' +clean: + mise exec -- python3 -c 'import shutil; [shutil.rmtree(p, ignore_errors=True) for p in ("dist", ".artifacts")]' diff --git a/engineering-profile.json b/engineering-profile.json new file mode 100644 index 0000000..e97788c --- /dev/null +++ b/engineering-profile.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "profile": "go-cli", + "commands": { + "install": [ + "make", + "install" + ], + "lint": [ + "make", + "lint" + ], + "test": [ + "make", + "test" + ], + "build": [ + "make", + "build" + ], + "check": [ + "make", + "check" + ], + "clean": [ + "make", + "clean" + ], + "dev": { + "unsupported": "Interactive arcade sessions require caller-owned terminal and account configuration." + }, + "stop": { + "unsupported": "Interactive arcade sessions require caller-owned terminal and account configuration." + } + } +} diff --git a/go.work.sum b/go.work.sum index 57434d9..cdb0839 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,2 +1,4 @@ +github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoGXLwLQOZE= github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= diff --git a/mise.toml b/mise.toml deleted file mode 100644 index 966f88a..0000000 --- a/mise.toml +++ /dev/null @@ -1,2 +0,0 @@ -[tools] -go = "1.26.2" diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100644 index 0000000..78d9297 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +if [[ "$VERSION" != dev && ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Unsupported version string: $VERSION" >&2 + exit 1 +fi +mkdir -p dist +# linux/386 and friends excluded on purpose: wazero's compiler backend +# covers amd64/arm64, and everything else falls back to the +# interpreter — playable, but not something worth publishing. +for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64; do + GOOS="${target%/*}"; GOARCH="${target#*/}" + bin=termcade + [ "$GOOS" = windows ] && bin=termcade.exe + CGO_ENABLED=0 GOOS="$GOOS" GOARCH="$GOARCH" \ + go build -trimpath -ldflags "-s -w -X main.version=$VERSION" \ + -o "dist/$bin" . + name="termcade_${GOOS^}_${GOARCH}" + case "$GOARCH" in amd64) name="termcade_${GOOS^}_x86_64";; esac + if [ "$GOOS" = windows ]; then + (cd dist && zip -q "${name}.zip" "$bin" && rm "$bin") + else + tar -czf "dist/${name}.tar.gz" -C dist "$bin" && rm "dist/$bin" + fi +done + +set -euo pipefail +(cd dist && sha256sum -- *.tar.gz *.zip > checksums.txt) +cat dist/checksums.txt diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100644 index 0000000..9ba2128 --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +unformatted="$(gofmt -l .)" +if [ -n "$unformatted" ]; then + echo "::error::gofmt would change these files:" + echo "$unformatted" + exit 1 +fi + +go vet ./... +go vet ./sdk/... + +GOWORK=off go vet ./... diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100644 index 0000000..0f72330 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +go test -race -count=1 -timeout 10m ./... ./sdk/... +GOWORK=off go build ./...