Skip to content

Instantly share code, notes, and snippets.

@algonzalez
Last active March 13, 2025 03:15
Show Gist options
  • Save algonzalez/7318ca587110d9192f2af5027df5092e to your computer and use it in GitHub Desktop.
Save algonzalez/7318ca587110d9192f2af5027df5092e to your computer and use it in GitHub Desktop.
Justfile implementation of the boilerplate makefile for Go projects by Alex Edwards
# ==============================================================================
# Justfile implementation of the Go project makefile from Alex Edwards:
# https://www.alexedwards.net/blog/a-time-saving-makefile-for-your-go-projects
# Notes:
# - I'm a newbie in both Go and justfiles, so let me know what can be improved
# - should be cross-platform, but only tested in Windows and Ubuntu under WSL
# - confirm task is not needed as it is built-in using [confirm] attribute
# - removed the `-race` argument in the test targets;
# it requires CGO_ENABLED=1 (at least on Windows).
# - commented out the `upx` call in the deploy target; I don't currently use it.
# - GOOS and GOARCH values are now `prod_os` and `prod_arch`
# variables used from the deploy target
# - commented out the `staticcheck` call in audit until I've had
# a chance to review what it's checking with the given arguments
# - commented out the `govulncheck` call in audit;
# it downgrades to the prior go version -- don't know why yet
# - prod-deploy allows you to specify the build OS and architecture as arguments.
# This makes it more complicated, but demonstrates a nice feature of justfile.
# ==============================================================================
# Dependencies:
# - just command runner. To install: https://just.systems/man/en/packages.html
# - PowerShell 7.x or greater on Windows.
# May work with default installed PowerShell 5.x but will need to change
# the windows-shell value from "pwsh.exe" to "powershell.exe"
# - Bash or equivalent shell on Linux and macOS
# ==============================================================================
# just manual: https://just.systems/man/en/
# just repo: https://github.com/casey/just
# ==============================================================================
set windows-shell := ["pwsh.exe", "-NonInteractive", "-NoLogo", "-NoProfile", "-Command"]
set shell := ["bash", "-uc"]
set unstable # required to use the [script()] attribute
# TODO: Change these variables as necessary
main_package_path := "." # "./cmd/example"
binary_name := "example"
bin_dir := "/tmp/bin"
prod_os := "windows" # used for GOOS in production-deploy task
prod_arch := "amd64" # used for GOARCH in production-deploy task
help_text := """
Usage:
just TARGET
Available targets:"""
# print the help message
@_default:
echo "{{help_text}}"
just --list --no-aliases --unsorted --list-heading ""
# --------------------
# HELPERS
# --------------------
# print the help message
help: _default
# check for untracked or uncommitted changes
[unix]
_no-dirty:
if [ -d .git ]; then test -z "$(git status --porcelain)"; fi;
# check for untracked or uncommitted changes
[windows]
_no-dirty:
if ((Test-Path ".git") -and ($(git status --porcelain)) -ne $nil) { exit 1 }
# --------------------
# QUALITY CONTROL
# --------------------
# && denotes dependencies that run after current one
# run quality control checks
[group("Quality Control")]
audit: && _audit-gofmt-check _audit-more
go mod tidy -diff
go mod verify
# NOTE: `test -z` not available in powershell, so using os-specifc dependencies
[unix]
_audit-gofmt-check:
test -z "$(gofmt -l .)"
[windows]
_audit-gofmt-check:
if ($(gofmt -l .) -ne $nil) { exit 1 }
_audit-more:
go vet ./...
# TODO: read up on what it checks and what the arguments mean
# go run honnef.co/go/tools/cmd/staticcheck@latest -checks='all,-ST1000,-U1000' ./...
# TODO: downgrades go version!!! TODO: WHY?
# go run golang.org/x/vuln/cmd/govulncheck@latest ./...
# run all tests
[group("Quality Control")]
test:
go test -v -buildvcs ./...
#
# run all test and display coverage
[group("Quality Control")]
test-cover:
go test -v -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out
# --------------------
# DEVELOPMENT
# --------------------
# tidy mod files and format .go files
[group("Development")]
tidy:
go mod tidy -v
go fmt ./..
# build the application
[group("Development")]
build:
# Include additional build steps, like TypeScript, SCSS or Tailwind compilation here...
go build -o='/tmp/bin/{{binary_name}}' '{{main_package_path}}'
# run the application
[group("Development")]
[unix]
run: build
'/tmp/bin/{{binary_name}}'
# run the application
[group("Development")]
[windows]
run: build
. '/tmp/bin/{{binary_name}}'
# run the application with reloading on file changes
[group("Development")]
run-live:
# TODO what is this tool?
# go run github.com/cosmtrek/[email protected] \
# --build.cmd "make build" --build.bin "/tmp/bin/{{binary_name}}" --build.delay "100" \
# --build.exclude_dir "" \
# --build.include_ext "go, tpl, tmpl, html, css, scss, js, ts, sql, jpeg, jpg, gif, png, bmp, svg, webp, ico" \
# --misc.clean_on_exit "true"
# --------------------
# OPERATIONS
# --------------------
# push changes to the remote Git repo
[group("Operations")]
[confirm]
push: audit _no-dirty
git push
# deploy the application to production
[group("Operations")]
[unix]
[confirm("Run 'prod-deploy' target?")]
prod-deploy os="" arch="": audit _no-dirty
#!/usr/bin/env bash
set -euo pipefail
if [ "{{arch}}" == "" ]; then goarch="{{prod_arch}}"; else goarch="{{arch}}"; fi;
if [ "{{os}}" == "" ]; then goos="{{prod_os}}"; else goos="{{os}}"; fi;
if [ $goos == "macos" ]; then goos="darwin"; else goos=$goos; fi;
if [ $goos == "darwin" ]; then out_os="macos"; else out_os=$goos; fi;
if [ $goos == "windows" ]; then bin_name="{{binary_name}}.exe"; else bin_name="{{binary_name}}"; fi;
out_dir="{{bin_dir}}/${out_os}_$goarch";
echo "Deploying: $out_dir/$bin_name";
env GOOS="$goos" GOARCH="$goarch" go build -o="$out_dir/$bin_name" "{{main_package_path}}"
test -f "${out_dir}/${bin_name}"
# upx -5 '/tmp/bin/{{prod_os}}_{{prod_arch}}/{{binary_name}}'
# Include additional deployment steps here...
# deploy the application to production
[group("Operations")]
[windows]
[confirm("Run 'prod-deploy' target?")]
[script("pwsh","-NonInteractive","-NoLogo","-NoProfile","-Command")]
@prod-deploy os="" arch="": audit _no-dirty
$goarch = if ("{{arch}}" -eq "") { "{{prod_arch}}" } else { "{{arch}}" }
$goos = if ("{{os}}" -eq "") { "{{prod_os}}" } else { "{{os}}" };
if ($goos -eq "macos") { $goos="darwin" };
$out_os = if ($goos -eq "darwin") { "macos" } else { $goos };
$bin_name = if ($goos -eq "windows") { "{{binary_name}}.exe" } else { "{{binary_name}}" };
$out_dir = "{{bin_dir}}/$($out_os)_$goarch";
echo "Deploying: $out_dir/$bin_name";
if (!(Test-Path "$($out_dir)")) { New-Item -ItemType Directory -Path "$($out_dir)" | Out-Null };
$env:GOOS="$goos"; $env:GOARCH="$goarch"; go build -o="$out_dir/$bin_name" "{{main_package_path}}"; $env:GOOS=""; $env:GOARCH="";
if (!(Test-Path "$out_dir/$bin_name" -PathType leaf)) { exit 1 }
# upx -5 '/tmp/bin/{{prod_os}}_{{prod_arch}}/{{binary_name}}'
# Include additional deployment steps here...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment