Skip to content

Instantly share code, notes, and snippets.

@itchyny
Last active May 14, 2024 04:28
Show Gist options
  • Save itchyny/e2257b1f1b35b9440d78a89852a3cb5e to your computer and use it in GitHub Desktop.
Save itchyny/e2257b1f1b35b9440d78a89852a3cb5e to your computer and use it in GitHub Desktop.
A checker for my own Go product repositories
#!/bin/bash
set -euo pipefail
git status >/dev/null || exit 1
err=
error_message() {
printf '%s\n\n' "$*" >&2
err=1
}
shopt -s nullglob
for f in .github/workflows/*.yaml; do
git grep -F "push, pull_request" "$f" &&
error_message "Fix CI triggers in $f (do not make actions run duplicately)."
git grep -q -F "actions/setup-go" "$f" &&
! git grep -q -E 'go-version: (1\.x|.*matrix\.go|\$\{\{)' "$f" && {
git grep -F "go-version:" "$f" &&
error_message "Fix 'go-version' in $f to use 1.x or matrix."
}
for action in \
actions/checkout@v4 \
actions/cache@v4 \
actions/setup-go@v5 \
actions/upload-artifact@v4 \
actions/download-artifact@v4 \
docker/metadata-action@v5 \
docker/setup-qemu-action@v3 \
docker/setup-buildx-action@v3 \
docker/login-action@v3 \
docker/build-push-action@v5 \
docker/bake-action@v4; do
git grep -q -F "${action%@v*}" "$f" &&
! git grep -q -F "$action" "$f" && {
git grep -F "${action%@v*}" "$f"
error_message "Update to '$action' in $f."
}
done
git grep -F "actions/create-release" "$f" &&
error_message "Stop using deprecated 'actions/create-release' in $f."
git grep -F "actions/upload-release-asset" "$f" &&
error_message "Stop using deprecated 'actions/upload-release-asset' in $f."
git grep -E "@(master|main)" "$f" &&
error_message "Fix action version in $f" \
"(use @v1 or @v2, otherwise updates in actions may break your CI)".
git grep -q -F "runs-on:" "$f" &&
git grep -P 'ubuntu-\d+\.\d+' "$f" &&
error_message "Fix ubuntu version in $f" \
"(use 'ubuntu-latest', otherwise you will forget to update)."
git grep -q -F "matrix:" "$f" &&
! git grep -q "fail-fast:" "$f" &&
error_message "Specify 'fail-fast: false' in $f."
git grep -F "::set-env" "$f" &&
error_message "Migrate deprecated '::set-env' to \$GITHUB_ENV in $f."
git grep -F "::set-output" "$f" &&
error_message "Migrate deprecated '::set-output' to \$GITHUB_OUTPUT in $f."
git grep -F "::save-state" "$f" &&
error_message "Migrate deprecated '::save-state' to \$GITHUB_STATE in $f."
git grep -q "^permissions:" "$f" ||
error_message "Specify 'permissions' to allow minimum required access in $f."
git grep -q "docker/build-push-action" "$f" &&
! git grep -q "provenance: false" "$f" &&
error_message "Specify 'provenance: false' on building Docker images in $f."
[[ "${f##*/}" =~ ^release.ya?ml$ ]] &&
error_message "Unify release workflow $f to CI workflow."
done
if [[ -f LICENSE ]]; then
git grep -q -F "The MIT License" LICENSE &&
git grep -q -F "$(whoami)" LICENSE &&
git log -1 --format=%cs 2>&1 | grep -q "^$(date +%Y)" &&
! git grep -q -E "$(date +%Y).*$(whoami)" LICENSE &&
error_message "Update copyright year in LICENSE."
fi
if [[ -f README.md ]]; then
git grep -F "godoc.org" README.md &&
error_message "Fix 'godoc.org' to 'pkg.go.dev' in README.md."
git grep -F "go get " README.md &&
error_message "Fix 'go get' to 'go install' in README.md"
git grep -P 'http://(?!localhost|\d+\.\d+\.\d+\.\d+)' README.md &&
error_message "Fix links to https in README.md."
git grep -P "(?<=\()https://github.com/[^/]+/[^/]+/workflows/[^/]+/badge.svg" README.md &&
error_message "Fix Actions badge to switch to actions workflow URL in README.md."
git grep -P "(?<=\()https://github.com/[^/]+/[^/]+/(?:actions/)?workflows/[^/]+/badge.svg(?=\))" README.md &&
error_message "Fix Actions badge to filter by branch in README.md."
git grep -P "(?<=\()https://github.com/[^/]+/[^/]+/actions(?=\))" README.md &&
error_message "Fix Actions link to filter by branch in README.md."
git grep -P "(?<=^(\S{,40}) \()https://github.com/\1(?=\))" README.md &&
error_message "Fix link to the author in README.md to wrap by <...>."
fi
if [[ -f Makefile ]]; then
git grep -E "clean +build" Makefile &&
error_message "Fix 'make all' in Makefile ('make all' should not 'clean')."
git grep -P '\bgo test\b' Makefile | grep -v -- -race &&
error_message "Add '-race' to 'go test' in Makefile."
git grep -q -F "/motemen/gobump/cmd/gobump" Makefile &&
error_message "Fix 'gobump' path in Makefile."
git grep -F "GO111MODULE=on" Makefile &&
error_message "Remove 'GO111MODULE=on' in Makefile."
git grep -E "cd .* go get " Makefile &&
error_message "Fix 'go get' to 'go install' in Makefile."
git grep -q "golint" Makefile &&
error_message "Migrate deprecated 'golint' to 'staticcheck'."
git grep -q "staticcheck" Makefile &&
! git grep -q "staticcheck.*-checks all" Makefile &&
error_message "Specify '-checks all(,-ST1000)?' to staticcheck."
git grep "staticcheck@master" Makefile &&
error_message "Specify '@latest' of staticcheck."
git grep -q "cross:" Makefile &&
! git grep -q "CREDITS:" Makefile &&
error_message "Add 'CREDITS' to the artifacts."
git grep -q "goxz" Makefile &&
git grep "[-]arch=amd64,arm64" Makefile &&
error_message "Remove '-arch=amd64,arm64' from 'goxz' flags, since it is by default."
git grep -q "bump:" Makefile &&
git grep "ifneq.*shell git status --porcelain" Makefile &&
error_message "Delay git invocation."
git grep -q "CREDITS:" Makefile &&
! git grep -q "/CREDITS" .gitignore &&
! git ls-files --error-unmatch CREDITS &>/dev/null &&
error_message "Add '/CREDITS' to .gitignore."
test -f .dockerignore &&
git grep -q "CREDITS:" Makefile &&
! git grep -q "/CREDITS" .dockerignore &&
! git ls-files --error-unmatch CREDITS &>/dev/null &&
error_message "Add '/CREDITS' to .dockerignore."
git grep -q "CREDITS:" Makefile &&
test -f go.sum &&
! git grep -q -E "CREDITS:.*go.sum" Makefile &&
error_message "Add 'go.sum' to CREDITS dependency in Makefile."
fi
if [[ -f go.mod ]]; then
git grep -E '^go 1\.(1[0-9]|2[0-1])$' go.mod &&
error_message "Bump up Go version in go.mod."
git grep -E '^go 1\.[0-9]+\.[0-9]+$' go.mod &&
error_message "Do not specify Go patch version in go.mod."
[[ -f go.sum ]] ||
error_message "Add go.sum (run 'go mod tidy && touch go.sum'," \
"even empty go.sum is important for dependency caching)."
go vet ./... ||
error_message "go vet ./..."
command -v golint &>/dev/null ||
go install golang.org/x/lint/golint@latest
golint -set_exit_status ./... ||
error_message "golint -set_exit_status ./..."
command -v staticcheck &>/dev/null ||
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck -checks all,-ST1000 ./... ||
error_message "staticcheck -checks all,-ST1000 ./..."
command -v gocritic &>/dev/null ||
go install github.com/go-critic/go-critic/cmd/gocritic@latest
gocritic check -disable=ifElseChain,appendAssign ./... ||
error_message "gocritic check -disable=ifElseChain ./..."
command -v revive &>/dev/null ||
go install github.com/mgechev/revive@latest
revive -config "${XDG_CONFIG_HOME:-$HOME}/revive.toml" -set_exit_status -formatter=friendly ./... ||
error_message "revive -set_exit_status -formatter=friendly ./..."
command -v gosec &>/dev/null ||
go install github.com/securego/gosec/v2/cmd/gosec@latest
gosec -quiet -exclude-generated -severity=high ./... ||
error_message "gosec -exclude-generated -severity=high ./..."
git grep -E '\bio/ioutil\b' &&
error_message "Stop using deprecated 'io/ioutil' package."
repo="$(git config --get remote.origin.url | sed -E 's#^.*github.com[:/]|.git$##g')" && {
url="https://goreportcard.com/report/github.com/$repo"
response=$(curl -sSfL "$url" | sed -n 's/var response *= \(.*\);/console.log(JSON.stringify(\1))/p' | node)
if [[ "$response" != "false" ]]; then
echo "$response" | jq -cr '.checks[] | select(.name != "gocyclo" and .percentage < 1) |
"\(.name): \(.percentage * 100)%"' | grep ^ &&
error_message "See goreportcard." && open "$url"
fi
}
elif git ls-files --error-unmatch '*.go' &>/dev/null; then
error_message "Use Go modules (add go.mod)."
fi
if [[ -z "$err" ]]; then
printf '\e[0;30;46m \e[0m\n'
printf '\e[0;30;46m OK \e[0m\n'
printf '\e[0;30;46m \e[0m\n'
else
printf '\e[0;30;41m \e[0m\n'
printf '\e[0;30;41m NG \e[0m\n'
printf '\e[0;30;41m \e[0m\n'
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment