From 7315f83f9dd8bd83f7bc1bbb782977db6d37f5e3 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Wed, 25 Oct 2023 09:08:43 -0400 Subject: [PATCH] Upgrade tool management (#2188) * migrate to binny and taskfile Signed-off-by: Alex Goodman * update binny to not require github token Signed-off-by: Alex Goodman * added support for automatically building snapshots Signed-off-by: Alex Goodman * detect source changes for snapshot builds Signed-off-by: Alex Goodman * fail workflow explicitly when snapshot cache restoral fails Signed-off-by: Alex Goodman * match snapshot restoral paths Signed-off-by: Alex Goodman --------- Signed-off-by: Alex Goodman --- .binny.yaml | 96 ++++ .github/actions/bootstrap/action.yaml | 29 +- .github/scripts/goreleaser-install.sh | 398 --------------- .github/workflows/release.yaml | 3 - .github/workflows/update-bootstrap-tools.yml | 86 ++-- .../workflows/update-cpe-dictionary-index.yml | 3 + .../workflows/update-stereoscope-release.yml | 3 + .github/workflows/validations.yaml | 58 ++- .gitignore | 2 + .goreleaser.yaml | 2 +- Makefile | 424 ++-------------- Taskfile.yaml | 470 ++++++++++++++++++ schema/cyclonedx/Makefile | 2 +- 13 files changed, 707 insertions(+), 869 deletions(-) create mode 100644 .binny.yaml delete mode 100755 .github/scripts/goreleaser-install.sh create mode 100644 Taskfile.yaml diff --git a/.binny.yaml b/.binny.yaml new file mode 100644 index 000000000..6d60dc8f9 --- /dev/null +++ b/.binny.yaml @@ -0,0 +1,96 @@ +tools: + - name: binny + version: + want: v0.6.2 + method: github-release + with: + repo: anchore/binny + + - name: quill + version: + want: v0.4.1 + method: github-release + with: + repo: anchore/quill + + - name: golangci-lint + version: + want: v1.55.0 + method: github-release + with: + repo: golangci/golangci-lint + + - name: glow + version: + want: v1.5.1 + method: github-release + with: + repo: charmbracelet/glow + + - name: cosign + version: + want: v2.2.0 + method: github-release + with: + repo: sigstore/cosign + + - name: yajsv + version: + want: v1.4.1 + method: github-release + with: + repo: neilpa/yajsv + + - name: goreleaser + version: + want: v1.21.2 + method: github-release + with: + repo: goreleaser/goreleaser + + - name: gosimports + version: + want: v0.3.8 + method: github-release + with: + repo: rinchsan/gosimports + + - name: chronicle + version: + want: v0.8.0 + method: github-release + with: + repo: anchore/chronicle + + - name: bouncer + version: + want: v0.4.0 + method: github-release + with: + repo: wagoodman/go-bouncer + + - name: benchstat + version: + want: latest + method: go-proxy + with: + module: golang.org/x/perf + allow-unresolved-version: true + method: go-install + with: + entrypoint: cmd/benchstat + module: golang.org/x/perf + + - name: task + version: + want: v3.30.1 + method: github-release + with: + repo: go-task/task + + - name: gh + version: + want: v2.35.0 + method: github-release + with: + repo: cli/cli diff --git a/.github/actions/bootstrap/action.yaml b/.github/actions/bootstrap/action.yaml index d8308336b..4165cd33b 100644 --- a/.github/actions/bootstrap/action.yaml +++ b/.github/actions/bootstrap/action.yaml @@ -6,23 +6,29 @@ inputs: description: "Go version to install" required: true default: "1.21.x" + go-dependencies: + description: "Download go dependencies" + 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" + default: "1ac8281053" + compute-fingerprints: + description: "Compute test fixture fingerprints" required: true - default: "f8b6d31dea" + default: "true" bootstrap-apt-packages: description: "Space delimited list of tools to install via apt" default: "libxml2-utils" + runs: using: "composite" steps: # note: go mod and build is automatically cached on default with v4+ - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0 + if: inputs.go-version != '' with: go-version: ${{ inputs.go-version }} @@ -30,17 +36,17 @@ runs: id: tool-cache uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 with: - path: ${{ github.workspace }}/.tmp - key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + path: ${{ github.workspace }}/.tool + key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }} - - name: (cache-miss) Bootstrap project tools + - name: Install project tools shell: bash - if: steps.tool-cache.outputs.cache-hit != 'true' - run: make bootstrap-tools + run: make tools - - name: Bootstrap go dependencies + - name: Install go dependencies + if: inputs.go-dependencies == 'true' shell: bash - run: make bootstrap-go + run: make ci-bootstrap-go - name: Install apt packages if: inputs.bootstrap-apt-packages != '' @@ -49,6 +55,7 @@ runs: DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y ${{ inputs.bootstrap-apt-packages }} - name: Create all cache fingerprints + if: inputs.compute-fingerprints == 'true' shell: bash run: make fingerprints diff --git a/.github/scripts/goreleaser-install.sh b/.github/scripts/goreleaser-install.sh deleted file mode 100755 index ac990bf82..000000000 --- a/.github/scripts/goreleaser-install.sh +++ /dev/null @@ -1,398 +0,0 @@ -#!/bin/sh -set -e -# Code generated by godownloader on 2019-12-25T12:47:14Z. DO NOT EDIT. -# - -usage() { - this=$1 - cat </dev/null -} -echoerr() { - echo "$@" 1>&2 -} -log_prefix() { - echo "$0" -} -_logp=6 -log_set_priority() { - _logp="$1" -} -log_priority() { - if test -z "$1"; then - echo "$_logp" - return - fi - [ "$1" -le "$_logp" ] -} -log_tag() { - case $1 in - 0) echo "emerg" ;; - 1) echo "alert" ;; - 2) echo "crit" ;; - 3) echo "err" ;; - 4) echo "warning" ;; - 5) echo "notice" ;; - 6) echo "info" ;; - 7) echo "debug" ;; - *) echo "$1" ;; - esac -} -log_debug() { - log_priority 7 || return 0 - echoerr "$(log_prefix)" "$(log_tag 7)" "$@" -} -log_info() { - log_priority 6 || return 0 - echoerr "$(log_prefix)" "$(log_tag 6)" "$@" -} -log_err() { - log_priority 3 || return 0 - echoerr "$(log_prefix)" "$(log_tag 3)" "$@" -} -log_crit() { - log_priority 2 || return 0 - echoerr "$(log_prefix)" "$(log_tag 2)" "$@" -} -uname_os() { - os=$(uname -s | tr '[:upper:]' '[:lower:]') - case "$os" in - cygwin_nt*) os="windows" ;; - mingw*) os="windows" ;; - msys_nt*) os="windows" ;; - esac - echo "$os" -} -uname_arch() { - arch=$(uname -m) - case $arch in - x86_64) arch="amd64" ;; - x86) arch="386" ;; - i686) arch="386" ;; - i386) arch="386" ;; - aarch64) arch="arm64" ;; - armv5*) arch="armv5" ;; - armv6*) arch="armv6" ;; - armv7*) arch="armv7" ;; - esac - echo ${arch} -} -uname_os_check() { - os=$(uname_os) - case "$os" in - darwin) return 0 ;; - dragonfly) return 0 ;; - freebsd) return 0 ;; - linux) return 0 ;; - android) return 0 ;; - nacl) return 0 ;; - netbsd) return 0 ;; - openbsd) return 0 ;; - plan9) return 0 ;; - solaris) return 0 ;; - windows) return 0 ;; - esac - log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" - return 1 -} -uname_arch_check() { - arch=$(uname_arch) - case "$arch" in - 386) return 0 ;; - amd64) return 0 ;; - arm64) return 0 ;; - armv5) return 0 ;; - armv6) return 0 ;; - armv7) return 0 ;; - ppc64) return 0 ;; - ppc64le) return 0 ;; - mips) return 0 ;; - mipsle) return 0 ;; - mips64) return 0 ;; - mips64le) return 0 ;; - s390x) return 0 ;; - amd64p32) return 0 ;; - esac - log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" - return 1 -} -untar() { - tarball=$1 - case "${tarball}" in - *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; - *.tar) tar --no-same-owner -xf "${tarball}" ;; - *.zip) unzip "${tarball}" ;; - *) - log_err "untar unknown archive format for ${tarball}" - return 1 - ;; - esac -} -http_download_curl() { - local_file=$1 - source_url=$2 - header=$3 - if [ -z "$header" ]; then - code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") - else - code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") - fi - if [ "$code" != "200" ]; then - log_debug "http_download_curl received HTTP status $code" - return 1 - fi - return 0 -} -http_download_wget() { - local_file=$1 - source_url=$2 - header=$3 - if [ -z "$header" ]; then - wget -q -O "$local_file" "$source_url" - else - wget -q --header "$header" -O "$local_file" "$source_url" - fi -} -http_download() { - log_debug "http_download $2" - if is_command curl; then - http_download_curl "$@" - return - elif is_command wget; then - http_download_wget "$@" - return - fi - log_crit "http_download unable to find wget or curl" - return 1 -} -http_copy() { - tmp=$(mktemp) - http_download "${tmp}" "$1" "$2" || return 1 - body=$(cat "$tmp") - rm -f "${tmp}" - echo "$body" -} -github_release() { - owner_repo=$1 - version=$2 - test -z "$version" && version="latest" - giturl="https://github.com/${owner_repo}/releases/${version}" - json=$(http_copy "$giturl" "Accept:application/json") - test -z "$json" && return 1 - version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') - test -z "$version" && return 1 - echo "$version" -} -hash_sha256() { - TARGET=${1:-/dev/stdin} - if is_command gsha256sum; then - hash=$(gsha256sum "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command sha256sum; then - hash=$(sha256sum "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command shasum; then - hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command openssl; then - hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f a - else - log_crit "hash_sha256 unable to find command to compute sha-256 hash" - return 1 - fi -} -hash_sha256_verify() { - TARGET=$1 - checksums=$2 - if [ -z "$checksums" ]; then - log_err "hash_sha256_verify checksum file not specified in arg2" - return 1 - fi - BASENAME=${TARGET##*/} - want=$(grep "${BASENAME}$" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) - if [ -z "$want" ]; then - log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" - return 1 - fi - got=$(hash_sha256 "$TARGET") - if [ "$want" != "$got" ]; then - log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" - return 1 - fi -} -cat /dev/null </dev/null | jq -r '.Version') - BOUNCER_LATEST_VERSION=$(go list -m -json github.com/wagoodman/go-bouncer@latest 2>/dev/null | jq -r '.Version') - CHRONICLE_LATEST_VERSION=$(go list -m -json github.com/anchore/chronicle@latest 2>/dev/null | jq -r '.Version') - GORELEASER_LATEST_VERSION=$(go list -m -json github.com/goreleaser/goreleaser@latest 2>/dev/null | jq -r '.Version') - GOSIMPORTS_LATEST_VERSION=$(go list -m -json github.com/rinchsan/gosimports@latest 2>/dev/null | jq -r '.Version') - YAJSV_LATEST_VERSION=$(go list -m -json github.com/neilpa/yajsv@latest 2>/dev/null | jq -r '.Version') - COSIGN_LATEST_VERSION=$(go list -m -json github.com/sigstore/cosign/v2@latest 2>/dev/null | jq -r '.Version') - QUILL_LATEST_VERSION=$(go list -m -json github.com/anchore/quill@latest 2>/dev/null | jq -r '.Version') - GLOW_LATEST_VERSION=$(go list -m -json github.com/charmbracelet/glow@latest 2>/dev/null | jq -r '.Version') - - # update version variables in the Makefile - sed -r -i -e 's/^(GOLANGCILINT_VERSION := ).*/\1'${GOLANGCILINT_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(BOUNCER_VERSION := ).*/\1'${BOUNCER_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(CHRONICLE_VERSION := ).*/\1'${CHRONICLE_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(GORELEASER_VERSION := ).*/\1'${GORELEASER_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(GOSIMPORTS_VERSION := ).*/\1'${GOSIMPORTS_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(YAJSV_VERSION := ).*/\1'${YAJSV_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(COSIGN_VERSION := ).*/\1'${COSIGN_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(QUILL_VERSION := ).*/\1'${QUILL_LATEST_VERSION}'/' Makefile - sed -r -i -e 's/^(GLOW_VERSION := ).*/\1'${GLOW_LATEST_VERSION}'/' Makefile - - # export the versions for use with create-pull-request - echo "GOLANGCILINT=$GOLANGCILINT_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "BOUNCER=$BOUNCER_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "CHRONICLE=$CHRONICLE_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "GORELEASER=$GORELEASER_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "GOSIMPORTS=$GOSIMPORTS_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "YAJSV=$YAJSV_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "COSIGN=$COSIGN_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "QUILL=$QUILL_LATEST_VERSION" >> $GITHUB_OUTPUT - echo "GLOW=GLOW_LATEST_VERSION" >> $GITHUB_OUTPUT + - name: "Update tool versions" id: latest-versions + run: | + make update-tools + make list-tools + + export NO_COLOR=1 + delimiter="$(openssl rand -hex 8)" + + { + echo "status<<${delimiter}" + make list-tool-updates + echo "${delimiter}" + } >> $GITHUB_OUTPUT + + { + echo "### Tool version status" + echo "\`\`\`" + make list-tool-updates + echo "\`\`\`" + } >> $GITHUB_STEP_SUMMARY - uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a #v2.1.0 id: generate-token @@ -68,19 +54,13 @@ jobs: with: signoff: true delete-branch: true - branch: auto/latest-bootstrap-tools + branch: auto/latest-tools labels: dependencies - commit-message: 'chore(deps): update bootstrap tools to latest versions' - title: 'chore(deps): update bootstrap tools to latest versions' + commit-message: 'chore(deps): update tools to latest versions' + title: 'chore(deps): update tools to latest versions' body: | - - [golangci-lint ${{ steps.latest-versions.outputs.GOLANGCILINT }}](https://github.com/golangci/golangci-lint/releases/tag/${{ steps.latest-versions.outputs.GOLANGCILINT }}) - - [bouncer ${{ steps.latest-versions.outputs.BOUNCER }}](https://github.com/wagoodman/go-bouncer/releases/tag/${{ steps.latest-versions.outputs.BOUNCER }}) - - [chronicle ${{ steps.latest-versions.outputs.CHRONICLE }}](https://github.com/anchore/chronicle/releases/tag/${{ steps.latest-versions.outputs.CHRONICLE }}) - - [goreleaser ${{ steps.latest-versions.outputs.GORELEASER }}](https://github.com/goreleaser/goreleaser/releases/tag/${{ steps.latest-versions.outputs.GORELEASER }}) - - [gosimports ${{ steps.latest-versions.outputs.GOSIMPORTS }}](https://github.com/rinchsan/gosimports/releases/tag/${{ steps.latest-versions.outputs.GOSIMPORTS }}) - - [yajsv ${{ steps.latest-versions.outputs.YAJSV }}](https://github.com/neilpa/yajsv/releases/tag/${{ steps.latest-versions.outputs.YAJSV }}) - - [cosign ${{ steps.latest-versions.outputs.COSIGN }}](https://github.com/sigstore/cosign/releases/tag/${{ steps.latest-versions.outputs.COSIGN }}) - - [quill ${{ steps.latest-versions.outputs.QUILL }}](https://github.com/anchore/quill/releases/tag/${{ steps.latest-versions.outputs.QUILL }}) - - [glow ${{ steps.latest-versions.outputs.GLOW }}](https://github.com/charmbracelet/glow/releases/tag/${{ steps.latest-versions.outputs.GLOW }}) - This is an auto-generated pull request to update all of the bootstrap tools to the latest versions. + ``` + ${{ steps.latest-versions.outputs.status }} + ``` + This is an auto-generated pull request to update all of the tools to the latest versions. token: ${{ steps.generate-token.outputs.token }} diff --git a/.github/workflows/update-cpe-dictionary-index.yml b/.github/workflows/update-cpe-dictionary-index.yml index fd0a71b5b..34abd163c 100644 --- a/.github/workflows/update-cpe-dictionary-index.yml +++ b/.github/workflows/update-cpe-dictionary-index.yml @@ -18,6 +18,9 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 + - name: Bootstrap environment + uses: ./.github/actions/bootstrap + - name: Bootstrap environment uses: ./.github/actions/bootstrap diff --git a/.github/workflows/update-stereoscope-release.yml b/.github/workflows/update-stereoscope-release.yml index d3b13a5e4..ed5d00a63 100644 --- a/.github/workflows/update-stereoscope-release.yml +++ b/.github/workflows/update-stereoscope-release.yml @@ -24,6 +24,9 @@ jobs: go-version: ${{ env.GO_VERSION }} stable: ${{ env.GO_STABLE_VERSION }} + - name: Bootstrap environment + uses: ./.github/actions/bootstrap + - run: | LATEST_VERSION=$(git ls-remote https://github.com/anchore/stereoscope main | head -n1 | awk '{print $1;}') diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 5da90fecb..41363b2d8 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -11,6 +11,7 @@ permissions: contents: read jobs: + Static-Analysis: # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline name: "Static analysis" @@ -101,12 +102,6 @@ jobs: - name: Bootstrap environment uses: ./.github/actions/bootstrap with: - # why have another build cache key? We don't want unit/integration/etc test build caches to replace - # the snapshot build cache, which includes builds for all OSs and architectures. As long as this key is - # unique from the build-cache-key-prefix in other CI jobs, we should be fine. - # - # note: ideally this value should match what is used in release (just to help with build times). - build-cache-key-prefix: "snapshot" bootstrap-apt-packages: "" - name: Build snapshot artifacts @@ -117,7 +112,12 @@ jobs: - name: Upload snapshot artifacts uses: actions/cache/save@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 with: - path: snapshot + # we need to preserve the snapshot data itself as well as the task data that confirms if the + # snapshot build is stale or not. Otherwise the downstream jobs will attempt to rebuild the snapshot + # even though it already exists. + path: | + snapshot + .task key: snapshot-build-${{ github.run_id }} @@ -129,12 +129,24 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 + - name: Bootstrap environment + uses: ./.github/actions/bootstrap + - name: Download snapshot build + id: snapshot-cache uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 with: - path: snapshot + path: | + snapshot + .task + fail-on-cache-miss: true key: snapshot-build-${{ github.run_id }} + # workaround for https://github.com/actions/cache/issues/1265 + - name: (cache-miss) Snapshot build missing + if: steps.snapshot-cache.outputs.cache-hit != 'true' + run: echo "unable to download snapshots from previous job" && false + - name: Run comparison tests (Linux) run: make compare-linux @@ -165,12 +177,29 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 + - name: Bootstrap environment + uses: ./.github/actions/bootstrap + with: + bootstrap-apt-packages: "" + compute-fingerprints: "false" + go-dependencies: false + go-version: "" + - name: Download snapshot build + id: snapshot-cache uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 with: - path: snapshot + path: | + snapshot + .task + fail-on-cache-miss: true key: snapshot-build-${{ github.run_id }} + # workaround for https://github.com/actions/cache/issues/1265 + - name: (cache-miss) Snapshot build missing + if: steps.snapshot-cache.outputs.cache-hit != 'true' + run: echo "unable to download snapshots from previous job" && false + - name: Restore docker image cache for compare testing id: mac-compare-testing-cache uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 @@ -203,10 +232,19 @@ jobs: key: ${{ runner.os }}-cli-test-cache-${{ hashFiles('test/cli/test-fixtures/cache.fingerprint') }} - name: Download snapshot build + id: snapshot-cache uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 with: - path: snapshot + path: | + snapshot + .task + fail-on-cache-miss: true key: snapshot-build-${{ github.run_id }} + # workaround for https://github.com/actions/cache/issues/1265 + - name: (cache-miss) Snapshot build missing + if: steps.snapshot-cache.outputs.cache-hit != 'true' + run: echo "unable to download snapshots from previous job" && false + - name: Run CLI Tests (Linux) run: make cli diff --git a/.gitignore b/.gitignore index fe0c7972e..d80e8f4ff 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ bin/ /build /dist /snapshot +/.tool +/.task # changelog generation CHANGELOG.md diff --git a/.goreleaser.yaml b/.goreleaser.yaml index f31f769df..1a12342d0 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -41,7 +41,7 @@ builds: ldflags: *build-ldflags hooks: post: - - cmd: .tmp/quill sign-and-notarize "{{ .Path }}" --dry-run={{ .IsSnapshot }} --ad-hoc={{ .IsSnapshot }} -vv + - cmd: .tool/quill sign-and-notarize "{{ .Path }}" --dry-run={{ .IsSnapshot }} --ad-hoc={{ .IsSnapshot }} -vv env: - QUILL_LOG_FILE=/tmp/quill-{{ .Target }}.log diff --git a/Makefile b/Makefile index 5a569e136..9089ee619 100644 --- a/Makefile +++ b/Makefile @@ -1,406 +1,46 @@ -BIN := syft -TEMP_DIR := ./.tmp +OWNER = anchore +PROJECT = syft -# Command templates ################################# -LINT_CMD := $(TEMP_DIR)/golangci-lint run --tests=false -GOIMPORTS_CMD := $(TEMP_DIR)/gosimports -local github.com/anchore -RELEASE_CMD := $(TEMP_DIR)/goreleaser release --clean -SNAPSHOT_CMD := $(RELEASE_CMD) --skip-publish --skip-sign --snapshot -CHRONICLE_CMD = $(TEMP_DIR)/chronicle -GLOW_CMD = $(TEMP_DIR)/glow - -# Tool versions ################################# -GOLANGCILINT_VERSION := v1.55.0 -GOSIMPORTS_VERSION := v0.3.8 -BOUNCER_VERSION := v0.4.0 -CHRONICLE_VERSION := v0.8.0 -GORELEASER_VERSION := v1.21.2 -YAJSV_VERSION := v1.4.1 -COSIGN_VERSION := v2.2.0 -QUILL_VERSION := v0.4.1 -GLOW_VERSION := v1.5.1 - -# 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 ################################# -COMPARE_DIR := ./test/compare -COMPARE_TEST_IMAGE := centos:8.2.2004 -COVERAGE_THRESHOLD := 62 # the quality gate lower threshold for unit test total % coverage (by function statements) - -## Build variables ################################# -VERSION := $(shell git describe --dirty --always --tags) -DIST_DIR := ./dist -SNAPSHOT_DIR := ./snapshot -CHANGELOG := CHANGELOG.md -OS := $(shell uname | tr '[:upper:]' '[:lower:]') -SNAPSHOT_BIN := $(realpath $(shell pwd)/$(SNAPSHOT_DIR)/$(OS)-build_$(OS)_amd64_v1/$(BIN)) - -ifndef VERSION - $(error VERSION is not set) -endif - -define title - @printf '$(TITLE)$(1)$(RESET)\n' -endef - -define safe_rm_rf - bash -c 'test -z "$(1)" && false || rm -rf $(1)' -endef - -define safe_rm_rf_children - bash -c 'test -z "$(1)" && false || rm -rf $(1)/*' -endef - -.DEFAULT_GOAL:=help - - -.PHONY: all -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 check-json-schema-drift ## Run all static analysis checks - -.PHONY: test -test: unit integration validate-cyclonedx-schema benchmark test-utils cli ## Run all tests (currently unit, integration, linux compare, and cli tests) +TOOL_DIR = .tool +BINNY = $(TOOL_DIR)/binny +TASK = $(TOOL_DIR)/task +.DEFAULT_GOAL := make-default ## Bootstrapping targets ################################# -.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) +# 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/$(OWNER)/binny/main/install.sh | sh -s -- -b $(TOOL_DIR) -.PHONY: bootstrap-tools -bootstrap-tools: $(TEMP_DIR) - curl -sSfL https://raw.githubusercontent.com/anchore/quill/main/install.sh | sh -s -- -b $(TEMP_DIR)/ $(QUILL_VERSION) - 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) - .github/scripts/goreleaser-install.sh -d -b $(TEMP_DIR)/ $(GORELEASER_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) - GOBIN="$(realpath $(TEMP_DIR))" go install github.com/neilpa/yajsv@$(YAJSV_VERSION) - GOBIN="$(realpath $(TEMP_DIR))" go install github.com/sigstore/cosign/v2/cmd/cosign@$(COSIGN_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 +.PHONY: task +$(TASK) task: $(BINNY) + @$(BINNY) install task -q -.PHONY: bootstrap-go -bootstrap-go: +.PHONY: ci-bootstrap-go +ci-bootstrap-go: go mod download -$(TEMP_DIR): - mkdir -p $(TEMP_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 $(TASK) + $(TASK) $@ +## Shim targets ################################# -## Static analysis targets ################################# +.PHONY: make-default +make-default: $(TASK) + @# run the default task in the taskfile + @$(TASK) -.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 .)" +# 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 ','") - # run all golangci-lint rules - $(LINT_CMD) - @[ -z "$(shell $(GOIMPORTS_CMD) -d .)" ] || (echo "goimports needs to be fixed" && false) +.PHONY: $(TASKS) +$(TASKS): $(TASK) + @$(TASK) $@ - # 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: ## Ensure transitive dependencies are compliant with the current license policy - $(call title,Checking for license compliance) - $(TEMP_DIR)/bouncer check ./... - -check-go-mod-tidy: - @ .github/scripts/go-mod-tidy-check.sh && echo "go.mod and go.sum are tidy!" - -check-json-schema-drift: - $(call title,Ensure there is no drift between the JSON schema and the code) - @.github/scripts/json-schema-drift-check.sh - -## Testing targets ################################# - -.PHONY: unit -unit: $(TEMP_DIR) fixtures ## Run unit tests (with coverage) - $(call title,Running unit tests) - go test -race -coverprofile $(TEMP_DIR)/unit-coverage-details.txt $(shell go list ./... | grep -v anchore/syft/test) - @.github/scripts/coverage.py $(COVERAGE_THRESHOLD) $(TEMP_DIR)/unit-coverage-details.txt - -.PHONY: integration -integration: ## Run integration tests - $(call title,Running integration tests) - go test -v ./test/integration - go run -race cmd/syft/main.go alpine:latest - -.PHONY: validate-cyclonedx-schema -validate-cyclonedx-schema: - cd schema/cyclonedx && make - -.PHONY: cli -cli: $(SNAPSHOT_DIR) ## Run CLI tests - chmod 755 "$(SNAPSHOT_BIN)" - $(SNAPSHOT_BIN) version - SYFT_BINARY_LOCATION='$(SNAPSHOT_BIN)' \ - go test -count=1 -timeout=15m -v ./test/cli - -.PHONY: test-utils -test-utils: - python .github/scripts/labeler_test.py - - -## Benchmark test targets ################################# - -.PHONY: benchmark -benchmark: $(TEMP_DIR) ## Run benchmark tests and compare against the baseline (if available) - $(call title,Running benchmark tests) - go test -p 1 -run=^Benchmark -bench=. -count=7 -benchmem ./... | tee $(TEMP_DIR)/benchmark-$(VERSION).txt - (test -s $(TEMP_DIR)/benchmark-main.txt && \ - $(TEMP_DIR)/benchstat $(TEMP_DIR)/benchmark-main.txt $(TEMP_DIR)/benchmark-$(VERSION).txt || \ - $(TEMP_DIR)/benchstat $(TEMP_DIR)/benchmark-$(VERSION).txt) \ - | tee $(TEMP_DIR)/benchstat.txt - -.PHONY: show-benchstat -show-benchstat: - @cat $(TEMP_DIR)/benchstat.txt - - -## Test-fixture-related targets ################################# - -# note: this is used by CI to determine if various test fixture cache should be restored or recreated -fingerprints: - $(call title,Creating all test cache input fingerprints) - - # for IMAGE integration test fixtures - cd test/integration/test-fixtures && \ - make cache.fingerprint - - # for BINARY test fixtures - cd syft/pkg/cataloger/binary/test-fixtures && \ - make cache.fingerprint - - # for JAVA BUILD test fixtures - cd syft/pkg/cataloger/java/test-fixtures/java-builds && \ - make cache.fingerprint - - # for GO BINARY test fixtures - cd syft/pkg/cataloger/golang/test-fixtures/archs && \ - make binaries.fingerprint - - # for RPM test fixtures - cd syft/pkg/cataloger/rpm/test-fixtures && \ - make rpms.fingerprint - - # for Kernel test fixtures - cd syft/pkg/cataloger/kernel/test-fixtures && \ - make cache.fingerprint - - # for INSTALL integration test fixtures - cd test/install && \ - make cache.fingerprint - - # for CLI test fixtures - cd test/cli/test-fixtures && \ - make cache.fingerprint - -.PHONY: fixtures -fixtures: - $(call title,Generating test fixtures) - cd syft/pkg/cataloger/java/test-fixtures/java-builds && make - cd syft/pkg/cataloger/rpm/test-fixtures && make - cd syft/pkg/cataloger/binary/test-fixtures && make - -.PHONY: show-test-image-cache -show-test-image-cache: ## Show all docker and image tar cache - $(call title,Docker daemon cache) - @docker images --format '{{.ID}} {{.Repository}}:{{.Tag}}' | grep stereoscope-fixture- | sort - - $(call title,Tar cache) - @find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" | sort - -.PHONY: show-test-snapshots -show-test-snapshots: ## Show all test snapshots - $(call title,Test snapshots) - @find . -type f -wholename "**/test-fixtures/snapshot/*" | sort - - -## install.sh testing targets ################################# - -install-test: $(SNAPSHOT_DIR) - cd test/install && \ - make - -install-test-cache-save: $(SNAPSHOT_DIR) - cd test/install && \ - make save - -install-test-cache-load: $(SNAPSHOT_DIR) - cd test/install && \ - make load - -install-test-ci-mac: $(SNAPSHOT_DIR) - cd test/install && \ - make ci-test-mac - -.PHONY: generate-compare-file -generate-compare-file: - $(call title,Generating compare test file) - go run ./cmd/syft $(COMPARE_TEST_IMAGE) -o json > $(COMPARE_DIR)/test-fixtures/acceptance-centos-8.2.2004.json - -# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately -.PHONY: compare-mac -compare-mac: $(TEMP_DIR) $(SNAPSHOT_DIR) ## Run compare tests on build snapshot binaries and packages (Mac) - $(call title,Running compare test: Run on Mac) - $(COMPARE_DIR)/mac.sh \ - $(SNAPSHOT_DIR) \ - $(COMPARE_DIR) \ - $(COMPARE_TEST_IMAGE) \ - $(TEMP_DIR) - -# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately -.PHONY: compare-linux -compare-linux: compare-test-deb-package-install compare-test-rpm-package-install ## Run compare tests on build snapshot binaries and packages (Linux) - -.PHONY: compare-test-deb-package-install -compare-test-deb-package-install: $(TEMP_DIR) $(SNAPSHOT_DIR) - $(call title,Running compare test: DEB install) - $(COMPARE_DIR)/deb.sh \ - $(SNAPSHOT_DIR) \ - $(COMPARE_DIR) \ - $(COMPARE_TEST_IMAGE) \ - $(TEMP_DIR) - -.PHONY: compare-test-rpm-package-install -compare-test-rpm-package-install: $(TEMP_DIR) $(SNAPSHOT_DIR) - $(call title,Running compare test: RPM install) - $(COMPARE_DIR)/rpm.sh \ - $(SNAPSHOT_DIR) \ - $(COMPARE_DIR) \ - $(COMPARE_TEST_IMAGE) \ - $(TEMP_DIR) - - -## Code and data generation targets ################################# - -.PHONY: generate-json-schema -generate-json-schema: ## Generate a new json schema - cd syft/internal && go generate . && cd jsonschema && go run . - -.PHONY: generate-license-list -generate-license-list: ## Generate an updated spdx license list - go generate ./internal/spdxlicense/... - gofmt -s -w ./internal/spdxlicense - -.PHONY: generate-cpe-dictionary-index -generate-cpe-dictionary-index: ## Build the CPE index based off of the latest available CPE dictionary - $(call title,Building CPE index) - go generate ./syft/pkg/cataloger/common/cpe/dictionary - - -## Build-related targets ################################# - -.PHONY: build -build: - CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o $@ ./cmd/syft - -$(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 - $(SNAPSHOT_CMD) --config $(TEMP_DIR)/goreleaser.yaml - -.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: - @.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) \ - --config $(TEMP_DIR)/goreleaser.yaml \ - --release-notes <(cat $(CHANGELOG)) \ - || (cat /tmp/quill-*.log && false)" - - # upload the version file that supports the application version update check (excluding pre-releases) - .github/scripts/update-version-file.sh "$(DIST_DIR)" "$(VERSION)" - -.PHONY: ci-check -ci-check: - @.github/scripts/ci-check.sh - -## Cleanup targets ################################# - -.PHONY: clean -clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache - $(call safe_rm_rf_children,$(TEMP_DIR)) - -.PHONY: clean-snapshot -clean-snapshot: - $(call safe_rm_rf,$(SNAPSHOT_DIR)) - rm -f $(TEMP_DIR)/goreleaser.yaml - -.PHONY: clean-dist -clean-dist: clean-changelog - $(call safe_rm_rf,$(DIST_DIR)) - rm -f $(TEMP_DIR)/goreleaser.yaml - -.PHONY: clean-changelog -clean-changelog: - rm -f $(CHANGELOG) VERSION - -clean-test-image-cache: clean-test-image-tar-cache clean-test-image-docker-cache ## Clean test image cache - -.PHONY: clear-test-image-tar-cache -clean-test-image-tar-cache: ## Delete all test cache (built docker image tars) - find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" -delete - -.PHONY: clear-test-image-docker-cache -clean-test-image-docker-cache: ## Purge all test docker images - docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs -r docker rmi --force - -## 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}' +help: $(TASK) + @$(TASK) -l diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 000000000..1b7a229fa --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,470 @@ + +version: "3" +vars: + OWNER: anchore + PROJECT: syft + + # static file dirs + TOOL_DIR: .tool + TMP_DIR: .tmp + + # used for changelog generation + CHANGELOG: CHANGELOG.md + NEXT_VERSION: VERSION + + # used for snapshot builds + OS: + sh: uname -s | tr '[:upper:]' '[:lower:]' + ARCH: + sh: | + [ "$(uname -m)" = "x86_64" ] && echo "amd64_v1" || echo $(uname -m) + PROJECT_ROOT: + sh: echo $PWD + # note: the snapshot dir must be a relative path starting with ./ + SNAPSHOT_DIR: ./snapshot + SNAPSHOT_BIN: "{{ .PROJECT_ROOT }}/{{ .SNAPSHOT_DIR }}/{{ .OS }}-build_{{ .OS }}_{{ .ARCH }}/{{ .PROJECT }}" + SNAPSHOT_CMD: "{{ .TOOL_DIR }}/goreleaser release --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --skip=publish --skip=sign" + BUILD_CMD: "{{ .TOOL_DIR }}/goreleaser build --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --single-target" + RELEASE_CMD: "{{ .TOOL_DIR }}/goreleaser release --config {{ .TMP_DIR }}/goreleaser.yaml --clean --release-notes {{ .CHANGELOG }}" + VERSION: + sh: git describe --dirty --always --tags + + # used for install and acceptance testing + COMPARE_DIR: ./test/compare + COMPARE_TEST_IMAGE: centos:8.2.2004 + +tasks: + + ## High-level tasks ################################# + + default: + desc: Run all validation tasks + aliases: + - pr-validations + - validations + cmds: + - task: static-analysis + - task: test + - task: install-test + + static-analysis: + desc: Run all static analysis tasks + cmds: + - task: check-go-mod-tidy + - task: check-licenses + - task: lint + - task: check-json-schema-drift + + test: + desc: Run all levels of test + cmds: + - task: unit + - task: integration + - task: validate-cyclonedx-schema + - task: benchmark + - task: test-utils + - task: cli + + ## Bootstrap tasks ################################# + + binny: + internal: true + # desc: Get the binny tool + generates: + - "{{ .TOOL_DIR }}/binny" + status: + - "test -f {{ .TOOL_DIR }}/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: + - "{{ .TOOL_DIR }}/binny check -v" + cmd: "{{ .TOOL_DIR }}/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: "{{ .TOOL_DIR }}/binny update -v" + silent: true + + list-tools: + desc: List all tools needed for CI and local development + deps: [binny] + cmd: "{{ .TOOL_DIR }}/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: "{{ .TOOL_DIR }}/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 . + - "{{ .TOOL_DIR }}/gosimports -local github.com/anchore -w ." + - go mod tidy + + lint-fix: + desc: Auto-format all source code + run golangci lint fixers + deps: [tools] + cmds: + - task: format + - "{{ .TOOL_DIR }}/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 + - "{{ .TOOL_DIR }}/golangci-lint run --tests=false" + + + check-licenses: + # desc: Ensure transitive dependencies are compliant with the current license policy + deps: [tools] + cmd: "{{ .TOOL_DIR }}/bouncer check ./..." + + check-go-mod-tidy: + # desc: Ensure go.mod and go.sum are up to date + cmds: + - cmd: .github/scripts/go-mod-tidy-check.sh && echo "go.mod and go.sum are tidy!" + silent: true + + check-json-schema-drift: + desc: Ensure there is no drift between the JSON schema and the code + cmds: + - .github/scripts/json-schema-drift-check.sh + + + ## Testing tasks ################################# + + unit: + desc: Run unit tests + deps: [tmpdir] + vars: + TEST_PKGS: + sh: "go list ./... | grep -v {{ .OWNER }}/{{ .PROJECT }}/test | tr '\n' ' '" + + # unit test coverage threshold (in % coverage) + COVERAGE_THRESHOLD: 62 + 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 + + integration: + desc: Run integration tests + cmds: + - "go test -v ./test/integration" + # exercise most of the CLI with the data race detector + - "go run -race cmd/syft/main.go alpine:latest" + + validate-cyclonedx-schema: + desc: Run integration tests + cmds: + - "cd schema/cyclonedx && make" + + cli: + desc: Run CLI tests + # note: we don't want to regenerate the snapshot unless we have to. In CI it's probable + # that the cache being restored with the correct binary will be rebuilt since the timestamps + # and local checksums will not line up. + deps: [tools, snapshot] + sources: + - "{{ .SNAPSHOT_BIN }}" + - ./test/cli/** + - ./**/*.go + cmds: + - cmd: "echo 'testing binary: {{ .SNAPSHOT_BIN }}'" + silent: true + + - cmd: "test -f {{ .SNAPSHOT_BIN }} || (find {{ .SNAPSHOT_DIR }} && echo '\nno snapshot found' && false)" + silent: true + + - "go test -count=1 -timeout=15m -v ./test/cli" + env: + SYFT_BINARY_LOCATION: "{{ .SNAPSHOT_BIN }}" + + test-utils: + desc: Run tests for pipeline utils + sources: + - .github/scripts/labeler*.py + cmds: + - cmd: python .github/scripts/labeler_test.py + + + ## Benchmark test targets ################################# + + benchmark: + deps: [tmpdir] + sources: + - ./**/*.go + generates: + - "{{ .TMP_DIR }}/benchmark-main.txt" + cmds: + - "go test -p 1 -run=^Benchmark -bench=. -count=7 -benchmem ./... | tee {{ .TMP_DIR }}/benchmark-{{ .VERSION }}.txt" + - | + bash -c "(test -s {{ .TMP_DIR }}/benchmark-main.txt && \ + {{ .TOOL_DIR }}/benchstat {{ .TMP_DIR }}/benchmark-main.txt {{ .TMP_DIR }}/benchmark-{{ .VERSION }}.txt || \ + {{ .TOOL_DIR }}/benchstat {{ .TMP_DIR }}/benchmark-{{ .VERSION }}.txt) \ + | tee {{ .TMP_DIR }}/benchstat.txt" + + show-benchstat: + deps: [benchmark, tmpdir] + sources: + - "{{ .TMP_DIR }}/benchstat.txt" + cmds: + - cmd: "cat {{ .TMP_DIR }}/benchstat.txt" + silent: true + + + ## Test-fixture-related targets ################################# + + fingerprints: + desc: Generate test fixture fingerprints + generates: + - test/integration/test-fixtures/cache.fingerprint + - syft/pkg/cataloger/binary/test-fixtures/cache.fingerprint + - syft/pkg/cataloger/java/test-fixtures/java-builds/cache.fingerprint + - syft/pkg/cataloger/golang/test-fixtures/archs/binaries.fingerprint + - syft/pkg/cataloger/rpm/test-fixtures/rpms.fingerprint + - syft/pkg/cataloger/kernel/test-fixtures/cache.fingerprint + - test/install/cache.fingerprint + - test/cli/test-fixtures/cache.fingerprint + cmds: + # for IMAGE integration test fixtures + - "cd test/integration/test-fixtures && make cache.fingerprint" + # for BINARY test fixtures + - "cd syft/pkg/cataloger/binary/test-fixtures && make cache.fingerprint" + # for JAVA BUILD test fixtures + - "cd syft/pkg/cataloger/java/test-fixtures/java-builds && make cache.fingerprint" + # for GO BINARY test fixtures + - "cd syft/pkg/cataloger/golang/test-fixtures/archs && make binaries.fingerprint" + # for RPM test fixtures + - "cd syft/pkg/cataloger/rpm/test-fixtures && make rpms.fingerprint" + # for Kernel test fixtures + - "cd syft/pkg/cataloger/kernel/test-fixtures && make cache.fingerprint" + # for INSTALL integration test fixtures + - "cd test/install && make cache.fingerprint" + # for CLI test fixtures + - "cd test/cli/test-fixtures && make cache.fingerprint" + + fixtures: + desc: Generate test fixtures + cmds: + - "cd syft/pkg/cataloger/java/test-fixtures/java-builds && make" + - "cd syft/pkg/cataloger/rpm/test-fixtures && make" + - "cd syft/pkg/cataloger/binary/test-fixtures && make" + + show-test-image-cache: + silent: true + cmds: + - "echo '\nDocker daemon cache:'" + - "docker images --format '{{`{{.ID}}`}} {{`{{.Repository}}`}}:{{`{{.Tag}}`}}' | grep stereoscope-fixture- | sort" + - "echo '\nTar cache:'" + - 'find . -type f -wholename "**/test-fixtures/snapshot/*" | sort' + + + ## install.sh testing targets ################################# + + install-test: + cmds: + - "cd test/install && make" + + install-test-cache-save: + cmds: + - "cd test/install && make save" + + install-test-cache-load: + cmds: + - "cd test/install && make load" + + install-test-ci-mac: + cmds: + - "cd test/install && make ci-test-mac" + + generate-compare-file: + cmd: "go run ./cmd/syft {{ .COMPARE_TEST_IMAGE }} -o json > {{ .COMPARE_DIR }}/test-fixtures/acceptance-{{ .COMPARE_TEST_IMAGE }}.json" + + compare-mac: + deps: [tmpdir] + cmd: | + {{ .COMPARE_DIR }}/mac.sh \ + {{ .SNAPSHOT_DIR }} \ + {{ .COMPARE_DIR }} \ + {{ .COMPARE_TEST_IMAGE }} \ + {{ .TMP_DIR }} + + compare-linux: + cmds: + - task: compare-test-deb-package-install + - task: compare-test-rpm-package-install + + compare-test-deb-package-install: + deps: [tmpdir] + cmd: | + {{ .COMPARE_DIR }}/deb.sh \ + {{ .SNAPSHOT_DIR }} \ + {{ .COMPARE_DIR }} \ + {{ .COMPARE_TEST_IMAGE }} \ + {{ .TMP_DIR }} + + compare-test-rpm-package-install: + deps: [tmpdir] + cmd: | + {{ .COMPARE_DIR }}/rpm.sh \ + {{ .SNAPSHOT_DIR }} \ + {{ .COMPARE_DIR }} \ + {{ .COMPARE_TEST_IMAGE }} \ + {{ .TMP_DIR }} + + + ## Code and data generation targets ################################# + + generate: + desc: Add data generation tasks + cmds: + - task: generate-json-schema + - task: generate-license-list + - task: generate-cpe-dictionary-index + + generate-json-schema: + desc: Generate a new JSON schema + cmds: + - "cd syft/internal && go generate . && cd jsonschema && go run ." + + generate-license-list: + desc: Generate an updated license processing code off of the latest available SPDX license list + cmds: + - "go generate ./internal/spdxlicense/..." + - "gofmt -s -w ./internal/spdxlicense" + + generate-cpe-dictionary-index: + desc: Generate the CPE index based off of the latest available CPE dictionary + cmds: + - "go run ./cmd/cpe-dictionary-indexer/main.go" + + + ## 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: + - cmd/**/*.go + - syft/**/*.go + - internal/**/*.go + method: checksum + generates: + - "{{ .SNAPSHOT_BIN }}" + 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: + - "{{ .TOOL_DIR }}/chronicle -vv -n --version-file {{ .NEXT_VERSION }} > {{ .CHANGELOG }}" + - "{{ .TOOL_DIR }}/glow {{ .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: + # desc: "[CI only] Are you in CI?" + cmds: + - cmd: .github/scripts/ci-check.sh + silent: true + + ci-release: + # desc: "[CI only] Create a release" + deps: [tools] + cmds: + - task: ci-check + - "{{ .TOOL_DIR }}/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" + + clean-cache: + desc: Remove all docker cache and local image tar cache + cmds: + - 'find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" -delete' + - "docker images --format '{{`{{.ID}}`}} {{`{{.Repository}}`}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs -r docker rmi --force" diff --git a/schema/cyclonedx/Makefile b/schema/cyclonedx/Makefile index 8b10c792e..70fbd9c33 100644 --- a/schema/cyclonedx/Makefile +++ b/schema/cyclonedx/Makefile @@ -4,4 +4,4 @@ validate-schema: go run ../../cmd/syft/main.go ubuntu:latest -vv -o cyclonedx > bom.xml xmllint --noout --schema ./cyclonedx.xsd bom.xml go run ../../cmd/syft/main.go ubuntu:latest -vv -o cyclonedx-json > bom.json - ../../.tmp/yajsv -s cyclonedx.json bom.json + ../../.tool/yajsv -s cyclonedx.json bom.json