#!/bin/sh
# script/lint: run golangci-lint over the whole tree.
#
# The linter is never installed on the host: it runs only inside the
# Dockerfile.lint build, one way, everywhere. A clean build is a clean
# lint. See Dockerfile.lint for why the lint step cannot be cached.
set -eu

ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"

main() {
    cd "$ROOT"

    # A value no other run repeats. Dockerfile.lint folds it into the
    # lint step's cache key, so the linter re-executes every run instead
    # of an unchanged tree returning a cached success having linted
    # nothing.
    cachebust="$(date +%s)-$$"

    tmp="$(mktemp -d "${TMPDIR:-/tmp}/pixa-lint.XXXXXX")"
    trap 'rm -rf "$tmp"' EXIT INT TERM

    # --progress=plain so the lint step's own output reaches the log we
    # check below; --output=type=cacheonly because we want the linter's
    # verdict, not an image left in the local store. The build status
    # travels through a file: a pipeline's exit status is tee's, not the
    # build's.
    (
        set +e
        docker build \
            --progress=plain \
            --build-arg CACHEBUST="$cachebust" \
            --output=type=cacheonly \
            -f Dockerfile.lint . 2>&1
        echo "$?" >"$tmp/status"
    ) | tee "$tmp/build.log"

    status="$(cat "$tmp/status" 2>/dev/null || echo 1)"
    [ "${status:-1}" -eq 0 ] || exit "${status:-1}"

    # The linter's start line must appear as build output, not only in
    # the build's echo of the RUN instruction. A step served from cache
    # prints the instruction and none of its output; a step that runs
    # prints a "#<n> <elapsed> ..." output line. Requiring that output
    # line means a future edit dropping the CACHEBUST reference from
    # Dockerfile.lint fails here rather than passing having linted
    # nothing.
    if ! grep -Eq '^#[0-9]+ +[0-9]+\.[0-9]+ +pixa-lint: running golangci-lint' \
            "$tmp/build.log"; then
        echo "script/lint: golangci-lint did not execute (cached step?)." >&2
        exit 1
    fi
}

main "$@"
