diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index e635e7cb..21fd34cb 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -119,7 +119,7 @@ and verify that its output is exactly `notarius v0.0.0`. - Invalid linker content cannot masquerade as a release version. - Existing CLI commands, help, streams, and exit classes remain unchanged. -## Stage 2: Add One Reusable Source-Candidate Checker +## Stage 2: Add One Reusable Source-Candidate Checker ✅ ### Goal diff --git a/scripts/check-release-source.sh b/scripts/check-release-source.sh new file mode 100755 index 00000000..69df48ec --- /dev/null +++ b/scripts/check-release-source.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +set -eu + +fail() { + printf '%s\n' "check-release-source: $*" >&2 + exit 1 +} + +if [ "$#" -ne 1 ]; then + fail "usage: $0 vMAJOR.MINOR.PATCH" +fi + +release_version=$1 +if ! printf '%s\n' "$release_version" | grep -E -x 'v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)' >/dev/null; then + fail "version must be a stable semantic version tag" +fi + +script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd) +repo_root=$(CDPATH= cd "$script_dir/.." && pwd) +cd "$repo_root" + +temporary_dir=$(mktemp -d "${TMPDIR:-/tmp}/notarius-release-source.XXXXXX") || fail "create temporary directory" +trap 'rm -rf "$temporary_dir"' 0 HUP INT TERM + +if ! grep -E '^module[[:space:]]+gitea\.maximumdirect\.net/eric/notarius([[:space:]]|$)' go.mod >/dev/null; then + fail "go.mod does not declare the expected module path" +fi + +if git ls-files --error-unmatch go.work >/dev/null 2>&1 || git ls-files --error-unmatch go.work.sum >/dev/null 2>&1; then + fail "tracked Go workspace files are not allowed" +fi +if [ -d vendor ]; then + fail "vendor directory is not allowed" +fi +if grep -E '^[[:space:]]*replace([[:space:]]|$)' go.mod >/dev/null; then + fail "go.mod replace directives are not allowed" +fi + +GOWORK=off go test -count=1 ./... +GOWORK=off go test -race -count=1 ./... +GOWORK=off go vet ./... +GOWORK=off go build ./... +GOWORK=off go mod tidy -diff + +unformatted=$(git ls-files '*.go' | while IFS= read -r go_file; do + fmt_output=$(gofmt -l "$go_file") + if [ -n "$fmt_output" ]; then + printf '%s\n' "$fmt_output" + fi +done) +if [ -n "$unformatted" ]; then + printf '%s\n' "$unformatted" >&2 + fail "tracked Go files are not gofmt formatted" +fi + +git diff --check +git diff --cached --check + +GOWORK=off go run ./cmd/notarius config validate --config examples/dnd-minimal.config.yml --pipeline dnd-session +GOWORK=off OPENROUTER_API_KEY=validation-placeholder go run ./cmd/notarius config validate --config examples/dnd-complete.config.yml --pipeline dnd-session + +host_os=$(GOWORK=off go env GOOS) +host_arch=$(GOWORK=off go env GOARCH) +version_symbol='gitea.maximumdirect.net/eric/notarius/internal/buildinfo.Override' + +build_target() { + target_os=$1 + target_arch=$2 + target_path="$temporary_dir/notarius-$target_os-$target_arch" + CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" GOWORK=off go build -trimpath \ + -ldflags "-X $version_symbol=$release_version" \ + -o "$target_path" ./cmd/notarius + if [ "$host_os" = "$target_os" ] && [ "$host_arch" = "$target_arch" ]; then + "$target_path" --version > "$temporary_dir/version-output" + printf 'notarius %s\n' "$release_version" > "$temporary_dir/expected-version-output" + if ! cmp -s "$temporary_dir/expected-version-output" "$temporary_dir/version-output"; then + fail "version output is incorrect for $target_os/$target_arch" + fi + fi +} + +build_target linux amd64 +build_target linux arm64 +build_target darwin amd64 +build_target darwin arm64