diff --git a/.github/actions/bootstrap/action.yaml b/.github/actions/bootstrap/action.yaml new file mode 100644 index 00000000..5544402d --- /dev/null +++ b/.github/actions/bootstrap/action.yaml @@ -0,0 +1,81 @@ +name: "Bootstrap" +description: "Bootstrap all tools and dependencies" +inputs: + go-version: + description: "Go version to install" + required: true + default: "1.19.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: "831180ac25" + 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: "" + +runs: + using: "composite" + steps: + - uses: actions/setup-go@v3 + with: + go-version: ${{ inputs.go-version }} + + - name: Restore tool cache + id: tool-cache + uses: actions/cache@v3 + with: + 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@v3 + 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@v3 + 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 }}- + + - 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 + + - name: Bootstrap CI dependencies + shell: bash + run: make ci-bootstrap + + - name: Install apt packages + if: inputs.bootstrap-apt-packages != '' + shell: bash + run: | + DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y ${{ inputs.bootstrap-apt-packages }} + diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh new file mode 100755 index 00000000..18f13cb4 --- /dev/null +++ b/.github/scripts/build.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -uo pipefail + +# Based on https://gist.github.com/eduncan911/68775dba9d3c028181e4 and https://gist.github.com/makeworld-the-better-one/e1bb127979ae4195f43aaa3ad46b1097 +# but improved to use the `go` command so it never goes out of date. + +type setopt >/dev/null 2>&1 + +contains() { + # Source: https://stackoverflow.com/a/8063398/7361270 + [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] +} + +mkdir -p snapshot +rm -f snapshot/* + +OUTPUT=snapshot/stereoscope-example +FAILURES="" + +# You can set your own flags on the command line +FLAGS=${FLAGS:-"-ldflags=\"-s -w\""} + +# A list of OSes and architectures to not build for, space-separated +# It can be set from the command line when the script is called. +NOT_ALLOWED_OS=${NOT_ALLOWED_OS:-"js android ios solaris illumos aix dragonfly plan9"} +NOT_ALLOWED_ARCH=${NOT_ALLOWED_ARCH:-"riscv64 mips mips64 mips64le ppc64 ppc64le s390x wasm"} + + +# Get all targets +while IFS= read -r target; do + GOOS=${target%/*} + GOARCH=${target#*/} + BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}" + + if contains "$NOT_ALLOWED_OS" "$GOOS" ; then + continue + fi + + if contains "$NOT_ALLOWED_ARCH" "$GOARCH" ; then + continue + fi + + # Check for arm and set arm version + if [[ $GOARCH == "arm" ]]; then + # Set what arm versions each platform supports + if [[ $GOOS == "darwin" ]]; then + arms="7" + elif [[ $GOOS == "windows" ]]; then + # This is a guess, it's not clear what Windows supports from the docs + # But I was able to build all these on my machine + arms="5 6 7" + elif [[ $GOOS == *"bsd" ]]; then + arms="6 7" + else + # Linux goes here + arms="5 6 7" + fi + + # Now do the arm build + for GOARM in $arms; do + BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}${GOARM}" + if [[ "${GOOS}" == "windows" ]]; then BIN_FILENAME="${BIN_FILENAME}.exe"; fi + CMD="GOARM=${GOARM} GOOS=${GOOS} GOARCH=${GOARCH} go build $FLAGS -o ${BIN_FILENAME} $@" + echo "${CMD}" + eval "${CMD}" || FAILURES="${FAILURES} ${GOOS}/${GOARCH}${GOARM}" + done + else + # Build non-arm here + if [[ "${GOOS}" == "windows" ]]; then BIN_FILENAME="${BIN_FILENAME}.exe"; fi + CMD="GOOS=${GOOS} GOARCH=${GOARCH} go build $FLAGS -o ${BIN_FILENAME} $@" + echo "${CMD}" + eval "${CMD}" || FAILURES="${FAILURES} ${GOOS}/${GOARCH}" + fi +done <<< "$(go tool dist list)" + +if [[ "${FAILURES}" != "" ]]; then + echo "" + echo "build failed for: ${FAILURES}" + exit 1 +fi \ No newline at end of file diff --git a/.github/scripts/coverage.py b/.github/scripts/coverage.py new file mode 100755 index 00000000..db14135c --- /dev/null +++ b/.github/scripts/coverage.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +import subprocess +import sys +import shlex + + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + +if len(sys.argv) < 3: + print("Usage: coverage.py [threshold] [go-coverage-report]") + sys.exit(1) + + +threshold = float(sys.argv[1]) +report = sys.argv[2] + + +args = shlex.split(f"go tool cover -func {report}") +p = subprocess.run(args, capture_output=True, text=True) + +percent_coverage = float(p.stdout.splitlines()[-1].split()[-1].replace("%", "")) +print(f"{bcolors.BOLD}Coverage: {percent_coverage}%{bcolors.ENDC}") + +if percent_coverage < threshold: + print(f"{bcolors.BOLD}{bcolors.FAIL}Coverage below threshold of {threshold}%{bcolors.ENDC}") + sys.exit(1) diff --git a/.github/scripts/go-mod-tidy-check.sh b/.github/scripts/go-mod-tidy-check.sh new file mode 100755 index 00000000..28f22fcd --- /dev/null +++ b/.github/scripts/go-mod-tidy-check.sh @@ -0,0 +1,30 @@ +#!/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 -p ${ORIGINAL_STATE_DIR}/* ./ && git update-index -q --refresh && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT + +# capturing original state of files... +cp go.mod go.sum "${ORIGINAL_STATE_DIR}" + +# capturing state of go.mod and go.sum after running go mod tidy... +go mod tidy +cp go.mod go.sum "${TIDY_STATE_DIR}" + +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 diff --git a/.github/workflows/benchmark-testing.yaml b/.github/workflows/benchmark-testing.yaml new file mode 100644 index 00000000..4cd87594 --- /dev/null +++ b/.github/workflows/benchmark-testing.yaml @@ -0,0 +1,58 @@ +name: "Benchmark testing" + +on: + workflow_dispatch: + pull_request: + +jobs: + + Benchmark-Test: + name: "Benchmark tests" + runs-on: ubuntu-20.04 + # note: we want benchmarks to run on pull_request events in order to publish results to a sticky comment, and + # we also want to run on push such that merges to main are recorded to the cache. For this reason we don't filter + # the job by event. + steps: + - uses: actions/checkout@v3 + + - name: Bootstrap environment + uses: ./.github/actions/bootstrap + + - name: Restore base benchmark result + uses: actions/cache@v3 + with: + path: test/results/benchmark-main.txt + # use base sha for PR or new commit hash for main push in benchmark result key + key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }} + + - name: Run benchmark tests + id: benchmark + run: | + REF_NAME=${GITHUB_REF##*/} make benchmark + OUTPUT=$(make show-benchstat) + OUTPUT="${OUTPUT//'%'/'%25'}" # URL encode all '%' characters + OUTPUT="${OUTPUT//$'\n'/'%0A'}" # URL encode all '\n' characters + OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters + echo "::set-output name=result::$OUTPUT" + + - uses: actions/upload-artifact@v3 + with: + name: benchmark-test-results + path: test/results/**/* + + - name: Update PR benchmark results comment + uses: marocchino/sticky-pull-request-comment@v2 + continue-on-error: true + with: + header: benchmark + message: | + ### Benchmark Test Results + +
+ Benchmark results from the latest changes vs base branch + + ``` + ${{ steps.benchmark.outputs.result }} + ``` + +
diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 4ed98466..f0314a6b 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -16,79 +16,28 @@ on: - main pull_request: -env: - GO_VERSION: "1.19.x" - jobs: Static-Analysis: name: "Static analysis" runs-on: ubuntu-20.04 steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: actions/checkout@v2 - - - name: Restore tool cache - id: tool-cache - uses: actions/cache@v2.1.3 - with: - path: ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + - uses: actions/checkout@v3 - - name: Restore go cache - id: go-cache - uses: actions/cache@v2.1.3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go-${{ env.GO_VERSION }}- - - - name: (cache-miss) Bootstrap all project dependencies - if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' - run: make bootstrap + - name: Bootstrap environment + uses: ./.github/actions/bootstrap - - name: Bootstrap CI environment dependencies - run: make ci-bootstrap - - - name: Run static analysis - run: make static-analysis + - name: Run static analysis + run: make static-analysis Unit-Test: name: "Unit tests" runs-on: ubuntu-20.04 steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Restore tool cache - id: tool-cache - uses: actions/cache@v2.1.3 - with: - path: ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} - - - name: Restore go cache - id: go-cache - uses: actions/cache@v2.1.3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go-${{ env.GO_VERSION }}- - - - name: (cache-miss) Bootstrap all project dependencies - if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' - run: make bootstrap - - - name: Bootstrap CI environment dependencies - run: make ci-bootstrap + - name: Bootstrap environment + uses: ./.github/actions/bootstrap - name: Run unit tests run: make unit @@ -102,11 +51,10 @@ jobs: name: "Integration tests" runs-on: ubuntu-20.04 steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} + - uses: actions/checkout@v3 - - uses: actions/checkout@v2 + - name: Bootstrap environment + uses: ./.github/actions/bootstrap - name: Enable systemd for podman socket activation run: | @@ -128,29 +76,6 @@ jobs: with: limit-access-to-actor: true - - name: Restore tool cache - id: tool-cache - uses: actions/cache@v2.1.3 - with: - path: ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} - - - name: Restore go cache - id: go-cache - uses: actions/cache@v2.1.3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go-${{ env.GO_VERSION }}- - - - name: (cache-miss) Bootstrap all project dependencies - if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' - run: make bootstrap - - - name: Bootstrap CI environment dependencies - run: make ci-bootstrap - - name: Build key for test-fixture cache run: make integration-fingerprint @@ -177,77 +102,15 @@ jobs: - name: Run integration tests run: make integration - Benchmark-Test: - name: "Benchmark tests" + Build-Snapshot-Artifacts: + name: "Build snapshot artifacts" runs-on: ubuntu-20.04 - # note: we want benchmarks to run on pull_request events in order to publish results to a sticky comment, and - # we also want to run on push such that merges to main are recorded to the cache. For this reason we don't filter - # the job by event. steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: actions/checkout@v2 - - - name: Restore tool cache - id: tool-cache - uses: actions/cache@v2.1.3 - with: - path: ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} - - - name: Restore go cache - id: go-cache - uses: actions/cache@v2.1.3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go-${{ env.GO_VERSION }}- - - - name: (cache-miss) Bootstrap all project dependencies - if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' - run: make bootstrap - - - name: Bootstrap CI environment dependencies - run: make ci-bootstrap - - - name: Restore base benchmark result - uses: actions/cache@v2 - with: - path: test/results/benchmark-main.txt - # use base sha for PR or new commit hash for main push in benchmark result key - key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }} - - - name: Run benchmark tests - id: benchmark - run: | - REF_NAME=${GITHUB_REF##*/} make benchmark - OUTPUT=$(make show-benchstat) - OUTPUT="${OUTPUT//'%'/'%25'}" # URL encode all '%' characters - OUTPUT="${OUTPUT//$'\n'/'%0A'}" # URL encode all '\n' characters - OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters - echo "::set-output name=result::$OUTPUT" - - - uses: actions/upload-artifact@v2 - with: - name: benchmark-test-results - path: test/results/**/* - - - name: Update PR benchmark results comment - uses: marocchino/sticky-pull-request-comment@v2 - continue-on-error: true - with: - header: benchmark - message: | - ### Benchmark Test Results + - uses: actions/checkout@v3 -
- Benchmark results from the latest changes vs base branch + - name: Bootstrap environment + uses: ./.github/actions/bootstrap - ``` - ${{ steps.benchmark.outputs.result }} - ``` + - name: Build snapshot artifacts + run: make snapshot -
diff --git a/.gitignore b/.gitignore index 930ca30b..26630caf 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ coverage.txt **/test-fixtures/cache/ **/*.fingerprint +snapshot/ # Binaries for programs and plugins *.exe diff --git a/Makefile b/Makefile index 181594bb..74de855c 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,15 @@ -TEMPDIR = ./.tmp -RESULTSDIR = test/results -COVER_REPORT = $(RESULTSDIR)/unit-coverage-details.txt -COVER_TOTAL = $(RESULTSDIR)/unit-coverage-summary.txt -LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --config .golangci.yaml +TEMP_DIR = ./.tmp + +# Command templates ################################# +LINT_CMD = $(TEMP_DIR)/golangci-lint run --tests=false --config .golangci.yaml + +# Tool versions ################################# +GOLANGCILINT_VERSION := v1.51.0 +GOSIMPORTS_VERSION := v0.3.5 +BOUNCER_VERSION := v0.4.0 +CHRONICLE_VERSION := v0.5.1 + +# Formatting variables ################################# BOLD := $(shell tput -T linux bold) PURPLE := $(shell tput -T linux setaf 5) GREEN := $(shell tput -T linux setaf 2) @@ -11,15 +18,16 @@ RED := $(shell tput -T linux setaf 1) RESET := $(shell tput -T linux sgr0) TITLE := $(BOLD)$(PURPLE) SUCCESS := $(BOLD)$(GREEN) -# the quality gate lower threshold for unit test total % coverage (by function statements) -COVERAGE_THRESHOLD := 48 + +# Test variables ################################# +COVERAGE_THRESHOLD := 55 # the quality gate lower threshold for unit test total % coverage (by function statements) ifeq "$(strip $(VERSION))" "" override VERSION = $(shell git describe --always --tags --dirty) endif -ifndef TEMPDIR - $(error TEMPDIR is not set) +ifndef TEMP_DIR + $(error TEMP_DIR is not set) endif ifndef REF_NAME @@ -31,37 +39,43 @@ define title endef .PHONY: all -all: static-analysis test ## Run all checks (linting, all tests, and dependencies license checks) +all: static-analysis test ## Run all linux-based checks (linting, license check, unit, integration, and linux compare tests) @printf '$(SUCCESS)All checks pass!$(RESET)\n' +.PHONY: static-analysis +static-analysis: check-go-mod-tidy lint check-licenses ## Run all static analysis checks + .PHONY: test -test: unit integration benchmark ## Run all levels of test +test: unit integration benchmark ## Run all tests (currently unit and integrations) -.PHONY: help -help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}' + +## Bootstrapping targets ################################# .PHONY: ci-bootstrap ci-bootstrap: bootstrap - sudo apt install -y bc curl -sLO https://github.com/sylabs/singularity/releases/download/v3.10.0/singularity-ce_3.10.0-focal_amd64.deb && sudo apt-get install -y -f ./singularity-ce_3.10.0-focal_amd64.deb -$(RESULTSDIR): - mkdir -p $(RESULTSDIR) - -.PHONY: boostrap -bootstrap: $(RESULTSDIR) ## Download and install all project dependencies (+ prep tooling in the ./tmp dir) - $(call title,Downloading dependencies) - @pwd - # prep temp dirs - mkdir -p $(TEMPDIR) - mkdir -p $(RESULTSDIR) - # install go dependencies +.PHONY: bootstrap +bootstrap: $(TEMP_DIR) bootstrap-go bootstrap-tools ## Download and install all tooling dependencies (+ prep tooling in the ./tmp dir) + $(call title,Bootstrapping dependencies) + +.PHONY: bootstrap-tools +bootstrap-tools: $(TEMP_DIR) + GO111MODULE=off GOBIN=$(realpath $(TEMP_DIR)) go get -u golang.org/x/perf/cmd/benchstat + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMP_DIR)/ $(GOLANGCILINT_VERSION) + curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMP_DIR)/ $(BOUNCER_VERSION) + curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMP_DIR)/ $(CHRONICLE_VERSION) + # the only difference between goimports and gosimports is that gosimports removes extra whitespace between import blocks (see https://github.com/golang/go/issues/20818) + GOBIN="$(realpath $(TEMP_DIR))" go install github.com/rinchsan/gosimports/cmd/gosimports@$(GOSIMPORTS_VERSION) + +.PHONY: bootstrap-go +bootstrap-go: go mod download - # install utilities - [ -f "$(TEMPDIR)/benchstat" ] || GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat - [ -f "$(TEMPDIR)/golangci" ] || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.51.0 - [ -f "$(TEMPDIR)/bouncer" ] || curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.4.0 + +$(TEMP_DIR): + mkdir -p $(TEMP_DIR) + +## Static analysis targets ################################# .PHONY: static-analysis static-analysis: check-licenses lint @@ -71,40 +85,55 @@ lint: ## Run gofmt + golangci lint checks $(call title,Running linters) @printf "files with gofmt issues: [$(shell gofmt -l -s .)]\n" @test -z "$(shell gofmt -l -s .)" - $(LINTCMD) + $(LINT_CMD) .PHONY: lint-fix lint-fix: ## Auto-format all source code + run golangci lint fixers $(call title,Running lint fixers) gofmt -w -s . - $(LINTCMD) --fix + $(LINT_CMD) --fix go mod tidy .PHONY: check-licenses check-licenses: $(call title,Validating licenses for go dependencies) - $(TEMPDIR)/bouncer check + $(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: $(RESULTSDIR) ## Run unit tests (with coverage) +unit: $(TEMP_DIR) ## Run unit tests (with coverage) $(call title,Running unit tests) - go test --race -coverprofile $(COVER_REPORT) $(shell go list ./... | grep -v anchore/stereoscope/test/integration) - @go tool cover -func $(COVER_REPORT) | grep total | awk '{print substr($$3, 1, length($$3)-1)}' > $(COVER_TOTAL) - @echo "Coverage: $$(cat $(COVER_TOTAL))" - @if [ $$(echo "$$(cat $(COVER_TOTAL)) >= $(COVERAGE_THRESHOLD)" | bc -l) -ne 1 ]; then echo "$(RED)$(BOLD)Failed coverage quality gate (> $(COVERAGE_THRESHOLD)%)$(RESET)" && false; fi + go test -coverprofile $(TEMP_DIR)/unit-coverage-details.txt $(shell go list ./... | grep -v anchore/stereoscope/test) + @.github/scripts/coverage.py $(COVERAGE_THRESHOLD) $(TEMP_DIR)/unit-coverage-details.txt + + +.PHONY: integration +integration: integration-tools ## Run integration tests + $(call title,Running integration tests) + go test -v ./test/integration + +## Benchmark test targets ################################# + .PHONY: benchmark -benchmark: $(RESULTSDIR) ## Run benchmark tests and compare against the baseline (if available) +benchmark: $(TEMP_DIR) ## Run benchmark tests and compare against the baseline (if available) $(call title,Running benchmark tests) - go test -cpu 2 -p 1 -run=^Benchmark -bench=. -count=5 -benchmem ./... | tee $(RESULTSDIR)/benchmark-$(REF_NAME).txt - (test -s $(RESULTSDIR)/benchmark-main.txt && \ - $(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-main.txt $(RESULTSDIR)/benchmark-$(REF_NAME).txt || \ - $(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-$(REF_NAME).txt) \ - | tee $(RESULTSDIR)/benchstat.txt + go test -cpu 2 -p 1 -run=^Benchmark -bench=. -count=5 -benchmem ./... | tee $(TEMP_DIR)/benchmark-$(REF_NAME).txt + (test -s $(TEMP_DIR)/benchmark-main.txt && \ + $(TEMP_DIR)/benchstat $(TEMP_DIR)/benchmark-main.txt $(TEMP_DIR)/benchmark-$(REF_NAME).txt || \ + $(TEMP_DIR)/benchstat $(TEMP_DIR)/benchmark-$(REF_NAME).txt) \ + | tee $(TEMP_DIR)/benchstat.txt + .PHONY: show-benchstat show-benchstat: - @cat $(RESULTSDIR)/benchstat.txt + @cat $(TEMP_DIR)/benchstat.txt + +## Test-fixture-related targets ################################# # note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted .PHONY: integration-fingerprint @@ -127,11 +156,22 @@ integration-tools-load: integration-tools-save: @cd test/integration/tools && make save-cache -.PHONY: integration -integration: integration-tools ## Run integration tests - $(call title,Running integration tests) - go test -v ./test/integration +## Build-related targets ################################# + +.PHONY: snapshot +snapshot: ## Build the binary + $(call title,Build compatability test) + @.github/scripts/build.sh + +## Cleanup targets ################################# .PHONY: clear-test-cache clear-test-cache: ## Delete all test cache (built docker image tars) find . -type f -wholename "**/test-fixtures/cache/*.tar" -delete + + +## Halp! ################################# + +.PHONY: help +help: ## Display this help + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}' diff --git a/pkg/file/metadata.go b/pkg/file/metadata.go index 5ba884af..4dab4021 100644 --- a/pkg/file/metadata.go +++ b/pkg/file/metadata.go @@ -2,12 +2,13 @@ package file import ( "archive/tar" - "github.com/anchore/stereoscope/internal/log" "io" "os" "path" "path/filepath" + "github.com/anchore/stereoscope/internal/log" + "github.com/sylabs/squashfs" ) diff --git a/pkg/file/type.go b/pkg/file/type.go index 0d587a1b..2555fd46 100644 --- a/pkg/file/type.go +++ b/pkg/file/type.go @@ -37,7 +37,7 @@ func AllTypes() []Type { func TypeFromTarType(ty byte) Type { switch ty { - case tar.TypeReg, tar.TypeRegA: + case tar.TypeReg, tar.TypeRegA: // nolint: staticcheck return TypeReg case tar.TypeLink: return TypeHardLink