#!/usr/bin/env bash set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" go_tool="${repo_root}/scripts/local/go.sh" verify_tool="${repo_root}/scripts/local/verify.sh" mkdir -p "${HOME}/.pi/agent" work="$(mktemp -d "${HOME}/.pi/agent/go-tooling-test.XXXXXX")" hook_work="$(mktemp -d "${repo_root}/services/luci/target/go-hook-test.XXXXXX")" bench_work="$(mktemp -d "${repo_root}/services/luci/target/go-tooling-test.XXXXXX")" trap 'rm -rf "${work}" "${hook_work}" "${bench_work}"' EXIT write_module() { local name="$1" mkdir -p "${work}/services/${name}" cat >"${work}/services/${name}/go.mod" </dev/null 2>&1; then echo "expected failure: $*" >&2 exit 1 fi return 0 } expect_go_failure() { if REPO_ROOT="${work}" "${go_tool}" "$@" >/dev/null 2>&1; then echo "expected Go check failure: $*" >&2 exit 1 fi return 0 } write_module alpha write_module beta mkdir -p "${work}/services/alpha/nested" "${work}/services/alpha/ignored" "${work}/scripts/local" "${work}/.go-modcache/example.invalid/cache" cat >"${work}/.go-modcache/example.invalid/cache/go.mod" <<'EOF' module example.invalid/cache go 1.26.0 EOF cat >"${work}/.go-modcache/example.invalid/cache/cache.go" <<'EOF' package cache func Broken() { missing } EOF cat >"${work}/services/alpha/nested/go.mod" <<'EOF' module example.invalid/nested go 1.26.0 EOF cat >"${work}/services/alpha/foo.go" <<'EOF' package alpha func Answer()int{return 42} EOF cat >"${work}/services/beta/foo.go" <<'EOF' package beta func Answer() int { return 42 } EOF cat >"${work}/services/beta/keep.go" <<'EOF' package beta func Keep() int { return 7 } EOF cat >"${work}/services/beta/delete me.go" <<'EOF' package beta func Delete() int { return 8 } EOF cat >"${work}/services/alpha/nested/foo.go" <<'EOF' package nested func Answer()int{return 42} EOF cat >"${work}/services/alpha/ignored/ignored.go" <<'EOF' package ignored this is not Go EOF cat >"${work}/.gitignore" <<'EOF' /services/alpha/ignored/ /.go-modcache/ /.go-cache/ EOF git -C "${work}" init --quiet touch "${work}/scripts/local/go.sh" "${work}/scripts/local/check-staged.sh" before="$(sha256sum "${work}/services/alpha/foo.go")" expect_go_failure check read services/alpha/foo.go after="$(sha256sum "${work}/services/alpha/foo.go")" [[ "${before}" == "${after}" ]] || { echo "read modified source" >&2 exit 1 } REPO_ROOT="${work}" "${go_tool}" check write services/alpha/foo.go >/dev/null output="$(REPO_ROOT="${work}" "${go_tool}" check read services/alpha/go.mod)" [[ "${output%%$'\n'*}" == "go modules: services/alpha" ]] || { echo "module file scope selected: ${output}" >&2 exit 1 } expect_go_failure check read services/alpha expect_go_failure check read services/alpha/nested/foo.go REPO_ROOT="${work}" "${go_tool}" check write services/alpha/nested/foo.go >/dev/null output="$(REPO_ROOT="${work}" "${go_tool}" check read services/alpha)" [[ "${output%%$'\n'*}" == "go modules: services/alpha services/alpha/nested" ]] || { echo "directory scope selected: ${output}" >&2 exit 1 } output="$(REPO_ROOT="${work}" "${go_tool}" check read .)" [[ "${output%%$'\n'*}" == "go modules: services/alpha services/alpha/nested services/beta" ]] || { echo "root scope selected: ${output}" >&2 exit 1 } output="$(REPO_ROOT="${work}" "${go_tool}" check read services/alpha/ignored/ignored.go)" [[ "${output}" == "no Go modules selected" ]] || { echo "gitignored source selected: ${output}" >&2 exit 1 } output="$(REPO_ROOT="${work}" "${go_tool}" check read scripts/local/check-staged.sh)" [[ "${output%%$'\n'*}" == "go modules: services/alpha services/alpha/nested services/beta" ]] || { echo "automation scope selected: ${output}" >&2 exit 1 } ignored_before="$(sha256sum "${work}/services/alpha/ignored/ignored.go")" REPO_ROOT="${work}" "${go_tool}" check write . >/dev/null ignored_after="$(sha256sum "${work}/services/alpha/ignored/ignored.go")" [[ "${ignored_before}" == "${ignored_after}" ]] || { echo "gitignored source formatted" >&2 exit 1 } mkdir -p "${hook_work}/scripts/local" "${hook_work}/fake-bin" cp -a "${work}/services" "${hook_work}/" cp "${work}/.gitignore" "${hook_work}/.gitignore" cp "${repo_root}/scripts/local/"{go.sh,check.sh,check-staged.sh,shell-check.sh} "${hook_work}/scripts/local/" cat >"${hook_work}/fake-bin/shfmt" <<'EOF' #!/usr/bin/env bash exit 0 EOF cat >"${hook_work}/fake-bin/shellcheck" <<'EOF' #!/usr/bin/env bash exit 0 EOF chmod +x "${hook_work}/fake-bin/"{shfmt,shellcheck} cat >"${hook_work}/justfile" <<'EOF' set positional-arguments check *args: @scripts/local/check.sh "$@" EOF cat >"${hook_work}/lefthook.yml" <<'EOF' pre-commit: jobs: - name: check run: scripts/local/check-staged.sh EOF git -C "${hook_work}" init --quiet git -C "${hook_work}" config user.email test@example.invalid git -C "${hook_work}" config user.name test git -C "${hook_work}" add . git -C "${hook_work}" commit --quiet -m initial git -C "${hook_work}" rm --quiet -- "services/beta/delete me.go" staged_paths="$(git -C "${hook_work}" diff --cached --name-only --diff-filter=ACMRD)" [[ "${staged_paths}" == "services/beta/delete me.go" ]] || { echo "staged deletion not selected: ${staged_paths}" >&2 exit 1 } output="$(cd "${hook_work}" && scripts/local/check.sh read "${staged_paths}")" [[ "${output%%$'\n'*}" == "go modules: services/beta" ]] || { echo "deleted file scope rejected: ${output}" >&2 exit 1 } output="$(cd "${hook_work}" && PATH="${hook_work}/fake-bin:${PATH}" scripts/local/check.sh read scripts/local/go.sh)" [[ "${output%%$'\n'*}" == "go modules: services/alpha services/alpha/nested services/beta" ]] || { echo "module helper change did not select all modules: ${output}" >&2 exit 1 } cat >"${hook_work}/fake-bin/just" <<'EOF' #!/usr/bin/env bash printf '%s\0' "$@" >>"${JUST_LOG}" EOF chmod +x "${hook_work}/fake-bin/just" just_log="${hook_work}/just.log" (cd "${hook_work}" && PATH="${hook_work}/fake-bin:${PATH}" JUST_LOG="${just_log}" lefthook run pre-commit >/dev/null) mapfile -d '' -t just_args <"${just_log}" [[ "${#just_args[@]}" -eq 3 && "${just_args[0]}" == check && "${just_args[1]}" == read && "${just_args[2]}" == "services/beta/delete me.go" ]] || { printf 'deleted-only hook args: %q\n' "${just_args[@]}" >&2 exit 1 } git -C "${hook_work}" reset --quiet : >"${just_log}" (cd "${hook_work}" && PATH="${hook_work}/fake-bin:${PATH}" JUST_LOG="${just_log}" lefthook run pre-commit >/dev/null) [[ ! -s "${just_log}" ]] || { echo "empty index ran all check" >&2 exit 1 } mkdir -p "${hook_work}/modules/tofu" "${hook_work}/fake-bin" printf 'resource "null_resource" "kept" {}\n' >"${hook_work}/modules/tofu/kept.tf" printf 'resource "null_resource" "deleted" {}\n' >"${hook_work}/modules/tofu/deleted.tf" rm "${hook_work}/modules/tofu/deleted.tf" cat >"${hook_work}/fake-bin/tofu" <<'EOF' #!/usr/bin/env bash printf '%s\n' "$*" >>"${TOFU_LOG}" EOF chmod +x "${hook_work}/fake-bin/tofu" tofu_log="${hook_work}/tofu.log" TOFU_LOG="${tofu_log}" PATH="${hook_work}/fake-bin:${PATH}" \ "${hook_work}/scripts/local/check.sh" read modules/tofu/deleted.tf >/dev/null grep -Fqx "fmt -check -recursive ${hook_work}/modules/tofu" "${tofu_log}" grep -Fqx "validate" "${tofu_log}" cat >"${work}/services/alpha/foo.go" <<'EOF' package alpha func Answer() int { return missing } EOF expect_go_failure check read services/alpha/foo.go empty="${bench_work}/empty.txt" valid="${bench_work}/valid.txt" malformed="${bench_work}/malformed.txt" : >"${empty}" printf 'BenchmarkBuildDashboard/small-12\t1\t1 ns/op\n' >"${valid}" printf 'BenchmarkBuildDashboard/small-12 malformed\n' >"${malformed}" expect_failure "${verify_tool}" luci-benchstat "${empty}" "${valid}" expect_failure "${verify_tool}" luci-benchstat "${valid}" "${malformed}" expect_failure "${verify_tool}" luci-bench 1 README.md expect_failure "${verify_tool}" luci-mutation README.md