build(Makefile): add per-target timing via SHELL wrapper (#22862)

pre-commit and pre-push only reported total elapsed time at the end,
making it hard to identify which jobs are slow.

Add a `MAKE_TIMED=1` mode that replaces `SHELL` with a wrapper
(`scripts/lib/timed-shell.sh`) to print wall-clock time for each
recipe. pre-commit and pre-push enable this on their sub-makes.

Ad-hoc use: `make MAKE_TIMED=1 test`
This commit is contained in:
Mathias Fredriksson
2026-03-09 23:07:33 +02:00
committed by GitHub
parent f07e266904
commit 56960585af
2 changed files with 55 additions and 4 deletions
+14 -4
View File
@@ -19,6 +19,16 @@ SHELL := bash
.SHELLFLAGS := -ceu
.ONESHELL:
# When MAKE_TIMED=1, replace SHELL with a wrapper that prints
# elapsed wall-clock time for each recipe. pre-commit and pre-push
# set this on their sub-makes so every parallel job reports its
# duration. Ad-hoc usage: make MAKE_TIMED=1 test
ifdef MAKE_TIMED
SHELL := $(CURDIR)/scripts/lib/timed-shell.sh
.SHELLFLAGS = $@ -ceu
export MAKE_TIMED
endif
# This doesn't work on directories.
# See https://stackoverflow.com/questions/25752543/make-delete-on-error-for-directory-targets
.DELETE_ON_ERROR:
@@ -753,10 +763,10 @@ endef
pre-commit:
start=$$(date +%s)
echo "=== Phase 1/2: gen + fmt ==="
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target gen fmt
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target MAKE_TIMED=1 gen fmt
$(check-unstaged)
echo "=== Phase 2/2: lint + build ==="
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target \
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target MAKE_TIMED=1 \
lint \
lint/typos \
build/coder-slim_$(GOOS)_$(GOARCH)$(GOOS_BIN_EXT)
@@ -767,10 +777,10 @@ pre-commit:
pre-push:
start=$$(date +%s)
echo "=== Phase 1/2: gen + fmt + postgres ==="
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target gen fmt test-postgres-docker
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target MAKE_TIMED=1 gen fmt test-postgres-docker
$(check-unstaged)
echo "=== Phase 2/2: lint + build + test ==="
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target \
$(MAKE) -j$(PARALLEL_JOBS) --output-sync=target MAKE_TIMED=1 \
lint \
lint/typos \
build/coder-slim_$(GOOS)_$(GOARCH)$(GOOS_BIN_EXT) \
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# timed-shell.sh wraps bash with per-target wall-clock timing.
#
# Recipe invocation: timed-shell.sh <target> -ceu <recipe>
# $(shell ...) calls: timed-shell.sh -c <command>
#
# Enable via Makefile:
# SHELL := $(CURDIR)/scripts/lib/timed-shell.sh
# .SHELLFLAGS = $@ -ceu
#
# $(shell ...) uses SHELL but passes -c directly, not .SHELLFLAGS.
# Detect this and delegate to bash without timing output.
if [[ $1 == -* ]]; then
exec bash "$@"
fi
set -eu
target=$1
shift
bold=$(tput bold 2>/dev/null) || true
green=$(tput setaf 2 2>/dev/null) || true
red=$(tput setaf 1 2>/dev/null) || true
reset=$(tput sgr0 2>/dev/null) || true
start=$(date +%s)
echo "${bold}==> ${target}${reset}"
set +e
bash "$@"
rc=$?
set -e
elapsed=$(($(date +%s) - start))
if ((rc == 0)); then
echo "${bold}${green}==> ${target} completed in ${elapsed}s${reset}"
else
echo "${bold}${red}==> ${target} FAILED after ${elapsed}s${reset}" >&2
exit $rc
fi