diff --git a/.agent/rules/auto-generated-files.md b/.agent/rules/auto-generated-files.md index 6393a64075..bde566d68e 100644 --- a/.agent/rules/auto-generated-files.md +++ b/.agent/rules/auto-generated-files.md @@ -63,23 +63,25 @@ If a change is needed in any matched file: ### Core generation commands +- Everything, in one shot: + - `./task generate` — aggregator that runs all generators below - OpenAPI SDK/CLI command stubs and related generated artifacts: - - `make generate` - - Includes generated `cmd/account/**`, `cmd/workspace/**`, `.gitattributes`, `internal/genkit/tagging.py`, and direct engine refresh. + - `./task generate-genkit` + - Includes generated `cmd/account/**`, `cmd/workspace/**`, `.gitattributes`, `internal/genkit/tagging.py`. - Direct engine generated YAML: - - `make generate-direct` (or `make generate-direct-apitypes`, `make generate-direct-resources`) + - `./task generate-direct` (or `./task generate-direct-apitypes`, `./task generate-direct-resources`) - Bundle schemas: - - `make schema` - - `make schema-for-docs` + - `./task generate-schema` + - `./task generate-schema-docs` - This can also refresh `bundle/internal/schema/annotations_openapi.yml` when OpenAPI annotation extraction is enabled. - Bundle docs: - - `make docs` + - `./task generate-docs` - Validation generated code: - - `make generate-validation` + - `./task generate-validation` - Mock files: - `go run github.com/vektra/mockery/v2@b9df18e0f7b94f0bc11af3f379c8a9aea1e1e8da` - Python bundle codegen: - - `make -C python codegen` + - `./task pydabs-codegen` ### Acceptance and test generated outputs diff --git a/.agent/skills/pr-checklist/SKILL.md b/.agent/skills/pr-checklist/SKILL.md index ae21c13ca0..a8d93af29f 100644 --- a/.agent/skills/pr-checklist/SKILL.md +++ b/.agent/skills/pr-checklist/SKILL.md @@ -3,26 +3,26 @@ name: pr-checklist description: Checklist to run before submitting a PR --- -Before submitting a PR, run these commands to match what CI checks. CI uses the **full** variants (not the diff-only wrappers), so `make lint` alone is insufficient. +Before submitting a PR, run these commands to match what CI checks. CI uses the full variants (not the `-q` diff-only wrappers), so `./task lint-q` alone is insufficient. ```bash -# 1. Formatting and checks (CI runs fmtfull, not fmt) -make fmtfull -make checks +# 1. Formatting and checks (CI runs fmt, not fmt-q) +./task fmt +./task checks -# 2. Linting (CI runs full golangci-lint, not the diff-only wrapper) -make lintfull +# 2. Linting (CI runs full golangci-lint across all modules, not the diff-only wrapper) +./task lint # 3. Tests (CI runs with both deployment engines) -make test +./task test # 4. If you changed bundle config structs or schema-related code: -make schema +./task generate-schema # 5. If you changed files in python/: -cd python && make codegen && make test && make lint && make docs +./task pydabs-codegen pydabs-test pydabs-lint pydabs-docs # 6. If you changed experimental/aitools or experimental/ssh: -make test-exp-aitools # only if aitools code changed -make test-exp-ssh # only if ssh code changed +./task test-exp-aitools # only if aitools code changed +./task test-exp-ssh # only if ssh code changed ``` diff --git a/.codegen.json b/.codegen.json index b8bb2b3ec5..e2a84cb8c1 100644 --- a/.codegen.json +++ b/.codegen.json @@ -12,9 +12,6 @@ "toolchain": { "required": [ "go" - ], - "post_generate": [ - "./tools/post-generate.sh" ] } } diff --git a/.github/actions/setup-build-environment/action.yml b/.github/actions/setup-build-environment/action.yml index 62d9bd66f1..9f5408d57d 100644 --- a/.github/actions/setup-build-environment/action.yml +++ b/.github/actions/setup-build-environment/action.yml @@ -38,7 +38,7 @@ runs: version: "0.8.9" - name: Install Python versions for tests - run: make install-pythons + run: ./task install-pythons shell: bash - name: Install ruff (Python linter and formatter) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 5787f519d5..1ce182801e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -36,7 +36,7 @@ jobs: run: git diff --exit-code - name: Run Go lint checks (does not include formatting checks) - run: go tool -modfile=tools/go.mod golangci-lint run --timeout=15m + run: ./task lint - name: Run ruff (Python linter and formatter) uses: astral-sh/ruff-action@0ce1b0bf8b818ef400413f810f8a11cdbda0034b # v4.0.0 @@ -44,14 +44,13 @@ jobs: version: "0.9.1" args: "format --check" - - name: "make fmtfull: Python and Go formatting" + - name: "task fmt: Python and Go formatting" # Python formatting is already checked above, but this also checks Go and YAML formatting - # and verifies that the make command works correctly run: | - make fmtfull + ./task fmt git diff --exit-code - - name: "make checks: custom checks outside of fmt and lint" + - name: "task checks: custom checks outside of fmt and lint" run: |- - make checks + ./task checks git diff --exit-code diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index fcd6930f64..47c0c9388b 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -77,7 +77,7 @@ jobs: # Only run if the target is in the list of targets from testmask if: ${{ contains(fromJSON(needs.testmask.outputs.targets), 'test') }} - name: "make test (${{matrix.os.name}}, ${{matrix.deployment}})" + name: "task test (${{matrix.os.name}}, ${{matrix.deployment}})" runs-on: ${{ matrix.os.runner }} permissions: @@ -137,23 +137,23 @@ jobs: if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' || github.event_name == 'schedule' }} env: ENVFILTER: DATABRICKS_BUNDLE_ENGINE=${{ matrix.deployment }} - run: make test + run: ./task test - name: Run tests with coverage - # Only run 'make cover' on push to main to make sure it does not get broken. + # Only run 'task cover' on push to main to make sure it does not get broken. if: ${{ github.event_name == 'push' }} env: ENVFILTER: DATABRICKS_BUNDLE_ENGINE=${{ matrix.deployment }} - run: make cover + run: ./task cover - name: Analyze slow tests - run: make slowest + run: ./task slowest - name: Check out.test.toml files are up to date shell: bash run: | if ! git diff --exit-code; then - echo "ERROR: detected changed files in the repository; Most likely you have out.test.toml files that are out of date. Run 'make generate-out-test-toml' to update." + echo "ERROR: detected changed files in the repository; Most likely you have out.test.toml files that are out of date. Run './task generate-out-test-toml' to update." exit 1 fi @@ -164,7 +164,7 @@ jobs: # Only run if the target is in the list of targets from testmask if: ${{ contains(fromJSON(needs.testmask.outputs.targets), 'test-exp-aitools') }} - name: "make test-exp-aitools (${{matrix.os.name}})" + name: "task test-exp-aitools (${{matrix.os.name}})" runs-on: ${{ matrix.os.runner }} permissions: @@ -201,7 +201,7 @@ jobs: - name: Run tests run: | - make test-exp-aitools + ./task test-exp-aitools test-exp-ssh: needs: @@ -210,7 +210,7 @@ jobs: # Only run if the target is in the list of targets from testmask if: ${{ contains(fromJSON(needs.testmask.outputs.targets), 'test-exp-ssh') }} - name: "make test-exp-ssh (${{matrix.os.name}})" + name: "task test-exp-ssh (${{matrix.os.name}})" runs-on: ${{ matrix.os.runner }} permissions: @@ -246,7 +246,7 @@ jobs: - name: Run tests run: | - make test-exp-ssh + ./task test-exp-ssh test-pipelines: needs: @@ -255,7 +255,7 @@ jobs: # Only run if the target is in the list of targets from testmask if: ${{ contains(fromJSON(needs.testmask.outputs.targets), 'test-pipelines') }} - name: "make test-pipelines (${{matrix.os.name}})" + name: "task test-pipelines (${{matrix.os.name}})" runs-on: ${{ matrix.os.runner }} permissions: @@ -291,7 +291,7 @@ jobs: - name: Run tests run: | - make test-pipelines + ./task test-pipelines # This job groups the result of all the above test jobs. # It is a required check, so it blocks auto-merge and the merge queue. @@ -340,15 +340,15 @@ jobs: - name: Verify that the schema is up to date run: | - if ! ( make schema && git diff --exit-code ); then - echo "The schema is not up to date. Please run 'make schema' and commit the changes." + if ! ( ./task --force generate-schema && git diff --exit-code ); then + echo "The schema is not up to date. Please run 'task generate-schema' and commit the changes." exit 1 fi - name: Verify that the generated enum and required fields are up to date run: | - if ! ( make generate-validation && git diff --exit-code ); then - echo "The generated enum and required fields are not up to date. Please run 'make generate-validation' and commit the changes." + if ! ( ./task --force generate-validation && git diff --exit-code ); then + echo "The generated enum and required fields are not up to date. Please run 'task generate-validation' and commit the changes." exit 1 fi @@ -360,18 +360,22 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: go.mod + - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: version: "0.6.5" - name: Verify that python/codegen is up to date - working-directory: python run: |- - make codegen + ./task pydabs-codegen if ! ( git diff --exit-code ); then - echo "Generated Python code is not up-to-date. Please run 'pushd python && make codegen' and commit the changes." + echo "Generated Python code is not up-to-date. Please run 'task pydabs-codegen' and commit the changes." exit 1 fi diff --git a/.github/workflows/python_push.yml b/.github/workflows/python_push.yml index 8a6d351dcb..1ac3cb376e 100644 --- a/.github/workflows/python_push.yml +++ b/.github/workflows/python_push.yml @@ -32,6 +32,11 @@ jobs: - name: Checkout repository and submodules uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: go.mod + - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: @@ -39,8 +44,7 @@ jobs: version: "0.6.5" - name: Run tests - working-directory: python - run: make test + run: ./task pydabs-test python_linters: name: lint @@ -50,14 +54,18 @@ jobs: - name: Checkout repository and submodules uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: go.mod + - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: version: "0.6.5" - name: Run lint - working-directory: python - run: make lint + run: ./task pydabs-lint python_docs: name: docs @@ -67,11 +75,15 @@ jobs: - name: Checkout repository and submodules uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: go.mod + - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: version: "0.6.5" - name: Run docs - working-directory: python - run: make docs + run: ./task pydabs-docs diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index e88986e223..864e6a1e94 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -172,7 +172,9 @@ jobs: - name: Build wheel working-directory: python - run: make build + run: | + rm -rf build dist + uv build . - name: Upload Python wheel uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 diff --git a/.gitignore b/.gitignore index b7c7726d93..5516d1a40b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,17 +28,28 @@ __pycache__ .ruff_cache -# Test results from 'make test' +# Test results from 'task test' test-output.json +test-output-unit.json +test-output-unit-root.json +test-output-unit-tools.json +test-output-unit-codegen.json +test-output-acc.json -# Built by make for 'make fmt' and yamlcheck.py in acceptance tests +# Taskfile cache +.task/ + +# Snapshot binary from 'task snapshot' +.databricks/ + +# Built for 'task fmt' and yamlcheck.py in acceptance tests tools/yamlfmt tools/yamlfmt.exe -# Built by make for 'make lint' +# Built for 'task lint' tools/golangci-lint -# Built by make for test filtering +# Built for test filtering tools/testmask/testmask # Cache for tools/gh_report.py @@ -50,6 +61,7 @@ dist/ # Local development notes, tmp /pr-* /tmp/ +/.tmp/ # Go workspace file go.work diff --git a/AGENTS.md b/AGENTS.md index 7386b4ec50..1eec48d0f5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,25 +12,27 @@ When moving code from one place to another, please don't unnecessarily change th ### Building and Testing -- `make build` - Build the CLI binary -- `make test` - Run unit tests for all packages +- `./task build` - Build the CLI binary +- `./task test` - Run unit and acceptance tests for all packages - `go test ./acceptance -run TestAccept/bundle/// -tail -test.v` - run a single acceptance test -- `make integration` - Run integration tests (requires environment variables) -- `make cover` - Generate test coverage reports +- `./task integration` - Run integration tests (requires environment variables) +- `./task cover` - Generate test coverage reports ### Code Quality -- `make lint` - Run linter on changed files only (uses lintdiff.py) -- `make lintfull` - Run full linter with fixes (golangci-lint) -- `make ws` - Run whitespace linter -- `make fmt` - Format code (Go, Python, YAML) -- `make checks` - Run quick checks (tidy, whitespace, links) +- `./task lint` - Run full linter across all Go modules (root, tools, codegen) +- `./task lint-q` - Run linter on changed files only (uses lintdiff.py, root module, with --fix) +- `./task ws` - Run whitespace linter +- `./task fmt` - Format all code (Go, Python, YAML) +- `./task fmt-q` - Format changed files only (incremental Go + Python + YAML) +- `./task checks` - Run quick checks (tidy, whitespace, links) ### Specialized Commands -- `make schema` - Generate bundle JSON schema -- `make docs` - Generate bundle documentation -- `make generate` - Generate CLI code from OpenAPI spec (requires universe repo) +- `./task generate-schema` - Generate bundle JSON schema +- `./task generate-docs` - Generate bundle documentation +- `./task generate-genkit` - Run genkit to generate CLI commands and tagging workflow (requires universe repo) +- `./task generate` - Run all generators ### Git Commands @@ -77,7 +79,7 @@ GIT_EDITOR=true GIT_SEQUENCE_EDITOR=true VISUAL=true GIT_PAGER=cat git rebase or # Development Tips -- Use `make test-update` to regenerate acceptance test outputs after changes +- Use `./task test-update` to regenerate acceptance test outputs after changes - The CLI binary supports both `databricks` and `pipelines` command modes based on executable name - Comments should explain "why", not "what" — reviewers consistently reject comments that merely restate the code diff --git a/Makefile b/Makefile index c763496ceb..41fe170494 100644 --- a/Makefile +++ b/Makefile @@ -1,287 +1,2 @@ -.PHONY: default -default: checks fmt lint - -# Default packages to test (all) -TEST_PACKAGES = ./acceptance/internal ./libs/... ./internal/... ./cmd/... ./bundle/... ./experimental/ssh/... . - -# Default acceptance test filter (all) -ACCEPTANCE_TEST_FILTER = "" - -GO_TOOL ?= go tool -modfile=tools/go.mod -GOTESTSUM_FORMAT ?= pkgname-and-test-fails -GOTESTSUM_CMD ?= ${GO_TOOL} gotestsum --format ${GOTESTSUM_FORMAT} --no-summary=skipped --jsonfile test-output.json --rerun-fails -LOCAL_TIMEOUT ?= 30m - - -.PHONY: lintfull -lintfull: ./tools/golangci-lint - ./tools/golangci-lint run --fix - -.PHONY: lint -lint: ./tools/golangci-lint - ./tools/lintdiff.py ./tools/golangci-lint run --fix - -.PHONY: tidy -tidy: - @# not part of golangci-lint, apparently - go mod tidy - -.PHONY: lintcheck -lintcheck: ./tools/golangci-lint - ./tools/golangci-lint run ./... - -.PHONY: fmtfull -fmtfull: ./tools/golangci-lint ./tools/yamlfmt - ruff format -n - ./tools/golangci-lint fmt - ./tools/yamlfmt . - -.PHONY: fmt -fmt: ./tools/golangci-lint ./tools/yamlfmt - ruff format -n - ./tools/lintdiff.py ./tools/golangci-lint fmt - ./tools/yamlfmt . - -# pre-building yamlfmt because it is invoked from tests and scripts -tools/yamlfmt: tools/go.mod tools/go.sum - go build -modfile=tools/go.mod -o tools/yamlfmt github.com/google/yamlfmt/cmd/yamlfmt - -tools/yamlfmt.exe: tools/go.mod tools/go.sum - go build -modfile=tools/go.mod -o tools/yamlfmt.exe github.com/google/yamlfmt/cmd/yamlfmt - -# pre-building golangci-lint because it's faster to run pre-built version -tools/golangci-lint: tools/go.mod tools/go.sum - go build -modfile=tools/go.mod -o tools/golangci-lint github.com/golangci/golangci-lint/v2/cmd/golangci-lint - -.PHONY: ws -ws: - ./tools/validate_whitespace.py - -.PHONY: wsfix -wsfix: - ./tools/validate_whitespace.py --fix - -.PHONY: links -links: - ./tools/update_github_links.py - -# Checks other than 'fmt' and 'lint'; these are fast, so can be run first -.PHONY: checks -checks: tidy ws links - - -.PHONY: install-pythons -install-pythons: - uv python install 3.9 3.10 3.11 3.12 3.13 - -.PHONY: test -test: test-unit test-acc - -.PHONY: test-unit -test-unit: - ${GOTESTSUM_CMD} --packages "${TEST_PACKAGES}" -- -timeout=${LOCAL_TIMEOUT} - -.PHONY: test-acc -test-acc: - ${GOTESTSUM_CMD} --packages ./acceptance/... -- -timeout=${LOCAL_TIMEOUT} -run ${ACCEPTANCE_TEST_FILTER} - -# Updates acceptance test output (local tests) -.PHONY: test-update -test-update: - -go test ./acceptance -run '^TestAccept$$' -update -timeout=${LOCAL_TIMEOUT} - -# Updates acceptance test output for template tests only -.PHONY: test-update-templates -test-update-templates: - -go test ./acceptance -run '^TestAccept/bundle/templates' -update -timeout=${LOCAL_TIMEOUT} - -# Regenerate out.test.toml files without running tests -.PHONY: generate-out-test-toml -generate-out-test-toml: - go test ./acceptance -run '^TestAccept$$' -only-out-test-toml -timeout=${LOCAL_TIMEOUT} - -# Updates acceptance test output (integration tests, requires access) -.PHONY: test-update-aws -test-update-aws: - deco env run -i -n aws-prod-ucws -- env DATABRICKS_TEST_SKIPLOCAL=1 go test ./acceptance -run ^TestAccept$$ -update -timeout=1h -v - -.PHONY: test-update-all -test-update-all: test-update test-update-aws - -.PHONY: slowest -slowest: - ${GO_TOOL} gotestsum tool slowest --jsonfile test-output.json --threshold 1s --num 50 - -.PHONY: cover -cover: - rm -fr ./acceptance/build/cover/ - VERBOSE_TEST=1 ${GOTESTSUM_CMD} --packages "${TEST_PACKAGES}" -- -coverprofile=coverage.txt -timeout=${LOCAL_TIMEOUT} - VERBOSE_TEST=1 CLI_GOCOVERDIR=build/cover ${GOTESTSUM_CMD} --packages ./acceptance/... -- -timeout=${LOCAL_TIMEOUT} -run ${ACCEPTANCE_TEST_FILTER} - rm -fr ./acceptance/build/cover-merged/ - mkdir -p acceptance/build/cover-merged/ - go tool covdata merge -i $$(printf '%s,' acceptance/build/cover/* | sed 's/,$$//') -o acceptance/build/cover-merged/ - go tool covdata textfmt -i acceptance/build/cover-merged -o coverage-acceptance.txt - -.PHONY: showcover -showcover: - go tool cover -html=coverage.txt - -.PHONY: acc-showcover -acc-showcover: - go tool cover -html=coverage-acceptance.txt - -.PHONY: build -build: tidy - go build - -# builds the binary in a VM environment (such as Parallels Desktop) where your files are mirrored from the host os -.PHONY: build-vm -build-vm: tidy - go build -buildvcs=false - -.PHONY: snapshot -snapshot: - go build -o .databricks/databricks - -# Produce release binaries and archives in the dist folder without uploading them anywhere. -# Useful for "databricks ssh" development, as it needs to upload linux releases to the /Workspace. -.PHONY: snapshot-release -snapshot-release: - goreleaser release --clean --skip docker --snapshot - -.PHONY: schema -schema: - go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema.json - -.PHONY: schema-for-docs -schema-for-docs: - go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema_for_docs.json --docs - -.PHONY: docs -docs: - go run ./bundle/docsgen ./bundle/internal/schema ./bundle/docsgen - -INTEGRATION = go run -modfile=tools/go.mod ./tools/testrunner/main.go ${GO_TOOL} gotestsum --format github-actions --rerun-fails --jsonfile output.json --packages "./acceptance ./integration/..." -- -parallel 4 -timeout=2h - -.PHONY: integration -integration: install-pythons - $(INTEGRATION) - -.PHONY: integration-short -integration-short: install-pythons - DATABRICKS_TEST_SKIPLOCAL=1 VERBOSE_TEST=1 $(INTEGRATION) -short - -.PHONY: dbr-integration -dbr-integration: install-pythons - DBR_ENABLED=true go test -v -timeout 4h -run TestDbrAcceptance$$ ./acceptance - -# DBR acceptance tests - run on Databricks Runtime using serverless compute -# These require deco env run for authentication -# Set DBR_TEST_VERBOSE=1 for detailed output (e.g., DBR_TEST_VERBOSE=1 make dbr-test) -.PHONY: dbr-test -dbr-test: - deco env run -i -n aws-prod-ucws -- make dbr-integration - -.PHONY: generate-validation -generate-validation: - go run ./bundle/internal/validation/. - gofmt -w -s ./bundle/internal/validation/generated - -# Rule to generate the CLI from a new version of the OpenAPI spec. -# I recommend running this rule from Arca because of faster build times -# because of better caching and beefier machines, but it should also work -# fine from your local mac. -# -# By default, this rule will use the universe directory in your home -# directory. You can override this by setting the UNIVERSE_DIR -# environment variable. -# -# Example: -# UNIVERSE_DIR=/Users/shreyas.goenka/universe make generate -UNIVERSE_DIR ?= $(HOME)/universe -GENKIT_BINARY := $(UNIVERSE_DIR)/bazel-bin/openapi/genkit/genkit_/genkit - -.PHONY: generate -generate: - @echo "Checking out universe at SHA: $$(cat .codegen/_openapi_sha)" - cd $(UNIVERSE_DIR) && git cat-file -e $$(cat $(PWD)/.codegen/_openapi_sha) 2>/dev/null || git fetch --filter=blob:none origin master && git checkout $$(cat $(PWD)/.codegen/_openapi_sha) - @echo "Building genkit..." - cd $(UNIVERSE_DIR) && bazel build //openapi/genkit - @echo "Generating CLI code..." - $(GENKIT_BINARY) update-sdk - cat .gitattributes.manual .gitattributes > .gitattributes.tmp && mv .gitattributes.tmp .gitattributes - -go test ./acceptance -run TestAccept/bundle/refschema -update &> /dev/null - @echo "Updating direct engine config..." - make generate-direct - go test ./bundle/internal/schema - -.codegen/openapi.json: .codegen/_openapi_sha - wget -O $@.tmp "https://openapi.dev.databricks.com/$$(cat $<)/specs/all-internal.json" && mv $@.tmp $@ && touch $@ - -.PHONY: generate-direct -generate-direct: generate-direct-apitypes generate-direct-resources - -.PHONY: generate-direct-apitypes -generate-direct-apitypes: bundle/direct/dresources/apitypes.generated.yml - -.PHONY: generate-direct-resources -generate-direct-resources: bundle/direct/dresources/resources.generated.yml - -.PHONY: generate-direct-clean -generate-direct-clean: - rm -f bundle/direct/dresources/apitypes.generated.yml bundle/direct/dresources/resources.generated.yml - -bundle/direct/dresources/apitypes.generated.yml: ./bundle/direct/tools/generate_apitypes.py .codegen/openapi.json acceptance/bundle/refschema/out.fields.txt - python3 $^ > $@ - -bundle/direct/dresources/resources.generated.yml: ./bundle/direct/tools/generate_resources.py .codegen/openapi.json bundle/direct/dresources/apitypes.generated.yml bundle/direct/dresources/apitypes.yml acceptance/bundle/refschema/out.fields.txt - python3 $^ > $@ - -.PHONY: test-exp-aitools -test-exp-aitools: - make test TEST_PACKAGES="./experimental/aitools/..." ACCEPTANCE_TEST_FILTER="TestAccept/apps" - -.PHONY: test-exp-ssh -test-exp-ssh: - make test TEST_PACKAGES="./experimental/ssh/..." ACCEPTANCE_TEST_FILTER="TestAccept/ssh" - -.PHONY: test-pipelines -test-pipelines: - make test TEST_PACKAGES="./cmd/pipelines/..." ACCEPTANCE_TEST_FILTER="TestAccept/pipelines" - - -# Benchmarks: - -.PHONY: bench1k -bench1k: - BENCHMARK_PARAMS="--jobs 1000" go test ./acceptance -v -tail -run TestAccept/bundle/benchmarks -timeout=120m - -.PHONY: bench100 -bench100: - BENCHMARK_PARAMS="--jobs 100" go test ./acceptance -v -tail -run TestAccept/bundle/benchmarks -timeout=120m - -# small benchmark to quickly test benchmark-related code -.PHONY: bench10 -bench10: - BENCHMARK_PARAMS="--jobs 10" go test ./acceptance -v -tail -run TestAccept/bundle/benchmarks -timeout=120m - -bench1k.log: - make bench1k | tee $@ - -bench100.log: - make bench100 | tee $@ - -bench10.log: - make bench10 | tee $@ - -.PHONY: bench1k_summary -bench1k_summary: bench1k.log - ./tools/bench_parse.py $< - -.PHONY: bench100_summary -bench100_summary: bench100.log - ./tools/bench_parse.py $< - -.PHONY: bench10_summary -bench10_summary: bench10.log - ./tools/bench_parse.py $< +.DEFAULT: + @./task "$@" diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000000..e56c658a2c --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,873 @@ +version: '3' + +vars: + # Absolute path so tasks with `dir:` (lint-go-tools, lint-go-codegen) can use it. + GO_TOOL: go tool -modfile={{.ROOT_DIR}}/tools/go.mod + TEST_PACKAGES: ./acceptance/internal ./libs/... ./internal/... ./cmd/... ./bundle/... ./experimental/ssh/... . + ACCEPTANCE_TEST_FILTER: "" + +tasks: + default: + desc: Quick dev loop (checks, formatters, incremental lint, tests). Use `all` for the full suite. + cmds: + - task: checks + - task: fmt-q + - task: lint-q + - task: test-update + + full: + desc: More complete dev loop + cmds: + - task: checks + - task: fmt + - task: lint + - task: test-update + + all: + desc: Run regeneration (except for genkit), all checks, lints and test updates + cmds: + # Skips generate-genkit (expensive, requires universe checkout, outputs are + # committed). Run `./task generate` explicitly when codegen inputs change. + - task: generate-refschema + - task: generate-schema + - task: generate-schema-docs + - task: generate-validation + - task: generate-docs + - task: generate-direct + - task: pydabs-codegen + - task: pydabs-lint + - task: pydabs-test + - task: checks + - task: fmt + - task: lint + - task: test-update-all + + # --- Linting --- + # + # Naming convention: the plain name is the full variant (default). Quick + # / incremental variants carry a `-q` suffix on the top-level namespace + # (e.g. `lint-q-go-root`). `./task` (default) uses the -q variants for + # speed; `./task all` uses the full variants. + + lint: + desc: Lint all Go files (root + tools + codegen modules) + cmds: + - task: lint-go + + lint-q: + desc: Lint changed Go files in root module (diff vs main, with --fix) + cmds: + - task: lint-q-go-root + + # `golangci-lint run` typechecks, so it stops at go.mod boundaries. We have + # one task per Go module; `lint-go` composes them to cover the whole repo. + # Children run in parallel — each uses its own TMPDIR (set inline on the + # golangci-lint command below) to avoid the shared /tmp lock that serializes + # concurrent golangci-lint invocations. This matters in two scenarios: + # 1. siblings of `lint-go` running in parallel on subprojects here, and + # 2. `lint-go` invocations in sibling worktrees running at the same time. + # The TMPDIR must live under the repo but NOT equal {{.ROOT_DIR}} itself + # (the Go toolchain refuses a go.mod inside os.TempDir, which would break + # golangci-lint's typechecker). + lint-go: + desc: Lint Go files across all modules (root, tools, codegen) + deps: ['lint-go-root', 'lint-go-tools', 'lint-go-codegen'] + + lint-go-root: + desc: Lint Go files in the root module + vars: + TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-root' + sources: &ROOT_LINT_SOURCES + - "**/*.go" + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + - .golangci.yaml + cmds: + - cmd: mkdir -p "{{.TMPDIR}}" + silent: true + - TMPDIR="{{.TMPDIR}}" {{.GO_TOOL}} golangci-lint run ./... + + lint-go-tools: + desc: Lint Go files in tools/ module + dir: tools + vars: + TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-tools' + sources: + - "**/*.go" + - '{{.ROOT_DIR}}/.golangci.yaml' + - go.mod + - go.sum + cmds: + - cmd: mkdir -p "{{.TMPDIR}}" + silent: true + # gocritic is disabled because root's ruleguard rules path is cwd-relative + # and cannot be resolved from this nested module. + - TMPDIR="{{.TMPDIR}}" {{.GO_TOOL}} golangci-lint run --disable gocritic ./... + + lint-go-codegen: + desc: Lint Go files in bundle/internal/tf/codegen module + dir: bundle/internal/tf/codegen + vars: + TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-codegen' + sources: + - "**/*.go" + - '{{.ROOT_DIR}}/.golangci.yaml' + - go.mod + - go.sum + cmds: + - cmd: mkdir -p "{{.TMPDIR}}" + silent: true + # gocritic is disabled because root's ruleguard rules path is cwd-relative + # and cannot be resolved from this nested module. + - TMPDIR="{{.TMPDIR}}" {{.GO_TOOL}} golangci-lint run --disable gocritic ./... + + lint-q-go-root: + desc: Lint changed Go files in root module (diff vs main, with --fix). Does not check tools/ or bundle/internal/tf/codegen — use `lint` for full coverage. + vars: + TMPDIR: '{{.ROOT_DIR}}/.tmp/golangci-lint-root' + sources: *ROOT_LINT_SOURCES + cmds: + - cmd: mkdir -p "{{.TMPDIR}}" + silent: true + - TMPDIR="{{.TMPDIR}}" ./tools/lintdiff.py {{.GO_TOOL}} golangci-lint run --fix + + # --- Formatting --- + + fmt: + desc: Format all files (Python, Go, YAML) + deps: ['fmt-python', 'fmt-go', 'fmt-yaml'] + + fmt-q: + desc: Format changed files (Python, incremental Go, YAML) + deps: ['fmt-python', 'fmt-q-go', 'fmt-yaml'] + + fmt-python: + desc: Format Python files + sources: + - "**/*.py" + cmds: + - ruff format -n + + # `golangci-lint fmt` walks the filesystem and doesn't typecheck, so it + # formats files across all nested modules (tools/, bundle/internal/tf/codegen/) + # in a single invocation. + fmt-go: + desc: Format all Go files + sources: &FMT_GO_SOURCES + - "**/*.go" + - .golangci.yaml + cmds: + - "{{.GO_TOOL}} golangci-lint fmt" + + fmt-q-go: + desc: Format changed Go files (diff vs main) + sources: *FMT_GO_SOURCES + cmds: + - "./tools/lintdiff.py {{.GO_TOOL}} golangci-lint fmt" + + fmt-yaml: + desc: Format YAML files + sources: + - "**/*.yml" + - "**/*.yaml" + - yamlfmt.yml + cmds: + - "{{.GO_TOOL}} yamlfmt ." + + # --- Code checks --- + + tidy: + desc: Run go mod tidy across all Go modules (root, tools, codegen) + deps: ['tidy-root', 'tidy-tools', 'tidy-codegen'] + + tidy-root: + desc: Run go mod tidy in root module + sources: + - go.mod + - go.sum + - "**/*.go" + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + cmds: + - go mod tidy + + tidy-tools: + desc: Run go mod tidy in tools/ module + dir: tools + sources: + - go.mod + - go.sum + - "**/*.go" + cmds: + - go mod tidy + + tidy-codegen: + desc: Run go mod tidy in bundle/internal/tf/codegen module + dir: bundle/internal/tf/codegen + sources: + - go.mod + - go.sum + - "**/*.go" + cmds: + - go mod tidy + + ws: + desc: Check whitespace + cmds: + - ./tools/validate_whitespace.py + + ws-fix: + desc: Fix whitespace issues + cmds: + - ./tools/validate_whitespace.py --fix + + links: + desc: Update GitHub links in docs + sources: + - "**/*.md" + cmds: + - ./tools/update_github_links.py + + checks: + desc: Run quick checks (tidy, whitespace, links) + # Sequential: `tidy` rewrites go.mod/go.sum and any future tidy work + # touching more paths should not race with whitespace/link scanners. + cmds: + - task: tidy + - task: ws + - task: links + + install-pythons: + desc: Install Python 3.9-3.13 via uv + cmds: + - uv python install 3.9 3.10 3.11 3.12 3.13 + + # --- Building --- + + # The root binary only imports bundle/, cmd/, experimental/, internal/, libs/, + # so changes to test-only trees (acceptance/, integration/), separate modules + # (tools/, bundle/internal/tf/codegen/), and _test.go files don't affect the build. + build: + desc: Build the CLI binary + deps: ['tidy-root'] + sources: &BUILD_SOURCES + - "**/*.go" + - exclude: "**/*_test.go" + - exclude: acceptance/** + - exclude: integration/** + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + - go.mod + - go.sum + generates: + - cli + cmds: + - go build + + snapshot: + desc: Build snapshot binary to .databricks/databricks + deps: ['tidy-root'] + sources: *BUILD_SOURCES + generates: + - .databricks/databricks + cmds: + - go build -o .databricks/databricks + + snapshot-release: + desc: Build release binaries locally without uploading + deps: ['tidy-root'] + # Same as BUILD_SOURCES + .goreleaser.yaml (list concat is not expressible + # via YAML anchor alone, so the shared block is duplicated here). + sources: + - "**/*.go" + - exclude: "**/*_test.go" + - exclude: acceptance/** + - exclude: integration/** + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + - go.mod + - go.sum + - .goreleaser.yaml + generates: + - dist/** + cmds: + - goreleaser release --clean --skip docker --snapshot + + # --- Testing --- + + test: + desc: Run unit and acceptance tests + deps: + - task: test-unit + - task: test-acc + vars: + ACCEPTANCE_TEST_FILTER: "{{.ACCEPTANCE_TEST_FILTER}}" + sources: + - test-output-unit.json + - test-output-acc.json + generates: + - test-output.json + cmds: + - cat test-output-unit.json test-output-acc.json > test-output.json + + test-unit: + desc: Run unit tests across all Go modules (root, tools, codegen) + deps: ['test-unit-root', 'test-unit-tools', 'test-unit-codegen'] + sources: + - test-output-unit-root.json + - test-output-unit-tools.json + - test-output-unit-codegen.json + generates: + - test-output-unit.json + cmds: + - cat test-output-unit-root.json test-output-unit-tools.json test-output-unit-codegen.json > test-output-unit.json + + test-unit-root: + desc: Run unit tests in root module + sources: + - "**/*.go" + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + - go.mod + - go.sum + cmds: + - | + {{.GO_TOOL}} gotestsum \ + --format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \ + --no-summary=skipped \ + --jsonfile test-output-unit-root.json \ + --rerun-fails \ + --packages "{{.TEST_PACKAGES}}" \ + -- -timeout=${LOCAL_TIMEOUT:-30m} + + test-unit-tools: + desc: Run unit tests in tools/ module + dir: tools + sources: + - "**/*.go" + - go.mod + - go.sum + cmds: + - | + {{.GO_TOOL}} gotestsum \ + --format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \ + --no-summary=skipped \ + --jsonfile {{.ROOT_DIR}}/test-output-unit-tools.json \ + --rerun-fails \ + --packages ./... \ + -- -timeout=${LOCAL_TIMEOUT:-30m} + + test-unit-codegen: + desc: Run unit tests in bundle/internal/tf/codegen module + dir: bundle/internal/tf/codegen + sources: + - "**/*.go" + - go.mod + - go.sum + cmds: + - | + {{.GO_TOOL}} gotestsum \ + --format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \ + --no-summary=skipped \ + --jsonfile {{.ROOT_DIR}}/test-output-unit-codegen.json \ + --rerun-fails \ + --packages ./... \ + -- -timeout=${LOCAL_TIMEOUT:-30m} + + test-acc: + desc: Run acceptance tests + # Sources mirror `build` (acceptance_test.go builds the CLI in-process via BuildCLI) + # plus acceptance/**. For test-acc the checked-in out.* files are golden inputs: + # changing them must re-run the test. test-update* excludes out.* because they + # are outputs there — see &ACC_SOURCES_UPDATE below. + sources: + - "**/*.go" + - exclude: "**/*_test.go" + - exclude: integration/** + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + - acceptance/** + - go.mod + - go.sum + cmds: + - | + {{.GO_TOOL}} gotestsum \ + --format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \ + --no-summary=skipped \ + --jsonfile test-output-acc.json \ + --rerun-fails \ + --packages ./acceptance/... \ + -- -timeout=${LOCAL_TIMEOUT:-30m}{{if .ACCEPTANCE_TEST_FILTER}} -run "{{.ACCEPTANCE_TEST_FILTER}}"{{end}} + + test-update: + desc: Update acceptance test output (local) + # Excludes out.* because the task rewrites them; keeping them in sources would + # invalidate the checksum and force a re-run on every invocation. + sources: &ACC_SOURCES_UPDATE + - "**/*.go" + - exclude: "**/*_test.go" + - exclude: integration/** + - exclude: tools/** + - exclude: bundle/internal/tf/codegen/** + - acceptance/** + - exclude: acceptance/**/out.* + - go.mod + - go.sum + cmds: + - "go test ./acceptance -run '^TestAccept$' -update -timeout=${LOCAL_TIMEOUT:-30m}" + + test-update-templates: + desc: Update acceptance test template output + sources: *ACC_SOURCES_UPDATE + cmds: + - "go test ./acceptance -run '^TestAccept/bundle/templates' -update -timeout=${LOCAL_TIMEOUT:-30m}" + + test-update-aws: + desc: Update acceptance test output (integration, requires deco access) + sources: *ACC_SOURCES_UPDATE + cmds: + - "deco env run -i -n aws-prod-ucws -- env DATABRICKS_TEST_SKIPLOCAL=1 go test ./acceptance -run ^TestAccept$ -update -timeout=1h -v" + + test-update-all: + desc: Update all acceptance test outputs + # Sequential: both tasks overwrite the same acceptance output files. + cmds: + - task: test-update + - task: test-update-aws + + slowest: + desc: Show 50 slowest tests from last run + cmds: + - "{{.GO_TOOL}} gotestsum tool slowest --jsonfile test-output.json --threshold 1s --num 50" + + cover: + desc: Run tests with coverage + cmds: + - rm -fr ./acceptance/build/cover/ + - | + VERBOSE_TEST=1 {{.GO_TOOL}} gotestsum \ + --format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \ + --no-summary=skipped \ + --jsonfile test-output.json \ + --rerun-fails \ + --packages "{{.TEST_PACKAGES}}" \ + -- -coverprofile=coverage.txt -timeout=${LOCAL_TIMEOUT:-30m} + - | + VERBOSE_TEST=1 CLI_GOCOVERDIR=build/cover {{.GO_TOOL}} gotestsum \ + --format ${GOTESTSUM_FORMAT:-pkgname-and-test-fails} \ + --no-summary=skipped \ + --jsonfile test-output.json \ + --rerun-fails \ + --packages ./acceptance/... \ + -- -timeout=${LOCAL_TIMEOUT:-30m}{{if .ACCEPTANCE_TEST_FILTER}} -run "{{.ACCEPTANCE_TEST_FILTER}}"{{end}} + - rm -fr ./acceptance/build/cover-merged/ + - mkdir -p acceptance/build/cover-merged/ + - "go tool covdata merge -i $(printf '%s,' acceptance/build/cover/* | sed 's/,$//') -o acceptance/build/cover-merged/" + - go tool covdata textfmt -i acceptance/build/cover-merged -o coverage-acceptance.txt + + showcover: + desc: Open unit test coverage report in browser + cmds: + - go tool cover -html=coverage.txt + + showcover-acc: + desc: Open acceptance test coverage report in browser + cmds: + - go tool cover -html=coverage-acceptance.txt + + # --- Specialized test suites --- + + # The `sources:` on each test:* subproject target is the single source of truth for: + # 1. Taskfile's own checksum-based caching (skip re-run if nothing changed) + # 2. CI triggering — tools/testmask reads these sources to decide which CI jobs to run + # Keep patterns narrow and specific. Changes to files outside these paths trigger the + # generic `test` target (the catch-all) instead. + + test-exp-aitools: + desc: Run experimental aitools unit and acceptance tests + sources: + - experimental/aitools/** + - acceptance/apps/** + deps: + - task: test-unit-root + vars: + TEST_PACKAGES: ./experimental/aitools/... + - task: test-acc + vars: + ACCEPTANCE_TEST_FILTER: TestAccept/apps + cmds: + - cat test-output-unit-root.json test-output-acc.json > test-output.json + + test-exp-ssh: + desc: Run experimental SSH unit and acceptance tests + sources: + - experimental/ssh/** + - acceptance/ssh/** + deps: + - task: test-unit-root + vars: + TEST_PACKAGES: ./experimental/ssh/... + - task: test-acc + vars: + ACCEPTANCE_TEST_FILTER: TestAccept/ssh + cmds: + - cat test-output-unit-root.json test-output-acc.json > test-output.json + + test-pipelines: + desc: Run pipelines unit and acceptance tests + sources: + - cmd/pipelines/** + - acceptance/pipelines/** + deps: + - task: test-unit-root + vars: + TEST_PACKAGES: ./cmd/pipelines/... + - task: test-acc + vars: + ACCEPTANCE_TEST_FILTER: TestAccept/pipelines + cmds: + - cat test-output-unit-root.json test-output-acc.json > test-output.json + + # --- Integration tests --- + + integration: + desc: Run integration tests (requires Databricks workspace) + deps: [install-pythons] + cmds: + - | + go run -modfile=tools/go.mod ./tools/testrunner/main.go \ + {{.GO_TOOL}} gotestsum \ + --format github-actions \ + --rerun-fails \ + --jsonfile output.json \ + --packages "./acceptance ./integration/..." \ + -- -parallel 4 -timeout=2h + + integration-short: + desc: Run short integration tests + deps: [install-pythons] + cmds: + - | + DATABRICKS_TEST_SKIPLOCAL=1 VERBOSE_TEST=1 \ + go run -modfile=tools/go.mod ./tools/testrunner/main.go \ + {{.GO_TOOL}} gotestsum \ + --format github-actions \ + --rerun-fails \ + --jsonfile output.json \ + --packages "./acceptance ./integration/..." \ + -- -parallel 4 -timeout=2h -short + + dbr-integration: + desc: Run DBR acceptance tests on Databricks Runtime + deps: [install-pythons] + cmds: + - "DBR_ENABLED=true go test -v -timeout 4h -run TestDbrAcceptance$ ./acceptance" + + dbr-test: + desc: Run DBR tests via deco env (requires deco + aws-prod-ucws access) + cmds: + - "deco env run -i -n aws-prod-ucws -- ./task dbr-integration" + + # --- Code generation --- + # + # Each generator declares tight `sources:` so Task's checksum cache re-runs only + # when inputs actually change. The reflection-based generators (refschema, + # schema, schema-docs, docs, validation) pick up SDK type changes via go.mod / + # go.sum. The aggregator `generate` orchestrates all of them; individual tasks + # can be invoked standalone. + + generate: + desc: Run all generators (genkit, refschema, schema, docs, validation, direct, pydabs) + cmds: + # Runs first: regenerates CLI command stubs from the OpenAPI spec at + # .codegen/_openapi_sha. SDK version bumps (go.mod/go.sum) are a manual + # step outside this task; TestConsistentDatabricksSdkVersion (run inside + # generate-genkit) asserts the two stay in sync. + - task: generate-genkit + # Refreshes acceptance/bundle/refschema/out.fields.txt, which feeds + # generate-direct-apitypes and generate-direct-resources below. + - task: generate-refschema + - task: generate-schema + - task: generate-schema-docs + - task: generate-validation + - task: generate-docs + - task: generate-direct + - task: pydabs-codegen + + # Drives genkit from a universe checkout. Genkit writes CLI command files into + # cmd/workspace and cmd/account, refreshes .gitattributes and + # .codegen/_openapi_sha, and emits .github/workflows/tagging.yml + + # tagging.py (+ lock) in the repo root plus a next-changelog workflow we + # don't keep. Genkit does NOT modify go.mod/go.sum — SDK bumps are a manual + # `go get` step before running this task. The cmds below then post-process + # genkit's output: assert the SDK version matches the OpenAPI SHA, drop the + # next-changelog workflow, relocate tagging.py under internal/genkit/ and + # rewrite the tagging.yml workflow to match, then yamlfmt + whitespace fix + # so the tree is clean. + generate-genkit: + desc: Run genkit to generate CLI commands and tagging workflow (requires universe repo) + sources: + - .codegen/_openapi_sha + - .gitattributes.manual + vars: + UNIVERSE_DIR: + sh: echo "${UNIVERSE_DIR:-$HOME/universe}" + cmds: + - | + echo "Checking out universe at SHA: $(cat .codegen/_openapi_sha)" + cd {{.UNIVERSE_DIR}} && \ + git cat-file -e $(cat {{.ROOT_DIR}}/.codegen/_openapi_sha) 2>/dev/null || \ + (git fetch --filter=blob:none origin master && \ + git checkout $(cat {{.ROOT_DIR}}/.codegen/_openapi_sha)) + - echo "Building genkit..." + - cd {{.UNIVERSE_DIR}} && bazel build //openapi/genkit + - echo "Generating CLI code..." + - "{{.UNIVERSE_DIR}}/bazel-bin/openapi/genkit/genkit_/genkit update-sdk" + - "cat .gitattributes.manual .gitattributes > .gitattributes.tmp && mv .gitattributes.tmp .gitattributes" + - go test -timeout 240s -run TestConsistentDatabricksSdkVersion github.com/databricks/cli/internal/build + - rm .github/workflows/next-changelog.yml + - mv tagging.py internal/genkit/tagging.py + - mv tagging.py.lock internal/genkit/tagging.py.lock + - | + if [ "$(uname)" = "Darwin" ]; then + sed -i '' 's|tagging.py|internal/genkit/tagging.py|g' .github/workflows/tagging.yml + else + sed -i 's|tagging.py|internal/genkit/tagging.py|g' .github/workflows/tagging.yml + fi + - "{{.GO_TOOL}} yamlfmt .github/workflows/tagging.yml" + - task: ws-fix + + # Refreshes out.fields.txt, which records the field paths / types emitted by + # `bundle debug refschema` (see cmd/bundle/debug/refschema.go). It reflects + # over types reachable from bundle/, so any bundle change or SDK bump (go.mod + # / go.sum) can affect the output. + generate-refschema: + desc: Regenerate acceptance/bundle/refschema/out.fields.txt + sources: + - bundle/**/*.go + - exclude: bundle/**/*_test.go + - acceptance/bundle/refschema/script + - acceptance/bundle/refschema/test.toml + - go.mod + - go.sum + generates: + - acceptance/bundle/refschema/out.fields.txt + cmds: + - go test ./acceptance -run TestAccept/bundle/refschema -update &> /dev/null + + generate-schema: + desc: Generate bundle JSON schema + sources: &SCHEMA_SOURCES + - bundle/internal/schema/*.go + - exclude: bundle/internal/schema/*_test.go + - bundle/internal/schema/annotations*.yml + - bundle/config/**/*.go + - exclude: bundle/config/**/*_test.go + - libs/jsonschema/**/*.go + - exclude: libs/jsonschema/**/*_test.go + - go.mod + - go.sum + generates: + - bundle/schema/jsonschema.json + cmds: + - go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema.json + + generate-schema-docs: + desc: Generate bundle JSON schema for documentation + sources: *SCHEMA_SOURCES + generates: + - bundle/schema/jsonschema_for_docs.json + cmds: + - go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema_for_docs.json --docs + + generate-docs: + desc: Generate bundle documentation + sources: + - bundle/docsgen/*.go + - exclude: bundle/docsgen/*_test.go + - bundle/docsgen/templates/** + - bundle/internal/schema/annotations*.yml + - bundle/internal/annotation/*.go + - exclude: bundle/internal/annotation/*_test.go + - bundle/config/**/*.go + - exclude: bundle/config/**/*_test.go + - libs/jsonschema/**/*.go + - exclude: libs/jsonschema/**/*_test.go + - go.mod + - go.sum + generates: + - bundle/docsgen/output/reference.md + - bundle/docsgen/output/resources.md + cmds: + - go run ./bundle/docsgen ./bundle/internal/schema ./bundle/docsgen + + generate-validation: + desc: Generate enum and required field validation code + sources: + - bundle/internal/validation/*.go + - exclude: bundle/internal/validation/*_test.go + - bundle/config/**/*.go + - exclude: bundle/config/**/*_test.go + - libs/structs/**/*.go + - exclude: libs/structs/**/*_test.go + - go.mod + - go.sum + generates: + - bundle/internal/validation/generated/**/*.go + cmds: + - go run ./bundle/internal/validation/. + - gofmt -w -s ./bundle/internal/validation/generated + + generate-direct: + desc: Generate direct engine config (apitypes + resources) + deps: ['generate-direct-apitypes', 'generate-direct-resources'] + + generate-direct-apitypes: + desc: Generate direct engine API types YAML + deps: ['generate-openapi-json'] + sources: + - bundle/direct/tools/generate_apitypes.py + - .codegen/openapi.json + - acceptance/bundle/refschema/out.fields.txt + generates: + - bundle/direct/dresources/apitypes.generated.yml + cmds: + - > + python3 bundle/direct/tools/generate_apitypes.py + .codegen/openapi.json + acceptance/bundle/refschema/out.fields.txt + > bundle/direct/dresources/apitypes.generated.yml + + generate-direct-resources: + desc: Generate direct engine resources YAML + deps: ['generate-direct-apitypes'] + sources: + - bundle/direct/tools/generate_resources.py + - .codegen/openapi.json + - bundle/direct/dresources/apitypes.generated.yml + - bundle/direct/dresources/apitypes.yml + - acceptance/bundle/refschema/out.fields.txt + generates: + - bundle/direct/dresources/resources.generated.yml + cmds: + - > + python3 bundle/direct/tools/generate_resources.py + .codegen/openapi.json + bundle/direct/dresources/apitypes.generated.yml + bundle/direct/dresources/apitypes.yml + acceptance/bundle/refschema/out.fields.txt + > bundle/direct/dresources/resources.generated.yml + + generate-openapi-json: + desc: Download OpenAPI spec (triggered by _openapi_sha change) + sources: + - .codegen/_openapi_sha + generates: + - .codegen/openapi.json + cmds: + - "wget -O .codegen/openapi.json.tmp \"https://openapi.dev.databricks.com/$(cat .codegen/_openapi_sha)/specs/all-internal.json\" && mv .codegen/openapi.json.tmp .codegen/openapi.json" + + # --- pydabs (python/databricks-bundles package) --- + + pydabs-test: + desc: Run pydabs tests + dir: python + sources: + - "**/*.py" + cmds: + - uv run python -m pytest databricks_tests --cov=databricks.bundles --cov-report html -vv + + pydabs-lint: + desc: Run pydabs lint checks + dir: python + sources: + - "**/*.py" + - pyproject.toml + - uv.lock + cmds: + - uv lock --check + - uv run ruff check databricks databricks_tests + - uv run pyright + - uv run ruff format --diff databricks databricks_tests + + pydabs-fmt: + desc: Format pydabs code + dir: python + sources: + - "**/*.py" + cmds: + - uv run ruff check --fix databricks databricks_tests || true + - uv run ruff format + + pydabs-docs: + desc: Generate pydabs documentation + dir: python + sources: + - "**/*.py" + - docs/** + generates: + - docs/_output/** + cmds: + - uv run --python 3.12 sphinx-build docs docs/_output --show-traceback --nitpicky --fresh-env --keep-going + + pydabs-codegen: + desc: Run pydabs codegen + dir: python + sources: + - codegen/** + - databricks/** + - databricks_tests/** + generates: + - databricks/bundles/** + cmds: + - | + find databricks/bundles -type d -mindepth 1 -maxdepth 1 \ + ! -path databricks/bundles/core \ + ! -path databricks/bundles/resources \ + -exec rm -rf {} \; + - cd codegen && uv run -m pytest codegen_tests + - cd codegen && uv run -m codegen.main --output .. + - uv run ruff check --fix databricks databricks_tests || true + - uv run ruff format + + pydabs-build: + desc: Build pydabs wheel + dir: python + cmds: + - rm -rf build dist + - uv build . + + # --- Benchmarks --- + + bench-1k: + desc: Benchmark with 1000 jobs + cmds: + - 'BENCHMARK_PARAMS="--jobs 1000" go test ./acceptance -v -tail -run TestAccept/bundle/benchmarks -timeout=120m | tee bench1k.log' + + bench-100: + desc: Benchmark with 100 jobs + cmds: + - 'BENCHMARK_PARAMS="--jobs 100" go test ./acceptance -v -tail -run TestAccept/bundle/benchmarks -timeout=120m | tee bench100.log' + + bench-10: + desc: Benchmark with 10 jobs (quick) + cmds: + - 'BENCHMARK_PARAMS="--jobs 10" go test ./acceptance -v -tail -run TestAccept/bundle/benchmarks -timeout=120m | tee bench10.log' + + bench-1k-summary: + desc: Run 1k benchmark and print summary + cmds: + - task: bench-1k + - ./tools/bench_parse.py bench1k.log + + bench-100-summary: + desc: Run 100 benchmark and print summary + cmds: + - task: bench-100 + - ./tools/bench_parse.py bench100.log + + bench-10-summary: + desc: Run 10 benchmark and print summary + cmds: + - task: bench-10 + - ./tools/bench_parse.py bench10.log diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 7b8cf95258..5e28108532 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -1473,9 +1473,11 @@ func prepareWheelBuildDirectory(t *testing.T, dir string) string { } func BuildYamlfmt(t *testing.T) { - // Using make here instead of "go build" directly cause it's faster when it's already built args := []string{ - "make", "-s", "tools/yamlfmt" + exeSuffix, + "go", "build", + "-modfile=tools/go.mod", + "-o", "tools/yamlfmt" + exeSuffix, + "github.com/google/yamlfmt/cmd/yamlfmt", } RunCommand(t, args, "..", []string{}) } diff --git a/bundle/docsgen/README.md b/bundle/docsgen/README.md index 220a14c1c9..0468945dc7 100644 --- a/bundle/docsgen/README.md +++ b/bundle/docsgen/README.md @@ -1,14 +1,14 @@ ## docs-autogen 1. Install [Golang](https://go.dev/doc/install) -2. Run `make docs` from the repo +2. Run `./task generate-docs` from the repo 3. See generated documents in `./bundle/docsgen/output` directory -4. To change descriptions update content in `./bundle/internal/schema/annotations.yml` or `./bundle/internal/schema/annotations_openapi_overrides.yml` and re-run `make docs` +4. To change descriptions update content in `./bundle/internal/schema/annotations.yml` or `./bundle/internal/schema/annotations_openapi_overrides.yml` and re-run `./task generate-docs` For simpler usage run it together with copy command to move resulting files to local `docs` repo. Note that it will overwrite any local changes in affected files. Example: ``` -make docs && cp bundle/docgen/output/*.md ../docs/source/dev-tools/bundles +task generate-docs && cp bundle/docgen/output/*.md ../docs/source/dev-tools/bundles ``` To change intro sections for files update them in `templates/` directory @@ -76,4 +76,4 @@ github.com/databricks/cli/bundle/config.Bundle: ### TODO -Add file watcher to track changes in the annotation files and re-run `make docs` script automtically +Add file watcher to track changes in the annotation files and re-run `./task generate-docs` script automtically diff --git a/bundle/internal/schema/main_test.go b/bundle/internal/schema/main_test.go index 1b655d2e16..e9421e4c6e 100644 --- a/bundle/internal/schema/main_test.go +++ b/bundle/internal/schema/main_test.go @@ -43,9 +43,9 @@ func copyFile(src, dst string) error { // Checks whether descriptions are added for new config fields in the annotations.yml file // If this test fails either manually add descriptions to the `annotations.yml` or do the following: // 1. for fields described outside of CLI package fetch latest schema from the OpenAPI spec and add path to file to DATABRICKS_OPENAPI_SPEC env variable -// 2. run `make schema` from the repository root to add placeholder descriptions +// 2. run `./task generate-schema` from the repository root to add placeholder descriptions // 2. replace all "PLACEHOLDER" values with the actual descriptions if possible -// 3. run `make schema` again to regenerate the schema with acutal descriptions +// 3. run `./task generate-schema` again to regenerate the schema with acutal descriptions func TestRequiredAnnotationsForNewFields(t *testing.T) { workdir := t.TempDir() annotationsPath := path.Join(workdir, "annotations.yml") diff --git a/python/Makefile b/python/Makefile deleted file mode 100644 index be0fe664c0..0000000000 --- a/python/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -sources = databricks databricks_tests - -fmt: - uv run ruff check --fix $(sources) || true - uv run ruff format - -docs: - # Python 3.12+ is needed for get_overloads - uv run --python 3.12 sphinx-build docs docs/_output --show-traceback --nitpicky --fresh-env --keep-going - -lint: - # check if lock matches the project metadata - uv lock --check - - uv run ruff check $(sources) - uv run pyright - uv run ruff format --diff - -codegen: - find databricks/bundles -type d -mindepth 1 -maxdepth 1 \ - ! -path databricks/bundles/core \ - ! -path databricks/bundles/resources \ - -exec rm -rf {} \; - - cd codegen; uv run -m pytest codegen_tests - cd codegen; uv run -m codegen.main --output .. - - uv run ruff check --fix $(sources) || true - uv run ruff format - -test: - uv run python -m pytest databricks_tests --cov=databricks.bundles --cov-report html -vv - -build: - rm -rf build dist - uv build . - -.PHONY: fmt docs lint codegen test build diff --git a/task b/task new file mode 100755 index 0000000000..a0f8232ee3 --- /dev/null +++ b/task @@ -0,0 +1,2 @@ +#!/bin/sh +exec go tool -modfile="$(dirname "$0")/tools/task/go.mod" task "$@" diff --git a/tools/go.mod b/tools/go.mod index 7dfc7a4ef4..fdb567331a 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -6,6 +6,8 @@ toolchain go1.25.9 require github.com/stretchr/testify v1.11.1 +require gopkg.in/yaml.v3 v3.0.1 + require ( 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect 4d63.com/gochecknoglobals v0.2.2 // indirect @@ -215,7 +217,6 @@ require ( google.golang.org/protobuf v1.36.6 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/gotestsum v1.12.1 // indirect honnef.co/go/tools v0.6.1 // indirect mvdan.cc/gofumpt v0.9.1 // indirect diff --git a/tools/lintdiff.py b/tools/lintdiff.py index 77b9ee6f51..aded17a285 100755 --- a/tools/lintdiff.py +++ b/tools/lintdiff.py @@ -13,6 +13,8 @@ import argparse import subprocess +NESTED_MODULES = ("bundle/internal/tf/codegen", "tools") + def parse_lines(cmd): # print("+ " + " ".join(cmd), file=sys.stderr, flush=True) @@ -52,7 +54,16 @@ def main(): cmd = args.args[:] + # `golangci-lint run` typechecks against the target go.mod and errors on + # paths under a different module; `fmt` walks the filesystem and is + # cross-module safe. Apply the nested-module filter only for `run`. + filter_nested = "run" in cmd + if changed is not None: + + def in_nested_module(path): + return filter_nested and any(path == m or path.startswith(m + "/") for m in NESTED_MODULES) + # We need to pass packages to golangci-lint, not individual files. # QQQ for lint we should also pass all dependent packages dirs = set() @@ -61,6 +72,8 @@ def main(): continue if filename.endswith(".go"): d = os.path.dirname(filename) + if in_nested_module(d): + continue dirs.add(d) dirs = ["./" + d for d in sorted(dirs) if os.path.exists(d)] diff --git a/tools/post-generate.sh b/tools/post-generate.sh deleted file mode 100755 index 4d65b70a35..0000000000 --- a/tools/post-generate.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -# Ensure the SDK version is consistent with the OpenAPI SHA the CLI is generated from. -go test -timeout 240s -run TestConsistentDatabricksSdkVersion github.com/databricks/cli/internal/build - -# Generate the bundle JSON schema. -make schema - -# Fetch version tags (required for make schema-for-docs). -git fetch origin 'refs/tags/v*:refs/tags/v*' - -make schema-for-docs - -# Generate bundle validation code for enuma and required fields. -make generate-validation - -# Remove the next-changelog.yml workflow. -rm .github/workflows/next-changelog.yml - -# Move the tagging.py file and its lock file to internal/genkit/. We do this to -# avoid cluttering the root directory. The lock file must stay next to tagging.py -# for `uv run --locked` to work in the tagging workflow. -mv tagging.py internal/genkit/tagging.py -mv tagging.py.lock internal/genkit/tagging.py.lock - -# Update the tagging.yml workflow to use the new tagging.py file location. -# The genkit generates "uv run --locked tagging.py", we need to rewrite it -# to point at the moved location. -if [[ "$(uname)" == "Darwin" ]]; then - # macOS (BSD sed) requires empty string after -i - sed -i '' 's|tagging.py|internal/genkit/tagging.py|g' .github/workflows/tagging.yml -else - # Linux (GNU sed) - sed -i 's|tagging.py|internal/genkit/tagging.py|g' .github/workflows/tagging.yml -fi -go tool -modfile=tools/go.mod yamlfmt .github/workflows/tagging.yml - -# Generate PyDABs code. -make -C python codegen - -# Fix whitespace issues in the generated code. -make wsfix diff --git a/tools/task/go.mod b/tools/task/go.mod new file mode 100644 index 0000000000..1b9ef1ced6 --- /dev/null +++ b/tools/task/go.mod @@ -0,0 +1,137 @@ +module github.com/databricks/cli/tools/task + +go 1.25.0 + +toolchain go1.25.9 + +require ( + cel.dev/expr v0.24.0 // indirect + charm.land/bubbles/v2 v2.0.0 // indirect + charm.land/bubbletea/v2 v2.0.1 // indirect + charm.land/lipgloss/v2 v2.0.0 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.17.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.5.3 // indirect + cloud.google.com/go/monitoring v1.24.2 // indirect + cloud.google.com/go/storage v1.58.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect + github.com/Ladicle/tabwriter v1.0.0 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/alecthomas/chroma/v2 v2.23.1 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.6 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect + github.com/aws/smithy-go v1.24.0 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chainguard-dev/git-urls v1.0.2 // indirect + github.com/charmbracelet/colorprofile v0.4.2 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect + github.com/charmbracelet/x/ansi v0.11.6 // indirect + github.com/charmbracelet/x/term v0.2.2 // indirect + github.com/charmbracelet/x/termios v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.2.2 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/dominikbraun/graph v0.23.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/go-task/task/v3 v3.49.1 // indirect + github.com/go-task/template v0.2.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect + github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.8.4 // indirect + github.com/hashicorp/go-version v1.8.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.20 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sajari/fuzzy v1.0.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.11.1 // indirect + github.com/u-root/u-root v0.15.1-0.20251208185023-2f8c7e763cf8 // indirect + github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect + github.com/ulikunitz/xz v0.5.15 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/zeebo/errs v1.4.0 // indirect + github.com/zeebo/xxh3 v1.1.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/time v0.14.0 // indirect + google.golang.org/api v0.256.0 // indirect + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/grpc v1.76.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997 // indirect + mvdan.cc/sh/v3 v3.12.1-0.20260124232039-e74afc18e65b // indirect +) + +tool github.com/go-task/task/v3/cmd/task diff --git a/tools/task/go.sum b/tools/task/go.sum new file mode 100644 index 0000000000..febb778ef7 --- /dev/null +++ b/tools/task/go.sum @@ -0,0 +1,309 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s= +charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI= +charm.land/bubbletea/v2 v2.0.1 h1:B8e9zzK7x9JJ+XvHGF4xnYu9Xa0E0y0MyggY6dbaCfQ= +charm.land/bubbletea/v2 v2.0.1/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= +charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo= +charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= +cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= +cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E= +cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/storage v1.58.0 h1:PflFXlmFJjG/nBeR9B7pKddLQWaFaRWx4uUi/LyNxxo= +cloud.google.com/go/storage v1.58.0/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= +cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= +cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg= +github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= +github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= +github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= +github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= +github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= +github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8= +github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE= +github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= +github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= +github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= +github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM= +github.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ= +github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= +github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY= +github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8= +github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA= +github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98= +github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= +github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= +github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= +github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= +github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= +github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= +github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= +github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= +github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= +github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elliotchance/orderedmap/v3 v3.1.0 h1:j4DJ5ObEmMBt/lcwIecKcoRxIQUEnw0L804lXYDt/pg= +github.com/elliotchance/orderedmap/v3 v3.1.0/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-task/task/v3 v3.49.1 h1:OR9WXLzliHXfrXl21sGLk4l45Rk6hGDJ1W7MhkioG+Y= +github.com/go-task/task/v3 v3.49.1/go.mod h1:5E84IeThhWRK9ksT1D7jQNtu+bvmYVkfJVlXHz3bD0A= +github.com/go-task/template v0.2.0 h1:xW7ek0o65FUSTbKcSNeg2Vyf/I7wYXFgLUznptvviBE= +github.com/go-task/template v0.2.0/go.mod h1:dbdoUb6qKnHQi1y6o+IdIrs0J4o/SEhSTA6bbzZmdtc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 h1:0HADrxxqaQkGycO1JoUUA+B4FnIkuo8d2bz/hSaTFFQ= +github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70/go.mod h1:fm2FdDCzJdtbXF7WKAMvBb5NEPouXPHFbGNYs9ShFns= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.8.4 h1:hGEd2xsuVKgwkMtPVufq73fAmZU/x65PPcqH3cb0D9A= +github.com/hashicorp/go-getter v1.8.4/go.mod h1:x27pPGSg9kzoB147QXI8d/nDvp2IgYGcwuRjpaXE9Yg= +github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= +github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= +github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v4 v4.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo= +github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= +github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo= +github.com/sebdah/goldie/v2 v2.8.0 h1:dZb9wR8q5++oplmEiJT+U/5KyotVD+HNGCAc5gNr8rc= +github.com/sebdah/goldie/v2 v2.8.0/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/u-root/u-root v0.15.1-0.20251208185023-2f8c7e763cf8 h1:cq+DjLAjz3ZPwh0+G571O/jMH0c0DzReDPLjQGL2/BA= +github.com/u-root/u-root v0.15.1-0.20251208185023-2f8c7e763cf8/go.mod h1:JNauIV2zopCBv/6o+umxcT3bKe8YUqYJaTZQYSYpKss= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= +golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.256.0 h1:u6Khm8+F9sxbCTYNoBHg6/Hwv0N/i+V94MvkOSor6oI= +google.golang.org/api v0.256.0/go.mod h1:KIgPhksXADEKJlnEoRa9qAII4rXcy40vfI8HRqcU964= +google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 h1:LvZVVaPE0JSqL+ZWb6ErZfnEOKIqqFWUJE2D0fObSmc= +google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9/go.mod h1:QFOrLhdAe2PsTp3vQY4quuLKTi9j3XG3r6JPPaw7MSc= +google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= +google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= +google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997 h1:3bbJwtPFh98dJ6lxRdR3eLHTH1CmR3BcU6TriIMiXjE= +mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997/go.mod h1:Qy/zdaMDxq9sT72Gi43K3gsV+TtTohyDO3f1cyBVwuo= +mvdan.cc/sh/v3 v3.12.1-0.20260124232039-e74afc18e65b h1:PUPnLxbDzRO9kg/03l7TZk7+ywTv7FxmOhDHOtOdOtk= +mvdan.cc/sh/v3 v3.12.1-0.20260124232039-e74afc18e65b/go.mod h1:mencVHx2sy9XZG5wJbCA9nRUOE3zvMtoRXOmXMxH7sc= diff --git a/tools/testmask/git.go b/tools/testmask/git.go index 23c2592361..f803da4b38 100644 --- a/tools/testmask/git.go +++ b/tools/testmask/git.go @@ -23,3 +23,12 @@ func GetChangedFiles(headRef, baseRef string) ([]string, error) { return lines, nil } + +// GitRepoRoot returns the absolute path to the top-level directory of the git repo. +func GitRepoRoot() (string, error) { + output, err := exec.Command("git", "rev-parse", "--show-toplevel").Output() + if err != nil { + return "", fmt.Errorf("failed to find git repo root: %w", err) + } + return strings.TrimSpace(string(output)), nil +} diff --git a/tools/testmask/git_test.go b/tools/testmask/git_test.go index b62e9885ec..abf0bd1ba3 100644 --- a/tools/testmask/git_test.go +++ b/tools/testmask/git_test.go @@ -4,6 +4,11 @@ import ( "testing" ) +// gitEmptyTreeSHA is the well-known SHA of the empty tree object. Git resolves +// it without requiring a commit to reference it, so diffing against it works +// even on shallow clones where HEAD~N is unavailable (as in CI). +const gitEmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" + func TestGetChangedFiles(t *testing.T) { // Test with HEAD to HEAD - should return empty list result, err := GetChangedFiles("HEAD", "HEAD") @@ -15,8 +20,8 @@ func TestGetChangedFiles(t *testing.T) { t.Errorf("expected empty list, got %q", result) } - // Test with HEAD to HEAD~2 - should produce non-empty result if there are commits - result, err = GetChangedFiles("HEAD", "HEAD~2") + // Test against the empty tree - should produce non-empty result (all files in HEAD) + result, err = GetChangedFiles("HEAD", gitEmptyTreeSHA) if err != nil { t.Errorf("unable to run git: %q", err) return diff --git a/tools/testmask/main.go b/tools/testmask/main.go index 6ef68df36a..dd71cbee5f 100644 --- a/tools/testmask/main.go +++ b/tools/testmask/main.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" ) func main() { @@ -17,13 +18,25 @@ func main() { headRef := os.Args[1] baseRef := os.Args[2] + repoRoot, err := GitRepoRoot() + if err != nil { + fmt.Fprintf(os.Stderr, "Error finding repo root: %v\n", err) + os.Exit(1) + } + + mappings, err := LoadTargetMappings(filepath.Join(repoRoot, "Taskfile.yml")) + if err != nil { + fmt.Fprintf(os.Stderr, "Error loading target mappings: %v\n", err) + os.Exit(1) + } + changedFiles, err := GetChangedFiles(headRef, baseRef) if err != nil { fmt.Fprintf(os.Stderr, "Error getting changed files: %v\n", err) os.Exit(1) } - targets := GetTargets(changedFiles) + targets := GetTargets(changedFiles, mappings) err = json.NewEncoder(os.Stdout).Encode(targets) if err != nil { fmt.Fprintf(os.Stderr, "Error encoding targets: %v\n", err) diff --git a/tools/testmask/targets.go b/tools/testmask/targets.go index f4566ea7d4..35d8bbcfc7 100644 --- a/tools/testmask/targets.go +++ b/tools/testmask/targets.go @@ -1,14 +1,21 @@ package main import ( + "fmt" "maps" + "os" "slices" "strings" + + "gopkg.in/yaml.v3" ) -type targetMapping struct { - prefixes []string - target string +// ciTargets lists the Taskfile task names whose `sources:` define the +// trigger set for their corresponding CI job of the same name. +var ciTargets = []string{ + "test-exp-aitools", + "test-exp-ssh", + "test-pipelines", } // commonTriggerPatterns lists patterns that trigger all test targets. @@ -18,44 +25,76 @@ var commonTriggerPatterns = []string{ ".github/actions/setup-build-environment/", } -var fileTargetMappings = []targetMapping{ - { - prefixes: slices.Concat(commonTriggerPatterns, []string{ - // Specify files that match targets below and should still trigger the "test" target. - }), - target: "test", - }, - { - prefixes: slices.Concat(commonTriggerPatterns, []string{ - "experimental/aitools/", - }), - target: "test-exp-aitools", - }, - { - prefixes: slices.Concat(commonTriggerPatterns, []string{ - "experimental/ssh/", - "acceptance/ssh/", - }), - target: "test-exp-ssh", - }, - { - prefixes: slices.Concat(commonTriggerPatterns, []string{ - "cmd/pipelines/", - "acceptance/pipelines/", - }), - target: "test-pipelines", - }, +type targetMapping struct { + prefixes []string + target string +} + +type taskfile struct { + Tasks map[string]taskfileTask `yaml:"tasks"` +} + +// Sources uses []any to tolerate non-string entries (e.g. `- exclude: tools/**`) +// that appear on other tasks in Taskfile.yml. We only care about string globs; +// map entries are skipped in LoadTargetMappings. +type taskfileTask struct { + Sources []any `yaml:"sources"` +} + +// LoadTargetMappings reads Taskfile.yml and builds target mappings for CI tasks +// by extracting `sources:` from each task listed in ciTargets. +func LoadTargetMappings(taskfilePath string) ([]targetMapping, error) { + data, err := os.ReadFile(taskfilePath) + if err != nil { + return nil, fmt.Errorf("read %s: %w", taskfilePath, err) + } + var tf taskfile + if err := yaml.Unmarshal(data, &tf); err != nil { + return nil, fmt.Errorf("parse %s: %w", taskfilePath, err) + } + + mappings := []targetMapping{ + {prefixes: slices.Clone(commonTriggerPatterns), target: "test"}, + } + for _, name := range ciTargets { + t, ok := tf.Tasks[name] + if !ok { + return nil, fmt.Errorf("task %q not found in %s", name, taskfilePath) + } + if len(t.Sources) == 0 { + return nil, fmt.Errorf("task %q in %s has no sources", name, taskfilePath) + } + prefixes := slices.Clone(commonTriggerPatterns) + for _, src := range t.Sources { + s, ok := src.(string) + if !ok { + continue + } + prefixes = append(prefixes, sourceToPrefix(s)) + } + mappings = append(mappings, targetMapping{prefixes: prefixes, target: name}) + } + return mappings, nil +} + +// sourceToPrefix converts a Taskfile source glob like "dir/**" into a prefix +// suitable for strings.HasPrefix matching ("dir/"). +func sourceToPrefix(src string) string { + src = strings.TrimSuffix(src, "/**") + if !strings.HasSuffix(src, "/") { + src += "/" + } + return src } // GetTargets matches files to targets based on patterns and returns the matched targets. -func GetTargets(files []string) []string { +func GetTargets(files []string, mappings []targetMapping) []string { targetSet := make(map[string]bool) unmatchedFiles := []string{} for _, file := range files { - // Check all mappings for this file (a file can match multiple targets). matched := false - for _, mapping := range fileTargetMappings { + for _, mapping := range mappings { for _, prefix := range mapping.prefixes { if strings.HasPrefix(file, prefix) { targetSet[mapping.target] = true @@ -69,12 +108,10 @@ func GetTargets(files []string) []string { } } - // If there are unmatched files, add the "test" target to run all tests. if len(unmatchedFiles) > 0 { targetSet["test"] = true } - // If there are no targets, add the "test" target to run all tests. if len(targetSet) == 0 { return []string{"test"} } diff --git a/tools/testmask/targets_test.go b/tools/testmask/targets_test.go index 4ca347fb37..fe248d8d41 100644 --- a/tools/testmask/targets_test.go +++ b/tools/testmask/targets_test.go @@ -1,9 +1,6 @@ package main import ( - "os" - "regexp" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -11,6 +8,9 @@ import ( ) func TestGetTargets(t *testing.T) { + mappings, err := LoadTargetMappings("../../Taskfile.yml") + require.NoError(t, err) + tests := []struct { name string files []string @@ -31,6 +31,13 @@ func TestGetTargets(t *testing.T) { }, targets: []string{"test-pipelines"}, }, + { + name: "acceptance_apps_triggers_aitools", + files: []string{ + "acceptance/apps/basic/script", + }, + targets: []string{"test-exp-aitools"}, + }, { name: "non_matching", files: []string{ @@ -77,54 +84,13 @@ func TestGetTargets(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - targets := GetTargets(tt.files) + targets := GetTargets(tt.files, mappings) assert.Equal(t, tt.targets, targets) }) } } -func TestTargetsExistInMakefile(t *testing.T) { - // Collect all targets from fileTargetMappings - expectedTargets := make(map[string]bool) - for _, mapping := range fileTargetMappings { - expectedTargets[mapping.target] = true - } - - // Also include "test" since it's used in GetTargets - expectedTargets["test"] = true - - // Read and parse Makefile to extract target names - makefileTargets := parseMakefileTargets(t, "../../Makefile") - - // Verify all expected targets exist in Makefile - var missingTargets []string - for target := range expectedTargets { - if !makefileTargets[target] { - missingTargets = append(missingTargets, target) - } - } - - if len(missingTargets) > 0 { - t.Errorf("The following targets are defined in targets.go but do not exist in Makefile: %v", missingTargets) - } -} - -// parseMakefileTargets parses a Makefile and returns a set of target names -func parseMakefileTargets(t *testing.T, makefilePath string) map[string]bool { - targets := make(map[string]bool) - targetRegex := regexp.MustCompile(`^([a-zA-Z0-9_-]+):`) - - content, err := os.ReadFile(makefilePath) - require.NoError(t, err) - - lines := strings.Split(string(content), "\n") - for _, line := range lines { - // Match Makefile target pattern: target: - matches := targetRegex.FindStringSubmatch(line) - if len(matches) > 1 { - targets[matches[1]] = true - } - } - - return targets +func TestLoadTargetMappingsMissingFile(t *testing.T) { + _, err := LoadTargetMappings("nonexistent.yml") + assert.Error(t, err) }