diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..9f363e1 --- /dev/null +++ b/.envrc @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +export DIRENV_WARN_TIMEOUT=20s + +use flake diff --git a/.github/workflows/golang.yaml b/.github/workflows/golang.yaml index 8a4633c..51a83dc 100644 --- a/.github/workflows/golang.yaml +++ b/.github/workflows/golang.yaml @@ -7,28 +7,42 @@ on: branches: [main, develop] paths: - "**/*.go" + - ".github/workflows/golang.yaml" + - "flake.nix" - "go.mod" - "go.sum" pull_request: branches: [main, develop] paths: - "**/*.go" + - ".github/workflows/golang.yaml" + - "flake.nix" - "go.mod" - "go.sum" env: - GO_MODULE: https://github.com/opendefensecloud/testkit - GO_VERSION: 1.25.7 + GO_MODULE: https://github.com/opendefensecloud/solution-arsenal jobs: lint: runs-on: arc-scale-set + outputs: + go-version: ${{ steps.get-go-version.outputs.version }} steps: - uses: actions/checkout@v6 + - name: get-go-version + id: get-go-version + run: | + GO_VERSION="$(sed -nE 's/^[[:space:]]*goVersion[[:space:]]*=[[:space:]]*"([0-9]+\.[0-9]+\.[0-9]+)";[[:space:]]*$/\1/p' flake.nix)" + if [ "$(printf '%s\n' "$GO_VERSION" | sed '/^$/d' | wc -l)" -ne 1 ]; then + echo "::error::Expected exactly one goVersion assignment in flake.nix" + exit 1 + fi + echo "version=$GO_VERSION" >> $GITHUB_OUTPUT - uses: actions/setup-go@v6 with: - go-version: ${{ env.GO_VERSION }} - - name: lint-license + go-version: ${{ steps.get-go-version.outputs.version }} + - name: lint-license-and-shell run: | make lint-no-golangci - name: golangci-lint @@ -41,9 +55,10 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: - go-version: ${{ env.GO_VERSION }} + go-version: ${{ needs.lint.outputs.go-version }} - name: test - run: make test + run: | + make test - name: Convert coverage to lcov uses: jandelgado/gcov2lcov-action@v1.2.0 with: diff --git a/.gitignore b/.gitignore index 7acc55c..cbaad29 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,9 @@ go.work.sum # Editor/IDE # .idea/ # .vscode/ + +.direnv/ + +.pre-commit-config.yaml + +common.mk diff --git a/Makefile b/Makefile index 56584ff..3f3964b 100644 --- a/Makefile +++ b/Makefile @@ -1,117 +1,30 @@ - -# Setting SHELL to bash allows bash commands to be executed by recipes. -# Options are set to exit when a recipe line exits non-zero or a piped command fails. -SHELL = /usr/bin/env bash -o pipefail -.SHELLFLAGS = -ec - -# Set MAKEFLAGS to suppress entering/leaving directory messages -MAKEFLAGS += --no-print-directory - -BUILD_PATH ?= $(shell pwd) -HACK_DIR ?= $(shell cd hack 2>/dev/null && pwd) -LOCALBIN ?= $(BUILD_PATH)/bin - -OS := $(shell go env GOOS) -ARCH := $(shell go env GOARCH) - -GO ?= go -SHELLCHECK ?= shellcheck -OSV_SCANNER ?= osv-scanner -MKDOCS ?= mkdocs -DOCKER ?= docker -GINKGO ?= $(LOCALBIN)/ginkgo -GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint -SETUP_ENVTEST ?= $(LOCALBIN)/setup-envtest -ADDLICENSE ?= $(LOCALBIN)/addlicense -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen -OPENAPI_GEN ?= $(LOCALBIN)/openapi-gen -CRD_REF_DOCS ?= $(LOCALBIN)/crd-ref-docs -OCM ?= $(LOCALBIN)/ocm - -GINKGO_VERSION ?= $(shell go list -json -m -u github.com/onsi/ginkgo/v2 | jq -r '.Version') -GOLANGCI_LINT_VERSION ?= v2.10.1 -SETUP_ENVTEST_VERSION ?= release-0.22 -ADDLICENSE_VERSION ?= v1.1.1 -CRD_REF_DOCS_VERSION ?= v0.2.0 +# Include ODC common make targets +DEV_KIT_VERSION := v1.0.4 +-include common.mk +common.mk: + curl --fail -sSL https://raw.githubusercontent.com/opendefensecloud/dev-kit/$(DEV_KIT_VERSION)/common.mk -o common.mk.download && \ + mv common.mk.download $@ export GOPRIVATE=*.go.opendefense.cloud/testkit export GNOSUMDB=*.go.opendefense.cloud/testkit export GNOPROXY=*.go.opendefense.cloud/testkit -##@ General - -# The help target prints out all targets with their descriptions organized -# beneath their categories. The categories are represented by '##@' and the -# target descriptions by '##'. The awk commands is responsible for reading the -# entire set of makefiles included in this invocation, looking for lines of the -# file as xyz: ## something, and then pretty-format the target and help. Then, -# if there's a line with ##@ something, that gets pretty-printed as a category. -# More info on the usage of ANSI control characters for terminal formatting: -# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters -# More info on the awk command: -# http://linuxcommand.org/lc3_adv_awk.php - -help: ## Display this help. - @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) - -.PHONY: clean -clean: - rm -rf $(LOCALBIN) - +LICENSE := apache +LICENSE_COMMENT := BWI GmbH and Testkit contributors .PHONY: fmt -fmt: addlicense golangci-lint ## Add license headers and format - echo $(ADDLICENCE) - find . -not -path '*/.*' -name '*.go' -exec $(ADDLICENSE) -c 'BWI GmbH and Testkit contributors' -l apache -s=only {} + +fmt: $(GOLANGCI_LINT) ## Add license headers and format + $(MAKE) addlicense license=$(LICENSE) comment='$(LICENSE_COMMENT)' pattern='*\.go' $(GO) fmt ./... $(GOLANGCI_LINT) run --fix -.PHONY: mod -mod: ## Do go mod tidy, download, verify - @$(GO) mod tidy - @$(GO) mod download - @$(GO) mod verify - .PHONY: lint -lint: lint-no-golangci golangci-lint ## Run linters such as golangci-lint and addlicence checks - $(GOLANGCI_LINT) run -v +lint: lint-no-golangci golangci-lint ## Run linters .PHONY: lint-no-golangci -lint-no-golangci: addlicense - find . -not -path '*/.*' -name '*.go' -exec $(ADDLICENSE) -check -l apache -s=only {} ';' - -.PHONY: scan -scan: - $(OSV_SCANNER) scan --config ./.osv-scanner.toml -r . +lint-no-golangci: $(ADDLICENSE) + $(MAKE) addlicense-check license=$(LICENSE) comment='$(LICENSE_COMMENT)' pattern='*\.go' .PHONY: test -test: ginkgo ## Run all tests +test: $(GINKGO) ## Run all tests $(GINKGO) -r -cover --fail-fast --require-suite -covermode count --output-dir=$(BUILD_PATH) -coverprofile=testkit.coverprofile $(testargs) - -TIMESTAMP ?= $(shell date '+%Y%m%d%H%M%S') - -$(LOCALBIN): - mkdir -p $(LOCALBIN) - -.PHONY: golangci-lint -golangci-lint: $(LOCALBIN) ## Download golangci-lint locally if necessary. - @test -s $(LOCALBIN)/golangci-lint && $(LOCALBIN)/golangci-lint --version | grep -q $(GOLANGCI_LINT_VERSION) || \ - GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) - -.PHONY: ginkgo -ginkgo: $(LOCALBIN) ## Download ginkgo locally if necessary. - @test -s $(LOCALBIN)/ginkgo && $(LOCALBIN)/ginkgo version | grep -q $(subst v,,$(GINKGO_VERSION)) || \ - GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION) - -.PHONY: addlicense -addlicense: $(LOCALBIN) ## Download addlicense locally if necessary. - @test -s $(LOCALBIN)/addlicense && grep -q $(ADDLICENSE_VERSION) $(LOCALBIN)/.addlicense-version 2>/dev/null || \ - GOBIN=$(LOCALBIN) go install github.com/google/addlicense@$(ADDLICENSE_VERSION); \ - echo $(ADDLICENSE_VERSION) > $(LOCALBIN)/.addlicense-version - - - -.PHONY: crd-ref-docs -crd-ref-docs: $(LOCALBIN) ## Download crd-ref-docs locally if necessary. - @test -s $(LOCALBIN)/crd-ref-docs && $(LOCALBIN)/crd-ref-docs --version | grep -q $(CRD_REF_DOCS_VERSION) || \ - GOBIN=$(LOCALBIN) go install github.com/elastic/crd-ref-docs@$(CRD_REF_DOCS_VERSION) \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..8816be1 --- /dev/null +++ b/flake.lock @@ -0,0 +1,262 @@ +{ + "nodes": { + "dev-kit": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "git-hooks": "git-hooks", + "go-overlay": [ + "go-overlay" + ], + "gomod2nix": "gomod2nix", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1777018789, + "narHash": "sha256-zPYQuLwrMwlYyFAG3aiTta65xaZglt9YSS6/ploHXaY=", + "owner": "opendefensecloud", + "repo": "dev-kit", + "rev": "8158d30fafe63a596db9b6fe2680b7c72b1a8cc4", + "type": "github" + }, + "original": { + "owner": "opendefensecloud", + "repo": "dev-kit", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "dev-kit", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776796298, + "narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "3cfd774b0a530725a077e17354fbdb87ea1c4aad", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "git-hooks_2": { + "inputs": { + "flake-compat": "flake-compat_2", + "gitignore": "gitignore_2", + "nixpkgs": [ + "go-overlay", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765016596, + "narHash": "sha256-rhSqPNxDVow7OQKi4qS5H8Au0P4S3AYbawBSmJNUtBQ=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "dev-kit", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "go-overlay", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "go-overlay": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "git-hooks": "git-hooks_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776919902, + "narHash": "sha256-ndo8Ca96g6XNg4uTlomWuf2R9nd5W+6d0/fEWNie69I=", + "owner": "purpleclay", + "repo": "go-overlay", + "rev": "957454a0dde6ffcaf14d4a792f061d7dce903258", + "type": "github" + }, + "original": { + "owner": "purpleclay", + "repo": "go-overlay", + "type": "github" + } + }, + "gomod2nix": { + "inputs": { + "flake-utils": [ + "dev-kit", + "flake-utils" + ], + "nixpkgs": [ + "dev-kit", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770585520, + "narHash": "sha256-yBz9Ozd5Wb56i3e3cHZ8WcbzCQ9RlVaiW18qDYA/AzA=", + "owner": "nix-community", + "repo": "gomod2nix", + "rev": "1201ddd1279c35497754f016ef33d5e060f3da8d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "gomod2nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1776877367, + "narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0726a0ecb6d4e08f6adced58726b95db924cef57", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "dev-kit": "dev-kit", + "flake-utils": "flake-utils", + "go-overlay": "go-overlay", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..fe28f2d --- /dev/null +++ b/flake.nix @@ -0,0 +1,31 @@ +{ + description = "testkit development flake"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + + go-overlay = { + url = "github:purpleclay/go-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; + + dev-kit = { + url = "github:opendefensecloud/dev-kit"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.go-overlay.follows = "go-overlay"; + inputs.flake-utils.follows = "flake-utils"; + }; + }; + + outputs = { flake-utils, dev-kit, ... }: + flake-utils.lib.eachDefaultSystem (system: + { + devShells.default = dev-kit.lib.mkShell { + inherit system; + goVersion = "1.26.2"; + }; + } + ); +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..47b5870 --- /dev/null +++ b/renovate.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"], + "postUpdateOptions": ["gomodTidy"], + "packageRules": [ + { + "matchManagers": ["gomod"], + "matchDepTypes": ["golang"], + "rangeStrategy": "bump" + }, + { + "matchDatasources": ["docker", "golang-version"], + "matchPackageNames": ["go", "golang"], + "groupName": "golang version sync", + "groupSlug": "go-version" + } + ], + "customManagers": [ + { + "customType": "regex", + "managerFilePatterns": ["/(^|/)flake\\.nix$/"], + "matchStrings": [ + "goVersion\\s*=\\s*\"(?\\d+\\.\\d+\\.\\d+)\"" + ], + "depNameTemplate": "go", + "datasourceTemplate": "golang-version" + }, + { + "customType": "regex", + "managerFilePatterns": [ + "Makefile" + ], + "matchStrings": [ + "DEV_KIT_VERSION := (?v[0-9]+\\.[0-9]+\\.[0-9]+)" + ], + "datasourceTemplate": "github-releases", + "depNameTemplate": "opendefensecloud/dev-kit", + "versioningTemplate": "semver" + }, + { + "customType": "regex", + "managerFilePatterns": [ + "tools.lock" + ], + "matchStrings": [ + "(?[^\\s]+) (?[^@]+)@(?v?[^\\s]+)" + ], + "versioningTemplate": "semver", + "datasourceTemplate": "go" + } + ] +} diff --git a/tools.lock b/tools.lock new file mode 100644 index 0000000..c42d80d --- /dev/null +++ b/tools.lock @@ -0,0 +1,4 @@ +addlicense github.com/google/addlicense@v1.1.1 +ginkgo github.com/onsi/ginkgo/v2/ginkgo@v2.28.1 +golangci-lint github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 +osv-scanner github.com/google/osv-scanner/v2/cmd/osv-scanner@v2.3.5