scripts-to-rule-them-all #58
@@ -6,4 +6,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# actions/checkout v4.2.2, 2026-03-16
|
# actions/checkout v4.2.2, 2026-03-16
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||||
- run: docker build .
|
- run: script/cibuild
|
||||||
|
|||||||
35
Makefile
35
Makefile
@@ -13,18 +13,24 @@ GOLDFLAGS += -X main.Version=$(VERSION)
|
|||||||
GOLDFLAGS += -X main.Gitrev=$(GITREV_BUILD)
|
GOLDFLAGS += -X main.Gitrev=$(GITREV_BUILD)
|
||||||
GOFLAGS := -ldflags "$(GOLDFLAGS)"
|
GOFLAGS := -ldflags "$(GOLDFLAGS)"
|
||||||
|
|
||||||
.PHONY: docker default run ci test check lint fmt fmt-check hooks fixme
|
.PHONY: bootstrap setup docker default run ci test check lint fmt fmt-check hooks fixme
|
||||||
|
|
||||||
default: fmt test
|
default: fmt test
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
@script/bootstrap
|
||||||
|
|
||||||
|
setup:
|
||||||
|
@script/setup
|
||||||
|
|
||||||
run: ./bin/mfer
|
run: ./bin/mfer
|
||||||
./$<
|
./$<
|
||||||
./$< gen
|
./$< gen
|
||||||
|
|
||||||
ci: test
|
ci: test
|
||||||
|
|
||||||
test: $(SOURCEFILES) mfer/mf.pb.go
|
test:
|
||||||
go test -v --timeout 10s ./...
|
@script/test
|
||||||
|
|
||||||
$(PROTOC_GEN_GO):
|
$(PROTOC_GEN_GO):
|
||||||
test -e $(PROTOC_GEN_GO) || go install -v google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1
|
test -e $(PROTOC_GEN_GO) || go install -v google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1
|
||||||
@@ -32,14 +38,14 @@ $(PROTOC_GEN_GO):
|
|||||||
fixme:
|
fixme:
|
||||||
@grep -nir fixme . | grep -v Makefile
|
@grep -nir fixme . | grep -v Makefile
|
||||||
|
|
||||||
check: test lint fmt-check
|
check:
|
||||||
|
@script/check
|
||||||
|
|
||||||
fmt-check: mfer/mf.pb.go
|
fmt-check:
|
||||||
sh -c 'test -z "$$(gofmt -l .)"'
|
@script/fmt-check
|
||||||
|
|
||||||
hooks:
|
hooks:
|
||||||
echo '#!/bin/sh\nmake check' > .git/hooks/pre-commit
|
@script/install-precommit
|
||||||
chmod +x .git/hooks/pre-commit
|
|
||||||
|
|
||||||
devprereqs:
|
devprereqs:
|
||||||
which golangci-lint || go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v2.0.2
|
which golangci-lint || go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v2.0.2
|
||||||
@@ -54,17 +60,14 @@ bin/mfer: $(SOURCEFILES) mfer/mf.pb.go
|
|||||||
clean:
|
clean:
|
||||||
rm -rfv mfer/*.pb.go bin/mfer cmd/mfer/mfer *.dockerimage
|
rm -rfv mfer/*.pb.go bin/mfer cmd/mfer/mfer *.dockerimage
|
||||||
|
|
||||||
fmt: mfer/mf.pb.go
|
fmt:
|
||||||
gofumpt -l -w mfer internal cmd
|
@script/fmt
|
||||||
golangci-lint run --fix
|
|
||||||
-prettier -w *.json
|
|
||||||
-prettier -w *.md
|
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
golangci-lint run
|
@script/lint
|
||||||
sh -c 'test -z "$$(gofmt -l .)"'
|
|
||||||
|
|
||||||
docker: sneak-mfer.$(ARCH).tzst.dockerimage
|
docker:
|
||||||
|
@script/docker
|
||||||
|
|
||||||
sneak-mfer.$(ARCH).tzst.dockerimage: $(SOURCEFILES) vendor.tzst modcache.tzst
|
sneak-mfer.$(ARCH).tzst.dockerimage: $(SOURCEFILES) vendor.tzst modcache.tzst
|
||||||
docker build --progress plain --build-arg GITREV=$(GITREV_BUILD) -t sneak/mfer .
|
docker build --progress plain --build-arg GITREV=$(GITREV_BUILD) -t sneak/mfer .
|
||||||
|
|||||||
36
README.md
36
README.md
@@ -25,8 +25,39 @@ software. A compatible javascript library is planned.
|
|||||||
|
|
||||||
# Build Status
|
# Build Status
|
||||||
|
|
||||||
CI runs via `docker build .` which executes `make check` (formatting,
|
CI runs via `script/cibuild` (`docker build .`), which executes `make
|
||||||
linting, tests). The `main` branch must always be green.
|
check` (formatting, linting, tests). The `main` branch must always be
|
||||||
|
green.
|
||||||
|
|
||||||
|
# Entrypoints
|
||||||
|
|
||||||
|
This repository adheres to the
|
||||||
|
[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all)
|
||||||
|
standard: normalized scripts in `script/` are the entrypoints for the
|
||||||
|
development workflow, and the Makefile targets are thin shims that call
|
||||||
|
them. We provide:
|
||||||
|
|
||||||
|
- `script/bootstrap` — install all dependencies (Go, golangci-lint, Go
|
||||||
|
module download), idempotently
|
||||||
|
- `script/setup` — make a fresh clone ready for development: runs
|
||||||
|
`script/bootstrap`, then `script/install-precommit`
|
||||||
|
- `script/projectname` — output the project name (`mfer`); used by other
|
||||||
|
scripts such as `script/docker`
|
||||||
|
- `script/test` — run the test suite (`go test`), regenerating the
|
||||||
|
protobuf code first if it is stale
|
||||||
|
- `script/lint` — run `golangci-lint` and verify `gofmt` cleanliness
|
||||||
|
- `script/fmt` — format all code and docs (writes): `gofumpt`,
|
||||||
|
`golangci-lint run --fix`, and prettier for JSON/Markdown
|
||||||
|
- `script/fmt-check` — check formatting without writing
|
||||||
|
- `script/check` — run `script/test`, `script/lint`, and
|
||||||
|
`script/fmt-check`
|
||||||
|
- `script/docker` — build the Docker image tagged with the project name
|
||||||
|
- `script/cibuild` — CI entrypoint: `docker build .` (the Dockerfile
|
||||||
|
runs the checks)
|
||||||
|
- `script/precommit` — pre-commit checks: `go mod tidy` verification,
|
||||||
|
then `script/check`
|
||||||
|
- `script/install-precommit` — install the git pre-commit hook that
|
||||||
|
runs `script/precommit`
|
||||||
|
|
||||||
# Participation
|
# Participation
|
||||||
|
|
||||||
@@ -126,6 +157,7 @@ The manifest file would do several important things:
|
|||||||
# Open Questions
|
# Open Questions
|
||||||
|
|
||||||
- Should the manifest file include checksums of individual file chunks, or just for the whole assembled file?
|
- Should the manifest file include checksums of individual file chunks, or just for the whole assembled file?
|
||||||
|
|
||||||
- If so, should the chunksize be fixed or dynamic?
|
- If so, should the chunksize be fixed or dynamic?
|
||||||
|
|
||||||
- Should the manifest signature format be GnuPG signatures, or those from
|
- Should the manifest signature format be GnuPG signatures, or those from
|
||||||
|
|||||||
124
TODO.md
124
TODO.md
@@ -1,12 +1,12 @@
|
|||||||
# Workflow
|
# Workflow
|
||||||
|
|
||||||
* branch (from `main`)
|
- branch (from `main`)
|
||||||
* do the work in Next Step
|
- do the work in Next Step
|
||||||
* move Next Step to the top of Completed Steps
|
- move Next Step to the top of Completed Steps
|
||||||
* move the top item of Future Steps into Next Step
|
- move the top item of Future Steps into Next Step
|
||||||
* commit (`TODO.md` changes in the same commit as the work)
|
- commit (`TODO.md` changes in the same commit as the work)
|
||||||
* merge to `main` if the branch is not protected, otherwise open a PR
|
- merge to `main` if the branch is not protected, otherwise open a PR
|
||||||
* push
|
- push
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
|
|
||||||
@@ -23,6 +23,8 @@ commit the uncommitted work (32 modified Go files, new untracked
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints,
|
||||||
|
Makefile shims, README Entrypoints section
|
||||||
- 2026-07-03: aligned repo tooling, docs, and config with standardized
|
- 2026-07-03: aligned repo tooling, docs, and config with standardized
|
||||||
policies (7d9a138, on chore/align-repo-policies, unmerged)
|
policies (7d9a138, on chore/align-repo-policies, unmerged)
|
||||||
- 2026-06-28: moved to standardized repo policies (#56, on main)
|
- 2026-06-28: moved to standardized repo policies (#56, on main)
|
||||||
@@ -42,64 +44,64 @@ commit the uncommitted work (32 modified Go files, new untracked
|
|||||||
|
|
||||||
- Compliance (fold of TODO.md audit 2026-07-02; verify which items the
|
- Compliance (fold of TODO.md audit 2026-07-02; verify which items the
|
||||||
in-flight branch already closes, then check off):
|
in-flight branch already closes, then check off):
|
||||||
- Add .editorconfig (canonical copy from sneak/prompts)
|
- Add .editorconfig (canonical copy from sneak/prompts)
|
||||||
- Add standardized .golangci.yml (present untracked on the branch;
|
- Add standardized .golangci.yml (present untracked on the branch;
|
||||||
user-owned, copy verbatim)
|
user-owned, copy verbatim)
|
||||||
- Make .gitignore cover secrets (.env, *.key, *.pem), OS files
|
- Make .gitignore cover secrets (.env, _.key, _.pem), OS files
|
||||||
(.DS_Store), and editor files (*.swp, *~)
|
(.DS_Store), and editor files (_.swp, _~)
|
||||||
- Make fmt-check/lint verify with gofumpt, not gofmt -l, so
|
- Make fmt-check/lint verify with gofumpt, not gofmt -l, so
|
||||||
`make check` matches what `make fmt` writes
|
`make check` matches what `make fmt` writes
|
||||||
- Add README "Getting Started" section with copy-pasteable
|
- Add README "Getting Started" section with copy-pasteable
|
||||||
install/usage block
|
install/usage block
|
||||||
- Move FORMAT.md from repo root to docs/ and update the AGENTS.md
|
- Move FORMAT.md from repo root to docs/ and update the AGENTS.md
|
||||||
reference
|
reference
|
||||||
- Pin Makefile-installed Go tools (protoc-gen-go@v1.28.1,
|
- Pin Makefile-installed Go tools (protoc-gen-go@v1.28.1,
|
||||||
golangci-lint@v2.0.2) by module hash, not mutable tag
|
golangci-lint@v2.0.2) by module hash, not mutable tag
|
||||||
- Set `make test` timeout to 30s (currently 10s)
|
- Set `make test` timeout to 30s (currently 10s)
|
||||||
- Add explicit README "Rationale" heading (content exists under other
|
- Add explicit README "Rationale" heading (content exists under other
|
||||||
names); name the author in the README Description first line
|
names); name the author in the README Description first line
|
||||||
- Reconcile root-level AGENTS.md with directory-hygiene policy (keep
|
- Reconcile root-level AGENTS.md with directory-hygiene policy (keep
|
||||||
or relocate)
|
or relocate)
|
||||||
- Add a `make build` target
|
- Add a `make build` target
|
||||||
- Rewrite `make hooks` to use printf or a heredoc instead of
|
- Rewrite `make hooks` to use printf or a heredoc instead of
|
||||||
non-portable `echo '...\n...'`
|
non-portable `echo '...\n...'`
|
||||||
- Answer the 14 owner design questions in the README 1.0 roadmap:
|
- Answer the 14 owner design questions in the README 1.0 roadmap:
|
||||||
- Format: simplify MFFileChecksum; store file mode; drop atime;
|
- Format: simplify MFFileChecksum; store file mode; drop atime;
|
||||||
specify path normalization rules; version byte after magic;
|
specify path normalization rules; version byte after magic;
|
||||||
length-prefix after magic
|
length-prefix after magic
|
||||||
- Signatures: hash covers compressed or uncompressed data; sign raw
|
- Signatures: hash covers compressed or uncompressed data; sign raw
|
||||||
bytes vs hex canonical string; detached .mf.sig support; GPG
|
bytes vs hex canonical string; detached .mf.sig support; GPG
|
||||||
subprocess vs pure-Go crypto
|
subprocess vs pure-Go crypto
|
||||||
- Implementation: deterministic manifests by default; consolidate
|
- Implementation: deterministic manifests by default; consolidate
|
||||||
duplicate scanner/checker implementations; export the manifest
|
duplicate scanner/checker implementations; export the manifest
|
||||||
type; canonical Go module path for 1.0
|
type; canonical Go module path for 1.0
|
||||||
- Format and correctness:
|
- Format and correctness:
|
||||||
- Resolve proto go_package vs go.mod module path inconsistency
|
- Resolve proto go_package vs go.mod module path inconsistency
|
||||||
- Specify and validate path invariants (UTF-8, forward-slash,
|
- Specify and validate path invariants (UTF-8, forward-slash,
|
||||||
relative, no .., no leading /)
|
relative, no .., no leading /)
|
||||||
- Remove or deprecate atime; reserve mode field; add version byte
|
- Remove or deprecate atime; reserve mode field; add version byte
|
||||||
(all pending design answers)
|
(all pending design answers)
|
||||||
- Write a standalone format specification document
|
- Write a standalone format specification document
|
||||||
- Library:
|
- Library:
|
||||||
- Delete internal/scanner and internal/checker; consolidate on the
|
- Delete internal/scanner and internal/checker; consolidate on the
|
||||||
mfer/ package versions (pending design answer)
|
mfer/ package versions (pending design answer)
|
||||||
- Add decompression size limit via io.LimitReader in
|
- Add decompression size limit via io.LimitReader in
|
||||||
deserializeInner()
|
deserializeInner()
|
||||||
- Fix errors.Is dead code in checker; make AddFile verify
|
- Fix errors.Is dead code in checker; make AddFile verify
|
||||||
totalRead == size
|
totalRead == size
|
||||||
- Export manifest type or define a public interface (pending)
|
- Export manifest type or define a public interface (pending)
|
||||||
- Replace GPG subprocess with pure-Go crypto (pending); add timeouts
|
- Replace GPG subprocess with pure-Go crypto (pending); add timeouts
|
||||||
to remaining subprocess calls
|
to remaining subprocess calls
|
||||||
- CLI:
|
- CLI:
|
||||||
- Kebab-case primary flag names; fix fetch URL construction with
|
- Kebab-case primary flag names; fix fetch URL construction with
|
||||||
url.JoinPath; add http.Client timeout and retry with backoff to
|
url.JoinPath; add http.Client timeout and retry with backoff to
|
||||||
fetch; rate-limit Checker progress output; add --deterministic
|
fetch; rate-limit Checker progress output; add --deterministic
|
||||||
flag or default; wire top-level --version properly
|
flag or default; wire top-level --version properly
|
||||||
- Testing:
|
- Testing:
|
||||||
- Fuzz NewManifestFromReader; end-to-end tests for freshen and fetch
|
- Fuzz NewManifestFromReader; end-to-end tests for freshen and fetch
|
||||||
- Documentation:
|
- Documentation:
|
||||||
- Promote docs/FORMAT.md as primary spec reference; audit error
|
- Promote docs/FORMAT.md as primary spec reference; audit error
|
||||||
messages; document the signature scheme fully
|
messages; document the signature scheme fully
|
||||||
- Release:
|
- Release:
|
||||||
- Finalize module path, bump version constant, SemVer --version
|
- Finalize module path, bump version constant, SemVer --version
|
||||||
output, tag v1.0.0
|
output, tag v1.0.0
|
||||||
|
|||||||
155
script/bootstrap
Executable file
155
script/bootstrap
Executable file
@@ -0,0 +1,155 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/bootstrap: install all dependencies needed to build and develop
|
||||||
|
# this repo. Idempotent: every install is guarded by a check so already
|
||||||
|
# installed tools are skipped. Base tooling comes from nix, apt, brew,
|
||||||
|
# or apk (detected in that order); assumes NOTHING is present (not git,
|
||||||
|
# make, node, yarn, go, or python). Node is used directly if installed;
|
||||||
|
# otherwise a pinned version is installed via nvm (installing nvm
|
||||||
|
# itself first, from a hash-verified release archive, never curl | sh).
|
||||||
|
#
|
||||||
|
# Uncomment the language sections in main() that apply to this repo.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
# Pinned versions, 2026-07-06. Never "latest" or "lts"; exact versions.
|
||||||
|
NODE_VERSION="22.17.0"
|
||||||
|
NVM_VERSION="0.40.3"
|
||||||
|
# sha256 of https://github.com/nvm-sh/nvm/archive/refs/tags/v0.40.3.tar.gz
|
||||||
|
NVM_SHA256="5f4d6aaa04a177dc93c985e31dbc411ab6b8c6e1e21d8015dbc1372625fcd1d0"
|
||||||
|
YARN_VERSION="1.22.22"
|
||||||
|
|
||||||
|
PKGMGR=""
|
||||||
|
SUDO=""
|
||||||
|
|
||||||
|
detect_pkgmgr() {
|
||||||
|
[ -n "$PKGMGR" ] && return 0
|
||||||
|
if command -v nix-env >/dev/null 2>&1; then
|
||||||
|
PKGMGR="nix"
|
||||||
|
elif command -v apt-get >/dev/null 2>&1; then
|
||||||
|
PKGMGR="apt"
|
||||||
|
elif command -v brew >/dev/null 2>&1; then
|
||||||
|
PKGMGR="brew"
|
||||||
|
elif command -v apk >/dev/null 2>&1; then
|
||||||
|
PKGMGR="apk"
|
||||||
|
else
|
||||||
|
echo "bootstrap: no supported package manager (nix, apt, brew, apk)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PKGMGR" = "apt" ]; then
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
if [ "$(id -u)" != "0" ]; then
|
||||||
|
SUDO="sudo"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# pkg_install <nix-attr> <apt-pkg> <brew-formula> <apk-pkg>
|
||||||
|
pkg_install() {
|
||||||
|
detect_pkgmgr
|
||||||
|
case "$PKGMGR" in
|
||||||
|
nix) nix-env -iA "nixpkgs.$1" ;;
|
||||||
|
apt) $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y "$2" ;;
|
||||||
|
brew) brew install "$3" ;;
|
||||||
|
apk) apk add --no-cache "$4" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
missing() {
|
||||||
|
! command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# verify_sha256 <file> <expected-hash>
|
||||||
|
verify_sha256() {
|
||||||
|
if command -v sha256sum >/dev/null 2>&1; then
|
||||||
|
actual="$(sha256sum "$1" | cut -d' ' -f1)"
|
||||||
|
else
|
||||||
|
actual="$(shasum -a 256 "$1" | cut -d' ' -f1)"
|
||||||
|
fi
|
||||||
|
if [ "$actual" != "$2" ]; then
|
||||||
|
echo "bootstrap: sha256 mismatch for $1" >&2
|
||||||
|
echo " expected: $2" >&2
|
||||||
|
echo " actual: $actual" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# nvm is a bash script; run a command in a bash with nvm loaded
|
||||||
|
nvm_sh() {
|
||||||
|
bash -c ". \"\$HOME/.nvm/nvm.sh\" && $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_nvm() {
|
||||||
|
[ -s "$HOME/.nvm/nvm.sh" ] && return 0
|
||||||
|
# nvm prerequisites; nvm itself requires bash, so install it too
|
||||||
|
if missing bash; then pkg_install bash bash bash bash; fi
|
||||||
|
if missing curl; then pkg_install curl curl curl curl; fi
|
||||||
|
if missing git; then pkg_install git git git git; fi
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
curl -fsSL -o "$tmp/nvm.tar.gz" \
|
||||||
|
"https://github.com/nvm-sh/nvm/archive/refs/tags/v${NVM_VERSION}.tar.gz"
|
||||||
|
verify_sha256 "$tmp/nvm.tar.gz" "$NVM_SHA256"
|
||||||
|
mkdir -p "$HOME/.nvm"
|
||||||
|
tar -xzf "$tmp/nvm.tar.gz" -C "$HOME/.nvm" --strip-components=1
|
||||||
|
rm -rf "$tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_node() {
|
||||||
|
if ! missing node; then return 0; fi
|
||||||
|
ensure_nvm
|
||||||
|
nvm_sh "nvm install $NODE_VERSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_yarn() {
|
||||||
|
if ! missing yarn; then return 0; fi
|
||||||
|
if ! missing corepack; then
|
||||||
|
corepack enable
|
||||||
|
corepack prepare "yarn@$YARN_VERSION" --activate
|
||||||
|
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
||||||
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && corepack enable && \
|
||||||
|
corepack prepare yarn@$YARN_VERSION --activate"
|
||||||
|
else
|
||||||
|
npm install -g "yarn@$YARN_VERSION"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_js_deps() {
|
||||||
|
if missing yarn && [ -s "$HOME/.nvm/nvm.sh" ]; then
|
||||||
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && cd \"$ROOT\" && \
|
||||||
|
yarn install --frozen-lockfile"
|
||||||
|
else
|
||||||
|
yarn install --frozen-lockfile
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
# Base tooling (every repo)
|
||||||
|
if missing git; then pkg_install git git git git; fi
|
||||||
|
if missing make; then pkg_install gnumake make make make; fi
|
||||||
|
|
||||||
|
# ---- JS / docs repos ----
|
||||||
|
# ensure_node
|
||||||
|
# ensure_yarn
|
||||||
|
# install_js_deps
|
||||||
|
|
||||||
|
# ---- Go repos ----
|
||||||
|
if missing go; then pkg_install go golang go go; fi
|
||||||
|
# golangci-lint: packaged in nix, brew, and apk. On apt there is no
|
||||||
|
# package: download a specific release archive from GitHub and
|
||||||
|
# verify its hash (verify_sha256), never curl | sh.
|
||||||
|
if missing golangci-lint; then
|
||||||
|
pkg_install golangci-lint golangci-lint golangci-lint golangci-lint
|
||||||
|
fi
|
||||||
|
go mod download
|
||||||
|
|
||||||
|
# ---- Python repos ----
|
||||||
|
# if missing python3; then pkg_install python3 python3 python3 python3; fi
|
||||||
|
# python3 -m venv .venv
|
||||||
|
# ./.venv/bin/pip install -e '.[dev]'
|
||||||
|
|
||||||
|
echo "bootstrap complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
15
script/check
Executable file
15
script/check
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/check: run all checks (test, lint, fmt-check). Our own
|
||||||
|
# extension to scripts-to-rule-them-all. Must not modify any files.
|
||||||
|
# Generic: usually needs no adaptation.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
"$SCRIPT_DIR/test"
|
||||||
|
"$SCRIPT_DIR/lint"
|
||||||
|
"$SCRIPT_DIR/fmt-check"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
14
script/cibuild
Executable file
14
script/cibuild
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/cibuild: run the CI build. The Dockerfile runs script/check
|
||||||
|
# (via make check), so a successful build implies all checks pass.
|
||||||
|
# Generic: needs no adaptation. The Gitea workflow runs this on push.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
docker build .
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
15
script/docker
Executable file
15
script/docker
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/docker: build the Docker image tagged with the project name.
|
||||||
|
# Identical in all repos; the tag comes from script/projectname.
|
||||||
|
# Generic: needs no adaptation.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
docker build -t "$("$SCRIPT_DIR/projectname")" .
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
27
script/fmt
Executable file
27
script/fmt
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/fmt: format all files (writes).
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
# Regenerate mfer/mf.pb.go from mfer/mf.proto if it is missing or stale
|
||||||
|
# (mirrors the old Makefile prerequisite; the generated file is
|
||||||
|
# committed, so this is normally a no-op).
|
||||||
|
ensure_pb() {
|
||||||
|
if [ ! -f mfer/mf.pb.go ] ||
|
||||||
|
[ -n "$(find mfer/mf.proto -newer mfer/mf.pb.go 2>/dev/null)" ]; then
|
||||||
|
(cd mfer && go generate .)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
ensure_pb
|
||||||
|
gofumpt -l -w mfer internal cmd
|
||||||
|
golangci-lint run --fix
|
||||||
|
# prettier is best-effort, as in the old Makefile (- prefix)
|
||||||
|
prettier -w *.json || true
|
||||||
|
prettier -w *.md || true
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
28
script/fmt-check
Executable file
28
script/fmt-check
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/fmt-check: check formatting (read-only). Same scope as
|
||||||
|
# script/fmt, but fails instead of writing.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
# Regenerate mfer/mf.pb.go from mfer/mf.proto if it is missing or stale
|
||||||
|
# (mirrors the old Makefile prerequisite; the generated file is
|
||||||
|
# committed, so this is normally a no-op).
|
||||||
|
ensure_pb() {
|
||||||
|
if [ ! -f mfer/mf.pb.go ] ||
|
||||||
|
[ -n "$(find mfer/mf.proto -newer mfer/mf.pb.go 2>/dev/null)" ]; then
|
||||||
|
(cd mfer && go generate .)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
ensure_pb
|
||||||
|
if [ -n "$(gofmt -l .)" ]; then
|
||||||
|
echo "gofmt: files need formatting:" >&2
|
||||||
|
gofmt -l . >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
17
script/install-precommit
Executable file
17
script/install-precommit
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/install-precommit: install the git pre-commit hook that runs
|
||||||
|
# script/precommit. Our own extension to scripts-to-rule-them-all.
|
||||||
|
# Generic: needs no adaptation.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
hook=".git/hooks/pre-commit"
|
||||||
|
printf '#!/bin/sh\nset -e\nscript/precommit\n' > .git/hooks/pre-commit
|
||||||
|
chmod +x .git/hooks/pre-commit
|
||||||
|
echo "pre-commit hook installed: runs script/precommit"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
17
script/lint
Executable file
17
script/lint
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/lint: run the linter.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
golangci-lint run
|
||||||
|
if [ -n "$(gofmt -l .)" ]; then
|
||||||
|
echo "gofmt: files need formatting:" >&2
|
||||||
|
gofmt -l . >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
20
script/precommit
Executable file
20
script/precommit
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/precommit: run by the git pre-commit hook; fails the commit if
|
||||||
|
# checks fail. Our own extension to scripts-to-rule-them-all. Go repo
|
||||||
|
# extras run first: go mod tidy and go fmt, failing the commit if they
|
||||||
|
# change go.mod or go.sum.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
go mod tidy
|
||||||
|
go fmt ./...
|
||||||
|
git diff --exit-code -- go.mod go.sum ||
|
||||||
|
{ echo "go mod tidy changed files; stage and retry" >&2; exit 1; }
|
||||||
|
"$SCRIPT_DIR/check"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
12
script/projectname
Executable file
12
script/projectname
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/projectname: output the name of this project. Our own
|
||||||
|
# extension to scripts-to-rule-them-all. Other scripts that need the
|
||||||
|
# name (e.g. script/docker) call this, so they can stay identical
|
||||||
|
# across all repos.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
main() {
|
||||||
|
echo "mfer"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
14
script/setup
Executable file
14
script/setup
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/setup: set up the repo for development after a fresh clone:
|
||||||
|
# installs dependencies (script/bootstrap) and the git pre-commit hook.
|
||||||
|
# Add any repo-specific initialization (db init, .env template) here.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
"$SCRIPT_DIR/bootstrap"
|
||||||
|
"$SCRIPT_DIR/install-precommit"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
23
script/test
Executable file
23
script/test
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/test: run the test suite.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
|
# Regenerate mfer/mf.pb.go from mfer/mf.proto if it is missing or stale
|
||||||
|
# (mirrors the old Makefile prerequisite; the generated file is
|
||||||
|
# committed, so this is normally a no-op).
|
||||||
|
ensure_pb() {
|
||||||
|
if [ ! -f mfer/mf.pb.go ] ||
|
||||||
|
[ -n "$(find mfer/mf.proto -newer mfer/mf.pb.go 2>/dev/null)" ]; then
|
||||||
|
(cd mfer && go generate .)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
ensure_pb
|
||||||
|
go test -v --timeout 10s ./...
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user