port makefile to taskfile (#584)

This commit is contained in:
Alex Goodman 2025-03-28 15:16:13 -04:00 committed by GitHub
commit dd450a7474
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 484 additions and 416 deletions

64
.binny.yaml Normal file
View file

@ -0,0 +1,64 @@
tools:
# we want to use a pinned version of binny to manage the toolchain (so binny manages itself!)
- name: binny
version:
want: v0.9.0
method: github-release
with:
repo: anchore/binny
# used for linting
- name: golangci-lint
version:
want: v1.64.8
method: github-release
with:
repo: golangci/golangci-lint
# used for showing the changelog at release
- name: glow
version:
want: v2.1.0
method: github-release
with:
repo: charmbracelet/glow
# used to release all artifacts
- name: goreleaser
version:
want: v2.8.1
method: github-release
with:
repo: goreleaser/goreleaser
# used at release to generate the changelog
- name: chronicle
version:
want: v0.8.0
method: github-release
with:
repo: anchore/chronicle
# used during static analysis for license compliance
- name: bouncer
version:
want: v0.4.0
method: github-release
with:
repo: wagoodman/go-bouncer
# used for running all local and CI tasks
- name: task
version:
want: v3.42.1
method: github-release
with:
repo: go-task/task
# used for triggering a release
- name: gh
version:
want: v2.69.0
method: github-release
with:
repo: cli/cli

View file

@ -5,18 +5,10 @@ inputs:
description: "Go version to install"
required: true
default: "1.24.x"
use-go-cache:
description: "Restore go cache"
required: true
default: "true"
cache-key-prefix:
description: "Prefix all cache keys with this value"
required: true
default: "efa04b89c1b1"
build-cache-key-prefix:
description: "Prefix build cache key with this value"
required: true
default: "f8b6d31dea"
bootstrap-apt-packages:
description: "Space delimited list of tools to install via apt"
default: ""
@ -35,39 +27,15 @@ runs:
path: ${{ github.workspace }}/.tmp
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
# note: we need to keep restoring the go mod cache before bootstrapping tools since `go install` is used in
# some installations of project tools.
- name: Restore go module cache
id: go-mod-cache
if: inputs.use-go-cache == 'true'
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ inputs.cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-
- name: (cache-miss) Bootstrap project tools
shell: bash
if: steps.tool-cache.outputs.cache-hit != 'true'
run: make bootstrap-tools
- name: Restore go build cache
id: go-cache
if: inputs.use-go-cache == 'true'
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
key: ${{ inputs.cache-key-prefix }}-${{ inputs.build-cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ inputs.cache-key-prefix }}-${{ inputs.build-cache-key-prefix }}-${{ runner.os }}-go-${{ inputs.go-version }}-
run: make tools
- name: (cache-miss) Bootstrap go dependencies
shell: bash
if: steps.go-mod-cache.outputs.cache-hit != 'true' && inputs.use-go-cache == 'true'
run: make bootstrap-go
if: steps.go-mod-cache.outputs.cache-hit != 'true'
run: go mod download -x
- name: Install apt packages
if: inputs.bootstrap-apt-packages != ''

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
red=$(tput setaf 1)
bold=$(tput bold)
normal=$(tput sgr0)
# assert we are running in CI (or die!)
if [[ -z "$CI" ]]; then
echo "${bold}${red}This step should ONLY be run in CI. Exiting...${normal}"
exit 1
fi

View file

@ -1,31 +0,0 @@
#!/usr/bin/env bash
set -eu
ORIGINAL_STATE_DIR=$(mktemp -d "TEMP-original-state-XXXXXXXXX")
TIDY_STATE_DIR=$(mktemp -d "TEMP-tidy-state-XXXXXXXXX")
trap "cp -v ${ORIGINAL_STATE_DIR}/* ./ && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT
echo "Capturing original state of files..."
cp -v go.mod go.sum "${ORIGINAL_STATE_DIR}"
echo "Capturing state of go.mod and go.sum after running go mod tidy..."
go mod tidy
cp -v go.mod go.sum "${TIDY_STATE_DIR}"
echo ""
set +e
# Detect difference between the git HEAD state and the go mod tidy state
DIFF_MOD=$(diff -u "${ORIGINAL_STATE_DIR}/go.mod" "${TIDY_STATE_DIR}/go.mod")
DIFF_SUM=$(diff -u "${ORIGINAL_STATE_DIR}/go.sum" "${TIDY_STATE_DIR}/go.sum")
if [[ -n "${DIFF_MOD}" || -n "${DIFF_SUM}" ]]; then
echo "go.mod diff:"
echo "${DIFF_MOD}"
echo "go.sum diff:"
echo "${DIFF_SUM}"
echo ""
printf "FAILED! go.mod and/or go.sum are NOT tidy; please run 'go mod tidy'.\n\n"
exit 1
fi

3
.gitignore vendored
View file

@ -12,6 +12,9 @@ VERSION
/bin
/.tool-versions
/.tmp
/.tool
/.mise.toml
/.task
# builds
/dist

371
Makefile
View file

@ -1,354 +1,47 @@
BIN = dive
TEMP_DIR = ./.tmp
PWD := ${CURDIR}
SHELL = /bin/bash -o pipefail
TEST_IMAGE = busybox:latest
OWNER = wagoodman
PROJECT = dive
# Tool versions #################################
GOLANG_CI_VERSION = v1.64.5
GOBOUNCER_VERSION = v0.4.0
GORELEASER_VERSION = v2.4.4
GOSIMPORTS_VERSION = v0.3.8
CHRONICLE_VERSION = v0.8.0
GLOW_VERSION = v1.5.1
DOCKER_CLI_VERSION = 28.0.0
# Command templates #################################
LINT_CMD = $(TEMP_DIR)/golangci-lint run --tests=false --timeout=2m --config .golangci.yaml
GOIMPORTS_CMD = $(TEMP_DIR)/gosimports -local github.com/wagoodman
RELEASE_CMD = DOCKER_CLI_VERSION=$(DOCKER_CLI_VERSION) $(TEMP_DIR)/goreleaser release --clean
SNAPSHOT_CMD = $(RELEASE_CMD) --skip=publish --skip=sign --snapshot
CHRONICLE_CMD = $(TEMP_DIR)/chronicle
GLOW_CMD = $(TEMP_DIR)/glow
# Formatting variables #################################
BOLD := $(shell tput -T linux bold)
PURPLE := $(shell tput -T linux setaf 5)
GREEN := $(shell tput -T linux setaf 2)
CYAN := $(shell tput -T linux setaf 6)
RED := $(shell tput -T linux setaf 1)
RESET := $(shell tput -T linux sgr0)
TITLE := $(BOLD)$(PURPLE)
SUCCESS := $(BOLD)$(GREEN)
# Test variables #################################
# the quality gate lower threshold for unit test total % coverage (by function statements)
COVERAGE_THRESHOLD := 30
## Build variables #################################
DIST_DIR = dist
SNAPSHOT_DIR = snapshot
OS=$(shell uname | tr '[:upper:]' '[:lower:]')
SNAPSHOT_BIN=$(realpath $(shell pwd)/$(SNAPSHOT_DIR)/$(OS)-build_$(OS)_amd64_v1/$(BIN))
CHANGELOG := CHANGELOG.md
VERSION=$(shell git describe --dirty --always --tags)
ifeq "$(strip $(VERSION))" ""
override VERSION = $(shell git describe --always --tags --dirty)
endif
## Variable assertions
ifndef TEMP_DIR
$(error TEMP_DIR is not set)
endif
ifndef DIST_DIR
$(error DIST_DIR is not set)
endif
ifndef SNAPSHOT_DIR
$(error SNAPSHOT_DIR is not set)
endif
define title
@printf '$(TITLE)$(1)$(RESET)\n'
endef
.PHONY: all
all: clean static-analysis test ## Run all static analysis and tests
@printf '$(SUCCESS)All checks pass!$(RESET)\n'
.PHONY: test
test: unit ## Run all tests (currently unit and cli tests)
$(TEMP_DIR):
mkdir -p $(TEMP_DIR)
TOOL_DIR = .tool
BINNY = $(TOOL_DIR)/binny
TASK = $(TOOL_DIR)/task
.DEFAULT_GOAL := make-default
## Bootstrapping targets #################################
.PHONY: bootstrap-tools
bootstrap-tools: $(TEMP_DIR)
$(call title,Bootstrapping tools)
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMP_DIR)/ $(CHRONICLE_VERSION)
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMP_DIR)/ $(GOLANG_CI_VERSION)
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMP_DIR)/ $(GOBOUNCER_VERSION)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/rinchsan/gosimports/cmd/gosimports@$(GOSIMPORTS_VERSION)
GOBIN="$(realpath $(TEMP_DIR))" go install github.com/charmbracelet/glow@$(GLOW_VERSION)
# note: we need to assume that binny and task have not already been installed
$(BINNY):
@mkdir -p $(TOOL_DIR)
@curl -sSfL https://raw.githubusercontent.com/anchore/binny/main/install.sh | sh -s -- -b $(TOOL_DIR)
.PHONY: bootstrap-go
bootstrap-go:
$(call title,Bootstrapping go dependencies)
go mod download
# note: we need to assume that binny and task have not already been installed
.PHONY: task
$(TASK) task: $(BINNY)
@$(BINNY) install task -q
.PHONY: bootstrap
bootstrap: bootstrap-go bootstrap-tools ## Download and install all go dependencies (+ prep tooling in the ./tmp dir)
# this is a bootstrapping catch-all, where if the target doesn't exist, we'll ensure the tools are installed and then try again
%:
@make --silent $(TASK)
@$(TASK) $@
## Shim targets #################################
## Development targets ###################################
.PHONY: make-default
make-default: $(TASK)
@# run the default task in the taskfile
@$(TASK)
#run: build
# $(BUILD_PATH) build -t dive-example:latest -f .data/Dockerfile.example .
#
#run-large: build
# $(BUILD_PATH) amir20/clashleaders:latest
#
#run-podman: build
# podman build -t dive-example:latest -f .data/Dockerfile.example .
# $(BUILD_PATH) localhost/dive-example:latest --engine podman
#
#run-podman-large: build
# $(BUILD_PATH) docker.io/amir20/clashleaders:latest --engine podman
#
#run-ci: build
# CI=true $(BUILD_PATH) dive-example:latest --ci-config .data/.dive-ci
#
#dev:
# docker run -ti --rm -v $(PWD):/app -w /app -v dive-pkg:/go/pkg/ golang:1.13 bash
#
#build: gofmt
# go build -o $(BUILD_PATH)
# for those of us that can't seem to kick the habit of typing `make ...` lets wrap the superior `task` tool
TASKS := $(shell bash -c "test -f $(TASK) && $(TASK) -l | grep '^\* ' | cut -d' ' -f2 | tr -d ':' | tr '\n' ' '" ) $(shell bash -c "test -f $(TASK) && $(TASK) -l | grep 'aliases:' | cut -d ':' -f 3 | tr '\n' ' ' | tr -d ','")
.PHONY: generate-test-data
generate-test-data:
docker build -t dive-test:latest -f .data/Dockerfile.test-image . && \
docker image save -o .data/test-docker-image.tar dive-test:latest && \
echo 'Exported test data!'
.PHONY: $(TASKS)
$(TASKS): $(TASK)
@$(TASK) $@
.PHONY: generate-compressed-test-images
generate-compressed-test-images:
for alg in uncompressed gzip estargz zstd; do \
for exporter in docker image; do \
docker buildx build \
-f .data/Dockerfile.minimal \
--tag test-dive-$${exporter}:$${alg} \
--output type=$${exporter},force-compression=true,compression=$${alg} . ; \
done ; \
done && \
echo 'Exported test data!'
## actual targets
.PHONY: generate-compressed-test-data
generate-compressed-test-data:
for alg in uncompressed gzip estargz zstd; \
do \
docker buildx build \
-f .data/Dockerfile.minimal \
--output type=tar,dest=.data/test-$${alg}-image.tar,force-compression=true,compression=$${alg} . ; \
docker buildx build \
-f .data/Dockerfile.minimal \
--output type=oci,dest=.data/test-oci-$${alg}-image.tar,force-compression=true,compression=$${alg} . ; \
done && \
echo 'Exported test data!'
## Static analysis targets #################################
.PHONY: static-analysis
static-analysis: lint check-go-mod-tidy check-licenses
.PHONY: lint
lint: ## Run gofmt + golangci lint checks
$(call title,Running linters)
# ensure there are no go fmt differences
@printf "files with gofmt issues: [$(shell gofmt -l -s .)]\n"
@test -z "$(shell gofmt -l -s .)"
# run all golangci-lint rules
$(LINT_CMD)
@[ -z "$(shell $(GOIMPORTS_CMD) -d .)" ] || (echo "goimports needs to be fixed" && false)
# go tooling does not play well with certain filename characters, ensure the common cases don't result in future "go get" failures
$(eval MALFORMED_FILENAMES := $(shell find . | grep -e ':'))
@bash -c "[[ '$(MALFORMED_FILENAMES)' == '' ]] || (printf '\nfound unsupported filename characters:\n$(MALFORMED_FILENAMES)\n\n' && false)"
.PHONY: format
format: ## Auto-format all source code
$(call title,Running formatters)
gofmt -w -s .
$(GOIMPORTS_CMD) -w .
go mod tidy
.PHONY: lint-fix
lint-fix: format ## Auto-format all source code + run golangci lint fixers
$(call title,Running lint fixers)
$(LINT_CMD) --fix
.PHONY: check-licenses
check-licenses:
$(TEMP_DIR)/bouncer check ./...
check-go-mod-tidy:
@ .github/scripts/go-mod-tidy-check.sh && echo "go.mod and go.sum are tidy!"
## Testing targets #################################
.PHONY: unit
unit: $(TEMP_DIR) ## Run unit tests (with coverage)
$(call title,Running unit tests)
go test -race -coverprofile $(TEMP_DIR)/unit-coverage-details.txt ./...
@.github/scripts/coverage.py $(COVERAGE_THRESHOLD) $(TEMP_DIR)/unit-coverage-details.txt
## Acceptance testing targets (CI only) #################################
# todo: add --pull=never when supported by host box
.PHONY: ci-test-docker-image
ci-test-docker-image:
docker run \
--rm \
-t \
-v /var/run/docker.sock:/var/run/docker.sock \
'docker.io/wagoodman/dive:latest-amd64' \
'${TEST_IMAGE}' \
--ci
.PHONY: ci-test-deb-package-install
ci-test-deb-package-install:
docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /${PWD}:/src \
-w /src \
ubuntu:latest \
/bin/bash -x -c "\
apt update && \
apt install -y curl && \
curl -L 'https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz' | \
tar -vxzf - docker/docker --strip-component=1 && \
mv docker /usr/local/bin/ &&\
docker version && \
apt install ./snapshot/dive_*_linux_amd64.deb -y && \
dive --version && \
dive '${TEST_IMAGE}' --ci \
"
.PHONY: ci-test-deb-package-install
ci-test-rpm-package-install:
docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /${PWD}:/src \
-w /src \
fedora:latest \
/bin/bash -x -c "\
curl -L 'https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz' | \
tar -vxzf - docker/docker --strip-component=1 && \
mv docker /usr/local/bin/ &&\
docker version && \
dnf install ./snapshot/dive_*_linux_amd64.rpm -y && \
dive --version && \
dive '${TEST_IMAGE}' --ci \
"
.PHONY: ci-test-linux-run
ci-test-linux-run: generate-compressed-test-images
ls -la $(SNAPSHOT_DIR)
ls -la $(SNAPSHOT_DIR)/dive_linux_amd64_v1
chmod 755 $(SNAPSHOT_DIR)/dive_linux_amd64_v1/dive && \
$(SNAPSHOT_DIR)/dive_linux_amd64_v1/dive '${TEST_IMAGE}' --ci && \
$(SNAPSHOT_DIR)/dive_linux_amd64_v1/dive --source docker-archive .data/test-kaniko-image.tar --ci --ci-config .data/.dive-ci
for alg in uncompressed gzip estargz zstd; do \
for exporter in docker image; do \
$(SNAPSHOT_DIR)/dive_linux_amd64_v1/dive "test-dive-$${exporter}:$${alg}" --ci ; \
done && \
$(SNAPSHOT_DIR)/dive_linux_amd64_v1/dive --source docker-archive .data/test-oci-$${alg}-image.tar --ci --ci-config .data/.dive-ci; \
done
# we're not attempting to test docker, just our ability to run on these systems. This avoids setting up docker in CI.
.PHONY: ci-test-mac-run
ci-test-mac-run:
chmod 755 $(SNAPSHOT_DIR)/dive_darwin_amd64_v1/dive && \
$(SNAPSHOT_DIR)/dive_darwin_amd64_v1/dive --source docker-archive .data/test-docker-image.tar --ci --ci-config .data/.dive-ci
# we're not attempting to test docker, just our ability to run on these systems. This avoids setting up docker in CI.
.PHONY: ci-test-windows-run
ci-test-windows-run:
dive.exe --source docker-archive .data/test-docker-image.tar --ci --ci-config .data/.dive-ci
dive.exe --source docker-archive .data/test-docker-image.tar --ci --ci-config .data/.dive-ci
## Build-related targets #################################
.PHONY: build
build: $(SNAPSHOT_DIR) ## Build release snapshot binaries and packages
$(SNAPSHOT_DIR): ## Build snapshot release binaries and packages
$(call title,Building snapshot artifacts)
@# create a config with the dist dir overridden
@echo "dist: $(SNAPSHOT_DIR)" > $(TEMP_DIR)/goreleaser.yaml
@cat .goreleaser.yaml >> $(TEMP_DIR)/goreleaser.yaml
@# build release snapshots
@bash -c "\
VERSION=$(VERSION:v%=%) \
$(SNAPSHOT_CMD) --config $(TEMP_DIR)/goreleaser.yaml \
"
.PHONY: cli
cli: $(SNAPSHOT_DIR) ## Run CLI tests
chmod 755 "$(SNAPSHOT_BIN)"
$(SNAPSHOT_BIN) version
go test -count=1 -timeout=15m -v ./test/cli
.PHONY: changelog
changelog: clean-changelog ## Generate and show the changelog for the current unreleased version
$(CHRONICLE_CMD) -vvv -n --version-file VERSION > $(CHANGELOG)
@$(GLOW_CMD) $(CHANGELOG)
$(CHANGELOG):
$(CHRONICLE_CMD) -vvv > $(CHANGELOG)
.PHONY: release
release: ## Cut a new release
@.github/scripts/trigger-release.sh
.PHONY: ci-release
ci-release: ci-check clean-dist $(CHANGELOG)
$(call title,Publishing release artifacts)
# create a config with the dist dir overridden
echo "dist: $(DIST_DIR)" > $(TEMP_DIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMP_DIR)/goreleaser.yaml
bash -c "$(RELEASE_CMD) --release-notes <(cat CHANGELOG.md) --config $(TEMP_DIR)/goreleaser.yaml"
.PHONY: ci-check
ci-check:
@.github/scripts/ci-check.sh
## Cleanup targets #################################
.PHONY: clean
clean: clean-dist clean-snapshot ## Remove previous builds, result reports, and test cache
.PHONY: clean-snapshot
clean-snapshot:
rm -rf $(SNAPSHOT_DIR) $(TEMP_DIR)/goreleaser.yaml
.PHONY: clean-dist
clean-dist: clean-changelog
rm -rf $(DIST_DIR) $(TEMP_DIR)/goreleaser.yaml
.PHONY: clean-changelog
clean-changelog:
rm -f $(CHANGELOG) VERSION
## Help! #################################
.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}'
help: $(TASK)
@$(TASK) -l

382
Taskfile.yaml Normal file
View file

@ -0,0 +1,382 @@
version: "3"
vars:
OWNER: wagoodman
PROJECT: dive
# static file dirs
TOOL_DIR: .tool
TMP_DIR: .tmp
# TOOLS
BINNY: "{{ .TOOL_DIR }}/binny"
CHRONICLE: "{{ .TOOL_DIR }}/chronicle"
GORELEASER: "{{ .TOOL_DIR }}/goreleaser"
GOLANGCI_LINT: "{{ .TOOL_DIR }}/golangci-lint"
TASK: "{{ .TOOL_DIR }}/task"
BOUNCER: "{{ .TOOL_DIR }}/bouncer"
GLOW: "{{ .TOOL_DIR }}/glow"
# used for changelog generation
CHANGELOG: CHANGELOG.md
NEXT_VERSION: VERSION
# note: the snapshot dir must be a relative path starting with ./
SNAPSHOT_DIR: ./snapshot
SNAPSHOT_CMD: "{{ .GORELEASER }} release --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --skip=publish --skip=sign"
BUILD_CMD: "{{ .GORELEASER }} build --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --single-target"
RELEASE_CMD: "{{ .GORELEASER }} release --clean --release-notes {{ .CHANGELOG }}"
VERSION:
sh: git describe --dirty --always --tags
# used for acceptance tests
TEST_IMAGE: busybox:latest
DOCKER_CLI_VERSION: 28.0.0
env:
GNUMAKEFLAGS: '--no-print-directory'
DOCKER_CLI_VERSION: "{{ .DOCKER_CLI_VERSION }}"
tasks:
## High-level tasks #################################
default:
desc: Run all validation tasks
aliases:
- pr-validations
- validations
cmds:
- task: static-analysis
- task: test
static-analysis:
desc: Run all static analysis tasks
cmds:
- task: check-go-mod-tidy
- task: check-licenses
- task: lint
test:
desc: Run all levels of test
cmds:
- task: unit
## Bootstrap tasks #################################
binny:
internal: true
# desc: Get the binny tool
generates:
- "{{ .BINNY }}"
status:
- "test -f {{ .BINNY }}"
cmd: "curl -sSfL https://raw.githubusercontent.com/anchore/binny/main/install.sh | sh -s -- -b .tool"
silent: true
tools:
desc: Install all tools needed for CI and local development
deps: [binny]
aliases:
- bootstrap
generates:
- ".binny.yaml"
- "{{ .TOOL_DIR }}/*"
status:
- "{{ .BINNY }} check -v"
cmd: "{{ .BINNY }} install -v"
silent: true
update-tools:
desc: Update pinned versions of all tools to their latest available versions
deps: [binny]
generates:
- ".binny.yaml"
- "{{ .TOOL_DIR }}/*"
cmd: "{{ .BINNY }} update -v"
silent: true
list-tools:
desc: List all tools needed for CI and local development
deps: [binny]
cmd: "{{ .BINNY }} list"
silent: true
list-tool-updates:
desc: List all tools that are not up to date relative to the binny config
deps: [binny]
cmd: "{{ .BINNY }} list --updates"
silent: true
tmpdir:
silent: true
generates:
- "{{ .TMP_DIR }}"
cmd: "mkdir -p {{ .TMP_DIR }}"
## Static analysis tasks #################################
format:
desc: Auto-format all source code
deps: [tools]
cmds:
- gofmt -w -s .
- go mod tidy
lint-fix:
desc: Auto-format all source code + run golangci lint fixers
deps: [tools]
cmds:
- task: format
- "{{ .GOLANGCI_LINT }} run --tests=false --fix"
lint:
desc: Run gofmt + golangci lint checks
vars:
BAD_FMT_FILES:
sh: gofmt -l -s .
BAD_FILE_NAMES:
sh: "find . | grep -e ':' || true"
deps: [tools]
cmds:
# ensure there are no go fmt differences
- cmd: 'test -z "{{ .BAD_FMT_FILES }}" || (echo "files with gofmt issues: [{{ .BAD_FMT_FILES }}]"; exit 1)'
silent: true
# ensure there are no files with ":" in it (a known back case in the go ecosystem)
- cmd: 'test -z "{{ .BAD_FILE_NAMES }}" || (echo "files with bad names: [{{ .BAD_FILE_NAMES }}]"; exit 1)'
silent: true
# run linting
- "{{ .GOLANGCI_LINT }} run --tests=false"
check-licenses:
# desc: Ensure transitive dependencies are compliant with the current license policy
deps: [tools]
cmd: "{{ .BOUNCER }} check ./..."
check-go-mod-tidy:
# desc: Ensure go.mod and go.sum are up to date
cmds:
- cmd: |
if ! go mod tidy -diff; then
echo "go.mod and/or go.sum need updates. Please run 'go mod tidy'"
exit 1
fi
silent: true
## Testing tasks #################################
unit:
desc: Run unit tests
deps:
- tmpdir
vars:
TEST_PKGS:
sh: "go list ./... | tr '\n' ' '"
# unit test coverage threshold (in % coverage)
COVERAGE_THRESHOLD: 30
cmds:
- "go test -coverprofile {{ .TMP_DIR }}/unit-coverage-details.txt {{ .TEST_PKGS }}"
- cmd: ".github/scripts/coverage.py {{ .COVERAGE_THRESHOLD }} {{ .TMP_DIR }}/unit-coverage-details.txt"
silent: true
## Acceptance tests #################################
ci-test-linux:
cmds:
- task: ci-test-linux-run
- task: ci-test-docker-image
- task: ci-test-deb-package-install
- task: ci-test-rpm-package-install
ci-test-docker-image:
desc: Test using the docker image
cmds:
- |
docker run \
--rm \
-t \
-v /var/run/docker.sock:/var/run/docker.sock \
'docker.io/wagoodman/dive:latest' \
'{{ .TEST_IMAGE }}' \
--ci
ci-test-deb-package-install:
desc: Test debian package installation
cmds:
- |
docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /${PWD}:/src \
-w /src \
ubuntu:latest \
/bin/bash -x -c "\
apt update && \
apt install -y curl && \
curl -L 'https://download.docker.com/linux/static/stable/x86_64/docker-{{ .DOCKER_CLI_VERSION }}.tgz' | \
tar -vxzf - docker/docker --strip-component=1 && \
mv docker /usr/local/bin/ &&\
docker version && \
apt install ./snapshot/dive_*_linux_amd64.deb -y && \
dive --version && \
dive '{{ .TEST_IMAGE }}' --ci \
"
ci-test-rpm-package-install:
desc: Test RPM package installation
cmds:
- |
docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /${PWD}:/src \
-w /src \
fedora:latest \
/bin/bash -x -c "\
curl -L 'https://download.docker.com/linux/static/stable/x86_64/docker-{{ .DOCKER_CLI_VERSION }}.tgz' | \
tar -vxzf - docker/docker --strip-component=1 && \
mv docker /usr/local/bin/ &&\
docker version && \
dnf install ./snapshot/dive_*_linux_amd64.rpm -y && \
dive --version && \
dive '{{ .TEST_IMAGE }}' --ci \
"
generate-compressed-test-images:
desc: Generate compressed test images for testing
cmds:
- |
for alg in uncompressed gzip estargz zstd; do \
for exporter in docker image; do \
docker buildx build \
-f .data/Dockerfile.minimal \
--tag test-dive-${exporter}:${alg} \
--output type=${exporter},force-compression=true,compression=${alg} . ; \
done ; \
done && \
echo 'Exported test data!'
generate-compressed-test-data:
desc: Generate compressed test data for testing
cmds:
- |
for alg in uncompressed gzip estargz zstd; \
do \
docker buildx build \
-f .data/Dockerfile.minimal \
--output type=tar,dest=.data/test-${alg}-image.tar,force-compression=true,compression=${alg} . ; \
docker buildx build \
-f .data/Dockerfile.minimal \
--output type=oci,dest=.data/test-oci-${alg}-image.tar,force-compression=true,compression=${alg} . ; \
done && \
echo 'Exported test data!'
ci-test-linux-run:
desc: Test Linux binary execution (CI only)
deps: [ci-check, generate-compressed-test-images]
cmds:
- |
ls -la {{ .SNAPSHOT_DIR }}
ls -la {{ .SNAPSHOT_DIR }}/dive_linux_amd64_v1
chmod 755 {{ .SNAPSHOT_DIR }}/dive_linux_amd64_v1/dive && \
{{ .SNAPSHOT_DIR }}/dive_linux_amd64_v1/dive '{{ .TEST_IMAGE }}' --ci && \
{{ .SNAPSHOT_DIR }}/dive_linux_amd64_v1/dive --source docker-archive .data/test-kaniko-image.tar --ci --ci-config .data/.dive-ci
- |
for alg in uncompressed gzip estargz zstd; do \
for exporter in docker image; do \
{{ .SNAPSHOT_DIR }}/dive_linux_amd64_v1/dive "test-dive-${exporter}:${alg}" --ci ; \
done && \
{{ .SNAPSHOT_DIR }}/dive_linux_amd64_v1/dive --source docker-archive .data/test-oci-${alg}-image.tar --ci --ci-config .data/.dive-ci; \
done
ci-test-mac-run:
desc: Test macOS binary execution (CI only)
deps: [ci-check]
cmds:
- |
chmod 755 {{ .SNAPSHOT_DIR }}/dive_darwin_amd64_v1/dive && \
{{ .SNAPSHOT_DIR }}/dive_darwin_amd64_v1/dive --source docker-archive .data/test-docker-image.tar --ci --ci-config .data/.dive-ci
## Build-related targets #################################
build:
desc: Build the project
deps: [tools, tmpdir]
generates:
- "{{ .PROJECT }}"
cmds:
- silent: true
cmd: |
echo "dist: {{ .SNAPSHOT_DIR }}" > {{ .TMP_DIR }}/goreleaser.yaml
cat .goreleaser.yaml >> {{ .TMP_DIR }}/goreleaser.yaml
- "{{ .BUILD_CMD }}"
snapshot:
desc: Create a snapshot release
aliases:
- build
deps: [tools, tmpdir]
sources:
- "**/*.go"
method: checksum
cmds:
- silent: true
cmd: |
echo "dist: {{ .SNAPSHOT_DIR }}" > {{ .TMP_DIR }}/goreleaser.yaml
cat .goreleaser.yaml >> {{ .TMP_DIR }}/goreleaser.yaml
- "{{ .SNAPSHOT_CMD }}"
changelog:
desc: Generate a changelog
deps: [tools]
generates:
- "{{ .CHANGELOG }}"
- "{{ .NEXT_VERSION }}"
cmds:
- "{{ .CHRONICLE }} -vv -n --version-file {{ .NEXT_VERSION }} > {{ .CHANGELOG }}"
- "{{ .GLOW }} -w 200 {{ .CHANGELOG }}"
## Release targets #################################
release:
desc: Create a release
interactive: true
deps: [tools]
cmds:
- cmd: .github/scripts/trigger-release.sh
silent: true
## CI-only targets #################################
ci-check:
preconditions:
- sh: test -n "$CI"
msg: "This step should ONLY be run in CI. Exiting..."
cmds:
- echo "Running in CI environment"
silent: true
internal: true
ci-release:
# desc: "[CI only] Create a release"
deps: [ci-check, tools]
cmds:
- "{{ .CHRONICLE }} -vvv > CHANGELOG.md"
- cmd: "cat CHANGELOG.md"
silent: true
- "{{ .RELEASE_CMD }}"
## Cleanup targets #################################
clean-snapshot:
desc: Remove any snapshot builds
cmds:
- "rm -rf {{ .SNAPSHOT_DIR }}"
- "rm -rf {{ .TMP_DIR }}/goreleaser.yaml"