diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c46743f1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Unified diff context lines contain a required single-space prefix. +third_party/rules_go_orchestrion/patches/**/0001-full-delta.patch whitespace=-blank-at-eol,-blank-at-eof diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ab38611..59ee9e34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,8 @@ env: # the current default tracer pin exercised by that fixture. GO_VERSION: "1.25.0" PYTHON_VERSION: "3.11" + BAZELISK_VERSION: "1.28.1" + BAZELISK_SHA256_LINUX_AMD64: "22e7d3a188699982f661cf4687137ee52d1f24fec1ec893d91a6c4d791a75de8" BUILDIFIER_VERSION: "8.2.1" BUILDIFIER_SHA256_LINUX_AMD64: "6ceb7b0ab7cf66fceccc56a027d21d9cc557a7f34af37d2101edb56b92fcfa1a" @@ -39,6 +41,8 @@ jobs: runs-on: ubuntu-latest outputs: docs_only: ${{ steps.classify.outputs.docs_only }} + rules_go_integration_matrix: ${{ steps.rules_go_matrix.outputs.integration_matrix }} + rules_go_upstreams: ${{ steps.rules_go_matrix.outputs.upstreams }} run_full_ci: ${{ steps.classify.outputs.run_full_ci }} steps: - name: Checkout @@ -46,6 +50,11 @@ jobs: with: fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Classify changed files id: classify shell: bash @@ -77,6 +86,14 @@ jobs: echo "${line}" >> "${GITHUB_OUTPUT}" done < <(./tools/dev/classify_ci_changes.sh "${base_sha}" "${head_sha}") + - name: Generate rules_go CI matrices + id: rules_go_matrix + shell: bash + run: | + python3 tools/dev/materialize_rules_go_fork.py list-upstreams | + python3 -c 'import json, sys; upstreams = [line.strip() for line in sys.stdin if line.strip()]; assert upstreams, "no rules_go upstreams found"; print("upstreams=" + json.dumps(upstreams, separators=(",", ":"))); print("integration_matrix=" + json.dumps({"upstream": upstreams, "module_system": ["workspace", "bzlmod"]}, separators=(",", ":")))' \ + >> "${GITHUB_OUTPUT}" + bazel-tests: needs: changes if: ${{ needs.changes.outputs.run_full_ci == 'true' }} @@ -84,7 +101,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - name: Checkout @@ -109,9 +126,119 @@ jobs: shell: bash run: ./bazelw test //tools/... --test_output=errors - - name: Run Bazel tests (go companion module) - if: matrix.os == 'ubuntu-latest' + - name: Build examples + timeout-minutes: 20 + shell: bash + run: | + if [[ "${{ runner.os }}" == "Windows" ]]; then + # Ubuntu and macOS build the full example matrix, including Go. + # Keep Windows coverage on the non-Go examples until the vendored + # rules_go Orchestrion stdlib action is stable there. + ./bazelw --output_user_root=C:/b build \ + -- \ + //examples/... \ + -//examples/single_service/src/go-project/... \ + -//examples/multi_service/src/go-project/... + else + ./bazelw build //examples/... + fi + + - name: Test examples + timeout-minutes: 20 + shell: bash + # --enable_runfiles is required on Windows so the dd_topt_java_test + # example can resolve -javaagent via $(rootpath); no-op on Linux/macOS. + run: | + if [[ "${{ runner.os }}" == "Windows" ]]; then + ./bazelw --output_user_root=C:/b test \ + --enable_runfiles \ + --test_output=errors \ + -- \ + //examples/... \ + -//examples/single_service/src/go-project/... \ + -//examples/multi_service/src/go-project/... + else + ./bazelw test //examples/... --test_output=errors + fi + + - name: Exercise single-service runtests script (dry-run) + shell: bash + # Keep CI deterministic and secret-free: this validates script wiring + # and command construction without requiring live Datadog credentials. + run: RUNTESTS_DRY_RUN=1 bash ./examples/single_service/runtests.sh + + - name: Exercise multi-service runtests script (dry-run) + shell: bash + # Keep CI deterministic and secret-free: this validates script wiring + # and command construction without requiring live Datadog credentials. + run: RUNTESTS_DRY_RUN=1 bash ./examples/multi_service/runtests.sh + + - name: Exercise example PowerShell runtests scripts (dry-run) + if: runner.os == 'Windows' + shell: pwsh + run: | + $env:RUNTESTS_DRY_RUN = "1" + foreach ($script in @( + "./examples/single_service/runtests.ps1", + "./examples/multi_service/runtests.ps1" + )) { + & $script + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + } + + - name: Ensure jq is available (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + if (Get-Command jq -ErrorAction SilentlyContinue) { + jq --version + exit 0 + } + choco install jq --no-progress -y + jq --version + + # Runs the same integration harness on Windows. + - name: Run mock server integration tests (Windows) + if: runner.os == 'Windows' + timeout-minutes: 15 + shell: pwsh + run: ./tools/tests/integration/run_mock_server_tests.ps1 + + - name: Validate enabled manifest sync and runtime paths (Windows) + if: runner.os == 'Windows' timeout-minutes: 10 + shell: pwsh + run: python tools/tests/integration/run_manifest_sync_tests.py --mode windows-enabled-smoke + + bazel-tests-ubuntu-main: + needs: changes + if: ${{ needs.changes.outputs.run_full_ci == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + # Fresh-run policy: keep this lane intentionally cacheless so every CI run + # re-evaluates repository rules from scratch. + # Guardrail: do not add Bazel cache steps (actions/cache, disk cache, + # remote cache) here without explicit maintainer approval. + - name: Run Bazel tests + shell: bash + run: ./bazelw test //tools/... --test_output=errors + + - name: Run Bazel tests (go companion module) shell: bash run: | ( @@ -121,8 +248,6 @@ jobs: ) - name: Run Bazel tests (python companion module) - if: matrix.os == 'ubuntu-latest' - timeout-minutes: 10 shell: bash run: | ( @@ -132,8 +257,6 @@ jobs: ) - name: Run Bazel tests (java companion module) - if: matrix.os == 'ubuntu-latest' - timeout-minutes: 10 shell: bash run: | ( @@ -143,8 +266,6 @@ jobs: ) - name: Run Bazel tests (nodejs companion module) - if: matrix.os == 'ubuntu-latest' - timeout-minutes: 10 shell: bash run: | ( @@ -154,8 +275,6 @@ jobs: ) - name: Run Bazel tests (dotnet companion module) - if: matrix.os == 'ubuntu-latest' - timeout-minutes: 10 shell: bash run: | ( @@ -165,8 +284,6 @@ jobs: ) - name: Run Bazel tests (ruby companion module) - if: matrix.os == 'ubuntu-latest' - timeout-minutes: 10 shell: bash run: | ( @@ -176,87 +293,95 @@ jobs: ) - name: Build examples - timeout-minutes: 20 shell: bash - run: | - if [[ "${{ runner.os }}" == "Windows" ]]; then - # Linux/macOS already build the full example matrix, including Go. - # Keep Windows coverage on the non-Go examples until the vendored - # rules_go Orchestrion stdlib action is stable there. - ./bazelw --output_user_root=C:/b build \ - -- \ - //examples/... \ - -//examples/single_service/src/go-project/... \ - -//examples/multi_service/src/go-project/... - else - ./bazelw build //examples/... - fi + run: ./bazelw build //examples/... - name: Test examples - timeout-minutes: 20 shell: bash - # --enable_runfiles is required on Windows so the dd_topt_java_test - # example can resolve -javaagent via $(rootpath); no-op on Linux/macOS. - run: | - if [[ "${{ runner.os }}" == "Windows" ]]; then - ./bazelw --output_user_root=C:/b test \ - --enable_runfiles \ - --test_output=errors \ - -- \ - //examples/... \ - -//examples/single_service/src/go-project/... \ - -//examples/multi_service/src/go-project/... - else - ./bazelw test //examples/... --test_output=errors - fi + run: ./bazelw test //examples/... --test_output=errors - name: Exercise single-service runtests script (dry-run) shell: bash - # Keep CI deterministic and secret-free: this validates script wiring - # and command construction without requiring live Datadog credentials. run: RUNTESTS_DRY_RUN=1 bash ./examples/single_service/runtests.sh - name: Exercise multi-service runtests script (dry-run) shell: bash - # Keep CI deterministic and secret-free: this validates script wiring - # and command construction without requiring live Datadog credentials. run: RUNTESTS_DRY_RUN=1 bash ./examples/multi_service/runtests.sh - # Exercises the uploader end-to-end against a local mock server. - - name: Run mock server integration tests (Linux) - if: runner.os == 'Linux' - # The guided Orchestrion bootstrap coverage in this harness now performs - # a full cold-start bootstrap before the mocked runtime assertions. Keep - # this lane bounded, but give it enough headroom to finish on slower - # GitHub-hosted Linux runners. - timeout-minutes: 30 + bazel-tests-ubuntu-mock-server: + needs: changes + if: ${{ needs.changes.outputs.run_full_ci == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + # The harness owns isolated output bases, so it does not benefit from the + # Bazel state created by the main Ubuntu lane. + - name: Run mock server integration tests shell: bash run: ./tools/tests/integration/run_mock_server_tests.sh - - name: Ensure jq is available (Windows) - if: runner.os == 'Windows' - shell: pwsh + - name: Run manifest sync and cache isolation integration + shell: bash + run: python3 tools/tests/integration/run_manifest_sync_tests.py --mode full + + bazel-tests-ubuntu: + name: bazel-tests (ubuntu-latest) + needs: + - changes + - bazel-tests-ubuntu-main + - bazel-tests-ubuntu-mock-server + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Require successful Ubuntu Bazel test shards + shell: bash + env: + CHANGES_RESULT: ${{ needs.changes.result }} + MAIN_RESULT: ${{ needs.bazel-tests-ubuntu-main.result }} + MOCK_SERVER_RESULT: ${{ needs.bazel-tests-ubuntu-mock-server.result }} + RUN_FULL_CI: ${{ needs.changes.outputs.run_full_ci }} run: | - if (Get-Command jq -ErrorAction SilentlyContinue) { - jq --version + if [[ "${CHANGES_RESULT}" != "success" ]]; then + echo "Change classification did not succeed: ${CHANGES_RESULT}" >&2 + exit 1 + fi + + if [[ "${RUN_FULL_CI}" != "true" ]]; then + echo "Ubuntu Bazel tests are not required for this change." exit 0 - } - choco install jq --no-progress -y - jq --version + fi - # Runs the same integration harness on Windows. - - name: Run mock server integration tests (Windows) - if: runner.os == 'Windows' - timeout-minutes: 15 - shell: pwsh - run: ./tools/tests/integration/run_mock_server_tests.ps1 + if [[ "${MAIN_RESULT}" != "success" ]]; then + echo "The main Ubuntu Bazel test shard did not succeed: ${MAIN_RESULT}" >&2 + exit 1 + fi - rules-go-variant-smoke: + if [[ "${MOCK_SERVER_RESULT}" != "success" ]]; then + echo "The Ubuntu mock-server shard did not succeed: ${MOCK_SERVER_RESULT}" >&2 + exit 1 + fi + + rules-go-variant-smoke-shard: + name: rules-go-variant-smoke-shard (${{ matrix.upstream }}) needs: changes if: ${{ needs.changes.outputs.run_full_ci == 'true' }} - # This job runs the smoke harness serially for every supported upstream. - # Keep enough headroom as the registry grows. - timeout-minutes: 75 + strategy: + fail-fast: false + max-parallel: 4 + matrix: + upstream: ${{ fromJSON(needs.changes.outputs.rules_go_upstreams) }} runs-on: ubuntu-latest steps: - name: Checkout @@ -285,18 +410,276 @@ jobs: - name: Run vendored rules_go smoke coverage shell: bash + env: + RULES_GO_UPSTREAM: ${{ matrix.upstream }} + RULES_GO_VARIANT: base + run: ./tools/dev/run_rules_go_variant_smoke.sh + + rules-go-variant-smoke: + needs: + - changes + - rules-go-variant-smoke-shard + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Require successful rules_go variant smoke shards + shell: bash + env: + CHANGES_RESULT: ${{ needs.changes.result }} + RUN_FULL_CI: ${{ needs.changes.outputs.run_full_ci }} + SHARD_RESULT: ${{ needs.rules-go-variant-smoke-shard.result }} + run: | + if [[ "${CHANGES_RESULT}" != "success" ]]; then + echo "Change classification did not succeed: ${CHANGES_RESULT}" >&2 + exit 1 + fi + + if [[ "${RUN_FULL_CI}" != "true" ]]; then + echo "rules_go variant smoke coverage is not required for this change." + exit 0 + fi + + if [[ "${SHARD_RESULT}" != "success" ]]; then + echo "One or more rules_go variant smoke shards did not succeed: ${SHARD_RESULT}" >&2 + exit 1 + fi + + workspace-compat-shard: + name: workspace-compat-shard (${{ matrix.upstream }}, ${{ matrix.module_system }}) + needs: changes + if: ${{ needs.changes.outputs.run_full_ci == 'true' }} + strategy: + fail-fast: false + max-parallel: 4 + matrix: ${{ fromJSON(needs.changes.outputs.rules_go_integration_matrix) }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Bazelisk + shell: bash + run: | + GO111MODULE=on go install github.com/bazelbuild/bazelisk@v1.28.1 + echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + + - name: Validate general Go companion consumer path + shell: bash + env: + MODULE_SYSTEM: ${{ matrix.module_system }} + ORCHESTRION_MODE: general + RULES_GO_UPSTREAM: ${{ matrix.upstream }} + RULES_GO_VARIANT: base + USE_BAZEL_VERSION: "8.4.1" run: | - while IFS= read -r upstream; do - RULES_GO_UPSTREAM="${upstream}" \ - RULES_GO_VARIANT="base" \ - ./tools/dev/run_rules_go_variant_smoke.sh - done < <(python3 tools/dev/materialize_rules_go_fork.py list-upstreams) + case "${MODULE_SYSTEM}" in + workspace) + ./tools/tests/integration/run_workspace_go_integration.sh + ;; + bzlmod) + ./tools/tests/integration/run_bzlmod_go_integration.sh + ;; + *) + echo "Unsupported module system: ${MODULE_SYSTEM}" >&2 + exit 1 + ;; + esac + + - name: Validate Test Optimization Go companion consumer path + shell: bash + env: + MODULE_SYSTEM: ${{ matrix.module_system }} + ORCHESTRION_MODE: test_optimization + RULES_GO_UPSTREAM: ${{ matrix.upstream }} + RULES_GO_VARIANT: base + USE_BAZEL_VERSION: "8.4.1" + run: | + case "${MODULE_SYSTEM}" in + workspace) + ./tools/tests/integration/run_workspace_go_integration.sh + ;; + bzlmod) + ./tools/tests/integration/run_bzlmod_go_integration.sh + ;; + *) + echo "Unsupported module system: ${MODULE_SYSTEM}" >&2 + exit 1 + ;; + esac workspace-compat: + needs: + - changes + - workspace-compat-shard + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Require successful workspace compatibility shards + shell: bash + env: + CHANGES_RESULT: ${{ needs.changes.result }} + RUN_FULL_CI: ${{ needs.changes.outputs.run_full_ci }} + SHARD_RESULT: ${{ needs.workspace-compat-shard.result }} + run: | + if [[ "${CHANGES_RESULT}" != "success" ]]; then + echo "Change classification did not succeed: ${CHANGES_RESULT}" >&2 + exit 1 + fi + + if [[ "${RUN_FULL_CI}" != "true" ]]; then + echo "Workspace compatibility coverage is not required for this change." + exit 0 + fi + + if [[ "${SHARD_RESULT}" != "success" ]]; then + echo "One or more workspace compatibility shards did not succeed: ${SHARD_RESULT}" >&2 + exit 1 + fi + + go-bootstrap-no-host-shard: + name: go-bootstrap-no-host-shard (${{ matrix.upstream }}, ${{ matrix.module_system }}) needs: changes if: ${{ needs.changes.outputs.run_full_ci == 'true' }} - timeout-minutes: 90 + strategy: + fail-fast: false + max-parallel: 4 + matrix: ${{ fromJSON(needs.changes.outputs.rules_go_integration_matrix) }} runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + # Do not use setup-go or `go install` in this lane. The consumer path must + # obtain its Go SDK from Bazel, while a sentinel shadows any Go binary + # already present in the hosted-runner image. + - name: Install Bazelisk without Go + shell: bash + run: | + set -euo pipefail + bin_dir="${RUNNER_TEMP}/bazelisk-bin" + bazelisk_path="${bin_dir}/bazelisk" + mkdir -p "${bin_dir}" + curl --fail --location --silent --show-error \ + --retry 3 \ + --output "${bazelisk_path}" \ + "https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VERSION}/bazelisk-linux-amd64" + printf '%s %s\n' "${BAZELISK_SHA256_LINUX_AMD64}" "${bazelisk_path}" | + sha256sum --check + chmod +x "${bazelisk_path}" + echo "${bin_dir}" >> "${GITHUB_PATH}" + + - name: Validate cold config transition without host Go + shell: bash + env: + CONFIG_TRANSITION_ONLY: "1" + EXPECTED_ORCHESTRION_CACHE_PHASE: extensions.bootstrap_cache_miss + FORBID_HOST_GO: "1" + MODULE_SYSTEM: ${{ matrix.module_system }} + ORCHESTRION_MODE: test_optimization + RULES_GO_UPSTREAM: ${{ matrix.upstream }} + RULES_GO_VARIANT: base + USE_BAZEL_VERSION: "8.4.1" + XDG_CACHE_HOME: ${{ runner.temp }}/rto-no-host-go-cache/${{ matrix.upstream }}/${{ matrix.module_system }} + run: | + set -euo pipefail + if [[ -e "${XDG_CACHE_HOME}" ]]; then + echo "Cold bootstrap cache path already exists: ${XDG_CACHE_HOME}" >&2 + exit 1 + fi + mkdir -p "${XDG_CACHE_HOME}" + case "${MODULE_SYSTEM}" in + workspace) + ./tools/tests/integration/run_workspace_go_integration.sh + ;; + bzlmod) + ./tools/tests/integration/run_bzlmod_go_integration.sh + ;; + *) + echo "Unsupported module system: ${MODULE_SYSTEM}" >&2 + exit 1 + ;; + esac + + - name: Validate warm cache restoration without host Go + shell: bash + env: + CONFIG_TRANSITION_ONLY: "1" + EXPECTED_ORCHESTRION_CACHE_PHASE: extensions.bootstrap_cache_hit + FORBID_HOST_GO: "1" + MODULE_SYSTEM: ${{ matrix.module_system }} + ORCHESTRION_MODE: test_optimization + RULES_GO_UPSTREAM: ${{ matrix.upstream }} + RULES_GO_VARIANT: base + USE_BAZEL_VERSION: "8.4.1" + XDG_CACHE_HOME: ${{ runner.temp }}/rto-no-host-go-cache/${{ matrix.upstream }}/${{ matrix.module_system }} + run: | + set -euo pipefail + case "${MODULE_SYSTEM}" in + workspace) + ./tools/tests/integration/run_workspace_go_integration.sh + ;; + bzlmod) + ./tools/tests/integration/run_bzlmod_go_integration.sh + ;; + *) + echo "Unsupported module system: ${MODULE_SYSTEM}" >&2 + exit 1 + ;; + esac + + go-bootstrap-no-host: + needs: + - changes + - go-bootstrap-no-host-shard + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Require successful no-host-Go bootstrap shards + shell: bash + env: + CHANGES_RESULT: ${{ needs.changes.result }} + RUN_FULL_CI: ${{ needs.changes.outputs.run_full_ci }} + SHARD_RESULT: ${{ needs.go-bootstrap-no-host-shard.result }} + run: | + if [[ "${CHANGES_RESULT}" != "success" ]]; then + echo "Change classification did not succeed: ${CHANGES_RESULT}" >&2 + exit 1 + fi + + if [[ "${RUN_FULL_CI}" != "true" ]]; then + echo "No-host-Go bootstrap coverage is not required for this change." + exit 0 + fi + + if [[ "${SHARD_RESULT}" != "success" ]]; then + echo "One or more no-host-Go bootstrap shards did not succeed: ${SHARD_RESULT}" >&2 + exit 1 + fi + + windows-go-bootstrap-shard: + name: windows-go-bootstrap-shard (${{ matrix.upstream }}, ${{ matrix.module_system }}) + needs: changes + if: ${{ needs.changes.outputs.run_full_ci == 'true' }} + strategy: + fail-fast: false + max-parallel: 4 + matrix: ${{ fromJSON(needs.changes.outputs.rules_go_integration_matrix) }} + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -317,24 +700,58 @@ jobs: GO111MODULE=on go install github.com/bazelbuild/bazelisk@v1.28.1 echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" - - name: Validate Go companion consumer paths + - name: Validate disabled-to-enabled bootstrap transition + shell: bash + env: + BAZEL_VERSION: "8.4.1" + MODULE_SYSTEM: ${{ matrix.module_system }} + ORCHESTRION_MODE: test_optimization + RULES_GO_UPSTREAM: ${{ matrix.upstream }} + RULES_GO_VARIANT: base + WINDOWS_CONFIG_TRANSITION_ONLY: "1" + run: | + case "${MODULE_SYSTEM}" in + workspace) + ./tools/tests/integration/run_workspace_go_integration.sh + ;; + bzlmod) + ./tools/tests/integration/run_bzlmod_go_integration.sh + ;; + *) + echo "Unsupported module system: ${MODULE_SYSTEM}" >&2 + exit 1 + ;; + esac + + # Keep one consolidated result while the expensive work runs in parallel. + windows-go-bootstrap-smoke: + needs: + - changes + - windows-go-bootstrap-shard + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Require successful Windows bootstrap shards shell: bash + env: + CHANGES_RESULT: ${{ needs.changes.result }} + RUN_FULL_CI: ${{ needs.changes.outputs.run_full_ci }} + SHARD_RESULT: ${{ needs.windows-go-bootstrap-shard.result }} run: | - while IFS= read -r upstream; do - for mode in general test_optimization; do - USE_BAZEL_VERSION=8.4.1 \ - RULES_GO_UPSTREAM="${upstream}" \ - RULES_GO_VARIANT="base" \ - ORCHESTRION_MODE="${mode}" \ - ./tools/tests/integration/run_workspace_go_integration.sh + if [[ "${CHANGES_RESULT}" != "success" ]]; then + echo "Change classification did not succeed: ${CHANGES_RESULT}" >&2 + exit 1 + fi - USE_BAZEL_VERSION=8.4.1 \ - RULES_GO_UPSTREAM="${upstream}" \ - RULES_GO_VARIANT="base" \ - ORCHESTRION_MODE="${mode}" \ - ./tools/tests/integration/run_bzlmod_go_integration.sh - done - done < <(python3 tools/dev/materialize_rules_go_fork.py list-upstreams) + if [[ "${RUN_FULL_CI}" != "true" ]]; then + echo "Windows Go bootstrap smoke is not required for this change." + exit 0 + fi + + if [[ "${SHARD_RESULT}" != "success" ]]; then + echo "One or more Windows Go bootstrap shards did not succeed: ${SHARD_RESULT}" >&2 + exit 1 + fi coverage-tools: needs: changes diff --git a/.github/workflows/docs-links.yml b/.github/workflows/docs-links.yml index 2c3a267a..1d59e8d4 100644 --- a/.github/workflows/docs-links.yml +++ b/.github/workflows/docs-links.yml @@ -57,7 +57,15 @@ jobs: SECURITY.md docs/**/*.md examples/**/*.md + tools/agent-skills/**/*.md ) + filtered=() + for file in "${files[@]}"; do + case "$file" in + third_party/*|docs/superpowers/plans/*) continue ;; + esac + filtered+=("$file") + done # lychee replaces the default success-code set when --accept is present. lychee \ --no-progress \ @@ -65,6 +73,6 @@ jobs: --accept '200..=299,429' \ --max-retries 2 \ --retry-wait-time 2 \ - "${files[@]}" + "${filtered[@]}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/shared-validation.yml b/.github/workflows/shared-validation.yml index 89cc51a8..d83de416 100644 --- a/.github/workflows/shared-validation.yml +++ b/.github/workflows/shared-validation.yml @@ -199,9 +199,30 @@ jobs: shell: bash run: python3 tools/core/schemas/check_schema_parser_parity.py - rules-go-fork-drift: + rules-go-fork-drift-matrix: + if: ${{ !inputs.docs_only && inputs.run_rules_go_fork_drift }} + runs-on: ubuntu-latest + outputs: + upstreams: ${{ steps.generate.outputs.upstreams }} + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ inputs.python_version }} + + - name: Generate rules_go profile matrix + id: generate + shell: bash + run: | + python3 tools/dev/materialize_rules_go_fork.py list-upstreams | + python3 -c 'import json, sys; upstreams = [line.strip() for line in sys.stdin if line.strip()]; assert upstreams, "no rules_go upstreams found"; print("upstreams=" + json.dumps(upstreams, separators=(",", ":")))' \ + >> "${GITHUB_OUTPUT}" + + rules-go-fork-drift-global: if: ${{ !inputs.docs_only && inputs.run_rules_go_fork_drift }} - timeout-minutes: 15 runs-on: ubuntu-latest steps: - name: Checkout @@ -229,13 +250,72 @@ jobs: python3 tools/dev/generate_rules_go_fork_maps.py --check RULES_GO_ORCHESTRION_CACHE="${RUNNER_TEMP}/rules_go_orchestrion_cache" \ python3 tools/dev/materialize_rules_go_fork.py check --all - python3 tools/dev/verify_rules_go_profiles.py \ - --public-denylist tools/dev/private_leak_public_denylist.txt - name: Verify rules_go fork release archive contents shell: bash run: python3 tools/dev/check_release_archive_contents.py + rules-go-fork-profile-shard: + name: rules-go-fork-profile-shard (${{ matrix.upstream }}) + needs: rules-go-fork-drift-matrix + if: ${{ !inputs.docs_only && inputs.run_rules_go_fork_drift }} + strategy: + fail-fast: false + max-parallel: 4 + matrix: + upstream: ${{ fromJSON(needs.rules-go-fork-drift-matrix.outputs.upstreams) }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ inputs.python_version }} + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: "1.25.0" + + - name: Verify rules_go consumer patch profile + shell: bash + run: | + python3 tools/dev/verify_rules_go_profiles.py \ + --upstream "${{ matrix.upstream }}" \ + --public-denylist tools/dev/private_leak_public_denylist.txt + + rules-go-fork-drift: + needs: + - rules-go-fork-drift-matrix + - rules-go-fork-drift-global + - rules-go-fork-profile-shard + if: ${{ always() && !inputs.docs_only && inputs.run_rules_go_fork_drift }} + runs-on: ubuntu-latest + steps: + - name: Require successful rules_go fork drift shards + shell: bash + env: + GLOBAL_RESULT: ${{ needs.rules-go-fork-drift-global.result }} + MATRIX_RESULT: ${{ needs.rules-go-fork-drift-matrix.result }} + PROFILE_RESULT: ${{ needs.rules-go-fork-profile-shard.result }} + run: | + if [[ "${MATRIX_RESULT}" != "success" ]]; then + echo "rules_go profile matrix generation did not succeed: ${MATRIX_RESULT}" >&2 + exit 1 + fi + + if [[ "${GLOBAL_RESULT}" != "success" ]]; then + echo "Global rules_go fork drift validation did not succeed: ${GLOBAL_RESULT}" >&2 + exit 1 + fi + + if [[ "${PROFILE_RESULT}" != "success" ]]; then + echo "One or more rules_go profile shards did not succeed: ${PROFILE_RESULT}" >&2 + exit 1 + fi + powershell-lint: if: ${{ !inputs.docs_only && inputs.run_powershell_lint }} timeout-minutes: 20 diff --git a/AGENTS.md b/AGENTS.md index d6cb7659..3c2bb5cc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,8 +14,8 @@ This repository ships Bazel integrations that fetch Datadog Test Optimization me The solution separates concerns into four phases: 1. **Fetch phase (module/repo resolution)**: repository rule fetches metadata from Datadog APIs. 2. **Execute phase (test runtime)**: tests run hermetically, consume pre-fetched metadata via runfiles, and write payloads to `TEST_UNDECLARED_OUTPUTS_DIR`. -3. **Validation phase (post-test)**: a dedicated doctor target (`bazel run //:dd_test_optimization_doctor`) validates local JSON payloads, Bazel metadata, Git metadata, and invalid payload-selection states. -4. **Upload phase (post-test)**: a dedicated uploader target (`bazel run //:dd_upload_payloads`) enriches and uploads payloads from `bazel-testlogs//test.outputs/`. +3. **Validation phase (post-test)**: a dedicated doctor target (`bazel run //:dd_test_optimization_doctor`) validates local JSON payloads, Bazel metadata, Git metadata, and invalid payload-selection states. +4. **Upload phase (post-test)**: a dedicated uploader target (`bazel run //:dd_upload_payloads`) enriches and uploads payloads from `bazel-testlogs//test.outputs/`. ## Documentation - User-facing onboarding and command flow: see `README.md` (use its `Reference links` section for deep references). @@ -24,23 +24,28 @@ The solution separates concerns into four phases: - Problem statement & proposal: see `docs/RFC.md` for background rationale and trade-offs (historical context). - Usage snippets: see `examples/README.md` for copy/paste single-service and multi-service examples. - Agent workflow for Go consumer onboarding: see `tools/agent-skills/go-test-optimization-onboarding/SKILL.md` for the neutral Codex-compatible skill that guides agents through WORKSPACE/Bzlmod Go instrumentation, validation, and troubleshooting. +- Agent workflow for Python consumer onboarding: see `tools/agent-skills/python-test-optimization-onboarding/SKILL.md` for the neutral Codex-compatible skill that guides agents through WORKSPACE/Bzlmod Python instrumentation, validation, and troubleshooting. - Agent workflow for Java consumer onboarding: see `tools/agent-skills/java-test-optimization-onboarding/SKILL.md` for the neutral Codex-compatible skill that guides agents through WORKSPACE/Bzlmod Java instrumentation, validation, and troubleshooting. - Agent workflow for rules_go upstream migrations: see `tools/agent-skills/rules-go-orchestrion-upstream-migration/SKILL.md` for the neutral Codex-compatible skill that guides agents through porting the vendored Orchestrion-enabled `rules_go` fork to a new upstream tag or commit. - Cross-repository integration fixture: see the sibling repository `../rules_test_optimization_tests` and its `README.md` for the consumer-style validation flow that must stay green after changes here. - For local validation of unpublished changes from this repo, switch that fixture repo from its pinned `git_override(...)` entries to the commented `local_path_override(...)` entries in `../rules_test_optimization_tests/MODULE.bazel` so Bazel resolves this checkout instead of GitHub. - Go fork maintenance details: see `third_party/rgo/v0_60_0/base.METADATA.json`, `third_party/rules_go_orchestrion/registry.json`, `third_party/rules_go_orchestrion/profiles/workspace_runtime.json`, `tools/dev/diff_rules_go_fork.py`, and `tools/dev/verify_rules_go_profiles.py`. -Agents: start with `README.md` for current operational behavior, then `CONTRIBUTING.md` for the maintained validation workflow. When instrumenting a Go consumer repository, load `tools/agent-skills/go-test-optimization-onboarding/SKILL.md` before editing that consumer. When instrumenting a Java consumer repository, load `tools/agent-skills/java-test-optimization-onboarding/SKILL.md` before editing that consumer. Use the overview and RFC when you need architecture details or design rationale/trade-off context. +Agents: start with `README.md` for current operational behavior, then `CONTRIBUTING.md` for the maintained validation workflow. When instrumenting a Go, Python, or Java consumer repository, load the matching skill under `tools/agent-skills/` before editing that consumer. Use the overview and RFC when you need architecture details or design rationale/trade-off context. ## Project Structure & Module Organization - `tools/` — Starlark sources plus developer and agent support files: - `core/common_utils.bzl` — shared utilities for logging, sanitization, validation, and deduplication used across multiple rule files. - `core/test_optimization_sync.bzl` — module extension + repo rule producing `.testoptimization/cache/http/settings.json`, per‑module files, and `.testoptimization/context.json`. - `core/test_optimization_multi_sync.bzl` — multi-service module extension for monorepos with multiple services. + - `core/test_optimization_manifest_sync.bzl` — manifest-driven aggregate + repository for invocation-scoped Go/Python target sets. It is separate from + static multi-sync and does not own target discovery or service derivation. - `core/test_optimization_uploader.bzl` — workspace-level uploader rule (normal rule, not test; runs via `bazel run`). - `dev/*_bootstrap.bzl` — dev-only bootstrap extensions wiring the local Go, Python, Java, NodeJS, .NET, and Ruby companion repos from this workspace root. - `dev/diff_rules_go_fork.py` — maintainer utility that regenerates the delta report for the vendored `rules_go` fork. - `agent-skills/go-test-optimization-onboarding/` — neutral agent skill for instrumenting Go consumer repositories with Test Optimization. + - `agent-skills/python-test-optimization-onboarding/` — neutral agent skill for instrumenting Python consumer repositories with Test Optimization. - `agent-skills/java-test-optimization-onboarding/` — neutral agent skill for instrumenting Java consumer repositories with Test Optimization. - `agent-skills/rules-go-orchestrion-upstream-migration/` — neutral agent skill for porting the vendored Orchestrion-enabled `rules_go` fork to a new upstream version. - `modules/go/` — Go companion module sources: @@ -61,11 +66,11 @@ Agents: start with `README.md` for current operational behavior, then `CONTRIBUT The sync rule creates `@test_optimization_data//` containing: - `BUILD` with public filegroups (`:test_optimization_files`, `:test_optimization_context`, `:module_`). - `export.bzl` exporting the `topt_data` dict for macros. -- `.testoptimization/cache/http/settings.json`, `.testoptimization/cache/http/known_tests.json`, `.testoptimization/cache/http/test_management.json`, `.testoptimization/manifest.txt`, `.testoptimization/context.json`. +- `.testoptimization/cache/http/settings.json`, `.testoptimization/cache/http/known_tests.json`, `.testoptimization/cache/http/test_management.json`, `.testoptimization/cache/http/flaky_tests.json`, `.testoptimization/manifest.txt`, `.testoptimization/context.json`, `.testoptimization/telemetry_facts.json`. - `.testoptimization/module_/` per-module splits for cache efficiency. ## Key Design Patterns -- **Per-module splitting**: known tests and test management data are split by module to reduce cache invalidation. +- **Per-module splitting**: known tests, test management, and flaky tests data are split by module to reduce cache invalidation. - **Sanitization**: module names are converted into Bazel-safe labels using `sanitize_label_fragment()` (lowercase, `[a-z0-9_]` only, deterministic suffixes). - **Go importpath inference**: `topt_go_payloads_selector` mirrors rules_go importpath logic (explicit `importpath` > `embed` provider > fallback `/`). - **Vendored rules_go forks for root workflows**: the repository root pins `rules_go` as a dev-only dependency and redirects it to `third_party/rgo/v0_60_0/base` with `local_path_override(...)`; consumer-facing core usage remains rules_go-free. @@ -91,17 +96,17 @@ The sync rule creates `@test_optimization_data//` containing: # Tests write payloads to TEST_UNDECLARED_OUTPUTS_DIR automatically # Bazel collects them to bazel-testlogs//test.outputs/ ./bazelw test //... || test_status=$?; test_status=${test_status:-0} - ./bazelw run //:dd_test_optimization_doctor || doctor_status=$?; doctor_status=${doctor_status:-0} + ./bazelw run //:dd_test_optimization_doctor || doctor_status=$?; doctor_status=${doctor_status:-0} if [ "$doctor_status" -ne 0 ]; then if [ "$test_status" -ne 0 ]; then exit "$test_status"; fi exit "$doctor_status" fi - ./bazelw run //:dd_upload_payloads -- --dry-run --validate-enrichment || dry_run_status=$?; dry_run_status=${dry_run_status:-0} + ./bazelw run //:dd_upload_payloads -- --dry-run --validate-enrichment || dry_run_status=$?; dry_run_status=${dry_run_status:-0} if [ "$dry_run_status" -ne 0 ]; then if [ "$test_status" -ne 0 ]; then exit "$test_status"; fi exit "$dry_run_status" fi - DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" ./bazelw run //:dd_upload_payloads + DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" ./bazelw run //:dd_upload_payloads upload_status=$? if [ "$test_status" -ne 0 ]; then exit "$test_status"; fi exit "$upload_status" @@ -129,7 +134,7 @@ The sync rule creates `@test_optimization_data//` containing: ## Coding Style & Naming Conventions - Starlark: 2‑space indent; `snake_case` for rules/macros/attrs; concise, descriptive docstrings. - Public labels are stable — do not rename `test_optimization_files`, `test_optimization_context`, or `module_`. -- Outputs under `.testoptimization/` are fixed: `manifest.txt`, `context.json`, `cache/http/settings.json`, `cache/http/known_tests.json`, `cache/http/test_management.json`, and per‑module canonical files exposed via `:module_` targets (runfiles rooted under the manifest directory). +- Outputs under `.testoptimization/` are fixed: `manifest.txt`, `context.json`, `telemetry_facts.json`, `cache/http/settings.json`, `cache/http/known_tests.json`, `cache/http/test_management.json`, `cache/http/flaky_tests.json`, and per-module canonical files exposed via `:module_` targets (runfiles rooted under the manifest directory). ## Testing Guidelines - Repository-local test matrix: @@ -157,15 +162,19 @@ The sync rule creates `@test_optimization_data//` containing: - In consumer workspaces, prefer `./bazelw test //...` when package layout permits. - Tests write payloads to `$TEST_UNDECLARED_OUTPUTS_DIR/payloads/{tests,coverage}` (Bazel's built-in writable directory). - Bazel automatically collects these to `bazel-testlogs///test.outputs/`. -- In consumer workspaces, run `./bazelw run //:dd_test_optimization_doctor` - after tests complete, then run `./bazelw run //:dd_upload_payloads -- --dry-run --validate-enrichment`, then upload with `./bazelw run //:dd_upload_payloads`. +- In consumer workspaces, run `./bazelw run //:dd_test_optimization_doctor` + after tests complete, then run `./bazelw run //:dd_upload_payloads -- --dry-run --validate-enrichment`, then upload with `./bazelw run //:dd_upload_payloads`. Do not run the real upload if doctor or dry-run enrichment validation fails. -- For Go, use `dd_topt_go_test` to set up the test with correct environment variables. -- Create ONE doctor target and ONE uploader target per workspace at the root BUILD.bazel. +- For Go, route the repository's central `dd_go_test` wrapper through + `dd_topt_go_test`; `--config=test-optimization` is the only user-facing + enable switch. +- Create ONE doctor target and ONE uploader target per workspace. Root is fine + for small repositories; use a lightweight package such as + `//tools/test_optimization` in monorepos. ## Consumer Tips (bzlmod) -- In `MODULE.bazel`: add `bazel_dep("datadog-rules-test-optimization", ...)` and `bazel_dep("datadog-rules-test-optimization-go", ...)`, then `use_extension("@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", "test_optimization_sync_extension")`, instantiate `test_optimization_sync(name = "test_optimization_data", service = "", runtime_name = "go", runtime_version = "")`, then `use_repo(..., "test_optimization_data")`. -- In root `BUILD.bazel`: create the workspace-level doctor and uploader: +- In `MODULE.bazel`: add `bazel_dep("datadog-rules-test-optimization", ...)` and `bazel_dep("datadog-rules-test-optimization-go", ...)`, then use `test_optimization_go_extension` from `@datadog-rules-test-optimization-go//:topt_go_extension.bzl`. Instantiate `test_optimization_go(name = "test_optimization_data", service = "", runtime_version = "", module_path = "")`, then `use_repo(..., "test_optimization_data")`. The public Go extension is config-gated by default. +- In a small root package or a lightweight monorepo package, create the workspace-level doctor and uploader: ```bzl load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") @@ -180,8 +189,8 @@ The sync rule creates `@test_optimization_data//` containing: data = ["@test_optimization_data//:test_optimization_context"], ) ``` -- In test `BUILD.bazel` files: `load("@datadog-rules-test-optimization-go//:topt_go_test.bzl", "dd_topt_go_test")` and `load("@test_optimization_data//:export.bzl", "topt_data")`; set `topt_data = topt_data` in `dd_topt_go_test(...)`. -- Import path inference (preferred): add a `go_library` and set `embed = [":"]` in your `dd_topt_go_test` call. The macro reads rules_go's provider to compute the same `importpath` `go_test` uses and selects the matching per‑module payload group. If no match exists, it falls back to the core bundle automatically. +- In the repository's central Go wrapper: load `dd_topt_go_test` and the generated `topt_data`, then delegate every public `dd_go_test(...)` call to the Datadog macro. Do not create separate plain and optimized onboarding paths. +- Import path inference (preferred): add a `go_library` and set `embed = [":"]` in the central wrapper call. The macro reads rules_go's provider to compute the same `importpath` `go_test` uses and selects the matching per-module payload group. Inferred misses use the core bundle. When synchronized metadata exposes module groups, an explicit `importpath` or `module_label_override` that does not match one fails analysis; when no groups exist, the canonical full bundle remains valid. - Fallback (no embed): if neither `embed` nor explicit `importpath` is provided, the macro computes `/` using the exported `topt_data["runtimes"]["go"]["module_path"]`. In this fallback mode only, it consults `topt_data["runtimes"]["go"]["module_included"]` as a coarse gate before attempting per‑module selection. - Tests can read `DD_TEST_OPTIMIZATION_MANIFEST_FILE` to resolve the manifest directory (via `filepath.Dir()`) and access synced payloads. - For Python/Java/NodeJS/.NET/Ruby companions, follow the corresponding quickstart sections in `README.md` (`Bzlmod + Python companion`, `Bzlmod + Java companion`, `Bzlmod + NodeJS companion`, `Bzlmod + .NET companion`, `Bzlmod + Ruby companion`). @@ -224,6 +233,25 @@ Note: Core module (`datadog-rules-test-optimization`) is rules-go free. The Go c - `@test_optimization_data//:module__` (example: `:module_go_service_core`). - Macros: `load("@test_optimization_data//:export.bzl", "topt_data_by_service")` then either pass `topt_data = topt_data_by_service[""]`, or pass the mapping and set `topt_service = ""` in `dd_topt_go_test`. +## Manifest-Driven Managed Usage +- Keep `test_optimization_manifest_sync` separate from static multi-sync. +- A consumer-owned managed command must discover and fully expand exact local + Go/Python test labels, derive service/runtime contexts, and pass a private + invocation-scoped manifest to Bazel. Do not add a committed target/service + mapping to this repository. +- The aggregate repo exports `topt_data_by_target`, + `topt_data_by_context`, `target_context_keys`, + `:test_optimization_context`, and `:expected_targets`. +- Central consumer wrappers use `topt_data_by_target.get()`. + Selected targets use the companion macro; absent targets retain the + consumer's raw path. +- The doctor receives `expected_targets_file = + "@test_optimization_data//:expected_targets"`. The uploader and doctor share + the aggregate `:test_optimization_context`. +- Automatic manifest onboarding currently supports Go and Python only. Static + single/multi-service APIs remain the supported path for Java, NodeJS, .NET, + and Ruby. + ## Hermetic Config - Use `--config=hermetic` to enable sandboxing, stable locale, and network blocking (see `examples/single_service/.bazelrc` and `examples/multi_service/.bazelrc` for the reference pattern). - Network: prefer `--sandbox_default_allow_network=false`; alternatively add `--modify_execution_info=TestRunner=+block-network`. @@ -237,7 +265,7 @@ Note: Core module (`datadog-rules-test-optimization`) is rules-go free. The Go c ## Security & Configuration Tips - Never write secrets to disk. Pass `DD_API_KEY`, `DD_SITE` via environment when running the uploader. -- `context.json` is non‑secret; include it via `@//:test_optimization_context` in the uploader's data. +- `context.json` and `telemetry_facts.json` are non-secret; include both through `@//:test_optimization_context` in doctor/uploader data. - If CODEOWNERS auto-discovery is not reliable in your environment, set `DD_TEST_OPTIMIZATION_CODEOWNERS_FILE` explicitly to a checked-in CODEOWNERS path. - Agentless uploads require `DD_API_KEY` and `DD_SITE`; EVP proxy requires `DD_TEST_OPTIMIZATION_AGENT_URL` (EVP headers handled by the rule). -- Uploader credentials are passed at runtime: `DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" ./bazelw run //:dd_upload_payloads` +- Uploader credentials are passed at runtime: `DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" ./bazelw run //:dd_upload_payloads` diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b50aa9d..0ef36051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,56 @@ versioning. ## [Unreleased] +### Added + +- Added `test_optimization_manifest_sync` and + `test_optimization_manifest_sync_extension` for consumer-managed, + invocation-scoped Go/Python monorepo onboarding. The new aggregate + repository exports target-to-context data, narrow per-context/per-module + labels, bundled contexts, and a generated exact-target file without requiring + a checked-in service registry. +- Added dynamic exact-target input support to the doctor and convenience + target macro, plus integration coverage for disabled behavior, deterministic + manifests, no-host-Go execution, multi-context enrichment, and metadata + cache isolation. +- Reusable Go WORKSPACE helpers for config-gated metadata sync and fixed-name + Orchestrion repository declaration, matching the public Go Bzlmod onboarding + contract. +- Added a non-default `rules_go` v0.62.0 support line with the maintained + Orchestrion integration and public consumer patch profile. + +### Changed +- The public Go Bzlmod extension now defaults `enabled_by_env` to `True`, so + omitting `--config=test-optimization` disables metadata sync and Orchestrion + together while the named config enables both. +- Config-gated Go and Python macros now consume disabled sync exports as real + runtime no-ops while preserving the consumer's ordinary public test target. + Go emits the public raw `go_test`; Python keeps the selected runner and applies + the CI Visibility runtime kill switch. +- Python payload selection now derives the normal module identifier from runtime + and Bazel package metadata, keeping explicit `module_identifier` values for + repository-specific exceptions. When module groups are available, explicit + identifiers and module-label overrides must match one; inferred or derived + misses and metadata with no module groups retain the canonical full-bundle + fallback. +- The Go WORKSPACE bootstrap template now generates one central config-gated + `dd_go_test` wrapper. The former optimized wrapper name is a compatibility + alias to that same function, not a second rollout path. +- Go consumers upgrading from `1.2.0` should rerun `dd_topt_go_bootstrap` with + `--write-bazelrc` before or with the Rule upgrade. The managed `.bazelrc` + update is idempotent and adds both metadata and Orchestrion activation to the + `test-optimization` config. Consumers that deliberately retain manual + always-enabled metadata may set `enabled_by_env = False`, but must also keep + the Orchestrion build setting enabled. + +### Fixed +- Go test analysis now fails with migration guidance when Test Optimization + metadata is enabled but the global Orchestrion build setting is disabled, + preventing a partial upgrade from silently dropping instrumentation. +- Config-disabled Go analysis now resolves stable empty Orchestrion repository + targets before host-Go discovery or source fetching, so ordinary targets do + not require Go to be installed merely because the integration is declared. + ## [1.2.0] - 2026-06-03 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index abb7db0b..67db57ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,11 +21,21 @@ This product includes software developed at Datadog - `:test_optimization_files` - `:test_optimization_context` - `:module_` +- Keep the three sync contracts separate: + - static single-service in `test_optimization_sync.bzl`; + - static multi-service in `test_optimization_multi_sync.bzl`; + - invocation-scoped Go/Python aggregation in + `test_optimization_manifest_sync.bzl`. + Manifest sync must not acquire target discovery, consumer naming policy, or a + checked-in target/service registry. ## Validation Commands - Canonical full-repo command: - `./bazelw test //...` + - On macOS with Bazel 8.5.1, append + `--noexperimental_split_xml_generation`. The split XML helper can terminate + with `SIGSEGV` independently of the test target. - Core module tests (repo root): - `./bazelw test //tools/...` @@ -72,6 +82,29 @@ This product includes software developed at Datadog - Mixed-runtime uploader changes are not done until both harnesses still pass: they cover single-context, explicit override, multi-context repo selection, and no-match fallback behavior. + - Manifest-driven Go/Python changes: + `python3 tools/tests/integration/run_manifest_sync_tests.py --mode full`. + This proves strict manifest validation, disabled no-op behavior, + deterministic output, target-specific cache invalidation, exact doctor + targets, aggregate enrichment, and no host Go. + - Windows manifest-disabled parsing: + `python tools/tests/integration/run_manifest_sync_tests.py --mode disabled`. +- Test Optimization bootstrap config: + - For config-gated Go and Python onboarding, keep + `--config=test-optimization` as the only user-facing switch. The shared + config entry is + `common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1`. + - Go additionally sets the existing `rules_go` Orchestrion `enabled=true` + build setting. Python-only consumers must not declare that Go-only label. + - Omitting the config is the documented complete opt-out for Go and Python: + metadata repositories use disabled stubs when `enabled_by_env = True`, Go + aliases select local empty targets, and Python keeps the consumer runner + without Test Optimization wiring. + - Other companions retain their existing enablement contract. Do not add + `enabled_by_env = True` to their sync repositories until their runtime + wrapper implements and tests the disabled export contract. + - Do not add a consumer-local Test Optimization bool flag or a second Go + Orchestrion repository chooser. - Go consumer integration harnesses: - Bzlmod default smoke: `tools/tests/integration/run_bzlmod_go_integration.sh` @@ -85,7 +118,33 @@ This product includes software developed at Datadog `USE_BAZEL_VERSION=8.4.1 RULES_GO_UPSTREAM=v0_61_1 RULES_GO_VARIANT=base tools/tests/integration/run_workspace_go_integration.sh` - Bzlmod base, rules_go v0_61_1: `USE_BAZEL_VERSION=8.4.1 RULES_GO_UPSTREAM=v0_61_1 RULES_GO_VARIANT=base tools/tests/integration/run_bzlmod_go_integration.sh` + - WORKSPACE base, rules_go v0_62_0: + `USE_BAZEL_VERSION=8.4.1 RULES_GO_UPSTREAM=v0_62_0 RULES_GO_VARIANT=base tools/tests/integration/run_workspace_go_integration.sh` + - Bzlmod base, rules_go v0_62_0: + `USE_BAZEL_VERSION=8.4.1 RULES_GO_UPSTREAM=v0_62_0 RULES_GO_VARIANT=base tools/tests/integration/run_bzlmod_go_integration.sh` + - Disabled alias gate for a fresh output root: + `WINDOWS_DISABLED_SMOKE_ONLY=1 RULES_GO_UPSTREAM=v0_60_0 RULES_GO_VARIANT=base tools/tests/integration/run_workspace_go_integration.sh` + - Enabled alias and payload gate with valid Orchestrion pins: + `WINDOWS_ENABLED_SMOKE_ONLY=1 RULES_GO_UPSTREAM=v0_60_0 RULES_GO_VARIANT=base tools/tests/integration/run_workspace_go_integration.sh` + - Same-output-root disabled then enabled transition for the public central + wrapper: + `CONFIG_TRANSITION_ONLY=1 RULES_GO_UPSTREAM=v0_60_0 RULES_GO_VARIANT=base tools/tests/integration/run_workspace_go_integration.sh` + - Cold bootstrap without host Go, using the Bazel-managed SDK and an isolated + bootstrap cache: + `cache_root="$(mktemp -d)"; CONFIG_TRANSITION_ONLY=1 FORBID_HOST_GO=1 EXPECTED_ORCHESTRION_CACHE_PHASE=extensions.bootstrap_cache_miss XDG_CACHE_HOME="$cache_root" RULES_GO_UPSTREAM=v0_60_0 RULES_GO_VARIANT=base tools/tests/integration/run_workspace_go_integration.sh` + - Repeat that command with the same `XDG_CACHE_HOME` and + `EXPECTED_ORCHESTRION_CACHE_PHASE=extensions.bootstrap_cache_hit` to prove + warm restoration also avoids host Go. Run both commands for WORKSPACE and + Bzlmod; CI covers both supported `rules_go` upstreams. - Each script now validates: + - the same consumer-owned central wrapper call expands to a raw `go_test` + without the named config and to the existing Orchestrion-backed shape + with it + - disabled then enabled resolution on one fixture workspace and output + root, with no intervening clean or shutdown + - no hidden Test Optimization targets, empty Orchestrion aliases, exact + disabled stubs, zero metadata HTTP requests, and no payload while + disabled - normal mode - hermetic mode with the inline CI sandbox/network-blocking flags - strict BEP fresh/cached uploader behavior @@ -138,25 +197,34 @@ This product includes software developed at Datadog - `bazel-tests`: - core tests (`//tools/...`) on Linux/macOS/Windows - - go companion tests (`modules/go`) on Linux/macOS/Windows - - integration harness on Linux/macOS (`.sh`) and Windows (`.ps1`) + - companion module tests on Linux + - mock-server integration harness on Linux (`.sh`) and Windows (`.ps1`) - examples build on Linux/macOS/Windows + - the Linux result aggregates independent main-suite and mock-server shards - `bazel-tests-hermetic`: - core tests with hermetic flags - - go companion tests with hermetic flags + - companion module tests with hermetic flags - scope policy: Linux-only by design today; non-Linux hermetic expansion is tracked separately to keep CI runtime bounded - `workspace-compat`: - - WORKSPACE base - - Bzlmod base + - one shard per supported `rules_go` upstream and WORKSPACE/Bzlmod pair + - general and Test Optimization modes run sequentially inside each shard - the Go integration scripts themselves cover normal mode, hermetic mode, and structural `aquery` checks +- `go-bootstrap-no-host`: + - one shard per supported `rules_go` upstream and WORKSPACE/Bzlmod pair + - installs Bazelisk without Go and shadows any hosted-runner `go` binary with + a failing sentinel + - proves both a cold Bazel-managed-SDK build and warm bootstrap-cache restore + without invoking host Go - `rules-go-variant-smoke`: - vendored `rules_go` variant verification and fast fork regression coverage + - one independent shard per supported upstream - Linux-only by design so the PR gate stays fast and stable - `rules-go-variant-extended`: - nightly/manual vendored `rules_go` variant coverage for slower XML, proto, cross, and cgo regression suites - Utility/lint lanes: - module version alignment check (`tools/dev/check_module_versions.py`) - `.bazelversion` parity check (`tools/dev/check_bazelversion_sync.py`) + - global fork drift checks plus one consumer patch-profile shard per supported `rules_go` upstream - shell scripts, PowerShell, Buildifier, gofmt, schema sync checks, fixture JSON checks, and Python tooling tests - Workflow dependency pinning: - Keep GitHub Actions pinned by commit SHA and preserve the `# vX.Y.Z` comment. @@ -183,6 +251,18 @@ This product includes software developed at Datadog `...-nodejs`, `...-dotnet`, `...-ruby`). - Language-specific orchestration stays isolated in `modules/`. - Dev bootstrap wiring in `tools/dev/*_bootstrap.bzl` is dev-only and cycle-safe. +- Manifest normalization and repository rendering are deterministic: equivalent + input order must produce byte-identical exports, BUILD content, and + expected-target JSON. +- One managed invocation must reuse one manifest path and metadata snapshot + across test, doctor, dry-run, and upload. A second invocation refetches once; + unchanged stable metadata must retain Bazel test-result cache hits, while + telemetry timing facts remain outside test action inputs. +- The manifest-driven API is additive. Do not change static single-service or + static multi-service semantics while modifying it. +- Validate cross-repository rollout in this order: + `rules_test_optimization`, then `rules_test_optimization_tests`, then the + consumer repository. A green Rule unit test does not replace consumer E2E. ## PR Checklist @@ -191,8 +271,14 @@ This product includes software developed at Datadog error diagnostics remain actionable. - [ ] Ran split-aware validation commands relevant to changed files. - [ ] Updated docs/snippets for any load-path, module, or API changes. +- [ ] Audited all first-party Markdown and agent skills affected by a public + onboarding change; vendored and local historical plan documents are excluded. +- [ ] For manifest-driven changes, proved no committed target/service mapping, + exact target-set validation, disabled no-fetch behavior, and deterministic + rendering. - [ ] For Go Orchestrion changes, documented any `orchestrion_mode` behavior, - unsupported `testify/suite` scope, opt-out flags, and payload metadata changes. + pin-file or explicit-version behavior, unsupported `testify/suite` scope, + opt-out flags, and payload metadata changes. - [ ] Updated `LICENSE-3rdparty.csv` for dependency or vendored-code changes. - [ ] Confirmed no stale references to removed legacy paths (for example `//tools/go:*`, replaced by `modules/go/...` targets). diff --git a/MODULE.bazel b/MODULE.bazel index 4d486e2f..b70d8ed3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -189,17 +189,76 @@ example_stub_repo = use_extension( "example_stub_repo_extension", dev_dependency = True, ) + +_EXAMPLE_STUB_LABELS = [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests", +] + +_EXAMPLE_STUB_SERVICE_KEYS = [ + "go_service", + "go_service_a", + "go_service_b", + "python_service", + "java_service", + "nodejs_service", + "dotnet_service", + "ruby_service", +] + example_stub_repo.example_stub_repo( name = "test_optimization_data", - service_keys = [ - "go_service", - "go_service_a", - "go_service_b", - "python_service", - "java_service", - "nodejs_service", - "dotnet_service", - "ruby_service", - ], -) -use_repo(example_stub_repo, "test_optimization_data") + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_keys = _EXAMPLE_STUB_SERVICE_KEYS, +) +example_stub_repo.example_stub_repo( + name = "test_optimization_data_go", + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_name = "go-service", +) +example_stub_repo.example_stub_repo( + name = "test_optimization_data_python", + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_name = "go-service", +) +example_stub_repo.example_stub_repo( + name = "test_optimization_data_java", + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_name = "go-service", +) +example_stub_repo.example_stub_repo( + name = "test_optimization_data_nodejs", + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_name = "go-service", +) +example_stub_repo.example_stub_repo( + name = "test_optimization_data_dotnet", + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_name = "go-service", +) +example_stub_repo.example_stub_repo( + name = "test_optimization_data_ruby", + enabled = False, + labels = _EXAMPLE_STUB_LABELS, + service_name = "go-service", +) +use_repo( + example_stub_repo, + "test_optimization_data", + "test_optimization_data_dotnet", + "test_optimization_data_go", + "test_optimization_data_java", + "test_optimization_data_nodejs", + "test_optimization_data_python", + "test_optimization_data_ruby", +) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 57a19a53..c14c2795 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -341,8 +341,8 @@ }, "//tools/tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "11ZYe98lW2gzeDxeH56YfpXqfu+Fz/W99x+6gbqhHpo=", - "usagesDigest": "ZvH9tnCNkZsHBe4vntqNT2rwFLibrjPI/w0NHRR5Lwg=", + "bzlTransitiveDigest": "TrTrDHJrP0Rre84rDDioXjXxdcPRZwzJZA21GdNKrkE=", + "usagesDigest": "EtFKqYPzQPpUPHFL/jjD4e+uC5rSFI+DlvubVmTxLT0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -350,10 +350,18 @@ "test_optimization_data": { "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", "attributes": { + "enabled": false, "go_module_included": false, "go_module_path": "example.com/stub", "go_sanitized_module_path": "example_com_stub", - "labels": [], + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], "out_dir": ".testoptimization", "repo_alias": "test_optimization_data", "service_name": "stub-service", @@ -368,6 +376,132 @@ "ruby_service" ] } + }, + "test_optimization_data_go": { + "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", + "attributes": { + "enabled": false, + "go_module_included": false, + "go_module_path": "example.com/stub", + "go_sanitized_module_path": "example_com_stub", + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], + "out_dir": ".testoptimization", + "repo_alias": "test_optimization_data_go", + "service_name": "go-service", + "service_keys": [] + } + }, + "test_optimization_data_python": { + "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", + "attributes": { + "enabled": false, + "go_module_included": false, + "go_module_path": "example.com/stub", + "go_sanitized_module_path": "example_com_stub", + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], + "out_dir": ".testoptimization", + "repo_alias": "test_optimization_data_python", + "service_name": "go-service", + "service_keys": [] + } + }, + "test_optimization_data_java": { + "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", + "attributes": { + "enabled": false, + "go_module_included": false, + "go_module_path": "example.com/stub", + "go_sanitized_module_path": "example_com_stub", + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], + "out_dir": ".testoptimization", + "repo_alias": "test_optimization_data_java", + "service_name": "go-service", + "service_keys": [] + } + }, + "test_optimization_data_nodejs": { + "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", + "attributes": { + "enabled": false, + "go_module_included": false, + "go_module_path": "example.com/stub", + "go_sanitized_module_path": "example_com_stub", + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], + "out_dir": ".testoptimization", + "repo_alias": "test_optimization_data_nodejs", + "service_name": "go-service", + "service_keys": [] + } + }, + "test_optimization_data_dotnet": { + "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", + "attributes": { + "enabled": false, + "go_module_included": false, + "go_module_path": "example.com/stub", + "go_sanitized_module_path": "example_com_stub", + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], + "out_dir": ".testoptimization", + "repo_alias": "test_optimization_data_dotnet", + "service_name": "go-service", + "service_keys": [] + } + }, + "test_optimization_data_ruby": { + "repoRuleId": "@@//tools/tests:example_stub_repo.bzl%example_stub_repo", + "attributes": { + "enabled": false, + "go_module_included": false, + "go_module_path": "example.com/stub", + "go_sanitized_module_path": "example_com_stub", + "labels": [ + "apps_ruby_example", + "company_product_example", + "example_nodejs_project", + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests" + ], + "out_dir": ".testoptimization", + "repo_alias": "test_optimization_data_ruby", + "service_name": "go-service", + "service_keys": [] + } } }, "recordedRepoMappingEntries": [] @@ -632,7 +766,7 @@ }, "@@rules_go+//go:extensions.bzl%orchestrion": { "general": { - "bzlTransitiveDigest": "uIO2EchVSMbv16d1L5xwC7jjFHQIFzeFujpfBcA4zU4=", + "bzlTransitiveDigest": "k6TuFeNdo4I01jk91s4xBDhniwJJf3syb0kGpA/q7QA=", "usagesDigest": "9kKEG/hjK4fnk42l4jAKDLhx9xExyCYAS8r8NlbPLMw=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, diff --git a/README.md b/README.md index 89c10c2e..9ddebbc1 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,71 @@ Pick the path that matches your repository: - **Bzlmod + .NET companion:** `dd_topt_dotnet_test` macro with analysis-time selection - **Bzlmod + Ruby companion:** `dd_topt_ruby_test` macro with analysis-time selection - **Bzlmod + multi-service monorepo:** one sync extension, per-service labels/exports +- **Managed Go/Python monorepo:** one invocation-scoped aggregate repository, + with targets and services derived by a consumer-owned command instead of a + checked-in mapping - **WORKSPACE mode:** fully supported for v1 when Bzlmod is disabled, including Go, Python, and Java companion helpers - **Other languages:** use core sync/uploader now, or follow companion patterns for custom `dd_topt__test` modules +### Sync contract comparison + +| Contract | Service selection | Repository shape | Intended use | +|---|---|---|---| +| `test_optimization_sync` | One checked-in service | One repository | Small or single-service workspaces | +| `test_optimization_multi_sync` | Checked-in service list | One repository per service plus an aggregator | Stable static multi-service wiring | +| `test_optimization_manifest_sync` | Invocation-scoped, fully expanded Go/Python targets | One aggregate repository with per-context and per-module labels | Consumer-owned managed commands that derive services automatically | + +The manifest-driven API is additive. Existing single-service and static +multi-service consumers do not need to migrate. + +### Ordinary and managed execution + +An ordinary test command omits `--config=test-optimization`. Config-gated Go +and Python wrappers preserve the repository's normal test behavior, the +manifest repository emits stable disabled stubs, and no Datadog metadata is +requested. + +A managed command owns two Bazel phases behind one user-facing entrypoint: + +1. query and fully expand the requested Go/Python test labels; +2. derive service and runtime contexts from those labels and write a private, + temporary manifest; +3. run metadata sync and the exact selected tests with + `--config=test-optimization`; +4. run the workspace doctor against the generated exact-target list, then run + uploader dry-run and optional upload. + +The command reuses one manifest path and one resolved metadata snapshot for +test, doctor, dry-run, and upload. A later command invocation creates a new +manifest path and fetches current backend state once. When the selected +settings and module payloads are unchanged, those stable test inputs remain +byte-identical and normal Bazel test-result cache hits are preserved. +`telemetry_facts.json` may contain different request timings between +invocations, but it is post-test context and is not a test action input. + +Adding or removing a target from the managed invocation changes the temporary +manifest; it does not require a committed target-to-service registry or +per-service repository declaration. The rules in this repository consume that +manifest, but target discovery and service-name policy remain owned by the +consumer command. + +```mermaid +flowchart LR + U[Requested Bazel labels] --> Q[Consumer-owned target discovery] + Q --> M[Temporary Go/Python manifest] + M --> R[One aggregate metadata repository] + R --> T[Exact selected tests] + T --> D[Doctor with exact target set] + D --> V[Uploader dry-run] + V --> X[Optional upload] +``` + +See [Installation Reference](docs/Installation_Reference.md#manifest-driven-managed-gopython-monorepos), +[Configuration Reference](docs/Configuration_Reference.md#manifest-sync-extension-attributes), +[Language Onboarding](docs/Language_Onboarding.md#automatic-managed-gopython-monorepos), +and [Troubleshooting](docs/Troubleshooting.md#manifest-driven-managed-runs) +for the detailed contract. + ## Documentation map Use this map to pick the right document instead of guessing from filenames. @@ -100,6 +162,7 @@ When multiple upstream `rules_go` versions are supported, `rules_go_upstream` selects the upstream support line. Omitting `rules_go_upstream` preserves the repository default. The default `rules_go_upstream` is currently `v0_60_0`, which preserves the existing `third_party/rgo/v0_60_0/base` path. +The registry also supports `v0_61_1` and `v0_62_0`. Maintainers track each supported upstream version with both patch series under `third_party/rules_go_orchestrion/patches//` and materialized base @@ -117,6 +180,34 @@ or merge it locally instead of vendoring a second complete `rules_go` tree. Use this checklist before your first CI rollout: +For config-gated Go and Python onboarding, the named `test-optimization` +config must include +`common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1`. The +public Go bootstrap helpers apply metadata gating by default. Manual Go +extension wiring uses the same config-gated default. Direct use of the +low-level core sync API in a config-gated Go or Python setup must opt into +`enabled_by_env = True`. Go +additionally needs +`build:test-optimization --@rules_go//go/private/orchestrion:enabled=true` +for Bzlmod, or the same flag with `@io_bazel_rules_go` for WORKSPACE. +Removing `--config=test-optimization` provides the complete metadata and +runtime opt-out for the Go and Python integrations described below. This +release does not change the enablement contract of the other companions. + +When the selected Go sync export is disabled, `dd_topt_go_test` validates its +macro-only inputs and selected service, then calls the supplied `go_test_rule` +directly under the public target name with the caller's original Go rule +arguments. It does not create the hidden raw test, payload selector, Bazel +metadata, Orchestrion pin, or public wrapper targets. This lets a consumer keep +one central `dd_go_test` entry point while the named config decides whether the +same BUILD call is a raw `go_test` or the existing enabled Test Optimization +shape. + +When a config-gated Python sync is disabled, `dd_topt_py_test` keeps the +consumer's normal runner and test arguments, omits Test Optimization metadata +and payload wiring, and applies the CI Visibility runtime kill switch +automatically. No per-target disable attribute is required. + 1. Keep the generated repo name as `test_optimization_data` (or consistently replace it in labels/commands if you choose another name). 2. Forward sync metadata environment variable names in `.bazelrc` under a named config, then use that config for test, doctor, and upload commands: @@ -248,19 +339,17 @@ test_optimization_sync.test_optimization_sync( use_repo(test_optimization_sync, "test_optimization_data") ``` +The low-level core API remains always enabled by default. Set +`enabled_by_env = True` only when this repository is part of the config-gated +Go or Python onboarding described below. Other companions retain their current +enablement contract. + ```bzl # BUILD.bazel (workspace root) -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") - -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = ["@test_optimization_data//:test_optimization_context"], -) +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") -dd_payload_uploader( - name = "dd_upload_payloads", - data = ["@test_optimization_data//:test_optimization_context"], +dd_test_optimization_targets( + name = "test_optimization", ) ``` @@ -378,9 +467,12 @@ The bootstrap helper: - creates a root `dd_upload_payloads` target when missing - can print or write the recommended `.bazelrc` block with `--print-bazelrc-snippet` or `--write-bazelrc` -- creates `//tools/build:dd_go_test.bzl` for workspace-local Go tests -- configures that wrapper with `orchestrion_mode = "test_optimization"` for the - standard Go `testing` Test Optimization path +- creates one central `//tools/build:dd_go_test.bzl` entry point for + workspace-local Go tests +- configures that wrapper to delegate every call to `dd_topt_go_test` with + `orchestrion_mode = "test_optimization"`; omitting the named config makes the + generated disabled export preserve normal `go_test` behavior under the same + public target name - writes a deterministic `orchestrion.tool.go` that matches the Bazel-side Orchestrion wiring - repins `dd-trace-go` and the Orchestrion-managed Go helper packages to the resolved tracer versions - writes a starter `orchestrion.yml` when missing @@ -438,7 +530,19 @@ Go setup. Manual Go callsites should set ### Bzlmod + Python companion (`dd_topt_py_test`) +Configure the Python sync extension with `enabled_by_env = True` and put +`common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1` in the +named config. Python does not declare `rules_go` and must not copy the Go-only +Orchestrion build flag. + ```bzl +bazel_dep(name = "datadog-rules-test-optimization", version = "1.2.0") +git_override( + module_name = "datadog-rules-test-optimization", + remote = "https://github.com/DataDog/rules_test_optimization.git", + commit = "", +) + bazel_dep(name = "datadog-rules-test-optimization-python", version = "1.2.0") git_override( module_name = "datadog-rules-test-optimization-python", @@ -446,6 +550,20 @@ git_override( commit = "", strip_prefix = "modules/python", ) + +python_topt = use_extension( + "@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", + "test_optimization_sync_extension", +) +python_topt.test_optimization_sync( + name = "test_optimization_data", + enabled_by_env = True, + runtime_module_path = "", + runtime_name = "python", + runtime_version = "3.12", + service = "python-service", +) +use_repo(python_topt, "test_optimization_data") ``` ```bzl @@ -483,7 +601,6 @@ dd_topt_py_test( name = "pkg_py_test", py_test_rule = my_repo_pytest_wrapper, runner_mode = "consumer_runner", - module_identifier = "example.python.pkg", srcs = glob(["test_*.py"]), deps = [ ":pkg_lib", @@ -497,8 +614,14 @@ dd_topt_py_test( In `consumer_runner` mode, pass a repository-owned `py_test_rule` wrapper or an explicit `main` that executes pytest with the ddtrace plugin enabled. The base `rules_python` `py_test` without `main` is rejected because it does not prove -pytest is actually running. Prefer `module_identifier` for payload selection in -this mode so the Datadog macro does not need to synthesize Python `imports`. +pytest is actually running. When the runtime module path and Bazel package path +identify the test, omit `module_identifier` and use the derived fallback. Pass +an explicit `module_identifier` only for a documented repository-specific +exception. When synchronized metadata exposes module groups, an explicit +identifier that does not match one fails analysis. If no module groups exist, +or an inferred or derived identifier misses, the selector uses the canonical +full bundle. The macro does not need to synthesize Python `imports` for the +normal path. Replace `@python_deps` with the repository name generated by your `rules_python` `pip_parse` / `pip.parse` setup. @@ -750,11 +873,12 @@ If your workspace always uses the same synced repo (`@test_optimization_data`) and the same underlying test rule symbols, create thin local wrappers so package BUILD files do not repeat `topt_data` and `*_test_rule`. -Keep plain wrappers and Test Optimization wrappers separate. A wrapper that is -loaded by non-instrumented BUILD files must not load -`@test_optimization_data//:export.bzl`, because the load itself consumes the -sync repository. Put the `@test_optimization_data` load only in the wrapper used -by instrumented targets. +For config-gated Go onboarding, keep one central wrapper. It always delegates +to `dd_topt_go_test`; the named config selects enabled metadata and +Orchestrion, while the stable disabled export preserves normal `go_test` +behavior without metadata requests. Python can use the same central-wrapper +shape when its sync repository sets `enabled_by_env = True`. Other companions +retain their existing enablement contract in this release. Single-service wrapper pattern for a simple Go workspace: @@ -915,6 +1039,7 @@ topt_go.test_optimization_sync( service = "go-service", runtime_name = "go", runtime_version = "1.25.0", + enabled_by_env = True, ) topt_ruby = use_extension( @@ -936,25 +1061,16 @@ Then load the matching export in each runtime-specific wrapper or BUILD file: - Go targets use `@test_optimization_data_go//:export.bzl` - Ruby targets use `@test_optimization_data_ruby//:export.bzl` -Root doctor/uploader wiring in a mixed-runtime workspace must bundle every +Workspace doctor/uploader wiring in a mixed-runtime setup must bundle every matching context target so validation and upload enrichment use the correct `context.json` per payload: ```bzl -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") - -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = [ - "@test_optimization_data_go//:test_optimization_context", - "@test_optimization_data_ruby//:test_optimization_context", - ], -) +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") -dd_payload_uploader( - name = "dd_upload_payloads", - data = [ +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ "@test_optimization_data_go//:test_optimization_context", "@test_optimization_data_ruby//:test_optimization_context", ], @@ -983,6 +1099,11 @@ test_optimization_sync( ) ``` +This low-level WORKSPACE example preserves the always-enabled core default. +The public Go extension is config-gated by default. Config-gated Python +consumers set `enabled_by_env = True` through their language-specific setup; +the other companions remain unchanged. + For Go in WORKSPACE mode, keep the core and Go companion as separate external repositories and load `dd_topt_go_test` from `@datadog-rules-test-optimization-go//:topt_go_test.bzl`. Prefer the public @@ -1011,8 +1132,11 @@ When Go tests live below the module root, pass the module-root pin files through or inject them from a repo-local wrapper. For large monorepos where root-level tool imports would churn or invalidate the main Go module, keep Orchestrion tool wiring in Bazel and use a repo-local -wrapper with package-local pin files or `orchestrion_pin_files = []`; do not add -a root `orchestrion.tool.go` just to satisfy the wrapper pattern. +wrapper with package-local pin files. An explicit +`orchestrion_pin_files = []` is valid only when the target package contains a +package-local `go.mod` that the macro can auto-discover. Otherwise pass visible +module-root labels, including `go.mod` and every relevant Orchestrion pin file; +do not add a root `orchestrion.tool.go` only to satisfy the wrapper pattern. For Python in WORKSPACE mode, declare `rules_python` and the core repository first, then use the public Python helper to declare only the Python companion: @@ -1077,17 +1201,17 @@ bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ --rules-go-variant base \ --rules-go-repo-name io_bazel_rules_go \ --write-bazelrc \ - --write-root-targets \ --write-orchestrion-files \ --write-wrapper-template ``` WORKSPACE mode does not edit `WORKSPACE`. It writes only Datadog-managed local -blocks/files such as `.bazelrc`, root doctor/uploader targets, -`orchestrion.tool.go`, `orchestrion.yml`, and an optional repo-local wrapper -template. By default it also avoids running Go module commands; pass an -explicit `--go-mod-sync=targeted` when you want bootstrap to repair the local -Orchestrion tool graph. +blocks/files such as `.bazelrc`, `orchestrion.tool.go`, `orchestrion.yml`, and +an optional repo-local wrapper template. Create the single doctor/uploader pair +in the monorepo's lightweight Test Optimization package instead of asking +bootstrap to modify the root BUILD. By default bootstrap also avoids running Go +module commands; pass an explicit `--go-mod-sync=targeted` when you want it to +repair the local Orchestrion tool graph. If your WORKSPACE repo also checks in Gazelle-style `go_repository(...)` declarations, ask bootstrap to validate those pins instead of discovering the @@ -1192,7 +1316,8 @@ Before rollout in a consumer repository, confirm the tracer/runtime implementati The extension performs these HTTP POST transactions (via host HTTP tooling: curl on Unix/macOS, PowerShell on Windows): -- Settings: always executed. Parses feature flags from response. +- Settings: always executed when the sync repository is enabled. Parses feature + flags from the response. Config-disabled repositories skip every HTTP request. - Known Tests: executed only when `known_tests_enabled: true` in Settings. - Test Management Tests: executed only when `test_management.enabled: true` in Settings. - Flaky Tests: executed only when `flaky_test_retries_enabled: true` in Settings. The raw backend response is persisted under `cache/http/flaky_tests.json` and then split into per-module `flaky_tests.json` files. @@ -1211,6 +1336,7 @@ Given an external repository name `` created by the extension, the ge - `cache/http/test_management.json` (Test Management Tests API response or minimal stub) - `cache/http/flaky_tests.json` (Flaky Tests API raw response or minimal stub `{"data": []}`) - `context.json` (Non-secret CI/Git/OS/runtime tags) + - `telemetry_facts.json` (Non-secret rule telemetry consumed by the uploader) - Per-module Known Tests/Test Management/Flaky Tests (via filegroups): each module has a target exposing canonical runfiles under `/cache/http/` with `known_tests.json`, `test_management.json`, and `flaky_tests.json`, scoped to that module. Physical files are stored under `/module_/` (default `` is `.testoptimization`). Reference settings with a single label: @@ -1242,7 +1368,9 @@ Sanitization rules for `` (file paths and target labels): - Consecutive underscores are collapsed, then leading/trailing underscores are trimmed - If collisions occur after sanitization, numeric suffixes like `_2`, `_3` are appended deterministically -Labels are computed from the union of module names across known tests and test management so a `module_` target always refers to a single module (avoids cross-feature collisions). +Labels are computed from the union of module names across known tests, test +management, and flaky tests so a `module_` target always refers to a +single module (avoids cross-feature collisions). Example usage: @@ -1358,8 +1486,12 @@ tools/test_optimization/run_test_optimization_ci.sh //... The wrapper creates a temporary BEP file for each Bazel test invocation and passes those files to doctor/uploader as repeatable `--bep-json` flags. The -default freshness source/mode is `auto`: when BEP is explicitly configured the -uploader uses it, otherwise it can use an explicitly configured legacy +doctor accounts for configured expected targets using the union of fresh and +cached BEP results, but validates payloads only from fresh outputs. An +all-cached expected-target invocation is therefore a successful no-op. The +uploader applies the same freshness filter and never uploads cached outputs. +The default freshness source/mode is `auto`: when BEP is explicitly configured, +the uploader uses it; otherwise it can use an explicitly configured legacy execution-log fallback. Artifact discovery defaults to local `bazel-testlogs` unless the wrapper or CLI sets `--artifact-source=bep`. In CI, uploads fail closed unless an explicit freshness source is available; outside CI the uploader @@ -1402,14 +1534,14 @@ bep_json="$(mktemp "${TMPDIR:-/tmp}/dd-topt-bep.XXXXXX.json")" artifact_staging_dir="$(mktemp -d "${TMPDIR:-/tmp}/dd-topt-artifacts.XXXXXX")" bazel test --config=test-optimization --build_event_json_file="$bep_json" //... -bazel run //:dd_test_optimization_doctor -- \ +bazel run --config=test-optimization //:dd_test_optimization_doctor -- \ --bep-json="$bep_json" \ --freshness-source=bep \ --freshness-mode=required \ --artifact-source=bep \ --artifact-staging-dir="$artifact_staging_dir" -bazel run //:dd_upload_payloads -- \ +bazel run --config=test-optimization //:dd_upload_payloads -- \ --bep-json="$bep_json" \ --freshness-source=bep \ --freshness-mode=required \ @@ -1478,7 +1610,7 @@ selective remote download flags, enable remote BEP artifact staging. Plain HTTP/HTTPS `outputs.zip` BEP carriers do not need a downloader: ```bash -bazel run //:dd_upload_payloads -- \ +bazel run --config=test-optimization //:dd_upload_payloads -- \ --bep-json="$bep_json" \ --freshness-source=bep \ --freshness-mode=required \ @@ -1562,9 +1694,18 @@ For complete uploader details, use [`docs/Uploader_Reference.md`](docs/Uploader_ ## Convenience macro: dd_topt_go_test -The `dd_topt_go_test` macro creates a `go_test` target with Datadog Test -Optimization data/env wiring included, and always runs through an internal -Orchestrion-enabled wrapper target. +The `dd_topt_go_test` macro preserves the caller's public target label in both +modes. When the selected sync export is enabled, that label is a public +`orch_go_test` wrapper around a hidden raw `go_test`, with Datadog Test +Optimization data/env wiring included. When the export is disabled, the same +label is the supplied raw `go_test_rule`; no Test Optimization-owned hidden +targets or argument mutations are created. + +Because the label is stable but its rule class is mode-dependent, automation +should prefer explicit target labels. If it uses Bazel's +`--test_lang_filters`, enabled Test Optimization invocations need `orch_go`, +ordinary raw Go invocations need `go`, and automation that covers both modes +should use `--test_lang_filters=go,orch_go` or omit the language filter. By default, it sets `rundir` to the current Bazel package when not explicitly provided. If you enable `stage_sources = True`, it instead defaults `rundir` @@ -1596,6 +1737,25 @@ go_topt.test_optimization_go( use_repo(go_topt, "test_optimization_data") ``` +The Go extension is config-gated by default, so the normal onboarding does not +need an enablement attribute. Consumers upgrading from `1.2.0` must add the +named config before updating the Rule; rerun `dd_topt_go_bootstrap` with +`--write-bazelrc` for an idempotent migration. A consumer that deliberately +keeps manually controlled, always-enabled metadata can set +`enabled_by_env = False`, but it must also keep the Orchestrion build setting +enabled; analysis rejects a partial activation. + +Without `--config=test-optimization`, the patched `rules_go` aliases select +package-local empty targets and the gated Orchestrion repository returns before +looking for a host Go binary or fetching/building Orchestrion source. The +disabled path therefore preserves the repository interface without requiring +Go to be installed on the analysis host. + +Consumer-owned central wrappers may always delegate capable packages to +`dd_topt_go_test`. The generated export and named config choose the raw or +instrumented shape, so BUILD callsites do not need a Test Optimization +attribute or a second macro name. + `module_path` should match the Go module path from `go.mod`. The sync rule still honors `GO_MODULE_PATH` first for CI overrides, but the explicit attr is the recommended default because it avoids repo-local `--repo_env` glue. @@ -1611,7 +1771,8 @@ the uploader enriches those JSON files with repository and Bazel metadata. Pass otherwise the default is `v2.9.0`. ```bash -bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap +bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ + --runtime-version ``` The bootstrap's default module-sync mode is `targeted`, which avoids a broad @@ -1619,30 +1780,60 @@ The bootstrap's default module-sync mode is `targeted`, which avoids a broad whole module, and use `--go-mod-sync=off` when another repository-owned command will update `go.mod` and `go.sum`. Use `--go-binary=/path/to/go` if the module must be synced with a specific Go SDK. The path must point to a `go` or -`go.exe` executable and must not include arguments. +`go.exe` executable and must not include arguments. This option controls the +one-time Go module update performed by bootstrap; enabled Bazel builds use the +SDK declared from `--runtime-version`. For WORKSPACE repos with checked-in `go_repository(...)` declarations, add `--check-go-repositories` after targeted sync. This catches stale `repositories.bzl` pins for `github.com/DataDog/orchestrion` and the three `dd-trace-go` modules before Bazel tries to build with mismatched versions. -If you wire Orchestrion manually instead of using bootstrap, you can also set -the tracer versions directly in `MODULE.bazel`. +Guided bootstrap declares a Bazel-managed Go SDK from `--runtime-version` and +passes its root and exact version to the Orchestrion repository. Enabled builds +therefore do not depend on a host `go` binary. The declaration is workspace-wide +and is not repeated for each service or test. -Shared-version form: +If you wire Orchestrion manually instead of using bootstrap, declare the same +SDK and let Bazel derive the selected tracer module versions from the +repository's checked-in `go.mod` and `go.sum`: ```bzl +test_optimization_go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +test_optimization_go_sdk.download( + name = "test_optimization_go_sdk", + version = "", +) +use_repo(test_optimization_go_sdk, "test_optimization_go_sdk") + orchestrion = use_extension("@rules_go//go:extensions.bzl", "orchestrion") orchestrion.from_source( version = "v1.9.0", - dd_trace_go_version = "v2.9.0", + dd_trace_go_pin_files = [ + "@//:go.mod", + "@//:go.sum", + ], + go_sdk_root = "@test_optimization_go_sdk//:ROOT", + go_sdk_version = "", ) use_repo(orchestrion, "rules_go_orchestrion_tool") ``` -Per-module form: +The root package must export those two files. Pin-file mode resolves direct and +transitive supported dd-trace-go modules with the Bazel-managed SDK and +`-mod=readonly`; it does not modify the consumer module. + +Use an explicit shared or per-module version only as an escape hatch for a +module graph that pin-file mode cannot resolve: ```bzl +test_optimization_go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +test_optimization_go_sdk.download( + name = "test_optimization_go_sdk", + version = "", +) +use_repo(test_optimization_go_sdk, "test_optimization_go_sdk") + orchestrion = use_extension("@rules_go//go:extensions.bzl", "orchestrion") orchestrion.from_source( version = "v1.9.0", @@ -1651,6 +1842,8 @@ orchestrion.from_source( "github.com/DataDog/dd-trace-go/contrib/net/http/v2": "v2.9.0", "github.com/DataDog/dd-trace-go/contrib/log/slog/v2": "v2.9.0", }, + go_sdk_root = "@test_optimization_go_sdk//:ROOT", + go_sdk_version = "", ) use_repo(orchestrion, "rules_go_orchestrion_tool") ``` @@ -1659,11 +1852,11 @@ The maintained repository integration scripts validate the hermetic Go path with explicit Bazel flags in the script itself. There is no special repo-root `--config=hermetic` shortcut for this flow. -If both settings are omitted, the default is still -`v2.9.0`. Manual setups must keep the local Go -module pins on the same effective versions, or the build will stop with a -mismatch error. Do not set both `dd_trace_go_version` and `dd_trace_go_versions` -in the same `orchestrion.from_source(...)` call. +If all three selection settings are omitted, the legacy default is still +`v2.9.0`. Manual setups must keep the local Go module pins on the same effective +versions, or the build will stop with a mismatch error. Do not combine +`dd_trace_go_pin_files`, `dd_trace_go_version`, or `dd_trace_go_versions` in +the same `orchestrion.from_source(...)` call. Bootstrap also refuses to take over tracer settings that are already managed manually outside its own managed block. @@ -1804,6 +1997,15 @@ dd_topt_go_test( ) ``` +When synchronized metadata exposes module groups, explicit `importpath` and +`module_label_override` selections fail analysis if their group is absent. If +no module groups exist, or inferred/derived selection misses, the selector uses +the canonical full bundle. Target metadata reports `full_bundle_disabled` when +no module groups exist and `full_bundle_no_match` when groups exist but +inferred/derived selection misses. The doctor rejects the latter by default; +only repositories that intentionally allow this generic fallback should set +`forbid_full_bundle_no_match = False` on the doctor target. + ### Multi-service usage This is the advanced/manual path. Guided bootstrap is intentionally limited to @@ -1882,9 +2084,9 @@ Fast checks before diving deep: - Verify sync env forwarding (`DD_API_KEY`, `DD_SITE`, and required `DD_GIT_*`) through `--repo_env`, not `--test_env`. - Force metadata refresh only when you intentionally need fresh backend state: - - `bazel sync --only= --repo_env=FETCH_SALT="$(date +%s)"` + - `bazel sync --config=test-optimization --only= --repo_env=FETCH_SALT="$(date +%s)"` - If Bazel reports WORKSPACE-disabled sync errors, retry with: - `bazel sync --enable_workspace --only= --repo_env=FETCH_SALT="$(date +%s)"` + `bazel sync --enable_workspace --config=test-optimization --only= --repo_env=FETCH_SALT="$(date +%s)"` - Do not add `FETCH_SALT` to normal `bazel test`, doctor, or uploader commands. - Confirm payload files exist under `bazel-testlogs/*/test.outputs/`, or that diff --git a/docs/Configuration_Reference.md b/docs/Configuration_Reference.md index 7e6fae58..cf448fa5 100644 --- a/docs/Configuration_Reference.md +++ b/docs/Configuration_Reference.md @@ -31,15 +31,15 @@ local files and managed blocks; it never edits `WORKSPACE` itself: | `--write-bazelrc` | `false` | Insert or replace the managed `.bazelrc` block. With `--guided`, bootstrap also continues the normal guided setup | | `--write-root-targets` | `false` | Insert or replace managed root `BUILD.bazel` blocks for doctor, uploader, and root pin exports | | `--write-orchestrion-files` | `false` | Write `orchestrion.tool.go`, `orchestrion.yml`, and pin-file exports for the selected Go module directory | -| `--write-wrapper-template` | `false` | Write a configurable repo-local Go wrapper template with plain and optimized wrapper paths | +| `--write-wrapper-template` | `false` | Write one config-gated repo-local Go wrapper template | | `--bazelrc-path` | `.bazelrc` | Path to the Bazel rc file updated by `--write-bazelrc` | | `--bazelrc-config` | `test-optimization` | Config name used by generated `common:` and `test:` lines | | `--sync-repo-name` | `test_optimization_data` | External repository name used by generated doctor, uploader, wrapper, and WORKSPACE sync snippets | | `--expected-target` | repeatable | Local label the generated doctor should require, for example `//pkg:go_default_test` | | `--wrapper-package` | `tools/build` | Workspace-relative Bazel package for the generated wrapper template | | `--wrapper-file` | `dd_topt_go_test.bzl` | Wrapper `.bzl` filename used by `--write-wrapper-template` | -| `--plain-wrapper-name` | `dd_go_test` | Plain local wrapper function name generated by the wrapper template | -| `--optimized-wrapper-name` | `dd_topt_go_test` | Optimized local wrapper function name generated by the wrapper template | +| `--plain-wrapper-name` | `dd_go_test` | Central local wrapper function name generated by the wrapper template | +| `--optimized-wrapper-name` | `dd_topt_go_test` | Compatibility alias for the central wrapper; not a separate enablement path | | `--datadog-fetch` | `git` | Fetch mode for `datadog-rules-test-optimization-go`: `git` or `archive` | | `--rules-go-fetch` | `git` | Fetch mode for the Orchestrion-enabled `rules_go` fork: `git` or `archive` | | `--rules-go-upstream` | `default` | Datadog-managed upstream support line. Omit this to preserve the repository default; the current default resolves to `v0_60_0` | @@ -98,12 +98,22 @@ Manual Orchestrion wiring in `MODULE.bazel` accepts: | Setting | Default | Description | |---------|---------|-------------| -| `orchestrion.from_source(..., dd_trace_go_version = "...")` | `v2.9.0` | Shared canonical tracer version that Bazel validates against the target Go module and uses for synthetic fallback paths | +| `orchestrion.from_source(..., dd_trace_go_pin_files = ["@//:go.mod", "@//:go.sum"])` | none | Preferred consumer mode. Derives exact direct and transitive supported tracer versions from one checked-in `go.mod` and `go.sum` using the Bazel-managed Go SDK and `-mod=readonly` | +| `orchestrion.from_source(..., dd_trace_go_version = "...")` | legacy `v2.9.0` when no selection mode is set | Explicit shared-version escape hatch that Bazel validates against the target Go module | | `orchestrion.from_source(..., dd_trace_go_versions = {...})` | none | Exact canonical per-module tracer versions that Bazel validates against the target Go module for `github.com/DataDog/dd-trace-go/v2`, `github.com/DataDog/dd-trace-go/contrib/net/http/v2`, and `github.com/DataDog/dd-trace-go/contrib/log/slog/v2` | +| `orchestrion.from_source(..., go_sdk_root = "@repo//:ROOT")` | none | Bazel-managed Go SDK root used to build Orchestrion instead of discovering a host `go` binary | +| `orchestrion.from_source(..., go_sdk_version = "...")` | none | Exact version of `go_sdk_root`; enables bootstrap-cache lookup before SDK materialization and is verified after materialization on a miss | Notes: - The selected version is workspace-wide for Go. There is no per-test override. +- Pin-file mode is the normal consumer path. It requires exactly one file named + `go.mod` and one named `go.sum`, requires `go_sdk_root`, never uses host Go, + and never edits either file. If a supported tracer module is absent or the + copied module cannot be resolved read-only, use the explicit per-module map. +- Guided bootstrap declares `go_sdk_root` and `go_sdk_version` from + `--runtime-version`. Manual wiring must set both together and keep the version + equal to the registered Go toolchain and Test Optimization `runtime_version`. - Bootstrap repins the local Go module to the same effective versions. - Bootstrap uses targeted module sync by default and does not run `go mod tidy` unless `--go-mod-sync=tidy` is selected. @@ -122,8 +132,8 @@ Notes: - Bootstrap refuses to proceed when active tracer settings already exist in `orchestrion.from_source(...)` calls outside its managed block. Those manual settings must be removed or migrated first. -- Do not set both `dd_trace_go_version` and `dd_trace_go_versions` in the same - `orchestrion.from_source(...)` call. +- `dd_trace_go_pin_files`, `dd_trace_go_version`, and + `dd_trace_go_versions` are mutually exclusive. - If the workspace setting and the effective local Go module versions differ, the build fails instead of mixing versions. @@ -175,6 +185,9 @@ Extension tag: `test_optimization_sync.test_optimization_sync(...)` | `http_execute_timeout_buffer_seconds` | int | `-1` attr / `60` effective | Optional outer execute-timeout buffer override (`-1` keeps env/default behavior) | | `known_tests` | bool | `True` | Local switch for Known Tests request. When `False`, request is skipped, a minimal stub is written, and settings are mutated to `known_tests_enabled=false` | | `test_management` | bool | `True` | Local switch for Test Management request. When `False`, request is skipped, a minimal stub is written, and settings are mutated to `test_management.enabled=false` | +| `flaky_tests` | bool | `True` | Local switch for Flaky Tests request. When `False`, request is skipped, a minimal stub is written, and settings are mutated to `flaky_test_retries_enabled=false` | +| `enabled` | bool | `True` | Hard enablement switch. When `False`, the repository emits the deterministic disabled interface and skips local Git discovery and metadata HTTP requests | +| `enabled_by_env` | bool | `False` | When `True`, additionally gate enablement on `DD_TEST_OPTIMIZATION_ENABLED` (`1`, `true`, `yes`, or `on`, case-insensitive). Unset and false values emit the disabled interface. The public Go extension and Go WORKSPACE helper override this low-level default to `True` | | `require_git_metadata` | bool | `False` | Strict local/CI validation for settings-request Git metadata. When `True`, sync fails before HTTP if repository URL, branch or tag, and commit SHA cannot be resolved | | `debug` | bool | `False` | Enables verbose repository-rule logging | @@ -208,9 +221,74 @@ Extension tag: `test_optimization_multi_sync.test_optimization_multi_sync(...)` | `http_execute_timeout_buffer_seconds` | int | `-1` attr / `60` effective | Optional outer execute-timeout buffer override propagated to each per-service sync repo (`-1` keeps env/default behavior) | | `known_tests` | bool | `True` | Known Tests kill-switch propagated to each per-service sync repo | | `test_management` | bool | `True` | Test Management kill-switch propagated to each per-service sync repo | +| `flaky_tests` | bool | `True` | Flaky Tests kill-switch propagated to each per-service sync repo | +| `enabled` | bool | `True` | Hard enablement switch propagated to every generated per-service sync repo | +| `enabled_by_env` | bool | `False` | Environment gate propagated to every generated per-service sync repo. Config-gated consumers must set this to `True` | | `require_git_metadata` | bool | `False` | Strict Git metadata validation propagated to each per-service sync repo | | `debug` | bool | `False` | Enables verbose logging for generated per-service sync repos | +## Manifest-sync extension attributes + +Extension tag: +`test_optimization_manifest_sync.test_optimization_manifest_sync(...)`. +The WORKSPACE repository rule has the same attributes. This API is only for a +consumer-managed, invocation-scoped Go/Python flow; static APIs remain +unchanged. + +| Attribute | Type | Default | Description | +|-----------|------|---------|-------------| +| `name` | string | required | Aggregate repository name | +| `repo_name` | string | repository name | WORKSPACE repository-rule-only apparent aggregate name used in generated labels; normally leave unset | +| `out_dir` | string | `contexts` | Relative root containing one `/.testoptimization` tree per context | +| `http_connect_timeout_seconds` | int | `-1` attr / `10` effective | Optional connect-timeout override | +| `http_max_time_seconds` | int | `-1` attr / `60` effective | Optional per-request max-time override | +| `http_retry_attempts` | int | `-1` attr / `3` effective | Optional request retry count | +| `http_retry_delay_seconds` | int | `-1` attr / `2` effective | Optional request retry delay | +| `http_execute_timeout_buffer_seconds` | int | `-1` attr / `60` effective | Optional outer execute-timeout buffer | +| `known_tests` | bool | `True` | Fetch and split Known Tests metadata | +| `test_management` | bool | `True` | Fetch and split Test Management metadata | +| `flaky_tests` | bool | `True` | Fetch and split Flaky Tests metadata | +| `enabled` | bool | `True` | Hard enablement switch | +| `enabled_by_env` | bool | `True` | Apply the named config gate; unset/false emits stable disabled stubs | +| `require_git_metadata` | bool | `False` | Fail enabled sync before HTTP when required Git metadata is missing | +| `debug` | bool | `False` | Enable repository-rule diagnostics | + +The implementation reserves +`DD_TEST_OPTIMIZATION_SERVICES_MANIFEST` as the fixed private handoff from a +consumer-owned managed command. It is not a public rollout switch and must not +be added to a user's `.bazelrc` or set in ordinary jobs. Enabled resolution +requires it to name a valid schema-v1 manifest; disabled resolution ignores it. + +One managed command invocation must keep that exact manifest path and +environment value for test, doctor, uploader dry-run, and optional upload. +Those phases therefore share one resolved repository snapshot. A later command +invocation owns a new temporary manifest path and performs one new fetch round. +Equivalent backend settings and module payloads remain byte-identical test +inputs, preserving Bazel test-result cache hits. `telemetry_facts.json` is +doctor/uploader context and must not be added to test action inputs. + +Schema v1 contains: + +- non-empty `contexts`, each with deterministic `key`, `service`, and a + `runtime` object (`name`, `version`, optional `arch`, and `module_path`); +- non-empty `targets`, each with a canonical local `label`, `context_key`, and + `service_derivation` (`application` or `domain_fallback`); +- Go and Python runtimes only. + +Validation rejects unknown keys, duplicate or non-canonical labels, duplicate +contexts, unused contexts, unsupported runtimes, key collisions, and targets +whose context is absent. Normalized contexts and targets are sorted so +equivalent manifests render byte-identical repository surfaces. + +Generated labels: + +- `:test_optimization_files_` +- `:test_optimization_context_` +- `:module__` +- aggregate `:test_optimization_files` +- aggregate `:test_optimization_context` +- `:expected_targets` + ## Uploader rule attributes Rule: `dd_payload_uploader(...)` @@ -226,6 +304,8 @@ Rule: `dd_payload_uploader(...)` | `filter_prefix` | bool | `False` | Only upload files matching `span_events_*.json` or `coverage_*.json` | | `gzip_payloads` | bool | `False` | Gzip test payloads before upload | | `data` | label_list | `[]` | Data files to include (for example, `context.json` for enrichment) | +| `expected_targets` | string_list | `[]` | Optional exact local labels expected in the matching BEP. Fresh and cached results jointly satisfy coverage; only fresh outputs are inspected or uploaded | +| `expected_targets_file` | label | unset | Optional schema-v1 exact-target file. Static and file inputs must match when both are non-empty | ## Doctor rule attributes @@ -238,8 +318,9 @@ delete, or rewrite source payloads. | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `name` | string | required | Target name | -| `data` | label_list | `["@test_optimization_data//:test_optimization_context"]` in examples | Context targets used to validate Git metadata before upload | +| `data` | label_list | `["@test_optimization_data//:test_optimization_context"]` in examples | Context targets bundle `context.json` and `telemetry_facts.json`. Doctor selects `context.json` for Git validation; the same labels can be reused by the uploader for enrichment and rule telemetry | | `expected_targets` | string_list | `[]` | Optional strict list of local Bazel test labels to validate. When empty, the doctor validates discovered Test Optimization output directories and ignores plain non-instrumented test outputs | +| `expected_targets_file` | label | unset | Optional schema-v1 JSON file containing the exact invocation-scoped target set. Static and file inputs must match when both are non-empty | | `require_git_metadata` | bool | `True` | Require `git.repository_url`, `git.commit.sha`, and `git.branch` or `git.tag` in synced context data | | `require_bazel_metadata` | bool | `True` | Require `bazel_target_metadata.json` next to selected payload outputs | | `require_json_payloads` | bool | `True` | Require parseable `.json` payload files | @@ -295,10 +376,11 @@ workspace root package. | `sync_repo_name` | string | `"test_optimization_data"` | Repository exposing `:test_optimization_context` | | `doctor_name` | string | `"dd_test_optimization_doctor"` | Generated doctor target name | | `uploader_name` | string | `"dd_upload_payloads"` | Generated uploader target name | -| `expected_targets` | string_list | `[]` | Strict labels passed to the doctor. List only instrumented runtime test targets that emit payloads | +| `expected_targets` | string_list | `[]` | Strict labels passed to both doctor and uploader. List only instrumented runtime test targets that emit payloads | +| `expected_targets_file` | label or `None` | `None` | Generated exact-target JSON file forwarded to both doctor and uploader for manifest-driven invocations | | `context_data` | label_list or `None` | `["@//:test_optimization_context"]` | Explicit context data labels when the default sync repo label is not enough | -| `doctor_kwargs` | dict or `None` | `{}` | Extra attrs for `dd_test_optimization_doctor`; cannot override `name`, `data`, or `expected_targets` | -| `uploader_kwargs` | dict or `None` | `{}` | Extra attrs for `dd_payload_uploader`; cannot override `name` or `data` | +| `doctor_kwargs` | dict or `None` | `{}` | Extra attrs for `dd_test_optimization_doctor`; cannot override `name`, `data`, `expected_targets`, or `expected_targets_file` | +| `uploader_kwargs` | dict or `None` | `{}` | Extra attrs for `dd_payload_uploader`; cannot override `name`, `data`, `expected_targets`, or `expected_targets_file` | Example: @@ -364,6 +446,32 @@ invocation. They do not include `FETCH_SALT`, `DD_GIT_*` test env, `DD_API_KEY` test env, upload endpoint test env, or `DD_CIVISIBILITY_AGENTLESS_ENABLED`. +For Go onboarding, the generated block also contains +`common: --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1` and the existing +`rules_go` analysis setting +`build: --@//go/private/orchestrion:enabled=true`. +`--config=` is the single user-facing switch: removing it disables +both metadata resolution and the real Orchestrion aliases. + +In that disabled state, the patched `rules_go` aliases select package-local +empty targets and the gated Orchestrion repository writes its stable empty +interface before host-Go discovery or source fetching. Analysis can therefore +resolve ordinary Go targets without a host Go binary while the config is absent. + +For Go, the disabled generated export also changes the macro expansion. +`dd_topt_go_test` performs its macro-input and service-selection validation, +then invokes the supplied `go_test_rule(name = name, **kwargs)` directly. It +does not run importpath inference, select metadata payloads, inject Datadog +environment/data/linker inputs, or create hidden Test Optimization or +Orchestrion targets. The enabled export preserves the existing instrumented +expansion. Consumer-owned wrappers can therefore expose one public Go test +macro in both modes. + +Config-gated Python onboarding uses the same +`DD_TEST_OPTIMIZATION_ENABLED=1` repository environment entry but does not use +the Go-only Orchestrion setting. The Java, NodeJS, .NET, and Ruby companions +retain their existing enablement contract in this release. + ## How data is fetched The sync rule executes HTTP requests with timeouts/retries to: diff --git a/docs/Initial_documentation.md b/docs/Initial_documentation.md index 9896579e..e88fc31e 100644 --- a/docs/Initial_documentation.md +++ b/docs/Initial_documentation.md @@ -11,31 +11,52 @@ This product includes software developed at Datadog This document explains the current implementation architecture in this repository. For installation and day-to-day usage, start with `README.md`. -> Last reviewed: 2026-05-07 +> Last reviewed: 2026-07-27 ## Approach Overview -The integration uses a Bazel module extension and repository rule to fetch -Datadog Test Optimization metadata during module/repo resolution, a +The integration uses a Bazel module extension and repository rule to +materialize the Test Optimization repository during module/repo resolution, a workspace-level doctor (via `bazel run`) to validate local outputs after tests, and a workspace-level uploader (via `bazel run`) to ship payloads from hermetic -test runs. +test runs. Enabled repositories fetch Datadog metadata. Config-gated disabled +repositories expose the same public Bazel interface using deterministic stubs +without local Git discovery or HTTP requests. The steps are: 1. **Module/repository sync**: - A module extension instantiates a repository rule that performs authenticated HTTP requests to Datadog (settings, known tests, and test‑management tests when enabled). It materializes JSON outputs under a configurable directory (default: `.testoptimization/`), writes a non‑secret `context.json`, and exposes public filegroups: + A module extension instantiates a repository rule that resolves enablement + before collecting local metadata. When enabled, it performs authenticated + HTTP requests to Datadog (settings, known tests, test-management tests, and + flaky tests when enabled). When disabled, it writes canonical + settings/cache/context stubs and does not inspect local Git or contact + Datadog. Both paths + materialize outputs under a configurable directory (default: + `.testoptimization/`) and expose the stable top-level filegroups: - `@//:test_optimization_files` (core bundle, includes `cache/http/settings.json`) - - `@//:test_optimization_context` (the `context.json` only) - - `@//:module_` (per‑module bundle: `cache/http/settings.json` + that module’s known/test‑management files) + - `@//:test_optimization_context` (`context.json` plus + `telemetry_facts.json`) + When an enabled response contains module data, the repository additionally + exposes `@//:module_` bundles with + `cache/http/settings.json` plus that module's known-tests, test-management, + and flaky-tests files. The sync also emits an `export.bzl` helper describing available module labels, the resolved `manifest_path`, and detected runtime/module hints for consumers. Per‑module targets expose canonical runfile names rooted at the manifest directory (`/...`, default `.testoptimization/...`) regardless of where split files are stored physically. Notes: - `DD_SITE` accepts bare host, app/api-prefixed host, or full URL; ASCII whitespace is trimmed and value is normalized to `https://api.`. - - Module labels are computed from the union of known-tests and test-management modules to avoid cross-feature collisions. + - Module labels are computed from the union of known-tests, + test-management, and flaky-tests modules to avoid cross-feature + collisions. Reference implementation: this repository 2. **Test instrumentation**: - Tests are instrumented by the tracer library as usual. Under Bazel, they discover synced metadata via runfiles (for example through `DD_TEST_OPTIMIZATION_MANIFEST_FILE`) and write test/coverage payloads to `TEST_UNDECLARED_OUTPUTS_DIR`. + Enabled tests are instrumented by the tracer library as usual. Under Bazel, + they discover synced metadata via runfiles (for example through + `DD_TEST_OPTIMIZATION_MANIFEST_FILE`) and write test/coverage payloads to + `TEST_UNDECLARED_OUTPUTS_DIR`. The config-gated Go and Python companions + consume the disabled export as a real no-op: they preserve the consumer's + ordinary test behavior without Test Optimization selectors, metadata + targets, or payload instrumentation. 3. **Payload validation and reporting**: A single workspace-level doctor runs via `bazel run` after tests complete and validates local JSON payloads, Bazel target metadata, Git metadata, and invalid Go payload-selection states. A single workspace-level uploader then discovers all `test.outputs/` directories in `bazel-testlogs/`, waits for payloads to quiesce, enriches them with `context.json`, and uploads via agentless (`DD_API_KEY`, `DD_SITE`) or EVP proxy (`DD_TEST_OPTIMIZATION_AGENT_URL`). @@ -57,6 +78,71 @@ The steps are: - Core module (`datadog-rules-test-optimization`) stays runtime-agnostic. - Language orchestration lives in companion modules (`datadog-rules-test-optimization-go`, `datadog-rules-test-optimization-python`, `datadog-rules-test-optimization-java`, `datadog-rules-test-optimization-nodejs`, `datadog-rules-test-optimization-dotnet`, `datadog-rules-test-optimization-ruby`). +### Static and manifest-driven repository architectures + +The original static APIs remain supported: + +- `test_optimization_sync` materializes one configured service. +- `test_optimization_multi_sync` materializes one repository per configured + service and an aggregator. + +`test_optimization_manifest_sync` is a separate managed API for dynamic +Go/Python monorepo invocations. A consumer-owned command first expands exact +test labels and derives service/runtime contexts. The repository rule then +validates the command-owned temporary manifest before any HTTP request and +materializes all contexts in one aggregate repository. Disabled mode ignores +the manifest entirely and emits the same stable public stubs without metadata +requests. + +```mermaid +flowchart TB + subgraph Consumer["Consumer-owned managed command"] + I[Requested target patterns] --> Q[Bazel query and target expansion] + Q --> N[Service/runtime derivation] + N --> M[Private temporary manifest] + end + + subgraph Repository["Bazel repository phase"] + M --> V[Strict schema validation] + V --> A[Aggregate external repository] + A --> C1[Context A files] + A --> C2[Context B files] + C1 --> MX[Module X label] + C1 --> MY[Module Y label] + C2 --> MZ[Module Z label] + end + + subgraph Execution["Bazel test and post-test phases"] + MX --> TX[Selected target X] + MY --> TY[Selected target Y] + MZ --> TZ[Selected target Z] + TX --> D[Doctor exact-target validation] + TY --> D + TZ --> D + D --> U[Uploader dry-run and optional upload] + end +``` + +The command presents one workflow to the user, but Bazel still has two +different phases. Target discovery must happen before repository resolution +because repository rules cannot discover the final analyzed test set. The +temporary manifest is therefore an internal handoff between those phases, not +user-maintained configuration. + +Within one managed command, test, doctor, uploader dry-run, and optional upload +reuse the exact same manifest path and external-repository snapshot. A later +command uses a new temporary path and fetches current backend state once. +Stable settings and per-module payload files are the test action inputs, so +unchanged backend responses preserve normal Bazel test-result caching. +`telemetry_facts.json` may vary with request timings but remains post-test +doctor/uploader context rather than a test input. + +Each selected target consumes only its context's settings and matching module +label. A module payload change invalidates targets in that module; a context +settings change invalidates all targets in that context; unrelated services +remain cache hits. Doctor and uploader consume the aggregate context target, +whose virtual context keys preserve exact per-payload enrichment. + ### Go macro and import path inference The `dd_topt_go_test` macro automatically selects the correct per‑module payloads by inferring the Go package `importpath` using `rules_go` providers, mirroring how `go_test` computes it. @@ -67,8 +153,14 @@ The `dd_topt_go_test` macro automatically selects the correct per‑module paylo 2) Provider‑based inference via `embed` 3) Fallback to `/`, where the module path is exported by the sync repo in `topt_data["runtimes"]["go"]["module_path"]` - Per‑module selection: - - When using (1) or (2), the macro always attempts per‑module selection and falls back to the full bundle if the module isn’t present. - - When using (3), the macro consults `topt_data["runtimes"]["go"]["module_included"]` as a coarse gate; if false, it uses the full bundle. + - When synchronized metadata exposes module groups, explicit `importpath` or + `module_label_override` values must match one or analysis fails. When no + module groups exist, the canonical full bundle remains valid. + - Provider-based inference via `embed` attempts per-module selection and may + fall back to the canonical full bundle on a miss. + - When using (3), the macro consults + `topt_data["runtimes"]["go"]["module_included"]` as a coarse gate; if + false, it uses the full bundle. Note: The core module no longer declares `rules_go`. The companion module `datadog-rules-test-optimization-go` declares `rules_go` for provider @@ -84,6 +176,11 @@ definitions only. Consumers still configure Go toolchains/SDK in their own 3) fallback from `/` when available, 4) full-bundle fallback. +When synchronized metadata exposes module groups, explicit +`module_identifier` and `module_label_override` values must match one or +analysis fails. The full-bundle fallback applies to inferred or derived +identifiers and to metadata with no module groups. + ### Java macro and package identifier inference `dd_topt_java_test` applies analysis-time selection with this precedence: @@ -211,10 +308,17 @@ flowchart TD A1[Bazel module extension\n test_optimization_sync_extension] A2[Repository rule\n test_optimization_sync] A1 --> A2 - A2 -->|POST Settings| D1[Datadog Settings API] - A2 -->|POST Known Tests (if enabled)| D2[Known Tests API] - A2 -->|POST Test Mgmt (if enabled)| D3[Test Management Tests API] - A2 --> A3[.testoptimization (default)\n manifest.txt\n context.json\n cache/http/settings.json\n cache/http/known_tests.json\n (per-module targets expose canonical files)\n cache/http/test_management.json\n (per-module targets expose canonical files)] + A2 --> G{Enabled?} + G -->|yes: POST Settings| D1[Datadog Settings API] + G -->|yes: POST Known Tests| D2[Known Tests API] + G -->|yes: POST Test Mgmt| D3[Test Management Tests API] + G -->|yes: POST Flaky Tests| D4[Flaky Tests API] + G -->|no| D0[Deterministic disabled stubs\n no local Git or HTTP] + D1 --> A3[.testoptimization (default)\n manifest.txt\n context.json\n telemetry_facts.json\n cache/http/settings.json\n cache/http/known_tests.json\n cache/http/test_management.json\n cache/http/flaky_tests.json\n (per-module targets expose canonical files)] + D2 --> A3 + D3 --> A3 + D4 --> A3 + D0 --> A3 A2 --> A4[export.bzl + BUILD\n filegroups per module] end @@ -264,13 +368,16 @@ Module/Repo Resolution | |-- POST Settings --> (Settings API) | |-- POST Known Tests (if enabled) --> (Known Tests API) | |-- POST Test Mgmt (if enabled) --> (Test Mgmt Tests API) + | |-- POST Flaky Tests (if enabled) --> (Flaky Tests API) | v | .testoptimization/ (default out_dir) | - manifest.txt | - context.json + | - telemetry_facts.json | - cache/http/settings.json | - cache/http/known_tests.json (+ per-module) | - cache/http/test_management.json (+ per-module) + | - cache/http/flaky_tests.json (+ per-module) | export.bzl + BUILD (filegroups) v Build Graph @@ -297,11 +404,12 @@ Optional: Multi-service aggregator ## Summary -The repository extension approach enables Bazel support for Test Optimization in -a hermetic, cache-friendly way. Metadata is fetched once during module/repo -resolution, exposed as filegroups, and consumed by tests via runfiles. -Per-module outputs limit cache impact to relevant targets. Post-test validation -and runtime uploads happen through workspace-level `bazel run` targets, -preserving hermetic execution for tests. Settings and Test Management remain -valuable even with occasional invalidations; Known Tests and any future TIA -integration should be opt-in to avoid disrupting established Bazel workflows. +The repository extension approach enables Bazel support for Test Optimization +in a hermetic, cache-friendly way. When enabled, metadata is fetched once during +module/repo resolution; when config-gated and disabled, the same labels expose +deterministic stubs without Git or network work. Per-module outputs limit cache +impact to relevant targets. Post-test validation and runtime uploads happen +through workspace-level `bazel run` targets, preserving hermetic execution for +tests. Settings and Test Management remain valuable even with occasional +invalidations; Known Tests and any future TIA integration should be opt-in to +avoid disrupting established Bazel workflows. diff --git a/docs/Installation_Reference.md b/docs/Installation_Reference.md index 73cdbe83..1bea65f3 100644 --- a/docs/Installation_Reference.md +++ b/docs/Installation_Reference.md @@ -206,6 +206,12 @@ test_optimization_sync.test_optimization_sync( use_repo(test_optimization_sync, "test_optimization_data") ``` +The low-level core sync remains always enabled by default. The public Go +extension is config-gated by default; config-gated Python onboarding sets +`enabled_by_env = True` in its language-specific setup. Do not add that +attribute to another companion until its runtime wrapper implements the +disabled export contract. + Core module note: `datadog-rules-test-optimization` is runtime-agnostic and does not declare language-rule dependencies. Language-specific orchestration lives in companion modules: @@ -307,17 +313,22 @@ bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ --rules-go-variant base \ --rules-go-repo-name io_bazel_rules_go \ --write-bazelrc \ - --write-root-targets \ --write-orchestrion-files \ --write-wrapper-template \ --expected-target //pkg:go_default_test ``` -The generated wrapper template creates a plain local wrapper and an optimized -local wrapper. Keep repository-specific scheduling, tags, flaky behavior, -Docker defaults, and platform constraints in the local policy helper; the -optimized wrapper owns only `topt_data`, `orchestrion_mode = "test_optimization"`, -and `orchestrion_pin_files`. +Create the single doctor/uploader pair in a lightweight monorepo package such +as `//tools/test_optimization`; reserve `--write-root-targets` for small +repositories that intentionally keep these targets in the root BUILD. + +The generated wrapper template creates one central local wrapper and retains +the former optimized name only as a compatibility alias. Keep +repository-specific scheduling, tags, flaky behavior, Docker defaults, and +platform constraints in the local policy helper; the central wrapper owns only +`topt_data`, `orchestrion_mode = "test_optimization"`, and +`orchestrion_pin_files`. Omitting `--config=test-optimization` preserves normal +`go_test` behavior through that same entry point. WORKSPACE mode does not run Go module commands unless `--go-mod-sync` is passed explicitly, so large repos can review generated files before changing `go.mod`/`go.sum`. @@ -387,6 +398,8 @@ Use `--write-bazelrc` to insert or replace the managed The generated config is named `test-optimization` by default: ```text +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true common:test-optimization --repo_env=DD_API_KEY common:test-optimization --repo_env=DD_SITE common:test-optimization --repo_env=DD_GIT_REPOSITORY_URL @@ -414,8 +427,9 @@ repeatable `--bep-json=` flags. This keeps parallel CI jobs and repeated local runs from overwriting or reusing stale BEP files. `FETCH_SALT` is intentionally not part of the generated default config. Use it -only in a separate force-refresh `bazel sync --only=` command when you -deliberately want fresh backend metadata. +only in a separate force-refresh +`bazel sync --config=test-optimization --only=` command when you +deliberately want fresh backend metadata from a config-gated repository. Run Go onboarding commands with this config: @@ -471,7 +485,7 @@ For a first-pass support request after tests have run, the customer can run only the doctor: ```bash -bazel run //:dd_test_optimization_doctor -- \ +bazel run --config=test-optimization //:dd_test_optimization_doctor -- \ --support-bundle .topt/reports/dd-test-optimization-support.zip ``` @@ -540,8 +554,14 @@ Use the default `runner_mode = "managed_pytest"` when the Datadog macro should own pytest execution. Use `runner_mode = "consumer_runner"` when a repository already has a Python test wrapper and must keep control of `main`, `imports`, and internal test policy. In `consumer_runner` mode, pass a custom -`py_test_rule` or an explicit `main` that runs pytest with ddtrace enabled, and -prefer `module_identifier` for payload selection. +`py_test_rule` or an explicit `main` that runs pytest with ddtrace enabled. When +the runtime module path and Bazel package path identify the test, omit +`module_identifier` and use the derived fallback. Keep an explicit +`module_identifier` only for a documented repository-specific exception. +When synchronized metadata exposes module groups, explicit +`module_identifier` and `module_label_override` values must match one or +analysis fails. Inferred or derived misses, and metadata with no module groups, +use the canonical full bundle. Python consumers can generate copy/paste onboarding snippets from the companion without running tests or changing lockfiles: @@ -602,10 +622,16 @@ test_optimization_sync = use_extension( "@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", "test_optimization_sync_extension", ) -test_optimization_sync.test_optimization_sync(name = "test_optimization_data") +test_optimization_sync.test_optimization_sync( + name = "test_optimization_data", +) use_repo(test_optimization_sync, "test_optimization_data") ``` +This core-only example preserves the always-enabled contract. Add +`enabled_by_env = True` only when deliberately composing the config-gated Go or +Python flow. + ### Multi-service usage (Bzlmod) Fetch multiple services with one extension and select per-service data by label: @@ -620,9 +646,11 @@ topt_multi = use_extension( topt_multi.test_optimization_multi_sync( name = "test_optimization_data", services = ["service-a", "service-b"], + runtime_module_path = "example.python.pkg", runtime_name = "python", runtime_version = "3.12", debug = True, + enabled_by_env = True, ) use_repo( @@ -656,6 +684,91 @@ Mixed-runtime note: keep runtime-specific sync repositories separate (for example one sync for Go services and another sync for Python services). A single `test_optimization_multi_sync` call currently models one runtime per invocation. +### Manifest-driven managed Go/Python monorepos + +Use this API only when a consumer-owned managed command discovers exact test +labels and derives service/runtime contexts for each invocation. It is not a +replacement for static single-service or static multi-service wiring. + +```bzl +# MODULE.bazel +topt_manifest = use_extension( + "@datadog-rules-test-optimization//tools/core:test_optimization_manifest_sync.bzl", + "test_optimization_manifest_sync_extension", +) + +topt_manifest.test_optimization_manifest_sync( + name = "test_optimization_data", +) + +use_repo(topt_manifest, "test_optimization_data") +``` + +The same repository rule is available to WORKSPACE consumers: + +```bzl +# WORKSPACE +load( + "@datadog-rules-test-optimization//tools/core:test_optimization_manifest_sync.bzl", + "test_optimization_manifest_sync", +) + +test_optimization_manifest_sync( + name = "test_optimization_data", +) +``` + +The declaration contains no service list. The managed command owns a private +temporary manifest with fully expanded local target labels and provides it only +to the child Bazel invocation. Users should run that command rather than +creating the manifest or its environment handoff manually. When +`--config=test-optimization` is absent, the repository ignores the manifest +and emits stable disabled stubs. When enabled, a missing or invalid manifest +fails before any metadata HTTP request. + +The command must reuse one manifest path for test, doctor, uploader dry-run, +and optional upload so all phases resolve the same metadata snapshot. The next +command invocation creates a new temporary manifest path and fetches current +backend state once. Equivalent selected settings/module files remain stable +test action inputs, preserving normal Bazel test-result cache hits; variable +`telemetry_facts.json` timing data remains post-test context. + +The generated aggregate repository exports: + +- `topt_data_by_target`: exact local label to context-specific `topt_data`; +- `topt_data_by_context`: deterministic context key to `topt_data`; +- `target_context_keys`: exact local label to context key; +- `@test_optimization_data//:test_optimization_context`: every generated + context for doctor/uploader enrichment; +- `@test_optimization_data//:expected_targets`: the exact selected-target JSON + contract for the doctor; +- `@test_optimization_data//:test_optimization_files_` and + `@test_optimization_data//:module__` for narrow + action inputs. + +The consumer's central Go/Python wrapper computes the current full label and +looks it up in `topt_data_by_target`. A present entry delegates to +`dd_topt_go_test` or `dd_topt_py_test`; an absent entry preserves the +repository's raw test behavior. Java, NodeJS, .NET, and Ruby do not use this +automatic manifest path in this release. + +Wire one doctor/uploader pair to the dynamic outputs: + +```bzl +load( + "@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", + "dd_test_optimization_targets", +) + +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ + "@test_optimization_data//:test_optimization_context", + ], + expected_targets_file = "@test_optimization_data//:expected_targets", +) +``` + Additional helper file exported by the generated repository: - `export.bzl` with a single dictionary `topt_data` containing: @@ -679,7 +792,7 @@ filegroup( srcs = ["@test_optimization_data//:test_optimization_files"], ) -# Access context.json separately (for the uploader) +# Access context.json and telemetry_facts.json through the shared context target. filegroup( name = "dd_test_opt_context", srcs = ["@test_optimization_data//:test_optimization_context"], @@ -784,6 +897,16 @@ test_optimization_sync( ) ``` +This generic WORKSPACE example preserves the always-enabled core default. The +public Go helpers apply metadata gating by default; the Python section adds +`enabled_by_env = True` where its macro can safely consume a disabled export. + +For a managed Go/Python monorepo, instantiate +`test_optimization_manifest_sync` instead of this static rule, as shown in +[Manifest-driven managed Go/Python monorepos](#manifest-driven-managed-gopython-monorepos). +The consumer-owned command supplies the private invocation manifest; do not +check a service list or target mapping into WORKSPACE. + ### 3) Depend on generated files in BUILD files ```bzl @@ -801,19 +924,12 @@ filegroup( ### 4) Add the doctor and uploader targets (one pair per workspace) ```bzl -# In root BUILD.bazel -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") - -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = ["@test_optimization_data//:test_optimization_context"], -) +# In root BUILD.bazel for a small repository, or in a lightweight monorepo +# package such as //tools/test_optimization. +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") -dd_payload_uploader( - name = "dd_upload_payloads", - # Provide context.json via runfiles so enrichment can occur - data = ["@test_optimization_data//:test_optimization_context"], +dd_test_optimization_targets( + name = "test_optimization", ) ``` @@ -823,7 +939,7 @@ of using the CI wrapper, reuse the BEP file created by the matching `bazel test --build_event_json_file=...` invocation: ```bash -bazel run --config=test-optimization //:dd_upload_payloads -- \ +bazel run --config=test-optimization //:dd_upload_payloads -- \ --bep-json="$bep_json" \ --freshness-source=bep \ --freshness-mode=required \ @@ -831,20 +947,16 @@ bazel run --config=test-optimization //:dd_upload_payloads -- \ --validate-enrichment ``` +Replace `` with the package used above, for example +`tools/test_optimization`. Use `//:dd_upload_payloads` only when the pair lives +in the root package. + Multi-service aggregator variant: ```bzl -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = [ - "@test_optimization_data//:test_optimization_context_service_a", - "@test_optimization_data//:test_optimization_context_service_b", - ], -) - -dd_payload_uploader( - name = "dd_upload_payloads", - data = [ +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ "@test_optimization_data//:test_optimization_context_service_a", "@test_optimization_data//:test_optimization_context_service_b", ], @@ -853,6 +965,18 @@ dd_payload_uploader( ### 5) Forward environment variables in `.bazelrc` +The metadata forwarding entries below apply to every runtime. Config-gated Go +and Python onboarding additionally includes: + +```text +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +# Go only; use the apparent rules_go repository name: +build:test-optimization --@io_bazel_rules_go//go/private/orchestrion:enabled=true +``` + +Python-only consumers omit the Go line. Java, NodeJS, .NET, and Ruby retain +their existing enablement contract and omit both lines in this release. + ```text # Repository rule (module/repo phase) — affects refetch common:test-optimization --repo_env=DD_API_KEY @@ -1048,12 +1172,18 @@ load("@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", test_optimization_sync( name = "test_optimization_data", - service = "py-service", + enabled_by_env = True, + runtime_module_path = "example.python.pkg", runtime_name = "python", runtime_version = "3.12", + service = "py-service", ) ``` +Pair this opt-in repository rule with +`common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1`. Python +does not use the Go-only `@rules_go//go/private/orchestrion:enabled` flag. + Then in package BUILD files, use either managed pytest mode: ```bzl @@ -1085,7 +1215,6 @@ dd_topt_py_test( name = "pkg_py_test", py_test_rule = repo_py_test, runner_mode = "consumer_runner", - module_identifier = "example.python.pkg", srcs = glob(["test_*.py"]), deps = [ requirement("ddtrace"), @@ -1236,26 +1365,40 @@ http_archive( load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") -load("@io_bazel_rules_go//go:orchestrion_workspace.bzl", "go_orchestrion_tool_repo") +load("@datadog-rules-test-optimization-go//:topt_go_orchestrion_repository.bzl", "dd_topt_go_orchestrion_tool_repo") + +dd_topt_go_orchestrion_tool_repo( + version = "", + dd_trace_go_pin_files = [ + "@//:go.mod", + "@//:go.sum", + ], + go_sdk_root = "@go_sdk//:ROOT", + go_sdk_version = "1.25.0", +) go_rules_dependencies() go_register_toolchains(version = "1.25.0") gazelle_dependencies() - -go_orchestrion_tool_repo( - version = "", - # Optional. When omitted, the helper uses the fork's current default - # shared dd-trace-go version. - dd_trace_go_version = "", -) ``` Notes for the helper: - `version` is required in WORKSPACE mode. -- `dd_trace_go_version` and `dd_trace_go_versions` are mutually exclusive. +- Export the root `go.mod` and `go.sum` from its BUILD package. Pin-file mode + derives every supported direct or transitive tracer module with + `-mod=readonly` and does not modify those files. +- `dd_trace_go_pin_files`, `dd_trace_go_version`, and + `dd_trace_go_versions` are mutually exclusive. The explicit forms are escape + hatches for module graphs that the normal pin-file mode cannot resolve. +- `go_sdk_root` must reference the SDK registered by + `go_register_toolchains`, and `go_sdk_version` must equal that toolchain + version. Enabled bootstrap uses this SDK instead of a host `go` binary. - Keep the default tool-repo name `rules_go_orchestrion_tool`; the current fork resolves that name internally. +- Declare the real tool repository before `go_rules_dependencies()`. The fork + supplies its own empty fallback for ordinary WORKSPACE consumers, so do not + load or declare a private stub repository yourself. - Do not configure `patches`, `patch_tool`, or `patch_args` for this integration; repositories that already own their `rules_go` patch stack should generate the public consumer patch profile and rebase or merge it locally. diff --git a/docs/Language_Onboarding.md b/docs/Language_Onboarding.md index c680c168..c7a70fa0 100644 --- a/docs/Language_Onboarding.md +++ b/docs/Language_Onboarding.md @@ -23,6 +23,8 @@ Rule of thumb: - Use one multi-sync aggregator per runtime for multi-service setups - In mixed-runtime monorepos, keep one sync repo per runtime/service slice - Use multi-sync aggregators only for multiple services of the same runtime +- Use manifest sync only behind a consumer-owned managed command that expands + exact Go/Python targets and derives services for the current invocation Shared runtime contract for every language: @@ -44,13 +46,12 @@ Shared runtime contract for every language: such as `//tools/test_optimization:dd_upload_payloads`. - Mixed-runtime uploader wiring must bundle every relevant `:test_optimization_context` target and let the uploader choose the matching - `context.json` per payload + `context.json` per payload while consuming each repository's + `telemetry_facts.json` for rule telemetry - `DD_TEST_OPTIMIZATION_CONTEXT_JSON` remains a legacy explicit override, not the recommended mixed-runtime wiring path -Shared `.bazelrc` forwarding. Prefer the generated block from -`dd_topt_go_bootstrap --print-bazelrc-snippet` or -`dd_topt_go_bootstrap --write-bazelrc` for Go workspaces: +Shared `.bazelrc` metadata forwarding for every runtime: ```text common:test-optimization --repo_env=DD_API_KEY @@ -65,6 +66,27 @@ test:test-optimization --remote_download_regex=.*test[.]outputs.* test:test-optimization --zip_undeclared_test_outputs ``` +Go and Python config-gated onboarding also adds the single enable switch below. +Omitting the named config then provides the complete metadata and runtime +opt-out for those two integrations. This release does not change the +enablement contract of the other companions: + +```text +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +``` + +Go workspaces also add the existing `rules_go` analysis-time setting. Prefer +the generated block from `dd_topt_go_bootstrap --print-bazelrc-snippet` or +`dd_topt_go_bootstrap --write-bazelrc`, which substitutes the consumer's actual +apparent repository name: + +```text +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true +# Use @io_bazel_rules_go instead of @rules_go in WORKSPACE mode. +``` + +Do not add that Go-only line to Python-only or other non-Go workspaces. + Pass `DD_GIT_*` only through `--repo_env`. Never forward it as test environment data because that makes Git metadata part of the test action cache key. For Go/Orchestrion, do not put `DD_TEST_OPTIMIZATION_AGENT_URL` or @@ -100,6 +122,79 @@ DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" \ //... ``` +## Automatic managed Go/Python monorepos + +This path is separate from the static recipes below. It is appropriate when a +large consumer already owns a command or pipeline adapter that can expand the +requested Bazel targets before running tests. + +The consumer command: + +1. expands target patterns and suites to canonical local labels; +2. identifies eligible targets created through the repository's central + `dd_go_test` or `dd_py_test` macro; +3. derives a service and runtime context from each full label; +4. writes a private invocation-scoped manifest; +5. runs the exact labels with `--config=test-optimization`, then doctor and + uploader dry-run. + +The Rule does not discover affected tests and does not prescribe a repository's +service grammar. A common consumer policy is to derive an application service +when the full package path contains a stable application segment and otherwise +fall back to the owning domain. The manifest records whether each target used +`application` or `domain_fallback` derivation. Ambiguous names or conflicting +runtime contexts must fail; they must not silently map to a global fallback. + +Central wrappers load `topt_data_by_target` from the aggregate repository and +look up the current full label. A selected label delegates to +`dd_topt_go_test` or `dd_topt_py_test`. An absent label follows the same raw +test path used without Test Optimization. This keeps adding and removing +services mechanical: + +- adding a new Go or Python test requires no Test Optimization BUILD edit; +- including its label in the managed invocation enrolls it automatically; +- removing the label from that invocation removes it from that run; +- no checked-in service list, `examples.bzl`, Gazelle extension, or ownership + registry is required. + +```mermaid +sequenceDiagram + participant User + participant Runner as Consumer-managed command + participant Bazel + participant Sync as Manifest aggregate repo + participant Post as Doctor/uploader + + alt ordinary command, config omitted + User->>Bazel: test requested labels + Bazel->>Sync: resolve disabled interface + Sync-->>Bazel: stable empty stubs, no HTTP + Bazel-->>User: normal Go/Python test behavior + else managed Test Optimization command + User->>Runner: test requested labels + Runner->>Bazel: query and expand exact targets + Runner->>Runner: derive contexts and temporary manifest + Runner->>Bazel: sync and test exact labels with config + Bazel->>Sync: materialize selected Go/Python contexts + Sync-->>Bazel: narrow per-context/module inputs + Runner->>Post: doctor exact targets, then dry-run + Post-->>User: validation result and optional upload + end +``` + +The aggregate repository is declared once using +`test_optimization_manifest_sync` or +`test_optimization_manifest_sync_extension`. Doctor/uploader wiring uses +`@test_optimization_data//:test_optimization_context` and +`@test_optimization_data//:expected_targets`; see the +[Installation Reference](Installation_Reference.md#manifest-driven-managed-gopython-monorepos). +The private manifest handoff belongs to the managed command and must not be +copied into ordinary `.bazelrc` configuration. + +Automatic manifest onboarding supports Go and Python in this release. Java, +NodeJS, .NET, and Ruby continue to use the static single-service or static +multi-service recipes in their sections below. + ## Go ### Single-service @@ -205,16 +300,18 @@ below the module root, pass the module-root pin files through Orchestrion path, and `test_optimization`, the standard Go `testing` Test Optimization path. For standard Go `testing`, set `orchestrion_mode = "test_optimization"` on the `dd_topt_go_test` call or -optimized repo-local wrapper. Automatic `testify/suite` instrumentation is not +central repo-local wrapper. Automatic `testify/suite` instrumentation is not part of that mode. For WORKSPACE monorepos, prefer bootstrap `--workspace-mode` to generate the -generic local scaffolding. It can write the root doctor/uploader targets, -`.bazelrc` block, Orchestrion pin files, and a split wrapper template while -leaving `WORKSPACE` placement under repository control. The generated wrapper -template keeps repo-specific policy in a local helper and exposes separate -plain and optimized wrapper functions, so large repositories do not have to -rediscover that split during onboarding. +generic local scaffolding. It can write the `.bazelrc` block, Orchestrion pin +files, and a config-gated central wrapper template while leaving `WORKSPACE` +placement under repository control. Put the single doctor/uploader pair in a +lightweight package instead of modifying the root BUILD. A large repository +can keep one public `dd_go_test`, route its enrolled package set to +`dd_topt_go_test` internally, and rely on `--config=test-optimization` to +choose the raw or instrumented shape without adding per-target Test +Optimization attributes. ### Large WORKSPACE monorepos @@ -269,35 +366,60 @@ datadog_go_test_optimization_workspace_repositories( rto_archive_prefix = "rules_test_optimization-", ) -load("@//go:orchestrion_workspace.bzl", "go_orchestrion_tool_repo") +load("@datadog-rules-test-optimization-go//:topt_go_orchestrion_repository.bzl", "dd_topt_go_orchestrion_tool_repo") -go_orchestrion_tool_repo( +dd_topt_go_orchestrion_tool_repo( version = "v1.9.0", - dd_trace_go_version = "v2.9.0", + dd_trace_go_pin_files = [ + "@//:go.mod", + "@//:go.sum", + ], + go_sdk_root = "@go_sdk//:ROOT", + go_sdk_version = "", ) load( - "@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", - "test_optimization_sync", + "@datadog-rules-test-optimization-go//:topt_go_workspace.bzl", + "dd_topt_go_workspace_sync_repositories", ) -test_optimization_sync( +dd_topt_go_workspace_sync_repositories( name = "test_optimization_data", service = "", - runtime_name = "go", runtime_version = "", - runtime_module_path = "", + module_path = "", require_git_metadata = True, ) ``` +The public Go helper enables metadata gating by default. The single +`--config=test-optimization` switch controls both metadata sync and the +Orchestrion aliases; no per-target or per-repository enable attribute is needed. +`@go_sdk//:ROOT` comes from the repository's central +`go_register_toolchains(version = "")` declaration. Keep that +version, `go_sdk_version`, and `runtime_version` equal so enabled bootstrap does +not depend on a host `go` binary. Export the root `go.mod` and `go.sum` from +their BUILD package. Pin-file mode resolves the complete selected module graph, +so changing `go.mod` is the only tracer-version update required for normal +onboarding. Use `dd_trace_go_version` or `dd_trace_go_versions` only as an +explicit escape hatch for module graphs that pin-file mode cannot represent. +Without the config, `dd_topt_go_test` delegates directly to the consumer's +original `go_test_rule` under the public name, preserves the caller's Go rule +kwargs, and creates no Test Optimization-owned hidden targets. With the config, +the same BUILD call uses the existing Orchestrion-backed Test Optimization +shape. + +Python follows the same single-switch contract when its sync declaration uses +`enabled_by_env = True`: without the config, the wrapper preserves the normal +test runner but omits Test Optimization metadata, instrumentation, and payloads. + If the environment can fetch Git repositories reliably, use `rules_go_fetch = "git"` and omit the archive attributes. If the environment mirrors or blocks GitHub codeload archives, publish the same commit to a mirror controlled by the consuming organization and point `rto_archive_url` at that mirror. -`runtime_module_path` is preferred for checked-in configuration because it makes +`module_path` on the public Go helper is preferred for checked-in configuration because it makes module selection explicit and does not depend on operator shell state. If the module path must stay environment-specific during local experiments, pass `GO_MODULE_PATH` with `--repo_env` instead of `--test_env`. @@ -315,7 +437,6 @@ bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ --rules-go-variant base \ --dd-trace-go-version v2.9.0 \ --write-bazelrc \ - --write-root-targets \ --write-orchestrion-files \ --write-wrapper-template \ --write-validation-script \ @@ -332,12 +453,12 @@ therefore emit JSON payloads. Do not list `.build_test`, compile-only, or other build-only controls as expected runtime targets; keep those under `--control-target` or run them separately before the doctor. -The generated wrapper template should be adapted to the repository's existing -wrapper layer. Keep scheduling, tags, flaky policy, Docker defaults, -platform constraints, and other repository-specific behavior in the local -helper. The optimized wrapper should call `dd_topt_go_test`, pass -`topt_data`, set `orchestrion_mode = "test_optimization"`, and always provide -module-root pin files: +The generated wrapper template should replace the implementation behind the +repository's existing central `dd_go_test` entry point. Keep scheduling, tags, +flaky policy, Docker defaults, platform constraints, and other +repository-specific behavior in the local helper. The same central wrapper +should call `dd_topt_go_test`, pass `topt_data`, set +`orchestrion_mode = "test_optimization"`, and provide module-root pin files: ```bzl orchestrion_mode = "test_optimization", @@ -350,8 +471,9 @@ orchestrion_pin_files = [ ``` Export the pin files from the root package if the repository's package layout -requires that for cross-package labels. Keep the plain wrapper path available -for controls and for tests that are not part of the rollout yet. +requires that for cross-package labels. Do not add a second optimized macro +name: omitting `--config=test-optimization` makes the generated disabled export +preserve normal `go_test` behavior under the existing entry point. If the repository has checked-in `go_repository` declarations, run bootstrap with `--check-go-repositories` and then use the repository-owned refresh command @@ -375,11 +497,16 @@ Validate in this order: support request, the doctor itself can write a doctor-only bundle with `--support-bundle=`. 5. Run - `bazel run --config=test-optimization //:dd_upload_payloads -- --dry-run --validate-enrichment`. + `bazel run --config=test-optimization //:dd_upload_payloads -- --dry-run --validate-enrichment`. 6. Run the real uploader with `DD_API_KEY` and `DD_SITE` in the command environment. Keep `DD_TEST_OPTIMIZATION_*` in the wrapper or CI environment, not in the test sandbox. +Replace `` with the package that owns the workspace's doctor and +uploader targets, such as `tools/test_optimization` in a large monorepo. Small +repositories that keep those targets in the root package can use +`//:dd_upload_payloads`. + For remote execution or remote cache setups, keep `test:test-optimization --remote_download_minimal` and `test:test-optimization --remote_download_regex=.*test[.]outputs.*` plus @@ -397,11 +524,15 @@ effective wrapper flags, runtime metadata, and `summary.md` into one redacted zip for escalation. Doctor-only bundles are simpler to request from a customer, but they do not include uploader dry-run or upload results. -If the doctor reports missing Git metadata, missing Bazel metadata, -`full_bundle_no_match`, or msgpack payloads, fix the sync, wrapper, tracer, or -uploader configuration. Do not work around those failures by adding `DD_GIT_*` -or upload endpoints to `--test_env`; that would make sandbox test actions -non-hermetic and can invalidate Bazel cache keys. +If the doctor reports missing Git metadata, missing Bazel metadata, msgpack +payloads, or `full_bundle_no_match` for a known pilot that requires module +selection, fix the sync, wrapper, tracer, or uploader configuration. Generic +inferred/derived selection may intentionally fall back to the canonical bundle; +that path reports `full_bundle_no_match` and requires the doctor target to set +`forbid_full_bundle_no_match = False`. Keep the default rejection for known +pilots. Do not work around failures by adding `DD_GIT_*` or upload endpoints to +`--test_env`; that would make sandbox test actions non-hermetic and can +invalidate Bazel cache keys. ### Multi-service @@ -469,20 +600,11 @@ dd_topt_go_test( ```bzl # root BUILD.bazel -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") - -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = [ - "@test_optimization_data//:test_optimization_context_go_service_a", - "@test_optimization_data//:test_optimization_context_go_service_b", - ], -) +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") -dd_payload_uploader( - name = "dd_upload_payloads", - data = [ +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ "@test_optimization_data//:test_optimization_context_go_service_a", "@test_optimization_data//:test_optimization_context_go_service_b", ], @@ -517,9 +639,11 @@ topt = use_extension( topt.test_optimization_sync( name = "test_optimization_data", - service = "py-service", + enabled_by_env = True, + runtime_module_path = "example.python.pkg", runtime_name = "python", runtime_version = "3.12", + service = "py-service", ) use_repo(topt, "test_optimization_data") @@ -591,7 +715,6 @@ dd_topt_py_test( name = "pkg_py_test", py_test_rule = repo_py_test, runner_mode = "consumer_runner", - module_identifier = "example.python.pkg", srcs = glob(["test_*.py"]), deps = [ ":pkg_lib", @@ -604,8 +727,18 @@ dd_topt_py_test( `consumer_runner` intentionally rejects the base `rules_python` `py_test` without an explicit `main`; that shape can execute a Python file directly and -does not prove pytest or ddtrace ran. Prefer `module_identifier` for selection -in this mode so the integration does not depend on Python import-path mutation. +does not prove pytest or ddtrace ran. When the runtime module path and Bazel +package path identify the test, omit `module_identifier` and use the derived +fallback. Keep an explicit `module_identifier` only for a documented +repository-specific exception. + +The derived identifier selects a module-specific payload when that module is +present in the synchronized metadata. If the backend has not materialized a +matching module group yet, the selector intentionally uses the exact canonical +payload bundle instead. When synchronized metadata exposes module groups, an +explicit `module_identifier` or `module_label_override` that does not match one +fails analysis. If no module groups exist, the canonical full bundle remains +valid; adding an explicit value does not create missing backend metadata. ### WORKSPACE single-service @@ -693,9 +826,11 @@ load("@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", test_optimization_sync( name = "test_optimization_data", - service = "py-service", + enabled_by_env = True, + runtime_module_path = "example.python.pkg", runtime_name = "python", runtime_version = "3.12", + service = "py-service", ) ``` @@ -773,8 +908,10 @@ topt = use_extension( topt.test_optimization_multi_sync( name = "test_optimization_data", services = ["py-service-a", "py-service-b"], + runtime_module_path = "example.python.pkg", runtime_name = "python", runtime_version = "3.12", + enabled_by_env = True, ) use_repo( @@ -806,20 +943,11 @@ dd_topt_py_test( ```bzl # root BUILD.bazel -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") - -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = [ - "@test_optimization_data//:test_optimization_context_py_service_a", - "@test_optimization_data//:test_optimization_context_py_service_b", - ], -) +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") -dd_payload_uploader( - name = "dd_upload_payloads", - data = [ +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ "@test_optimization_data//:test_optimization_context_py_service_a", "@test_optimization_data//:test_optimization_context_py_service_b", ], diff --git a/docs/Maintainers.md b/docs/Maintainers.md index d2f1ebc3..14c71d55 100644 --- a/docs/Maintainers.md +++ b/docs/Maintainers.md @@ -30,6 +30,11 @@ This document is for contributors and maintainers of - Integration harness: - Linux/macOS: `tools/tests/integration/run_mock_server_tests.sh` - Windows: `tools/tests/integration/run_mock_server_tests.ps1` +- Manifest-driven integration: + - Full Go/Python/cache/doctor/uploader: + `python3 tools/tests/integration/run_manifest_sync_tests.py --mode full` + - Windows disabled-path parsing: + `python tools/tests/integration/run_manifest_sync_tests.py --mode disabled` - Hermetic lane parity (local smoke): - Run the same commands with sandbox/network-blocking flags used in CI. - Version alignment guard: @@ -59,6 +64,38 @@ This document is for contributors and maintainers of do not add placeholder language packages under `tools/`. Language-specific orchestration belongs in `modules//`. +## Manifest-driven API ownership + +- `tools/core/test_optimization_manifest_sync.bzl` owns strict schema + validation, deterministic normalization, aggregate repository rendering, and + per-context materialization for Go/Python. +- `tools/core/test_optimization_sync.bzl` owns shared single-context fetch and + materialization. Static sync must continue to call the same implementation + without behavior drift. +- Companion modules own explicit-label consumption and language analysis. +- Consumer repositories own target discovery, affected-target expansion, + service-name grammar, managed-command orchestration, and rollout policy. +- Do not add a committed target/service mapping, Gazelle integration, + CODEOWNERS gate, or pipeline model to the Rule. + +Compatibility requirements: + +- static single-service and static multi-service APIs remain supported; +- disabled manifest resolution ignores the manifest and performs no HTTP or + local Git discovery; +- enabled resolution validates the complete manifest before HTTP; +- equivalent manifests render byte-identical public surfaces; +- target action inputs stay narrowed to one context/module where selection + succeeds; +- aggregate doctor/uploader contexts retain stable virtual keys; +- automatic manifest onboarding remains Go/Python-only until another companion + implements and proves the same contract. + +Changes spanning this contract are validated in order: Rule unit/integration +tests, consumer-style `_tests` WORKSPACE/Bzlmod fixtures, then the concrete +consumer repository. Public behavior changes also require a complete +first-party documentation and agent-skill audit. + ## Adding a language companion module Use this checklist when adding `dd_topt__test` support. @@ -84,7 +121,11 @@ Use this checklist when adding `dd_topt__test` support. identifier -> full bundle - module label resolution should match `module_` names from sync outputs - - Keep fallback-to-full-bundle behavior non-fatal. + - Keep inferred/derived fallback-to-full-bundle behavior non-fatal. When + synchronized metadata exposes module groups, require an explicit + identifier or module-label override to match one so configuration mistakes + fail analysis instead of silently selecting unrelated metadata. Preserve + the canonical full bundle when no module groups exist. 3. **Companion module dependency policy** - Keep root core module (`datadog-rules-test-optimization`) free of @@ -222,6 +263,9 @@ Notes: `runtests.sh` scripts. - CI runs example `runtests.sh` scripts in `RUNTESTS_DRY_RUN=1` mode to verify wiring without requiring Datadog credentials in PR checks. +- CI runs the full manifest integration on Linux and the disabled manifest path + on Windows. Keep the Linux cache sequence evidence-based through BEP rather + than test output text. - Repository tracks both `.bazelversion` and `MODULE.bazel.lock` in git to reduce local/CI drift. - `.bazelversion` is intentionally duplicated at repository root and companion diff --git a/docs/RFC.md b/docs/RFC.md index 1b3c89ce..5917b21a 100644 --- a/docs/RFC.md +++ b/docs/RFC.md @@ -70,7 +70,7 @@ Modern CI/CD pipelines benefit from Bazel's hermetic, reproducible builds and te We need an integration that: - Works with Bazel’s hermetic sandbox model (preferably with network blocked during test actions). -- Fetches Test Optimization metadata (settings, known tests, test management tests) at a time compatible with Bazel’s caching and repository resolution phases. +- Fetches Test Optimization metadata (settings, known tests, test management tests, and flaky tests) at a time compatible with Bazel’s caching and repository resolution phases. - Scales across languages and services, including multi‑service monorepos. - Minimizes cache invalidation scope to avoid unnecessary test re‑execution. - Uploads test and coverage payloads reliably from the same `bazel test` invocation without compromising hermeticity or leaking secrets to disk. @@ -84,7 +84,7 @@ This section describes what exists today prior to this proposal and the work in - Language tracers initialize within each test process (depending on the implementation this may be done from a parent process) and perform live network calls to Datadog to retrieve: - Service settings and feature flags. - - Known Tests and Test Management tests if the feature is enabled. + - Known Tests, Test Management tests, and Flaky Tests if each feature is enabled. - Also fetches CI/Git metadata inferred from environment variables or by running git commands directly if data is missing. - Tests execute and the tracer records results. At test process completion, the tracer uploads test and coverage payloads directly to Datadog using either agentless (API key \+ site) or an EVP proxy URL. @@ -121,12 +121,12 @@ At a high level, the proposal moves all network‑dependent metadata fetching ou - Phase 1 — [Sync at module/repo resolution](../tools/core/test_optimization_sync.bzl): - - A module extension instantiates a repository rule that performs the Datadog API calls for Settings (always), Known Tests (when enabled), and Test Management tests (when enabled). -- The rule writes deterministic JSON outputs under a configurable directory (default: `.testoptimization/`) and produces a non‑secret `context.json` with CI/Git/OS/runtime tags. It also writes a `manifest.txt` with a version marker (currently `version=1`) to track payload format changes. + - A module extension instantiates a repository rule that, when the repository is enabled, performs the Datadog API calls for Settings, Known Tests, Test Management tests, and Flaky Tests. Config-disabled repositories emit deterministic stubs without HTTP requests. +- The rule writes deterministic JSON outputs under a configurable directory (default: `.testoptimization/`) and produces non-secret `context.json` and `telemetry_facts.json` files with enrichment and rule-telemetry data. It also writes a `manifest.txt` with a version marker (currently `version=1`) to track payload format changes. - It generates a BUILD file exposing stable public filegroups: - `@//:test_optimization_files` (core bundle with `settings.json`), - - `@//:test_optimization_context` (`context.json` only), - - `@//:module_` (per‑module bundles with `settings.json` \+ that module’s known/test‑management files). + - `@//:test_optimization_context` (`context.json` plus `telemetry_facts.json`), + - `@//:module_` (per-module bundles with `settings.json` plus that module's known-tests, test-management, and flaky-tests files). - It emits `export.bzl` with a structured `topt_data` object describing the available per‑module labels, the resolved `manifest_path`, and language hints (e.g., Go module path inclusion). @@ -150,6 +150,16 @@ At a high level, the proposal moves all network‑dependent metadata fetching ou - A higher‑level “multi‑sync” extension materializes one repository per service and an aggregator repository that re‑exports per‑service filegroups and a service mapping (`topt_data_by_service`). Macros can select services by key without hardcoding repo aliases. +- [Invocation-scoped managed Go/Python monorepos](../tools/core/test_optimization_manifest_sync.bzl): + + - A separate manifest-sync extension materializes one aggregate repository + from exact targets and service/runtime contexts derived by a + consumer-owned command. It exports `topt_data_by_target`, narrow + per-context/per-module labels, bundled contexts, and an exact doctor target + file. This is a current implementation extension to the original proposal; + it does not replace the static APIs or move target discovery into a + repository rule. + Why this solves the problem - Hermeticity: User tests run offline; only the repository rule (during resolution) and the uploader (via `bazel run` at the end) require network. @@ -207,19 +217,20 @@ Repository Rule and Module Extension - The `test_optimization_sync_extension` tag is declared in `MODULE.bazel`. It instantiates `test_optimization_sync` with optional attributes: - `service`: explicit override for service name (else derived from `DD_SERVICE`). - `runtime_name`, `runtime_version`, `runtime_arch`: enrich `configurations` and `context.json`. - - `known_tests`, `test_management`: local kill‑switches to skip specific feature requests and emit minimal stubs while adjusting `settings.json` accordingly. + - `known_tests`, `test_management`, `flaky_tests`: local kill-switches to skip specific feature requests and emit minimal stubs while adjusting `settings.json` accordingly. - `debug`: increases logging verbosity and writes additional artifacts (e.g., request JSONs) for troubleshooting. - The repository rule performs: - 1. Settings request: always issued; response persisted to `cache/http/settings.json`. + 1. Settings request: always issued in enabled mode; response persisted to `cache/http/settings.json`. Config-disabled mode writes the canonical stub without a request. 2. Known Tests request: gated by settings and `known_tests` attribute; persisted to `cache/http/known_tests.json` and split by module (canonical per‑module files exposed by targets). 3. Test Management Tests request: gated by settings and `test_management` attribute; persisted to `cache/http/test_management.json` and split by module (canonical per‑module files exposed by targets). - 4. `context.json`: built locally from CI/git/OS/runtime information — non‑secret and safe to ship as runfiles. - 5. A generated `BUILD` file that exposes: + 4. Flaky Tests request: gated by settings and `flaky_tests` attribute; persisted to `cache/http/flaky_tests.json` and split by module (canonical per-module files exposed by targets). + 5. `context.json` and `telemetry_facts.json`: built locally from CI/git/OS/runtime and rule-telemetry information — non-secret and safe to ship as runfiles. + 6. A generated `BUILD` file that exposes: - `:test_optimization_files` → includes `cache/http/settings.json` and `manifest.txt` (stable bundle for most uses). - - `:test_optimization_context` → `context.json` (opt‑in for enrichment). - - `:module_` → per‑module bundle of settings \+ module‑specific JSONs. + - `:test_optimization_context` → `context.json` plus `telemetry_facts.json` (opt-in for enrichment and rule telemetry). + - `:module_` → per-module bundle of settings plus module-specific known-tests, test-management, and flaky-tests JSONs. - Per‑module targets expose canonical runfile names rooted at the manifest directory (`/...`, default `.testoptimization/...`) regardless of the physical split-file locations. - 6. An `export.bzl` with `topt_data` describing labels, the resolved `manifest_path`, and language‑specific hints (e.g., Go module path inclusion). + 7. An `export.bzl` with `topt_data` describing labels, the resolved `manifest_path`, and language-specific hints (e.g., Go module path inclusion). - HTTP behavior uses `curl` with fail‑fast and retries; `DD_SITE` is normalized; Windows and non‑Windows paths are handled. The rule declares all relevant env vars in `environ` so changes lead to re‑execution and fresh outputs. Per‑Module Labels and Sanitization @@ -230,6 +241,11 @@ Per‑Module Labels and Sanitization Multi‑Service Aggregation - For monorepos with multiple services, the multi‑service extension instantiates one repo per service plus an aggregator repo that exposes per‑service labels and a `topt_data_by_service` mapping. This allows macros to select a service by logical key without leaking the concrete repo alias. +- For managed Go/Python invocations, the later manifest-sync API instead + accepts an ephemeral exact-target/context manifest and creates one aggregate + repository. The consumer command owns discovery and service naming; Bazel + repository resolution owns validation and metadata materialization. Static + multi-service behavior remains unchanged. Runtime Uploader @@ -271,7 +287,7 @@ Language Macros - A Starlark aspect walks `embed` on the `go_test` target and reads `GoArchive.importpath` from rules_go providers, mirroring how `go_test` computes it. - A small rule uses the inferred importpath to pick the matching `:module_` filegroup from the synced repo and exposes it in runfiles; the macro sets `DD_TEST_OPTIMIZATION_MANIFEST_FILE` to `$(rlocationpath )` using `topt_data["manifest_path"]`, so custom `out_dir` values are supported. - Precedence: (1) explicit `importpath` kwarg on the `go_test`; (2) provider‑based inference via `embed`; (3) fallback to `/`. - - The exported `topt_data["runtimes"]["go"]["module_included"]` flag is consulted only in fallback mode; when inferring via (1) or (2), the macro always attempts per‑module selection and falls back to the full bundle if no match exists. + - When synchronized metadata exposes module groups, explicit `importpath` and `module_label_override` values must match one or analysis fails. Provider-based or derived inference, and metadata with no module groups, may use the canonical full bundle. The exported `topt_data["runtimes"]["go"]["module_included"]` flag is consulted only in fallback mode. - Module dependency: the Go companion module (`datadog-rules-test-optimization-go`) declares `bazel_dep("rules_go", )` to make provider loads visible under Bzlmod; it does not configure toolchains. Consumers must still configure `rules_go` and the Go SDK in their own `MODULE.bazel`. - [The existing `dd_topt_go_test` demonstrates this pattern and should be mirrored for other languages incrementally.](../modules/go/topt_go_test.bzl) diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md index d5af5ded..85aeaebd 100644 --- a/docs/Troubleshooting.md +++ b/docs/Troubleshooting.md @@ -10,11 +10,38 @@ This product includes software developed at Datadog Examples below assume the generated repository is named `test_optimization_data`. If you used a different `name`, replace labels and -`bazel sync --only=` accordingly. +repository names accordingly. For config-gated Go and Python repositories, +include `--config=test-optimization` in sync, test, doctor, and uploader +commands. Other companions retain their current activation contract. If Bazel reports that sync requires WORKSPACE support, add `--enable_workspace` to sync commands in this document. +## Test Optimization config and disabled mode + +For config-gated Go and Python onboarding, +`--config=test-optimization` is the single user-facing enablement switch. Both +languages set the metadata repository environment: + +```bazelrc +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +``` + +Go additionally sets the existing `rules_go` Orchestrion flag: + +```bazelrc +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true +``` + +When the config is omitted, the public Go extension's config-gated default and +repositories explicitly configured with `enabled_by_env = True` generate the +documented no-fetch stubs. Go aliases select local empty targets; Python keeps +the normal consumer runner without Test Optimization metadata or payload +wiring. Python-only consumers omit the Go line. For WORKSPACE Go, replace +`@rules_go` with the apparent repository name used by that workspace. Java, +NodeJS, .NET, and Ruby retain their existing enablement contract in this +release. + ## Quick triage map | Symptom | First checks | Likely section | @@ -27,7 +54,7 @@ If Bazel reports that sync requires WORKSPACE support, add | Upload network errors | credential mode (agentless vs EVP), intake reachability | Tests not uploading (network errors) | | CI failure requires log archaeology | archive the support bundle from the failing run | Collect diagnostic reports | | Module selection misses | `bazel query` for `module_*` targets and importpath/module label expectations | Per-module files not found | -| Go build fails with a tracer version mismatch | `dd_trace_go_version`, `dd_trace_go_versions`, `--dd-trace-go-version`, local `go.mod` pins | Go tracer version drift | +| Go build fails with a tracer version mismatch | `dd_trace_go_pin_files`, explicit version escape hatches, local `go.mod`/`go.sum` | Go tracer version drift | | Bazel resolves an older tracer or Orchestrion module in WORKSPACE mode | checked-in `go_repository(...)` pins | WORKSPACE go_repository drift | | WORKSPACE archive pins fail after a PR was squash-merged | generated pins commit reachability and archive SHA | Published Go pins | | Private/internal WORKSPACE fetch returns 404 | SSH git or authenticated archive access | Private repository fetch | @@ -41,7 +68,7 @@ from the same run. For the simplest customer ask after tests have already run, use the doctor directly: ```bash -bazel run //:dd_test_optimization_doctor -- \ +bazel run --config=test-optimization //:dd_test_optimization_doctor -- \ --support-bundle .topt/reports/dd-test-optimization-support.zip ``` @@ -207,10 +234,10 @@ values automatically. 2. **Force refetch only when intentional** with a cache-busting salt: ```bash - bazel sync --only= --repo_env=FETCH_SALT="$(date +%s)" + bazel sync --config=test-optimization --only= --repo_env=FETCH_SALT="$(date +%s)" ``` ```powershell - bazel sync --only= --repo_env=FETCH_SALT="$(Get-Date -UFormat %s)" + bazel sync --config=test-optimization --only= --repo_env=FETCH_SALT="$(Get-Date -UFormat %s)" ``` Do not put `FETCH_SALT` in `.bazelrc`, `bazel test`, doctor, or uploader commands. It deliberately breaks the repository-rule cache key and should be @@ -237,6 +264,92 @@ values automatically. debug = True, # Verbose logging ) ``` + Preserve the repository's existing `enabled_by_env` value; enabling debug + logging must not change its activation contract. + +## Manifest-driven managed runs + +These checks apply only to the automatic Go/Python path. Static single-service +and static multi-service consumers do not need an invocation manifest. + +### Enabled run reports a missing manifest + +The aggregate repository intentionally fails before HTTP when enabled without +the command-owned manifest. Run the consumer repository's managed Test +Optimization command. Do not add the internal manifest handoff to `.bazelrc` +or ordinary CI jobs. + +If a direct `bazel test --config=test-optimization` bypasses the managed +command, the failure is expected: target discovery must run first so the +repository rule receives exact targets and runtime contexts. + +### Doctor or uploader triggers another metadata fetch + +One managed command invocation must pass the same temporary manifest path to +test, doctor, uploader dry-run, and optional upload. If the request log shows +another fetch during a post-test phase, check that the command did not create a +new temporary directory or change +`DD_TEST_OPTIMIZATION_SERVICES_MANIFEST` between child Bazel processes. + +A later managed command intentionally creates a new manifest path and fetches +current backend state once. If its selected settings/module files are +unchanged, tests should remain Bazel cache hits even though +`telemetry_facts.json` contains new request timings. + +### Manifest is malformed or unsupported + +The error names the schema field rejected before metadata requests. Verify +that the consumer resolver emitted: + +- schema version `1`; +- canonical local labels such as `//pkg:test`, not patterns or external labels; +- unique, used contexts; +- only Go/Python runtimes; +- deterministic context keys matching service and runtime; +- `application` or `domain_fallback` for every target. + +Fix the resolver or its target input. Do not hand-edit the temporary manifest. + +### Unsupported target is absent from the aggregate mapping + +Only targets recognized by the consumer's central Go/Python macro policy are +eligible. A target absent from `topt_data_by_target` correctly keeps its raw +behavior. Inspect the managed command summary for unsupported labels and +confirm that the target is a runtime test, not a build-only companion. + +Java, NodeJS, .NET, and Ruby are intentionally outside automatic manifest +onboarding in this release. + +### Service or context collision + +The resolver and repository reject two logical services that sanitize to the +same context key, conflicting module paths or runtime versions for one +service/runtime, duplicate labels, and one label assigned to multiple +contexts. Change the consumer's deterministic naming grammar or split the +conflicting runtime contexts; do not append positional suffixes whose result +depends on input order. + +### Doctor expected-target mismatch + +The aggregate `:expected_targets` file is exact. A mismatch means the execution +set, BEP inputs, or doctor wiring does not match the manifest. The managed +command must test the fully expanded labels from the same discovery phase and +pass that invocation's BEP file to doctor. + +Cached tests do not emit fresh payloads. With configured expected targets, +strict BEP freshness accepts those cache hits as covered, validates no stale +local outputs for them, and lets uploader treat an all-cached invocation as a +no-op. If a cached target is reported as missing instead, verify that doctor +received the BEP from the exact matching `bazel test` invocation. Use separate +cache-isolation tests when validating action-key behavior. + +### Disabled mode or enabled bootstrap invokes host Go + +Disabled manifest sync must not read the manifest, contact Datadog, or resolve +the real Orchestrion tool repository. Enabled Go bootstrap uses the +Bazel-managed Go SDK and must not depend on a host `go` binary. If a host-Go +sentinel fires, verify the patched `rules_go` profile, generated SDK wiring, +and central wrapper before installing Go on the host. ## Published Go pins @@ -378,10 +491,10 @@ global root `BUILD.bazel` wiring unrelated to Test Optimization. 3. **Check DD_TEST_OPTIMIZATION_PAYLOADS_IN_FILES**: The macro should set this to `"true"`. Verify your test environment: ```bash - bazel test //your:test --test_output=all 2>&1 | grep DD_TEST_OPTIMIZATION + bazel test --config=test-optimization //your:test --test_output=all 2>&1 | grep DD_TEST_OPTIMIZATION ``` ```powershell - bazel test //your:test --test_output=all *>&1 | Select-String "DD_TEST_OPTIMIZATION" + bazel test --config=test-optimization //your:test --test_output=all *>&1 | Select-String "DD_TEST_OPTIMIZATION" ``` PowerShell uses `*>&1` (not Bash `2>&1`) to merge stderr/stdout. @@ -454,7 +567,10 @@ fails before upload. importpath that `rules_go` uses, or set `module_label_override` only when the module label is intentionally known. `module` and `module_override` are valid successful selections; `full_bundle_disabled` is valid when backend module - data is disabled. + data is disabled. Generic inferred/derived selection may intentionally use + the canonical full bundle and report `full_bundle_no_match`; the doctor + rejects that state by default, so only an intentionally generic consumer + should set `forbid_full_bundle_no_match = False`. 6. **Expected target output missing**: Run the exact target listed in `expected_targets` before the doctor. With remote execution or remote cache, @@ -739,12 +855,27 @@ module version. declarations after `go.mod` or `go.sum` changes so Bazel and the Go module graph agree. -3. **If you wire Orchestrion manually**, make sure both places match: - - `orchestrion.from_source(..., dd_trace_go_version = "")` - - or `orchestrion.from_source(..., dd_trace_go_versions = {...})` - - the effective local module graph resolved from `go.mod` and `go.sum` +3. **If you wire Orchestrion manually**, use the checked-in module as the + normal source of truth: + ```bzl + orchestrion.from_source( + dd_trace_go_pin_files = ["@//:go.mod", "@//:go.sum"], + go_sdk_root = "@test_optimization_go_sdk//:ROOT", + go_sdk_version = "", + version = "", + ) + ``` + Export both root files from their BUILD package. Bazel resolves all + supported direct and transitive tracer modules with hermetic Go and + `-mod=readonly`; it does not update `go.sum`. + +4. **If pin-file resolution reports an absent module, unsupported replacement, + or read-only failure**, fix the module with its normal dependency workflow. + If that graph intentionally cannot use pin-file mode, configure the exact + `dd_trace_go_versions` map as an escape hatch. Do not combine pin files with + either explicit version field. -4. **If you omitted the version entirely**, remember the default is +5. **If you omitted every selection mode**, remember the legacy default is `v2.9.0`. The build fails on purpose here. It is preventing Bazel from injecting one @@ -753,6 +884,40 @@ set of tracer versions while the local Go module still resolves another. `orchestrion.tool.go` still matters, but as required import/config wiring for Orchestrion, not as the source of truth for tracer versions. +## Enabled Orchestrion cannot find Go + +**Symptom**: + +```text +Could not find 'go' binary. Please ensure Go is installed. +``` + +**Cause**: the workspace uses Orchestrion wiring generated before the +Bazel-managed SDK contract was added, or a manual block omitted the SDK root +and version. Disabled mode still avoids the real repository, but enabled mode +must compile the patched Orchestrion binary on a cold cache miss. + +**Solution**: + +1. For Bzlmod, rerun guided bootstrap with the workspace's real Go toolchain + version: + ```bash + bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ + --guided \ + --service \ + --runtime-version \ + --write-bazelrc + ``` +2. For WORKSPACE, regenerate the reviewed snippet with + `--workspace-mode --print-workspace-snippet --runtime-version `. +3. Verify the generated SDK version equals the version passed to the + repository's central `go_register_toolchains(...)` call and the Test + Optimization sync repository. + +Do not install Go on the analysis host as the fix. The supported wiring uses +the Bazel-managed SDK on a cache miss and can restore a compatible warm +Orchestrion bootstrap before materializing that SDK. + ## WORKSPACE go_repository drift **Symptom**: `go.mod` and `go.sum` look correct, but Bazel still resolves an @@ -869,8 +1034,8 @@ client-side Bazel behavior. - PowerShell: set `$env:DD_API_KEY` and `$env:DD_SITE` first, then run `bazel run --config=test-optimization //:dd_upload_payloads` - Quote paths containing spaces and avoid `eval`-style wrappers. - For refetch debugging, use: - - `bazel sync --only= --repo_env=FETCH_SALT=` - - if required by workspace mode: `bazel sync --enable_workspace --only= --repo_env=FETCH_SALT=` + - `bazel sync --config=test-optimization --only= --repo_env=FETCH_SALT=` + - if required by workspace mode: `bazel sync --enable_workspace --config=test-optimization --only= --repo_env=FETCH_SALT=` ## Getting help @@ -878,10 +1043,10 @@ If issues persist: 1. **Enable debug mode** and capture full output: ```bash - bazel sync --only= --repo_env=FETCH_SALT= 2>&1 | tee debug.log + bazel sync --config=test-optimization --only= --repo_env=FETCH_SALT= 2>&1 | tee debug.log ``` ```powershell - bazel sync --only= --repo_env=FETCH_SALT= *>&1 | Tee-Object -FilePath debug.log + bazel sync --config=test-optimization --only= --repo_env=FETCH_SALT= *>&1 | Tee-Object -FilePath debug.log ``` 2. **Collect diagnostic info**: diff --git a/docs/Uploader_Reference.md b/docs/Uploader_Reference.md index 66fbac35..a36ab44e 100644 --- a/docs/Uploader_Reference.md +++ b/docs/Uploader_Reference.md @@ -35,6 +35,24 @@ The `test-optimization` config should contain the recommended Bazel test flags: `--remote_download_minimal`, `--remote_download_regex=.*test[.]outputs.*`, and `--zip_undeclared_test_outputs`. +For Go consumers using the reusable bootstrap, keep the phase-correct enablement +in the same config: + +```bazelrc +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true +``` + +This is one user-facing switch. Removing `--config=test-optimization` disables +both metadata resolution and the Orchestrion analysis aliases; it does not +require a second bool flag. In WORKSPACE repositories, use the apparent +`rules_go` repository name configured by that workspace. + +Config-gated Python consumers use only the +`DD_TEST_OPTIMIZATION_ENABLED=1` entry and omit the Go-specific Orchestrion +line. Java, NodeJS, .NET, and Ruby retain their existing enablement contract in +this release. + ```bash # Vendor the full tools/test_optimization/ helper directory, or set # DD_TEST_OPTIMIZATION_SUPPORT_BUNDLE_COLLECTOR to create_support_bundle.py. @@ -189,6 +207,12 @@ dd_payload_uploader( ) ``` +Each `:test_optimization_context` target bundles both `context.json` and +`telemetry_facts.json`. The uploader selects the matching context for payload +enrichment and consumes the bundled telemetry facts for rule-telemetry +augmentation. Do not pass only the physical `context.json` file when using the +normal target-based wiring. + ## Upload modes - **Agentless mode (default):** Requires `DD_API_KEY` and `DD_SITE`; uploads @@ -308,7 +332,7 @@ For first-pass support, the doctor can create a doctor-only bundle without the wrapper: ```bash -bazel run //:dd_test_optimization_doctor -- \ +bazel run --config=test-optimization //:dd_test_optimization_doctor -- \ --support-bundle .topt/reports/dd-test-optimization-support.zip ``` @@ -367,6 +391,9 @@ config, expected targets, BEP files and seen targets, fresh/cached/remote-only BEP outputs, selected and blocked BEP artifact carriers, staged `outputs.zip` or `test.outputs` artifacts, local/staged payload directories, payload counts, Bazel metadata, payload-selection counts, and failure messages. +When expected targets are configured, fresh and cached BEP labels jointly +satisfy target coverage. Only fresh outputs are validated; an all-cached +invocation succeeds with zero validated output directories. Example: @@ -393,9 +420,9 @@ config, BEP files, selected freshness source, BEP freshness counts, artifact staging counts, discovered payload directories, per-payload-type discovered, processed, failed, and skipped counts, aggregate upload failures, upload attempt status, final status, and exit code. The `result.reason_code` explains -common no-upload cases such as `target_cached_by_bazel`, -`bep_output_remote_only_without_downloader`, `no_payload_json_found`, -`payload_enrichment_failed`, and `upload_skipped_dry_run`. +common no-upload cases such as `bep_output_remote_only_without_downloader`, +`no_payload_json_found`, `payload_enrichment_failed`, and +`upload_skipped_dry_run`. The CI wrapper writes a separate dry-run uploader report when `--report-dir` is used. If only `DD_TEST_OPTIMIZATION_UPLOADER_REPORT_JSON` or @@ -602,8 +629,11 @@ or set `DD_TEST_OPTIMIZATION_EXECUTION_LOG_JSON` for the uploader run. `DD_TEST_OPTIMIZATION_MAX_WAIT_SEC` controls how long the uploader waits for payload discovery/quiescence before proceeding. - `> 0`: wait up to the configured budget for payload files to appear and settle. -- `0`: skip waiting loops immediately. If no payloads are found, uploader exits - cleanly with "nothing to upload" semantics. +- `0`: skip waiting loops immediately. When BEP freshness is configured, the + uploader evaluates that BEP before applying no-payload failure policy, so an + all-cached invocation is a no-op while missing fresh payloads still fail. + Without BEP freshness, the configured no-payload/`fail_on_error` policy + applies normally. ## Endpoints and headers @@ -676,6 +706,30 @@ payload discovery/quiescence before proceeding. - CODEOWNERS enrichment is best-effort: parse/lookup failures and misses do not fail uploads; debug mode logs counters and skip reasons. +### Manifest-driven aggregate contexts + +`test_optimization_manifest_sync` places every selected Go/Python runtime +context in one aggregate repository. Its +`:test_optimization_context` target carries a provider mapping deterministic +context keys to the matching `context.json`. Doctor and uploader convert those +entries into virtual repository keys of the form +`_`, which match the +`bazel.test_optimization.repo_name` written by selected targets. + +The managed doctor should also consume +`@test_optimization_data//:expected_targets` through +`expected_targets_file`. The file contains the exact canonical labels from the +invocation manifest. Static `expected_targets` and the generated file may be +used together only when they describe the same set; disagreement is a hard +error. + +A cached Bazel test does not produce a fresh payload for the current +invocation. With exact expected targets configured on both doctor and uploader, +fresh and cached BEP results jointly satisfy invocation coverage. Only fresh +outputs are validated or uploaded; an all-cached invocation is a successful +no-op. Every fresh expected output must independently contain a handled +payload, so one valid sibling output cannot hide an empty one. + ### Advanced: reuse an already-fetched context file If your workflow already resolved Test Optimization data during the test diff --git a/docs/go_orchestrion_bazel_deep_dive.md b/docs/go_orchestrion_bazel_deep_dive.md index 317d6edb..cf7b5809 100644 --- a/docs/go_orchestrion_bazel_deep_dive.md +++ b/docs/go_orchestrion_bazel_deep_dive.md @@ -96,8 +96,10 @@ dd_topt_go_test( ) ``` -But the raw `go_test` is built under a transition that enables the requested -Orchestrion mode in the vendored toolchain. +When Test Optimization is enabled, the raw `go_test` is built under a +transition that enables the requested Orchestrion mode in the vendored +toolchain. When the selected sync export is disabled, the macro instead creates +only the caller's public raw `go_test`. ### Why This Section Exists @@ -114,11 +116,17 @@ flowchart TD C --> D[Bzlmod MODULE.bazel patching or WORKSPACE local scaffolding] C --> E[orchestrion pin files] D --> F[vendored rules_go fork] + D --> W[Bazel-managed Go SDK] F --> G[rules_go Orchestrion extension] - G --> H[patched Orchestrion binary] - - I[BUILD: dd_topt_go_test] --> J[hidden raw go_test] - I --> K[public orch_go_test wrapper] + G --> U{Test Optimization enabled?} + U -->|no| V[stable empty repository\n no host Go or source fetch] + U -->|yes| H[patched Orchestrion binary] + W --> H + + I[BUILD: dd_topt_go_test] --> R{Sync export enabled?} + R -->|no| S[public raw go_test\n no Test Optimization targets] + R -->|yes| J[hidden raw go_test] + R -->|yes| K[public orch_go_test wrapper] K --> L[function transition] L --> J @@ -159,6 +167,11 @@ materializes the metadata repo used by `dd_topt_go_test`. - In manual single-service or multi-service setup, the Go macro only requires a compatible exported `topt_data` shape. That can come from the Go extension or from the core sync and multi-sync extensions. +- In a consumer-managed Go/Python monorepo, the separate manifest-sync + aggregate exports `topt_data_by_target`; the central Go wrapper passes the + matching entry to the same macro. Target discovery and service naming happen + before repository resolution in the consumer command, not in Orchestrion or + `rules_go`. The generated metadata repo then provides the per-service and per-module payload labels consumed by `dd_topt_go_test`. @@ -175,18 +188,20 @@ The bootstrap binary is the one-time workspace mutation step. Implementation: - [main.go](../modules/go/tools/dd_topt_go_bootstrap/main.go) -In guided Bzlmod mode, bootstrap does five things that matter for the current +In guided Bzlmod mode, bootstrap does six things that matter for the current architecture: 1. Ensures `MODULE.bazel` contains `bazel_dep(name = "rules_go", version = "0.60.0")` 2. Writes a managed `git_override` for `rules_go` pointing back to this repo with `strip_prefix = "third_party/rgo/v0_60_0/base"` -3. Enables the `@rules_go//go:extensions.bzl` Orchestrion extension and +3. Declares a Bazel-managed Go SDK from `--runtime-version` +4. Enables the `@rules_go//go:extensions.bzl` Orchestrion extension, passes the + SDK root and exact version, and imports `use_repo(orchestrion, "rules_go_orchestrion_tool")` -4. Sets the workspace-wide tracer selection with either +5. Sets the workspace-wide tracer selection with either `orchestrion.from_source(..., dd_trace_go_version = "...")` or `orchestrion.from_source(..., dd_trace_go_versions = {...})` -5. Runs `orchestrion pin` in the Go module and ensures: +6. Runs `orchestrion pin` in the Go module and ensures: - `go.mod` - `go.sum` - `orchestrion.tool.go` @@ -197,6 +212,7 @@ It aligns: - Bazel module wiring - the vendored `rules_go` fork +- the Bazel-managed Go SDK used to build Orchestrion - the selected `dd-trace-go` version used by Bazel injection - the pinned Go module files that Orchestrion expects @@ -218,6 +234,13 @@ instead of rewriting the tool repo's own `go.mod`. The selected tracer version is enforced later against the target module through the emitted `dd_trace_go_versions.json` file and the builder-side validation path. +Manual consumer wiring normally replaces bootstrap's explicit tracer selection +with `dd_trace_go_pin_files = ["@//:go.mod", "@//:go.sum"]`. The repository rule +uses the Bazel-managed Go SDK to resolve every supported direct or transitive +module with `-mod=readonly`, emits the same canonical +`dd_trace_go_versions.json`, and keys the bootstrap cache by that resolved map. +Explicit shared and per-module selections remain compatibility escape hatches. + #### Why This Exists Bootstrap centralizes the one-time mutations needed to make Bazel and @@ -231,17 +254,23 @@ target would need to carry fragile setup knowledge. Implementation: - [topt_go_test.bzl](../modules/go/topt_go_test.bzl) -The macro does three distinct jobs: +With an enabled sync export, the macro does three distinct jobs: 1. Select Datadog payload data 2. Prepare runtime env/data wiring for Test Optimization 3. Route the public test through the Orchestrion wrapper transition -The macro expands into: +The enabled macro expands into: - a hidden raw `go_test` - a public `orch_go_test` wrapper +With a disabled export, the macro validates its macro-only inputs and selected +service, then creates only the caller's public raw `go_test`. It does not create +the hidden test, payload selector, target metadata, Orchestrion pin, or wrapper +targets. The public label is therefore stable across modes, but the rule class +is not: it is `go_test` while disabled and `orch_go_test` while enabled. + The wrapper forwards `orchestrion_mode` into the vendored `rules_go` fork. The default mode is `general`, which preserves broad generic Orchestrion behavior. For standard Go `testing`, use `orchestrion_mode = "test_optimization"`. That @@ -278,14 +307,18 @@ in one place. Implementation: - [topt_go_orchestrion.bzl](../modules/go/topt_go_orchestrion.bzl) -The wrapper rule exists for one reason: it applies a function transition that -sets: +In the enabled path, the wrapper rule applies a function transition that sets +only: ```bzl -"@rules_go//go/private/orchestrion:enabled": True "@rules_go//go/private/orchestrion:mode": "general" or "test_optimization" ``` +The transition deliberately preserves the existing +`@rules_go//go/private/orchestrion:enabled` setting. The user-facing +`--config=test-optimization` config enables that setting during analysis; +omitting the config leaves it at the `rules_go` default of `False`. + The wrapper then symlinks the executable produced by the raw target and returns the same runfiles. @@ -295,7 +328,9 @@ an Orchestrion-enabled configuration. #### Why This Exists The transition wrapper lets the raw test build under a different configuration -without changing the public target shape that users and CI interact with. +without changing the public target label that users and CI invoke. Callers that +filter tests by rule language must account for the mode-dependent rule class: +`go` for the disabled raw target and `orch_go` for the enabled wrapper. ## Why the Vendored `rules_go` Fork Exists @@ -755,7 +790,10 @@ and Datadog contrib HTTP/slog helper roots. Some required woven dependencies are first touched inside sandboxed steps. Warming them reduces failures caused by lazy first access in those contexts. -## End-to-End Flow for a Go Test +## End-to-End Flow for an Enabled Go Test + +The disabled path stops at the macro: it creates the public raw `go_test` and +does not enter the wrapper, vendored Orchestrion, or payload path below. ```mermaid sequenceDiagram @@ -769,7 +807,7 @@ sequenceDiagram User->>Macro: declare Go test Macro->>Macro: select payload data + add pin files Macro->>Wrapper: public test target - Wrapper->>RG: build raw go_test with transition enabled + Wrapper->>RG: build raw go_test with mode transition; preserve enabled flag RG->>RG: compile customer packages RG->>Orch: compile woven stdlib as needed RG->>Orch: prepare synthetic testmain helper packagefiles diff --git a/docs/go_orchestrion_maintainer_state.md b/docs/go_orchestrion_maintainer_state.md index 5c9d8ac7..05f2c199 100644 --- a/docs/go_orchestrion_maintainer_state.md +++ b/docs/go_orchestrion_maintainer_state.md @@ -38,8 +38,10 @@ together. ```mermaid flowchart TD - A["Consumer BUILD: dd_topt_go_test"] --> B["Hidden raw go_test"] - A --> C["Test Optimization data repo"] + A["Consumer BUILD: dd_topt_go_test"] --> Z{"Selected sync export enabled?"} + Z -->|"no"| R["Public raw go_test; no TO-owned targets"] + Z -->|"yes"| B["Hidden raw go_test"] + Z -->|"yes"| C["Test Optimization data repo"] B --> D["Vendored rules_go fork"] D --> E["compilepkg / stdlib / link builders"] E --> F["orchestrion toolexec"] @@ -49,8 +51,10 @@ flowchart TD I --> J["CI Visibility runtime and payload files"] K["Bootstrap or manual MODULE wiring"] --> L["rules_go Orchestrion extension"] - L --> G - L --> M["dd_trace_go_versions.json"] + L --> N{"DD_TEST_OPTIMIZATION_ENABLED?"} + N -->|"no"| O["Stable empty repository and local aliases"] + N -->|"yes"| G + N -->|"yes"| M["dd_trace_go_versions.json"] M --> E ``` @@ -61,10 +65,17 @@ The important model is: - Orchestrion is not a post-processing step - the vendored fork makes Orchestrion part of the normal compile, stdlib, and link path +- without `--config=test-optimization`, the public test is the raw `go_test`, + the stable Orchestrion aliases select package-local empty targets, and the + gated repository returns before host-Go discovery or source fetching - `test_optimization` mode is the narrower standard Go `testing` path: customer packages and external `_test` packages compile normally, while stdlib `testing`, synthetic `testmain`, helper packagefiles, importcfg, and link support stay coherent +- the metadata input may come from static sync or from an invocation-scoped + manifest aggregate; this does not change Orchestrion compilation. In the + managed case, the consumer's central wrapper selects the exact + `topt_data_by_target` entry before calling `dd_topt_go_test`. ## Mode Contract @@ -102,15 +113,27 @@ Orchestrion and upstream `rules_go` do not provide together out of the box: In short: the fork is not ornamental. It is the compatibility layer that keeps Orchestrion coherent inside Bazel. -## Why The Orchestrion Tool Is Still Built +## Why The Orchestrion Tool Is Still Built When Enabled -On a true cold start, Bazel still builds the Orchestrion binary because: +On an enabled true cold start, Bazel still builds the Orchestrion binary +because: - the extension downloads Orchestrion source, not a prebuilt binary - we patch that source for Bazel compatibility before building it - the resulting binary is platform-specific - the bootstrap cache is host-local, so a fresh CI runner starts empty +The build uses the Bazel-managed Go SDK declared by guided bootstrap, not a +host `go` binary. The SDK version is also part of the bootstrap cache identity. +On a compatible cache hit, the extension restores the tool before materializing +the SDK repository; on a miss, it materializes the SDK and verifies that its +reported version matches the declaration. + +This cost does not apply to the config-disabled path. The patched repository +rule writes the stable empty interface before SDK or host-Go discovery, and the +vendored `rules_go` aliases avoid referencing the real tool repository while +the Orchestrion build setting is false. + The recent work changed one important part of this story: - Bazel no longer rewrites Orchestrion's own `go.mod` to force the target @@ -340,17 +363,20 @@ Measured with: - a new `--output_base` - the same shared cache root -Current warm numbers: +Current isolated warm-bootstrap observation: -- total build elapsed: `86.281s` -- critical path: `68.91s` -- Orchestrion bootstrap total: `3.955s` +- fresh Bazel output root with the same bootstrap cache: about `12.9s` total + command elapsed +- Orchestrion repository bootstrap within that command: about `1.8s` to `2.5s` +- cache identity source: the declared Bazel SDK, allowing restore before SDK + materialization The main conclusion is: - once the bootstrap artifact cache hits, the tool bootstrap is no longer the - main problem -- stdlib becomes the most visible remaining build step + main cost +- Bazel startup, repository mapping, and analysis account for most of the + remaining fresh-output-root command time ### Runtime correctness validation @@ -374,7 +400,8 @@ This validation is part of the baseline, not optional extra checking. ### 1. Cold Orchestrion tool build -This is still the largest single cost on a true cold start. +This is still the largest single cost on an enabled true cold start. The +config-disabled path does not build the tool. At this point, the likely remaining wins here are more architectural than incremental: diff --git a/docs/internal_monorepo_go_rollout_guide.md b/docs/internal_monorepo_go_rollout_guide.md index d1c858c1..0d97852b 100644 --- a/docs/internal_monorepo_go_rollout_guide.md +++ b/docs/internal_monorepo_go_rollout_guide.md @@ -17,6 +17,13 @@ Use [`Language_Onboarding.md`](./Language_Onboarding.md#large-workspace-monorepo for the step-by-step onboarding guide. Use this page as the operator checklist when the rollout needs a reviewable local pilot before wider adoption. +This page describes the static pilot path. A monorepo with a repository-owned +managed command that expands exact targets should instead use the +[automatic managed Go/Python contract](./Language_Onboarding.md#automatic-managed-gopython-monorepos). +That path derives services per invocation and does not check in pilot lists, +Gazelle policy, or ownership gates. Both paths share the same `rules_go`, +Orchestrion, doctor, and uploader safety requirements. + ## Published Contract - Consume one complete base `rules_go` Orchestrion tree. Do not copy patch @@ -49,26 +56,32 @@ SHA256, and archive prefix generated from the same published commit. - Use a commit that is reachable from `origin/main`; never publish feature-branch SHAs into consumer snippets. -- Configure `go_orchestrion_tool_repo(...)` with the current supported +- Configure `dd_topt_go_orchestrion_tool_repo(...)` with the current supported Orchestrion version and the current supported `dd-trace-go` Bazel-mode - version. -- Configure `test_optimization_sync(...)` with: + version, plus the repository's central `@go_sdk//:ROOT` label and exact Go + SDK version. Do not load the underlying `rules_go` repository rule directly + or repeat this wiring per service. +- Configure `dd_topt_go_workspace_sync_repositories(...)` with: - `service` - - `runtime_name = "go"` - `runtime_version` - - `runtime_module_path` + - `module_path` - `require_git_metadata = True` + The public helper supplies `runtime_name = "go"` and config-gated metadata + sync by default. - Keep repository-specific scheduling, Docker, tags, platform constraints, and flaky policy in the repository-local wrapper layer. -- Set `orchestrion_mode = "test_optimization"` in the optimized wrapper for +- Route the existing central Go wrapper through `dd_topt_go_test` and set + `orchestrion_mode = "test_optimization"` for standard Go `testing` Test Optimization pilots. The `general` mode remains available for explicit compatibility validation only. -- Keep a plain wrapper path for controls and unconverted tests. -- Convert only the agreed runtime-emitting pilot targets first. +- Keep BUILD callsites on that same wrapper; the named config controls whether + its expansion is normal or instrumented. +- Select only the agreed runtime-emitting pilot scope in central repository + policy. - Do not list `.build_test`, compile-only, or other build-only controls as doctor `expected_targets`. -- Add one root `dd_test_optimization_doctor` target. -- Add one root `dd_upload_payloads` target. +- Add one `dd_test_optimization_doctor` target and one `dd_upload_payloads` + target in a lightweight package such as `//tools/test_optimization`. - Use `.bazelrc` to activate `--remote_download_minimal --remote_download_regex=.*test[.]outputs.*` and `--zip_undeclared_test_outputs` for test commands. Pass a fresh @@ -78,6 +91,17 @@ SHA256, and archive prefix generated from the same published commit. `--artifact-staging-dir=`. - Pass `DD_GIT_*` only through `--repo_env`, never through `--test_env`. - Pass uploader credentials at `bazel run` time, not into test actions. +- Keep one user-facing `test-optimization` config with both phase-correct + switches: + + ```bazelrc + common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 + build:test-optimization --@io_bazel_rules_go//go/private/orchestrion:enabled=true + ``` + + Removing `--config=test-optimization` disables both metadata repositories + and Orchestrion aliases. The public Go helpers enable metadata gating by + default; they do not dynamically control Orchestrion repository declaration. ## Bootstrap Flow @@ -93,7 +117,6 @@ bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ --rules-go-variant base \ --dd-trace-go-version v2.9.0 \ --write-bazelrc \ - --write-root-targets \ --write-orchestrion-files \ --write-wrapper-template \ --write-validation-script \ @@ -102,9 +125,25 @@ bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ --shutdown-bazel-on-exit \ --default-jobs=1 \ --expected-target "//path/to/runtime/package:go_default_test" \ + --doctor-target "//tools/test_optimization:dd_test_optimization_doctor" \ + --upload-target "//tools/test_optimization:dd_upload_payloads" \ --control-target "//path/to/plain/control:go_default_test" ``` +Create the single doctor/uploader pair in +`//tools/test_optimization:BUILD.bazel`; do not use `--write-root-targets` for +this monorepo flow. + +### Updating an existing managed config + +When upgrading from the current release, rerun the same bootstrap with +`--write-bazelrc`. It replaces the content between the Datadog-managed markers +with the current single-config contract, preserves all content outside those +markers, and is idempotent. This adds both +`DD_TEST_OPTIMIZATION_ENABLED=1` and the existing `rules_go` Orchestrion flag to +the named config; consumers do not need a separate migration mode or a second +bool flag. + If the repository owns checked-in `go_repository(...)` declarations, run the repository-owned refresh command after targeted Go module sync and rerun bootstrap with `--check-go-repositories`. Bootstrap should verify those pins; it @@ -120,9 +159,9 @@ bazel test --config=test-optimization bazel test --config=test-optimization bazel test --config=test-optimization bazel test --config=test-optimization -bazel run --config=test-optimization //:dd_test_optimization_doctor -bazel run --config=test-optimization //:dd_upload_payloads -- --dry-run --validate-enrichment -DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" bazel run --config=test-optimization //:dd_upload_payloads +bazel run --config=test-optimization //tools/test_optimization:dd_test_optimization_doctor +bazel run --config=test-optimization //tools/test_optimization:dd_upload_payloads -- --dry-run --validate-enrichment +DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" bazel run --config=test-optimization //tools/test_optimization:dd_upload_payloads bazel shutdown ``` diff --git a/docs/rules_go_orchestrion_support_selection.md b/docs/rules_go_orchestrion_support_selection.md index 28d66c86..15a77309 100644 --- a/docs/rules_go_orchestrion_support_selection.md +++ b/docs/rules_go_orchestrion_support_selection.md @@ -26,6 +26,7 @@ The default `rules_go_upstream` is currently `v0_60_0`, which preserves the existing `third_party/rgo/v0_60_0/base` path. When multiple upstream `rules_go` versions are supported, use `rules_go_upstream` to choose the upstream support line. Omitting `rules_go_upstream` preserves the repository default. +The registry currently supports `v0_60_0`, `v0_61_1`, and `v0_62_0`. ## Selection Rule diff --git a/docs/rules_go_variant_maintenance_guide.md b/docs/rules_go_variant_maintenance_guide.md index 9affcdb1..9f81aeaa 100644 --- a/docs/rules_go_variant_maintenance_guide.md +++ b/docs/rules_go_variant_maintenance_guide.md @@ -16,11 +16,12 @@ Orchestrion-enabled `rules_go` support lines and public consumer patch profiles. ### `third_party/rgo//base/` The public base tree for one supported upstream. For example, the current -default upstream uses `third_party/rgo/v0_60_0/base`, and the v0.61.1 support -line uses `third_party/rgo/v0_61_1/base`. Each tree contains clean upstream -`rules_go` plus the generic Orchestrion support maintained by this repository. -Bugs in our integration are fixed in the affected materialized tree, then the -matching patch series is regenerated from that tree. +default upstream uses `third_party/rgo/v0_60_0/base`, and the additional +support lines use `third_party/rgo/v0_61_1/base` and +`third_party/rgo/v0_62_0/base`. Each tree contains clean upstream `rules_go` +plus the generic Orchestrion support maintained by this repository. Bugs in +our integration are fixed in the affected materialized tree, then the matching +patch series is regenerated from that tree. ### `third_party/rules_go_orchestrion/` @@ -263,3 +264,21 @@ they consume a complete base tree. Repositories that already own their `rules_go` patch stack should instead use a generated public consumer patch profile as a local rebase or merge input, then verify the regenerated private patch in their private patch order. + +## Test Optimization Alias Contract + +The public base trees keep the existing +`//go/private/orchestrion:enabled` setting as the analysis-time control. Their +stable Orchestrion aliases select package-local empty targets when the setting +is false and the real `rules_go_orchestrion_tool` files when it is true. +Consumers should expose one config that sets both effects: + +```bazelrc +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true +``` + +The public Go extension reads the metadata environment by default; low-level +repositories do so when explicitly configured with `enabled_by_env = True`. +Removing the config is the opt-out and must not require a consumer-owned +duplicate bool flag or stub repository. diff --git a/examples/README.md b/examples/README.md index 56b5fbdd..116c2b8c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -8,7 +8,11 @@ This product includes software developed at Datadog # Examples -This folder shows concise usage patterns for single-service and multi-service setups. These snippets are meant to be copied into your repo; in this repository we also keep them buildable (`//examples/...`) as a regression guard. +This folder shows concise usage patterns for static single-service, static +multi-service, and consumer-managed Go/Python setups. Static snippets are meant +to be copied into your repo; the managed example describes the boundary a +repository-owned command implements. In this repository we also keep the +existing static examples buildable (`//examples/...`) as a regression guard. Tip: commands use `bazel` for portability in consumer repos. In this repository, use `./bazelw` for local development convenience. @@ -39,6 +43,20 @@ repository, use `./bazelw` for local development convenience. - Provide sync credentials via environment and forward them to repository rules: - shell/CI secret: `DD_API_KEY` - `.bazelrc`: `common --repo_env=DD_API_KEY` (and optionally `common --repo_env=DD_SITE`) +- For config-gated Go and Python Test Optimization, make the documented config + the only user-facing switch: + + ```bazelrc + common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 + # Go only: + build:test-optimization --@rules_go//go/private/orchestrion:enabled=true + ``` + + Removing `--config=test-optimization` disables metadata resolution and the + matching Go/Python runtime wiring. Go additionally disables Orchestrion + analysis; in WORKSPACE mode, use the apparent `rules_go` repo name configured + by the workspace. Python-only consumers omit the Go line. Other companions + retain their existing enablement contract in this release. ## Single-service (classic) @@ -121,12 +139,75 @@ ruby.toolchain( ) use_repo(ruby, "ruby", "ruby_toolchains") register_toolchains("@ruby_toolchains//:all") + +go_topt = use_extension( + "@datadog-rules-test-optimization-go//:topt_go_extension.bzl", + "test_optimization_go_extension", +) +go_topt.test_optimization_go( + name = "test_optimization_data_go", + module_path = "example.com/single-service-go-project", + runtime_version = "1.25.0", + service = "go-service", +) +use_repo(go_topt, "test_optimization_data_go") + +runtime_topt = use_extension( + "@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", + "test_optimization_sync_extension", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_python", + enabled_by_env = True, + runtime_module_path = "example.python.project", + runtime_name = "python", + runtime_version = "3.12", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_java", + runtime_module_path = "com.example.topt", + runtime_name = "java", + runtime_version = "21", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_nodejs", + runtime_module_path = "example/nodejs/project", + runtime_name = "nodejs", + runtime_version = "22.22.0", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_dotnet", + runtime_module_path = "Company.Product.Example", + runtime_name = "dotnet", + runtime_version = "8.0", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_ruby", + runtime_module_path = "apps/ruby/example", + runtime_name = "ruby", + runtime_version = "3.3.9", + service = "go-service", +) +use_repo( + runtime_topt, + "test_optimization_data_dotnet", + "test_optimization_data_java", + "test_optimization_data_nodejs", + "test_optimization_data_python", + "test_optimization_data_ruby", +) ``` This mirrors the buildable `examples/single_service` workspace in this -repository: one Datadog service shared across several runtime-specific test -macros, with Go using the bootstrap-managed extension. If your team owns only -Python, Java, NodeJS, .NET, or Ruby, the simpler runtime-specific setup is in +repository: one logical Datadog service shared across several runtime-specific +sync repositories and test macros. A mixed-runtime workspace must not reuse the +Go export for Python, Java, NodeJS, .NET, or Ruby; each runtime needs its own +runtime metadata and context label. If your team owns only Python, Java, +NodeJS, .NET, or Ruby, the simpler runtime-specific setup is in [`docs/Language_Onboarding.md`](../docs/Language_Onboarding.md). The generated Go wrapper uses `orchestrion_mode = "test_optimization"` for @@ -141,6 +222,7 @@ Bootstrap once after adding the module prerequisites: bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ --guided \ --service go-service \ + --sync-repo-name test_optimization_data_go \ --runtime-version 1.25.0 \ --dd-trace-go-version v2.9.0 ``` @@ -189,7 +271,7 @@ BUILD.bazel (Python companion): ```bzl load("@python_deps//:requirements.bzl", "requirement") load("@datadog-rules-test-optimization-python//:topt_py_test.bzl", "dd_topt_py_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_python//:export.bzl", "topt_data") dd_topt_py_test( name = "pkg_py_test", @@ -214,14 +296,19 @@ runner. Repositories with an internal Python test wrapper should use `runner_mode = "consumer_runner"` and pass that wrapper through `py_test_rule`. In that mode the Datadog macro does not inject `run_pytest.py`, does not set -`main`, and does not synthesize `imports`. Prefer `module_identifier` for -payload selection so onboarding does not depend on import-path mutation. +`main`, and does not synthesize `imports`. When the runtime module path and +Bazel package path identify the test, omit `module_identifier` and use the +derived fallback. Keep an explicit `module_identifier` only for a documented +repository-specific exception. Derived or inferred misses may use the +canonical full bundle. When synchronized metadata exposes module groups, an +explicit `module_identifier` or `module_label_override` that does not match one +fails analysis; when no groups exist, the canonical full bundle remains valid. BUILD.bazel (Java companion): ```bzl load("@datadog-rules-test-optimization-java//:topt_java_test.bzl", "dd_topt_java_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_java//:export.bzl", "topt_data") dd_topt_java_test( name = "pkg_java_test", @@ -238,7 +325,7 @@ BUILD.bazel (NodeJS companion): ```bzl load("@aspect_rules_js//js:defs.bzl", "js_test") load("@datadog-rules-test-optimization-nodejs//:topt_nodejs_test.bzl", "dd_topt_nodejs_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_nodejs//:export.bzl", "topt_data") dd_topt_nodejs_test( name = "pkg_nodejs_test", @@ -254,7 +341,7 @@ BUILD.bazel (.NET companion): ```bzl load("@datadog-rules-test-optimization-dotnet//:topt_dotnet_test.bzl", "dd_topt_dotnet_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_dotnet//:export.bzl", "topt_data") load(":dotnet_test_adapter.bzl", "dotnet_csharp_test_adapter") dd_topt_dotnet_test( @@ -274,7 +361,7 @@ BUILD.bazel (Ruby companion): ```bzl load("@rules_ruby//ruby:defs.bzl", "rb_test") load("@datadog-rules-test-optimization-ruby//:topt_ruby_test.bzl", "dd_topt_ruby_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_ruby//:export.bzl", "topt_data") dd_topt_ruby_test( name = "pkg_ruby_test", @@ -289,23 +376,25 @@ dd_topt_ruby_test( Root BUILD.bazel (one doctor and one uploader per workspace): ```bzl -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") - -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = ["@test_optimization_data//:test_optimization_context"], -) - -dd_payload_uploader( - name = "dd_upload_payloads", - data = ["@test_optimization_data//:test_optimization_context"], +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") + +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ + "@test_optimization_data_go//:test_optimization_context", + "@test_optimization_data_python//:test_optimization_context", + "@test_optimization_data_java//:test_optimization_context", + "@test_optimization_data_nodejs//:test_optimization_context", + "@test_optimization_data_dotnet//:test_optimization_context", + "@test_optimization_data_ruby//:test_optimization_context", + ], ) ``` -Use the single-context form above only for single-runtime workspaces. Mixed- -runtime workspaces must add one `:test_optimization_context` label per -runtime/service repo so uploader enrichment stays aligned with each payload. +Use the default single-context form only for a single-runtime workspace whose +sync repository is named `test_optimization_data`. Mixed-runtime workspaces +must add one `:test_optimization_context` label per runtime/service repository +so uploader enrichment stays aligned with each payload. Running tests, validating payloads, and uploading payloads: @@ -368,6 +457,63 @@ Dry-run mode for CI/debugging: the commands that would run without executing Bazel test/upload operations. - PowerShell wrappers honor the same `RUNTESTS_DRY_RUN=1` environment variable. +## Managed manifest (automatic Go/Python monorepo) + +This is deliberately separate from the static examples. Declare one aggregate +repository without a service list: + +```bzl +# MODULE.bazel +topt_manifest = use_extension( + "@datadog-rules-test-optimization//tools/core:test_optimization_manifest_sync.bzl", + "test_optimization_manifest_sync_extension", +) +topt_manifest.test_optimization_manifest_sync( + name = "test_optimization_data", +) +use_repo(topt_manifest, "test_optimization_data") +``` + +A central consumer wrapper loads `topt_data_by_target`, computes the current +full label, and uses the optimized companion only when the label is present: + +```bzl +load("@test_optimization_data//:export.bzl", "topt_data_by_target") + +def dd_go_test(name, **kwargs): + label = "//%s:%s" % (native.package_name(), name) + topt_data = topt_data_by_target.get(label) + if topt_data == None: + _raw_dd_go_test(name = name, **kwargs) + return + dd_topt_go_test(name = name, topt_data = topt_data, **kwargs) +``` + +The equivalent central Python wrapper delegates selected labels to +`dd_topt_py_test` and preserves its existing raw path otherwise. Real consumer +wrappers must also preserve their repository-specific policy and companion +targets. + +Wire doctor/uploader to the aggregate outputs: + +```bzl +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ + "@test_optimization_data//:test_optimization_context", + ], + expected_targets_file = "@test_optimization_data//:expected_targets", +) +``` + +The temporary manifest and its Bazel environment handoff are owned by the +consumer's managed command. They are not user configuration and are +intentionally omitted from this copy/paste example. That command expands exact +Go/Python labels, derives services, performs sync, runs those labels, then runs +doctor and uploader dry-run. Adding a service means selecting its ordinary +central-macro target; no committed service map or repository declaration is +added. + ## Multi-service (aggregator, Go-only example) MODULE.bazel: @@ -472,6 +618,7 @@ topt_go.test_optimization_sync( service = "go-service", runtime_name = "go", runtime_version = "1.25.0", + enabled_by_env = True, ) topt_py = use_extension( @@ -480,9 +627,11 @@ topt_py = use_extension( ) topt_py.test_optimization_sync( name = "test_optimization_data_py", - service = "py-service", + enabled_by_env = True, + runtime_module_path = "example.python.pkg", runtime_name = "python", runtime_version = "3.12", + service = "py-service", ) use_repo(topt_go, "test_optimization_data_go") @@ -531,28 +680,19 @@ Doctor/uploader package (multi-service). Simple examples may put these in the root package, but large monorepos should prefer a lightweight package: ```bzl -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = [ - "@test_optimization_data//:test_optimization_context_go_service_a", - "@test_optimization_data//:test_optimization_context_go_service_b", - ], -) - -dd_payload_uploader( - name = "dd_upload_payloads", - data = [ - "@test_optimization_data//:test_optimization_context_go_service_a", - "@test_optimization_data//:test_optimization_context_go_service_b", - ], +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ + "@test_optimization_data//:test_optimization_context_go_service_a", + "@test_optimization_data//:test_optimization_context_go_service_b", + ], ) ``` Mixed-runtime example rule: - keep one sync repo per runtime/service - keep one logical uploader for the workspace; package-local placement is fine -- add every matching context target to uploader `data` +- pass every matching context target through `context_data` - do not use `DD_TEST_OPTIMIZATION_CONTEXT_JSON` as the normal mixed-runtime path diff --git a/examples/common/runtests_common.ps1 b/examples/common/runtests_common.ps1 index 39ea56a7..31983cc3 100644 --- a/examples/common/runtests_common.ps1 +++ b/examples/common/runtests_common.ps1 @@ -17,12 +17,16 @@ function Invoke-RunCmd { ) if ($env:RUNTESTS_DRY_RUN -eq "1") { - Write-Output ("[dry-run] {0} {1}" -f $Command, ($Args -join " ")) + if ($Args -notcontains "--config=test-optimization") { + throw "dry-run command is missing --config=test-optimization: $Command $($Args -join ' ')" + } + Write-Host ("[dry-run] {0} {1}" -f $Command, ($Args -join " ")) return 0 } - & $Command @Args - return $LASTEXITCODE + & $Command @Args | Out-Host + $exitCode = $LASTEXITCODE + return $exitCode } # Handle Get-BazelCommand behavior. @@ -61,22 +65,22 @@ function Invoke-ExampleRunTests { ) Write-Output "--- non-hermetic run" - $rc = Invoke-RunCmd -Command $bazelCmd -Args @("test", "//src/go-project/...", "--test_output=streamed", "--test_arg=-test.v", "--sandbox_debug", "--remote_download_minimal", "--remote_download_regex=.*test[.]outputs.*", "--zip_undeclared_test_outputs", "--build_event_json_file=$nonHermeticBep") + $rc = Invoke-RunCmd -Command $bazelCmd -Args @("test", "--config=test-optimization", "//src/go-project/...", "--test_output=streamed", "--test_arg=-test.v", "--sandbox_debug", "--remote_download_minimal", "--remote_download_regex=.*test[.]outputs.*", "--zip_undeclared_test_outputs", "--build_event_json_file=$nonHermeticBep") if ($rc -ne 0) { $testStatus = $rc } Write-Output "--- hermetic run" - $rc = Invoke-RunCmd -Command $bazelCmd -Args @("test", "//src/go-project/...", "--test_output=streamed", "--test_arg=-test.v", "--sandbox_debug", "--config=hermetic", "--remote_download_minimal", "--remote_download_regex=.*test[.]outputs.*", "--zip_undeclared_test_outputs", "--build_event_json_file=$hermeticBep") + $rc = Invoke-RunCmd -Command $bazelCmd -Args @("test", "--config=test-optimization", "--config=hermetic", "//src/go-project/...", "--test_output=streamed", "--test_arg=-test.v", "--sandbox_debug", "--remote_download_minimal", "--remote_download_regex=.*test[.]outputs.*", "--zip_undeclared_test_outputs", "--build_event_json_file=$hermeticBep") if ($rc -ne 0) { $testStatus = $rc } Write-Output "--- validating payloads" - $doctorStatus = Invoke-RunCmd -Command $bazelCmd -Args (@("run", "//:dd_test_optimization_doctor", "--") + $bepArgs) + $doctorStatus = Invoke-RunCmd -Command $bazelCmd -Args (@("run", "--config=test-optimization", "//:dd_test_optimization_doctor", "--") + $bepArgs) if ($doctorStatus -ne 0) { if ($testStatus -ne 0) { exit $testStatus } exit $doctorStatus } Write-Output "--- validating upload enrichment" - $dryRunStatus = Invoke-RunCmd -Command $bazelCmd -Args (@("run", "//:dd_upload_payloads", "--") + $bepArgs + @("--dry-run", "--validate-enrichment")) + $dryRunStatus = Invoke-RunCmd -Command $bazelCmd -Args (@("run", "--config=test-optimization", "//:dd_upload_payloads", "--") + $bepArgs + @("--dry-run", "--validate-enrichment")) if ($dryRunStatus -ne 0) { if ($testStatus -ne 0) { exit $testStatus } exit $dryRunStatus @@ -84,7 +88,7 @@ function Invoke-ExampleRunTests { Write-Output "--- uploading payloads" if (-not $env:DD_SITE) { $env:DD_SITE = "datadoghq.com" } - $uploadRc = Invoke-RunCmd -Command $bazelCmd -Args (@("run", "//:dd_upload_payloads", "--") + $bepArgs) + $uploadRc = Invoke-RunCmd -Command $bazelCmd -Args (@("run", "--config=test-optimization", "//:dd_upload_payloads", "--") + $bepArgs) if ($testStatus -ne 0) { exit $testStatus } exit $uploadRc diff --git a/examples/common/runtests_common.sh b/examples/common/runtests_common.sh index 6ac130a6..f7a46e1a 100644 --- a/examples/common/runtests_common.sh +++ b/examples/common/runtests_common.sh @@ -41,6 +41,18 @@ run_example_runtests() { # Handle run cmd behavior. run_cmd() { if [[ "${RUNTESTS_DRY_RUN:-0}" == "1" ]]; then + local arg + local has_test_optimization_config=0 + for arg in "$@"; do + if [[ "$arg" == "--config=test-optimization" ]]; then + has_test_optimization_config=1 + break + fi + done + if [[ "$has_test_optimization_config" -ne 1 ]]; then + echo "error: dry-run command is missing --config=test-optimization: $*" >&2 + return 1 + fi echo "[dry-run] $*" return 0 fi @@ -48,13 +60,13 @@ run_example_runtests() { } echo "--- non-hermetic run" - run_cmd "${bazelw}" test //src/go-project/... --test_output=streamed --test_arg=-test.v --sandbox_debug --remote_download_minimal --remote_download_regex=.*test[.]outputs.* --zip_undeclared_test_outputs --build_event_json_file="$non_hermetic_bep" || test_status=$? + run_cmd "${bazelw}" test --config=test-optimization //src/go-project/... --test_output=streamed --test_arg=-test.v --sandbox_debug --remote_download_minimal --remote_download_regex=.*test[.]outputs.* --zip_undeclared_test_outputs --build_event_json_file="$non_hermetic_bep" || test_status=$? echo "--- hermetic run" - run_cmd "${bazelw}" test //src/go-project/... --test_output=streamed --test_arg=-test.v --sandbox_debug --config=hermetic --remote_download_minimal --remote_download_regex=.*test[.]outputs.* --zip_undeclared_test_outputs --build_event_json_file="$hermetic_bep" || test_status=$? + run_cmd "${bazelw}" test --config=test-optimization --config=hermetic //src/go-project/... --test_output=streamed --test_arg=-test.v --sandbox_debug --remote_download_minimal --remote_download_regex=.*test[.]outputs.* --zip_undeclared_test_outputs --build_event_json_file="$hermetic_bep" || test_status=$? echo "--- validating payloads" - run_cmd "${bazelw}" run //:dd_test_optimization_doctor -- "${bep_args[@]}" || doctor_status=$? + run_cmd "${bazelw}" run --config=test-optimization //:dd_test_optimization_doctor -- "${bep_args[@]}" || doctor_status=$? if [[ "$doctor_status" -ne 0 ]]; then if [[ "$test_status" -ne 0 ]]; then return "$test_status" @@ -63,7 +75,7 @@ run_example_runtests() { fi echo "--- validating upload enrichment" - run_cmd "${bazelw}" run //:dd_upload_payloads -- "${bep_args[@]}" --dry-run --validate-enrichment || dry_run_status=$? + run_cmd "${bazelw}" run --config=test-optimization //:dd_upload_payloads -- "${bep_args[@]}" --dry-run --validate-enrichment || dry_run_status=$? if [[ "$dry_run_status" -ne 0 ]]; then if [[ "$test_status" -ne 0 ]]; then return "$test_status" @@ -73,7 +85,7 @@ run_example_runtests() { echo "--- uploading payloads" # Requires DD_API_KEY and DD_SITE environment variables. - DD_API_KEY="${DD_API_KEY:-}" DD_SITE="${DD_SITE:-datadoghq.com}" run_cmd "${bazelw}" run //:dd_upload_payloads -- "${bep_args[@]}" || upload_status=$? + DD_API_KEY="${DD_API_KEY:-}" DD_SITE="${DD_SITE:-datadoghq.com}" run_cmd "${bazelw}" run --config=test-optimization //:dd_upload_payloads -- "${bep_args[@]}" || upload_status=$? if [[ "$test_status" -ne 0 ]]; then return "$test_status" diff --git a/examples/multi_service/.bazelrc b/examples/multi_service/.bazelrc index 4a6123d2..3203f0ef 100644 --- a/examples/multi_service/.bazelrc +++ b/examples/multi_service/.bazelrc @@ -1,6 +1,10 @@ # Required on Windows for dd_topt_java_test: -javaagent paths only resolve under symlinked runfiles. build --enable_runfiles +# One user-facing switch for Go/Python metadata bootstrap and Go Orchestrion analysis. +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true + # Hermetic config (sandbox, stable env, network blocking) build:hermetic --incompatible_strict_action_env build:hermetic --spawn_strategy=sandboxed @@ -14,4 +18,3 @@ test:hermetic --test_env=LC_ALL=C # Uncomment and provide values via shell/CI secret store: # common --repo_env=DD_API_KEY # common --repo_env=DD_SITE - diff --git a/examples/multi_service/BUILD.bazel b/examples/multi_service/BUILD.bazel index 62600767..e93fed1c 100644 --- a/examples/multi_service/BUILD.bazel +++ b/examples/multi_service/BUILD.bazel @@ -4,21 +4,12 @@ # This product includes software developed at Datadog # (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") # ONE doctor and ONE uploader target per workspace. -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = [ - "@test_optimization_data//:test_optimization_context_go_service_a", - "@test_optimization_data//:test_optimization_context_go_service_b", - ], -) - -dd_payload_uploader( - name = "dd_upload_payloads", - data = [ +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ "@test_optimization_data//:test_optimization_context_go_service_a", "@test_optimization_data//:test_optimization_context_go_service_b", ], diff --git a/examples/single_service/.bazelrc b/examples/single_service/.bazelrc index 4a6123d2..3203f0ef 100644 --- a/examples/single_service/.bazelrc +++ b/examples/single_service/.bazelrc @@ -1,6 +1,10 @@ # Required on Windows for dd_topt_java_test: -javaagent paths only resolve under symlinked runfiles. build --enable_runfiles +# One user-facing switch for Go/Python metadata bootstrap and Go Orchestrion analysis. +common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1 +build:test-optimization --@rules_go//go/private/orchestrion:enabled=true + # Hermetic config (sandbox, stable env, network blocking) build:hermetic --incompatible_strict_action_env build:hermetic --spawn_strategy=sandboxed @@ -14,4 +18,3 @@ test:hermetic --test_env=LC_ALL=C # Uncomment and provide values via shell/CI secret store: # common --repo_env=DD_API_KEY # common --repo_env=DD_SITE - diff --git a/examples/single_service/BUILD.bazel b/examples/single_service/BUILD.bazel index 0e135c5a..e3d9eeef 100644 --- a/examples/single_service/BUILD.bazel +++ b/examples/single_service/BUILD.bazel @@ -4,16 +4,17 @@ # This product includes software developed at Datadog # (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. -load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor") -load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader") +load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets") # ONE doctor and ONE uploader target per workspace. -dd_test_optimization_doctor( - name = "dd_test_optimization_doctor", - data = ["@test_optimization_data//:test_optimization_context"], -) - -dd_payload_uploader( - name = "dd_upload_payloads", - data = ["@test_optimization_data//:test_optimization_context"], +dd_test_optimization_targets( + name = "test_optimization", + context_data = [ + "@test_optimization_data_go//:test_optimization_context", + "@test_optimization_data_python//:test_optimization_context", + "@test_optimization_data_java//:test_optimization_context", + "@test_optimization_data_nodejs//:test_optimization_context", + "@test_optimization_data_dotnet//:test_optimization_context", + "@test_optimization_data_ruby//:test_optimization_context", + ], ) diff --git a/examples/single_service/MODULE.bazel b/examples/single_service/MODULE.bazel index abc71021..25831de8 100644 --- a/examples/single_service/MODULE.bazel +++ b/examples/single_service/MODULE.bazel @@ -21,7 +21,11 @@ bazel_dep(name = "datadog-rules-test-optimization-dotnet", version = "1.2.0") bazel_dep(name = "datadog-rules-test-optimization-ruby", version = "1.2.0") # Run: -# bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap +# bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \ +# --guided \ +# --service go-service \ +# --runtime-version 1.25.0 \ +# --sync-repo-name test_optimization_data_go # after adding your Go module files to let Datadog pin Orchestrion and patch # the managed rules_go override block required by dd_topt_go_test. @@ -107,11 +111,61 @@ go_topt = use_extension( "test_optimization_go_extension", ) go_topt.test_optimization_go( - name = "test_optimization_data", + name = "test_optimization_data_go", debug = True, + module_path = "example.com/single-service-go-project", runtime_version = "1.25.0", - # Logical service identifier for Datadog metadata (not language-bound). - # A single service can include tests from multiple runtimes. service = "go-service", ) -use_repo(go_topt, "test_optimization_data") +use_repo(go_topt, "test_optimization_data_go") + +# Mixed-runtime workspaces use one sync repository per runtime. This keeps each +# macro's exported runtime metadata and payload-selection groups aligned. +runtime_topt = use_extension( + "@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", + "test_optimization_sync_extension", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_python", + enabled_by_env = True, + runtime_module_path = "example.python.project", + runtime_name = "python", + runtime_version = "3.12", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_java", + runtime_module_path = "com.example.topt", + runtime_name = "java", + runtime_version = "21", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_nodejs", + runtime_module_path = "example/nodejs/project", + runtime_name = "nodejs", + runtime_version = "22.22.0", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_dotnet", + runtime_module_path = "Company.Product.Example", + runtime_name = "dotnet", + runtime_version = "8.0", + service = "go-service", +) +runtime_topt.test_optimization_sync( + name = "test_optimization_data_ruby", + runtime_module_path = "apps/ruby/example", + runtime_name = "ruby", + runtime_version = "3.3.9", + service = "go-service", +) +use_repo( + runtime_topt, + "test_optimization_data_dotnet", + "test_optimization_data_java", + "test_optimization_data_nodejs", + "test_optimization_data_python", + "test_optimization_data_ruby", +) diff --git a/examples/single_service/src/dotnet-project/BUILD.bazel b/examples/single_service/src/dotnet-project/BUILD.bazel index 16dbd19c..68f7e813 100644 --- a/examples/single_service/src/dotnet-project/BUILD.bazel +++ b/examples/single_service/src/dotnet-project/BUILD.bazel @@ -5,7 +5,7 @@ # (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. load("@datadog-rules-test-optimization-dotnet//:topt_dotnet_test.bzl", "dd_topt_dotnet_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_dotnet//:export.bzl", "topt_data") load(":dotnet_test_adapter.bzl", "dotnet_csharp_test_adapter") dd_topt_dotnet_test( diff --git a/examples/single_service/src/go-project/BUILD.bazel b/examples/single_service/src/go-project/BUILD.bazel index f69c4f9d..eae57b70 100644 --- a/examples/single_service/src/go-project/BUILD.bazel +++ b/examples/single_service/src/go-project/BUILD.bazel @@ -6,7 +6,7 @@ load("@rules_go//go:def.bzl", "go_binary", "go_library") load("@datadog-rules-test-optimization-go//:topt_go_test.bzl", "dd_topt_go_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_go//:export.bzl", "topt_data") go_binary( name = "hello", diff --git a/examples/single_service/src/java-project/BUILD.bazel b/examples/single_service/src/java-project/BUILD.bazel index 0b02ff11..3bd7247a 100644 --- a/examples/single_service/src/java-project/BUILD.bazel +++ b/examples/single_service/src/java-project/BUILD.bazel @@ -5,7 +5,7 @@ # (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. load("@datadog-rules-test-optimization-java//:topt_java_test.bzl", "dd_topt_java_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_java//:export.bzl", "topt_data") java_library( name = "hello_lib", diff --git a/examples/single_service/src/nodejs-project/BUILD.bazel b/examples/single_service/src/nodejs-project/BUILD.bazel index 3263e954..d794ea43 100644 --- a/examples/single_service/src/nodejs-project/BUILD.bazel +++ b/examples/single_service/src/nodejs-project/BUILD.bazel @@ -6,7 +6,7 @@ load("@aspect_rules_js//js:defs.bzl", "js_test") load("@datadog-rules-test-optimization-nodejs//:topt_nodejs_test.bzl", "dd_topt_nodejs_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_nodejs//:export.bzl", "topt_data") dd_topt_nodejs_test( name = "hello_test", diff --git a/examples/single_service/src/python-project/BUILD.bazel b/examples/single_service/src/python-project/BUILD.bazel index 49a32aa4..89b412be 100644 --- a/examples/single_service/src/python-project/BUILD.bazel +++ b/examples/single_service/src/python-project/BUILD.bazel @@ -6,7 +6,9 @@ load("@datadog-rules-test-optimization-python//:topt_py_test.bzl", "dd_topt_py_test") load("@example_pip//:requirements.bzl", "requirement") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_python//:export.bzl", "topt_data") + +_TEST_OPTIMIZATION_EXPECTED = "1" if topt_data.get("enabled", True) else "0" exports_files( [ @@ -25,6 +27,7 @@ py_library( dd_topt_py_test( name = "hello_test", srcs = ["main_test.py"], + env = {"EXAMPLE_EXPECT_TEST_OPTIMIZATION": _TEST_OPTIMIZATION_EXPECTED}, imports = ["example/python/project"], main = "main_test.py", py_test_rule = py_test, @@ -38,6 +41,7 @@ dd_topt_py_test( dd_topt_py_test( name = "hello_pytest_test", srcs = ["pytest_test.py"], + env = {"EXAMPLE_EXPECT_TEST_OPTIMIZATION": _TEST_OPTIMIZATION_EXPECTED}, target_compatible_with = select({ "@platforms//os:windows": ["@platforms//:incompatible"], "//conditions:default": [], diff --git a/examples/single_service/src/python-project/main_test.py b/examples/single_service/src/python-project/main_test.py index 714e8160..c77dd54a 100644 --- a/examples/single_service/src/python-project/main_test.py +++ b/examples/single_service/src/python-project/main_test.py @@ -61,8 +61,13 @@ def test_greeting(self): module = _load_main_module() self.assertEqual("Hello from Python!", module.get_greeting()) - def test_manifest_metadata_files_present(self): + def test_manifest_metadata_contract(self): + expected = os.getenv("EXAMPLE_EXPECT_TEST_OPTIMIZATION", "1") == "1" manifest_rloc = os.getenv("DD_TEST_OPTIMIZATION_MANIFEST_FILE", "") + if not expected: + self.assertFalse(manifest_rloc, "disabled tests must not receive Test Optimization metadata") + return + self.assertTrue(manifest_rloc, "DD_TEST_OPTIMIZATION_MANIFEST_FILE should be set by dd_topt_py_test") manifest_path = _resolve_runfile(manifest_rloc) diff --git a/examples/single_service/src/python-project/pytest_test.py b/examples/single_service/src/python-project/pytest_test.py index d8bf67d3..f3badcfd 100644 --- a/examples/single_service/src/python-project/pytest_test.py +++ b/examples/single_service/src/python-project/pytest_test.py @@ -64,13 +64,13 @@ def test_greeting(): assert module.get_greeting() == "Hello from Python!" -def test_manifest_env_set(): +def test_manifest_env_contract(): + expected = os.getenv("EXAMPLE_EXPECT_TEST_OPTIMIZATION", "1") == "1" manifest_rloc = os.getenv("DD_TEST_OPTIMIZATION_MANIFEST_FILE", "") - assert manifest_rloc, "DD_TEST_OPTIMIZATION_MANIFEST_FILE should be set by dd_topt_py_test" - + if not expected: + assert not manifest_rloc, "disabled tests must not receive Test Optimization metadata" + return -def test_manifest_metadata_files_present(): - manifest_rloc = os.getenv("DD_TEST_OPTIMIZATION_MANIFEST_FILE", "") assert manifest_rloc, "DD_TEST_OPTIMIZATION_MANIFEST_FILE should be set by dd_topt_py_test" manifest_path = _resolve_runfile(manifest_rloc) diff --git a/examples/single_service/src/ruby-project/BUILD.bazel b/examples/single_service/src/ruby-project/BUILD.bazel index f88c87d3..416d9245 100644 --- a/examples/single_service/src/ruby-project/BUILD.bazel +++ b/examples/single_service/src/ruby-project/BUILD.bazel @@ -6,7 +6,7 @@ load("@datadog-rules-test-optimization-ruby//:topt_ruby_test.bzl", "dd_topt_ruby_test") load("@rules_ruby//ruby:defs.bzl", "rb_test") -load("@test_optimization_data//:export.bzl", "topt_data") +load("@test_optimization_data_ruby//:export.bzl", "topt_data") dd_topt_ruby_test( name = "hello_test", diff --git a/modules/dotnet/MODULE.bazel.lock b/modules/dotnet/MODULE.bazel.lock index 2dd9dae1..34afb0ca 100644 --- a/modules/dotnet/MODULE.bazel.lock +++ b/modules/dotnet/MODULE.bazel.lock @@ -140,8 +140,8 @@ "moduleExtensions": { "//tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "zC3aEdxLSUhPV6iwgCNk7hQr+1eO+rAQ5znCfGieX3g=", - "usagesDigest": "8+UVmqdhqtmEmW3r9vMffABIBlZnL2Mwd3je/6nAzu8=", + "bzlTransitiveDigest": "8Z0dqG8n5A2E4sAbWxvij+vncAodaOVqDuvzF/sm6wE=", + "usagesDigest": "wLZKZW3et9AZB9PdsRyNX8IC9uzvvBMQbjMnvx8yB2s=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/modules/go/BUILD.bazel b/modules/go/BUILD.bazel index 9e2e73b8..d736d37e 100644 --- a/modules/go/BUILD.bazel +++ b/modules/go/BUILD.bazel @@ -11,6 +11,8 @@ exports_files( "topt_go_test.bzl", "topt_go_infer.bzl", "topt_go_extension.bzl", + "topt_go_orchestrion_repository.bzl", + "topt_go_workspace.bzl", ], visibility = ["//visibility:public"], ) diff --git a/modules/go/MODULE.bazel.lock b/modules/go/MODULE.bazel.lock index 1d6ef91c..a122ea2f 100644 --- a/modules/go/MODULE.bazel.lock +++ b/modules/go/MODULE.bazel.lock @@ -148,7 +148,7 @@ "moduleExtensions": { "//tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "pLQ+JPOKAu2+EI916bm9tEvq/JkYkgWy+BM9tmAwBUY=", + "bzlTransitiveDigest": "PoT1vHfLILb9IHzanYU8Hjy3Lc2nLwTn2trTYqR3g/E=", "usagesDigest": "yco8+ejjp1y3GIF8UGLO928CMMuVMZAHdJKNqhZnoJo=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -157,6 +157,7 @@ "test_optimization_data": { "repoRuleId": "@@datadog-rules-test-optimization+//tools/tests:example_stub_repo.bzl%example_stub_repo", "attributes": { + "enabled": true, "go_module_included": false, "go_module_path": "example.com/stub", "go_sanitized_module_path": "example_com_stub", @@ -299,7 +300,7 @@ }, "@@rules_go+//go:extensions.bzl%orchestrion": { "general": { - "bzlTransitiveDigest": "cc8H+PwBLCld2fFbU/CAnDmFXupfV/Qj6+XdbJE98/k=", + "bzlTransitiveDigest": "A6ikJiKlwEi5hRrfBqTTwMADTITgDCpH46mkFqp1Avc=", "usagesDigest": "9kKEG/hjK4fnk42l4jAKDLhx9xExyCYAS8r8NlbPLMw=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, diff --git a/modules/go/tests/BUILD.bazel b/modules/go/tests/BUILD.bazel index 3076e960..acec191c 100644 --- a/modules/go/tests/BUILD.bazel +++ b/modules/go/tests/BUILD.bazel @@ -4,12 +4,23 @@ # This product includes software developed at Datadog # (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. +load( + ":test_extension.bzl", + "go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test", + "go_single_spec_propagates_non_default_enablement_and_flaky_tests_test", + "go_specs_default_to_config_gated_test", +) load( ":test_macro.bzl", "go_macro_ci_visibility_opt_out_target", "go_macro_ci_visibility_opt_out_wiring_test", "go_macro_default_general_public_wrapper_mode_target", "go_macro_default_general_public_wrapper_mode_test", + "go_macro_disabled_raw_target", + "go_macro_disabled_raw_wiring_test", + "go_macro_dynamic_manifest_payloads_test", + "go_macro_dynamic_manifest_target", + "go_macro_dynamic_manifest_wiring_test", "go_macro_env_none_target", "go_macro_env_none_wiring_test", "go_macro_explicit_service_target", @@ -18,6 +29,8 @@ load( "go_macro_general_mode_linker_flags_wiring_test", "go_macro_multi_service_target", "go_macro_multi_service_wiring_test", + "go_macro_orchestrion_enablement_mismatch_failure_test", + "go_macro_orchestrion_enablement_mismatch_target", "go_macro_orchestrion_pin_files_provider_test", "go_macro_orchestrion_pin_files_target", "go_macro_orchestrion_pin_files_wiring_test", @@ -78,6 +91,7 @@ load( "selector_empty_importpath_fallback_test", "selector_explicit_miss_failure_target", "selector_explicit_miss_failure_test", + "selector_explicit_namespaced_test", "selector_explicit_precedence_target", "selector_explicit_precedence_test", "selector_fallback_target", @@ -114,6 +128,14 @@ load( "select_module_group_name_test", "service_mapping_entries_filters_non_service_test", ) +load( + ":test_workspace_helpers.bzl", + "go_workspace_multi_specs_test", + "go_workspace_single_specs_test", + "go_workspace_specs_default_to_config_gated_test", + "orchestrion_call_spec_test", + "orchestrion_pin_file_call_spec_test", +) # Go-specific Starlark tests for orchestration selection and macro wiring. service_mapping_entries_filters_non_service_test( @@ -122,6 +144,65 @@ service_mapping_entries_filters_non_service_test( timeout = "short", ) +go_single_spec_propagates_non_default_enablement_and_flaky_tests_test( + name = "go_single_spec_propagates_non_default_enablement_and_flaky_tests_test", + size = "small", + timeout = "short", +) + +go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test( + name = "go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test", + size = "small", + timeout = "short", +) + +go_specs_default_to_config_gated_test( + name = "go_specs_default_to_config_gated_test", + size = "small", + timeout = "short", +) + +go_workspace_single_specs_test( + name = "go_workspace_single_specs_test", + size = "small", + timeout = "short", +) + +go_workspace_multi_specs_test( + name = "go_workspace_multi_specs_test", + size = "small", + timeout = "short", +) + +go_workspace_specs_default_to_config_gated_test( + name = "go_workspace_specs_default_to_config_gated_test", + size = "small", + timeout = "short", +) + +orchestrion_call_spec_test( + name = "orchestrion_call_spec_test", + size = "small", + timeout = "short", +) + +orchestrion_pin_file_call_spec_test( + name = "orchestrion_pin_file_call_spec_test", + size = "small", + timeout = "short", +) + +test_suite( + name = "workspace_helpers_tests", + tests = [ + ":go_workspace_multi_specs_test", + ":go_workspace_single_specs_test", + ":go_workspace_specs_default_to_config_gated_test", + ":orchestrion_call_spec_test", + ":orchestrion_pin_file_call_spec_test", + ], +) + resolve_topt_service_key_prefers_exact_then_sanitized_test( name = "resolve_topt_service_key_prefers_exact_then_sanitized_test", size = "small", @@ -190,6 +271,18 @@ selector_explicit_precedence_test( target_under_test = ":selector_explicit_precedence_target", ) +selector_explicit_precedence_target( + name = "selector_explicit_namespaced_target", + module_group_names = ["module_example_com_explicit_pkg"], + module_groups = [":module_manifest_context_example_com_explicit_pkg"], + tags = ["manual"], +) + +selector_explicit_namespaced_test( + name = "selector_explicit_namespaced_test", + target_under_test = ":selector_explicit_namespaced_target", +) + selector_embed_precedence_target( name = "selector_embed_precedence_target", tags = ["manual"], @@ -288,6 +381,16 @@ go_macro_single_service_target( tags = ["manual"], ) +go_macro_disabled_raw_target( + name = "go_macro_disabled_raw_target", + tags = ["manual"], +) + +go_macro_disabled_raw_wiring_test( + name = "go_macro_disabled_raw_wiring_test", + target_under_test = ":go_macro_disabled_raw_target", +) + go_macro_single_service_wiring_test( name = "go_macro_single_service_wiring_test", target_under_test = ":go_macro_single_service_target__raw_go_test", @@ -308,6 +411,21 @@ go_macro_multi_service_wiring_test( target_under_test = ":go_macro_multi_service_target__raw_go_test", ) +go_macro_dynamic_manifest_target( + name = "go_macro_dynamic_manifest_target", + tags = ["manual"], +) + +go_macro_dynamic_manifest_wiring_test( + name = "go_macro_dynamic_manifest_wiring_test", + target_under_test = ":go_macro_dynamic_manifest_target__raw_go_test", +) + +go_macro_dynamic_manifest_payloads_test( + name = "go_macro_dynamic_manifest_payloads_test", + target_under_test = ":go_macro_dynamic_manifest_target_topt_payloads", +) + go_macro_rundir_mismatch_target( name = "go_macro_rundir_mismatch_target", tags = ["manual"], @@ -568,6 +686,16 @@ validate_test_optimization_pin_files_missing_go_mod_failure_test( target_under_test = ":validate_test_optimization_pin_files_missing_go_mod_target", ) +go_macro_orchestrion_enablement_mismatch_target( + name = "go_macro_orchestrion_enablement_mismatch_target", + tags = ["manual"], +) + +go_macro_orchestrion_enablement_mismatch_failure_test( + name = "go_macro_orchestrion_enablement_mismatch_failure_test", + target_under_test = ":go_macro_orchestrion_enablement_mismatch_target", +) + wrapper_output_name_target_rule( name = "wrapper_output_name_non_windows_target", executable_basename = "hello_test__raw_go_test", @@ -652,9 +780,13 @@ test_suite( ":build_module_labels_valid_test", ":go_macro_ci_visibility_opt_out_wiring_test", ":go_macro_default_general_public_wrapper_mode_test", + ":go_macro_disabled_raw_wiring_test", + ":go_macro_dynamic_manifest_payloads_test", + ":go_macro_dynamic_manifest_wiring_test", ":go_macro_env_none_wiring_test", ":go_macro_explicit_service_wiring_test", ":go_macro_multi_service_wiring_test", + ":go_macro_orchestrion_enablement_mismatch_failure_test", ":go_macro_orchestrion_pin_files_provider_test", ":go_macro_orchestrion_pin_files_wiring_test", ":go_macro_public_wrapper_test", @@ -673,7 +805,12 @@ test_suite( ":go_macro_test_optimization_linker_opt_out_wiring_test", ":go_macro_test_optimization_mode_wiring_test", ":go_macro_test_optimization_public_wrapper_mode_test", + ":go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test", + ":go_single_spec_propagates_non_default_enablement_and_flaky_tests_test", + ":go_specs_default_to_config_gated_test", ":go_stub_includes_manifest_in_files_test", + ":go_workspace_multi_specs_test", + ":go_workspace_single_specs_test", ":has_go_mod_pin_test", ":has_package_local_go_mod_test", ":normalize_user_data_handles_none_test", @@ -681,6 +818,7 @@ test_suite( ":orch_transition_forwards_mode_test", ":orch_wrapper_materialized_actual_non_windows_test", ":orch_wrapper_materialized_actual_windows_test", + ":orchestrion_call_spec_test", ":orchestrion_metadata_enabled_test", ":resolve_topt_service_key_missing_failure_test", ":resolve_topt_service_key_prefers_exact_then_sanitized_test", @@ -690,6 +828,7 @@ test_suite( ":selector_embed_precedence_test", ":selector_empty_importpath_fallback_test", ":selector_explicit_miss_failure_test", + ":selector_explicit_namespaced_test", ":selector_explicit_precedence_test", ":selector_fallback_test", ":selector_include_disabled_test", @@ -702,6 +841,7 @@ test_suite( ":validate_orchestrion_mode_test", ":validate_test_optimization_pin_files_missing_go_mod_failure_test", ":windows_wrapper_uses_file_payload_mode_test", + ":workspace_helpers_tests", ":wrapper_output_name_non_windows_test", ":wrapper_output_name_windows_test", ], diff --git a/modules/go/tests/test_extension.bzl b/modules/go/tests/test_extension.bzl new file mode 100644 index 00000000..607fdd64 --- /dev/null +++ b/modules/go/tests/test_extension.bzl @@ -0,0 +1,75 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under +# the Apache 2.0 License. +# +# This product includes software developed at Datadog +# (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. + +"""Unit tests for the Go Bzlmod extension sync-spec builders.""" + +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load( + "@datadog-rules-test-optimization-go//:topt_go_extension.bzl", + "build_go_multi_repo_specs_for_tests", + "build_go_single_repo_spec_for_tests", +) + +def _go_single_spec_propagates_non_default_enablement_and_flaky_tests_test(ctx): + env = unittest.begin(ctx) + spec = build_go_single_repo_spec_for_tests( + name = "test_optimization_data_go", + service = "go-service", + module_path = "example.com/repo", + runtime_version = "1.25.9", + enabled = False, + enabled_by_env = False, + flaky_tests = False, + ) + asserts.equals(env, False, spec["enabled"]) + asserts.equals(env, False, spec["enabled_by_env"]) + asserts.equals(env, False, spec["flaky_tests"]) + asserts.equals(env, "go", spec["runtime_name"]) + return unittest.end(env) + +def _go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test(ctx): + env = unittest.begin(ctx) + specs = build_go_multi_repo_specs_for_tests( + name = "test_optimization_data_go", + services = ["go-service-a"], + module_path = "example.com/repo", + runtime_version = "1.25.9", + enabled = False, + enabled_by_env = False, + flaky_tests = False, + ) + asserts.equals(env, 1, len(specs)) + asserts.equals(env, False, specs[0]["enabled"]) + asserts.equals(env, False, specs[0]["enabled_by_env"]) + asserts.equals(env, False, specs[0]["flaky_tests"]) + asserts.equals(env, "go", specs[0]["runtime_name"]) + return unittest.end(env) + +def _go_specs_default_to_config_gated_test(ctx): + env = unittest.begin(ctx) + single = build_go_single_repo_spec_for_tests( + name = "test_optimization_data_go", + service = "go-service", + ) + multi = build_go_multi_repo_specs_for_tests( + name = "test_optimization_data_go", + services = ["go-service"], + ) + asserts.equals(env, True, single["enabled_by_env"]) + asserts.equals(env, True, multi[0]["enabled_by_env"]) + return unittest.end(env) + +go_single_spec_propagates_non_default_enablement_and_flaky_tests_test = unittest.make( + _go_single_spec_propagates_non_default_enablement_and_flaky_tests_test, +) + +go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test = unittest.make( + _go_multi_specs_propagate_non_default_enablement_and_flaky_tests_test, +) + +go_specs_default_to_config_gated_test = unittest.make( + _go_specs_default_to_config_gated_test, +) diff --git a/modules/go/tests/test_macro.bzl b/modules/go/tests/test_macro.bzl index 7d90955f..5ba12a78 100644 --- a/modules/go/tests/test_macro.bzl +++ b/modules/go/tests/test_macro.bzl @@ -39,6 +39,8 @@ load( ) load("@rules_go//go/private/orchestrion:pin_files.bzl", "OrchestrionPinFilesInfo") +_ORCHESTRION_ENABLED_SETTING = str(Label("@rules_go//go/private/orchestrion:enabled")) + ToptGoMacroCaptureInfo = provider( doc = "Captured arguments forwarded by dd_topt_go_test to the underlying go_test rule.", fields = { @@ -162,6 +164,13 @@ fake_executable_rule = rule( executable = True, ) +def _fake_metadata_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(out, "{}\n") + return [DefaultInfo(files = depset([out]))] + +fake_metadata_rule = rule(implementation = _fake_metadata_impl) + def _wrapper_output_name_target_impl(ctx): return [WrapperOutputNameInfo( output_name = select_wrapper_output_name_for_tests( @@ -180,8 +189,9 @@ wrapper_output_name_target_rule = rule( }, ) -def _single_service_topt_data(): +def _single_service_topt_data(enabled = True): return { + "enabled": enabled, "repo_name": "test_optimization_data", "service_name": "go-service", "manifest_path": ".testoptimization/manifest.txt", @@ -207,6 +217,20 @@ def _multi_service_topt_data(): "_meta": {"description": "non-service entry should be ignored"}, } +def _dynamic_manifest_topt_data(): + """Model one target entry exported by the manifest aggregate repository.""" + data = _single_service_topt_data() + data.update({ + "repo_name": "virtual_dynamic_repo_that_must_not_resolve", + "service_name": "dynamic-go-service", + "files_label": ":full_payload", + "manifest_label": ":test_macro.bzl", + "module_labels": [":module_example_com_explicit_pkg"], + "labels": ["ignored_static_label_that_must_not_resolve"], + "manifest_path": "ignored/static/manifest.txt", + }) + return data + def go_macro_single_service_target(name, tags = None): """Target-under-test: single-service wiring + default rundir path.""" dd_topt_go_test( @@ -222,6 +246,30 @@ def go_macro_single_service_target(name, tags = None): tags = tags, ) +def go_macro_dynamic_manifest_target(name, tags = None): + """Target under test for explicit labels from one dynamic manifest entry.""" + dd_topt_go_test( + name = name, + topt_data = _dynamic_manifest_topt_data(), + go_test_rule = _go_test_capture_rule, + importpath = "example.com/explicit/pkg", + tags = tags, + ) + +def go_macro_disabled_raw_target(name, tags = None): + """Target under test for the strict disabled raw go_test branch.""" + dd_topt_go_test( + name = name, + topt_data = _single_service_topt_data(enabled = False), + go_test_rule = _go_test_capture_rule, + data = [":test_macro.bzl"], + env = {"CUSTOM_ENV": "disabled"}, + gc_linkopts = ["-disabled-link-flag"], + importpath = "example.com/disabled/pkg", + rundir = "disabled/rundir", + tags = tags, + ) + def go_macro_multi_service_target(name, tags = None): """Target-under-test: sanitized service-key selection wiring.""" dd_topt_go_test( @@ -429,9 +477,14 @@ def orch_wrapper_materialized_actual_non_windows_target(name, tags = None): executable_name = "hello_test__raw_go_test", tags = ["manual"], ) + fake_metadata_rule( + name = name + "_metadata", + tags = ["manual"], + ) orch_go_test( name = name, actual = ":" + name + "_actual", + metadata = ":" + name + "_metadata", tags = tags, ) @@ -443,9 +496,23 @@ def orch_wrapper_materialized_actual_windows_target(name, tags = None): is_windows = True, tags = ["manual"], ) + fake_metadata_rule( + name = name + "_metadata", + tags = ["manual"], + ) orch_go_test( name = name, actual = ":" + name + "_actual", + metadata = ":" + name + "_metadata", + tags = tags, + ) + +def go_macro_orchestrion_enablement_mismatch_target(name, tags = None): + """Target under test for an incomplete config-gated Go upgrade.""" + dd_topt_go_test( + name = name, + topt_data = _single_service_topt_data(enabled = True), + go_test_rule = _go_test_capture_rule, tags = tags, ) @@ -482,6 +549,20 @@ def _go_macro_single_service_wiring_test_impl(ctx): asserts.true(env, captured.rundir.endswith("tests")) return analysistest.end(env) +def _go_macro_disabled_raw_wiring_test_impl(ctx): + """Assert disabled metadata forwards caller kwargs to one raw public test.""" + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + captured = target[ToptGoMacroCaptureInfo] + + asserts.equals(env, 1, len(captured.data_labels)) + asserts.true(env, _has_label_suffix(captured.data_labels, ":test_macro.bzl")) + asserts.equals(env, {"CUSTOM_ENV": "disabled"}, captured.env) + asserts.equals(env, ["-disabled-link-flag"], captured.gc_linkopts) + asserts.equals(env, "example.com/disabled/pkg", captured.importpath) + asserts.equals(env, "disabled/rundir", captured.rundir) + return analysistest.end(env) + def _go_macro_multi_service_wiring_test_impl(ctx): """Assert multi-service key resolution and passthrough attributes.""" env = analysistest.begin(ctx) @@ -502,6 +583,25 @@ def _go_macro_multi_service_wiring_test_impl(ctx): asserts.true(env, captured.rundir.endswith("tests")) return analysistest.end(env) +def _go_macro_dynamic_manifest_wiring_test_impl(ctx): + """Assert dynamic target entries avoid virtual-repository label fallback.""" + env = analysistest.begin(ctx) + captured = analysistest.target_under_test(env)[ToptGoMacroCaptureInfo] + asserts.true(env, _has_label_suffix(captured.data_labels, ":go_macro_dynamic_manifest_target_topt_payloads")) + asserts.true(env, _has_label_suffix(captured.data_labels, ":test_macro.bzl")) + asserts.false(env, _has_fragment(captured.data_labels, "virtual_dynamic_repo_that_must_not_resolve")) + asserts.equals(env, "dynamic-go-service", captured.env.get("DD_SERVICE")) + return analysistest.end(env) + +def _go_macro_dynamic_manifest_payloads_test_impl(ctx): + """Assert only the selected explicit module files reach the selector.""" + env = analysistest.begin(ctx) + files = analysistest.target_under_test(env)[DefaultInfo].files.to_list() + asserts.equals(env, 1, len(files)) + asserts.true(env, _has_file_basename(files, "module_example_com_explicit_pkg.payload")) + asserts.false(env, _has_file_basename(files, "full_payload.payload")) + return analysistest.end(env) + def _go_macro_rundir_mismatch_wiring_test_impl(ctx): """Assert custom rundir is honored when explicitly provided.""" env = analysistest.begin(ctx) @@ -699,9 +799,14 @@ def _go_macro_public_wrapper_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) files = target[DefaultInfo].files.to_list() - asserts.equals(env, 2, len(files)) + materialized_metadata = ( + "go_macro_single_service_target__wrapped_" + + "go_macro_single_service_target_topt_bazel_metadata.json" + ) + asserts.equals(env, 3, len(files)) asserts.true(env, _has_file_basename(files, "go_macro_single_service_target")) asserts.true(env, _has_file_basename(files, "go_macro_single_service_target__wrapped_go_macro_single_service_target__raw_go_test.sh")) + asserts.true(env, _has_file_basename(files, materialized_metadata)) run_env = target[RunEnvironmentInfo].environment manifest_env = run_env.get("DD_TEST_OPTIMIZATION_MANIFEST_FILE") asserts.true(env, manifest_env != None) @@ -834,6 +939,14 @@ def _validate_test_optimization_pin_files_missing_go_mod_failure_test_impl(ctx): asserts.expect_failure(env, "requires a package-local go.mod or explicit orchestrion_pin_files") return analysistest.end(env) +def _go_macro_orchestrion_enablement_mismatch_failure_test_impl(ctx): + """Assert a partial upgrade fails instead of silently dropping instrumentation.""" + env = analysistest.begin(ctx) + asserts.expect_failure(env, "Test Optimization metadata is enabled but Orchestrion is disabled") + asserts.expect_failure(env, "--config=test-optimization") + asserts.expect_failure(env, "--write-bazelrc") + return analysistest.end(env) + def _wrapper_output_name_non_windows_test_impl(ctx): """Assert non-Windows wrapper names remain extensionless.""" env = analysistest.begin(ctx) @@ -851,9 +964,12 @@ def _wrapper_output_name_windows_test_impl(ctx): def _windows_wrapper_uses_file_payload_mode_test_impl(ctx): """Assert Windows launchers preserve Bazel file mode instead of proxying uploads.""" env = unittest.begin(ctx) - content = windows_wrapper_content_for_tests("raw.exe") + content = windows_wrapper_content_for_tests("raw.exe", "target_metadata.json") asserts.true(env, "bazel_target_metadata.json" in content) + asserts.true(env, '"%SCRIPT_DIR%target_metadata.json"' in content) + asserts.false(env, "META_BASENAME" in content) asserts.true(env, '"%ACTUAL%" %*' in content) + asserts.true(env, "exit /b %ERRORLEVEL%" in content) asserts.false(env, "DD_TRACE_AGENT_URL" in content) asserts.false(env, "DD_CIVISIBILITY_AGENTLESS_ENABLED" in content) asserts.false(env, "DD_CIVISIBILITY_AGENTLESS_URL" in content) @@ -887,43 +1003,65 @@ def _validate_orchestrion_mode_test_impl(ctx): return unittest.end(env) def _orch_transition_forwards_mode_test_impl(ctx): - """Assert the wrapper transition enables Orchestrion and forwards the mode.""" + """Assert the wrapper transition forwards only the Orchestrion mode.""" env = unittest.begin(ctx) result = orch_transition_impl_for_tests(None, struct(orchestrion_mode = "test_optimization")) - asserts.equals(env, True, result["@rules_go//go/private/orchestrion:enabled"]) + asserts.equals(env, 1, len(result)) asserts.equals(env, "test_optimization", result["@rules_go//go/private/orchestrion:mode"]) + asserts.false(env, "@rules_go//go/private/orchestrion:enabled" in result) return unittest.end(env) def _orch_wrapper_materialized_actual_non_windows_test_impl(ctx): - """Assert the wrapper target ships the sibling raw executable.""" + """Assert the wrapper target ships transitioned inputs as siblings.""" env = analysistest.begin(ctx) target = analysistest.target_under_test(env) files = target[DefaultInfo].files.to_list() runfiles = target[DefaultInfo].default_runfiles.files.to_list() - asserts.equals(env, 2, len(files)) + materialized_metadata = ( + "orch_wrapper_materialized_actual_non_windows_target__wrapped_" + + "orch_wrapper_materialized_actual_non_windows_target_metadata.json" + ) + asserts.equals(env, 3, len(files)) asserts.true(env, _has_file_basename(files, "orch_wrapper_materialized_actual_non_windows_target")) asserts.true(env, _has_file_basename(files, "orch_wrapper_materialized_actual_non_windows_target__wrapped_hello_test__raw_go_test")) + asserts.true(env, _has_file_basename(files, materialized_metadata)) asserts.true(env, _has_file_basename(runfiles, "orch_wrapper_materialized_actual_non_windows_target__wrapped_hello_test__raw_go_test")) + asserts.true(env, _has_file_basename(runfiles, materialized_metadata)) return analysistest.end(env) def _orch_wrapper_materialized_actual_windows_test_impl(ctx): - """Assert the Windows wrapper target carries the sibling raw executable.""" + """Assert the Windows wrapper target ships transitioned inputs as siblings.""" env = analysistest.begin(ctx) target = analysistest.target_under_test(env) files = target[DefaultInfo].files.to_list() runfiles = target[DefaultInfo].default_runfiles.files.to_list() - asserts.equals(env, 2, len(files)) + materialized_metadata = ( + "orch_wrapper_materialized_actual_windows_target__wrapped_" + + "orch_wrapper_materialized_actual_windows_target_metadata.json" + ) + asserts.equals(env, 3, len(files)) asserts.true(env, _has_file_basename(files, "orch_wrapper_materialized_actual_windows_target.bat")) asserts.true(env, _has_file_basename(files, "orch_wrapper_materialized_actual_windows_target__wrapped_hello_test__raw_go_test.exe")) + asserts.true(env, _has_file_basename(files, materialized_metadata)) asserts.true(env, _has_file_basename(runfiles, "orch_wrapper_materialized_actual_windows_target__wrapped_hello_test__raw_go_test.exe")) + asserts.true(env, _has_file_basename(runfiles, materialized_metadata)) return analysistest.end(env) go_macro_single_service_wiring_test = analysistest.make( _go_macro_single_service_wiring_test_impl, ) +go_macro_disabled_raw_wiring_test = analysistest.make( + _go_macro_disabled_raw_wiring_test_impl, +) go_macro_multi_service_wiring_test = analysistest.make( _go_macro_multi_service_wiring_test_impl, ) +go_macro_dynamic_manifest_wiring_test = analysistest.make( + _go_macro_dynamic_manifest_wiring_test_impl, +) +go_macro_dynamic_manifest_payloads_test = analysistest.make( + _go_macro_dynamic_manifest_payloads_test_impl, +) go_macro_rundir_mismatch_wiring_test = analysistest.make( _go_macro_rundir_mismatch_wiring_test_impl, ) @@ -995,12 +1133,21 @@ go_macro_explicit_service_wiring_test = analysistest.make( ) go_macro_public_wrapper_test = analysistest.make( _go_macro_public_wrapper_test_impl, + config_settings = { + _ORCHESTRION_ENABLED_SETTING: True, + }, ) go_macro_test_optimization_public_wrapper_mode_test = analysistest.make( _go_macro_test_optimization_public_wrapper_mode_test_impl, + config_settings = { + _ORCHESTRION_ENABLED_SETTING: True, + }, ) go_macro_default_general_public_wrapper_mode_test = analysistest.make( _go_macro_default_general_public_wrapper_mode_test_impl, + config_settings = { + _ORCHESTRION_ENABLED_SETTING: True, + }, ) resolve_topt_service_key_missing_failure_test = analysistest.make( _resolve_topt_service_key_missing_failure_test_impl, @@ -1018,6 +1165,10 @@ validate_test_optimization_pin_files_missing_go_mod_failure_test = analysistest. _validate_test_optimization_pin_files_missing_go_mod_failure_test_impl, expect_failure = True, ) +go_macro_orchestrion_enablement_mismatch_failure_test = analysistest.make( + _go_macro_orchestrion_enablement_mismatch_failure_test_impl, + expect_failure = True, +) wrapper_output_name_non_windows_test = analysistest.make( _wrapper_output_name_non_windows_test_impl, ) diff --git a/modules/go/tests/test_payloads_selector.bzl b/modules/go/tests/test_payloads_selector.bzl index 18f06085..1e43b653 100644 --- a/modules/go/tests/test_payloads_selector.bzl +++ b/modules/go/tests/test_payloads_selector.bzl @@ -76,6 +76,10 @@ def selector_payload_fixture_targets(): name = "module_example_com_explicit_pkg", marker = "module:explicit", ) + _payload_marker( + name = "module_manifest_context_example_com_explicit_pkg", + marker = "module:explicit-namespaced", + ) _payload_marker( name = "module_example_com_embed_pkg", marker = "module:embed", @@ -112,7 +116,11 @@ def selector_payload_fixture_targets(): deps = [":deps_leaf"], ) -def selector_explicit_precedence_target(name, tags = None): +def selector_explicit_precedence_target( + name, + tags = None, + module_groups = None, + module_group_names = None): """explicit_importpath wins over embed-derived and fallback importpaths.""" topt_go_payloads_selector( name = name, @@ -120,7 +128,8 @@ def selector_explicit_precedence_target(name, tags = None): embeds = [":embed_wrapper"], fallback_importpath = "example.com/fallback/pkg", full_files = ":full_payload", - module_groups = _COMMON_MODULE_GROUPS, + module_group_names = module_group_names or [], + module_groups = module_groups or _COMMON_MODULE_GROUPS, include_per_module = True, tags = tags, ) @@ -296,6 +305,13 @@ def _selector_explicit_precedence_test_impl(ctx): _assert_selected(env, target, "module_example_com_explicit_pkg") return analysistest.end(env) +def _selector_explicit_namespaced_test_impl(ctx): + """Logical module names select physical context-namespaced labels.""" + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + _assert_selected(env, target, "module_manifest_context_example_com_explicit_pkg") + return analysistest.end(env) + def _selector_embed_precedence_test_impl(ctx): """Implement selector embed precedence test impl behavior.""" env = analysistest.begin(ctx) @@ -375,6 +391,9 @@ def _selector_omits_flaky_tests_test_impl(ctx): selector_explicit_precedence_test = analysistest.make( _selector_explicit_precedence_test_impl, ) +selector_explicit_namespaced_test = analysistest.make( + _selector_explicit_namespaced_test_impl, +) selector_embed_precedence_test = analysistest.make( _selector_embed_precedence_test_impl, ) diff --git a/modules/go/tests/test_workspace_helpers.bzl b/modules/go/tests/test_workspace_helpers.bzl new file mode 100644 index 00000000..43077a5f --- /dev/null +++ b/modules/go/tests/test_workspace_helpers.bzl @@ -0,0 +1,175 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under +# the Apache 2.0 License. +# +# This product includes software developed at Datadog +# (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. + +"""Unit tests for the public WORKSPACE bootstrap helpers.""" + +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load( + "@datadog-rules-test-optimization-go//:topt_go_orchestrion_repository.bzl", + "build_orchestrion_repo_call_for_tests", +) +load( + "@datadog-rules-test-optimization-go//:topt_go_workspace.bzl", + "build_go_workspace_sync_specs_for_tests", +) + +def _assert_sync_spec(env, spec, name, service, expected_enabled_by_env): + asserts.equals(env, name, spec["name"]) + asserts.equals(env, name, spec["repo_name"]) + asserts.equals(env, service, spec["service"]) + asserts.equals(env, "go", spec["runtime_name"]) + asserts.equals(env, "1.25.9", spec["runtime_version"]) + asserts.equals(env, "arm64", spec["runtime_arch"]) + asserts.equals(env, "example.com/workspace", spec["runtime_module_path"]) + asserts.equals(env, "custom_topt", spec["out_dir"]) + asserts.equals(env, False, spec["enabled"]) + asserts.equals(env, expected_enabled_by_env, spec["enabled_by_env"]) + asserts.equals(env, 11, spec["http_connect_timeout_seconds"]) + asserts.equals(env, 22, spec["http_max_time_seconds"]) + asserts.equals(env, 3, spec["http_retry_attempts"]) + asserts.equals(env, 4, spec["http_retry_delay_seconds"]) + asserts.equals(env, 5, spec["http_execute_timeout_buffer_seconds"]) + asserts.equals(env, False, spec["known_tests"]) + asserts.equals(env, False, spec["test_management"]) + asserts.equals(env, False, spec["flaky_tests"]) + asserts.equals(env, True, spec["require_git_metadata"]) + asserts.equals(env, True, spec["debug"]) + +def _go_workspace_single_specs_test(ctx): + env = unittest.begin(ctx) + result = build_go_workspace_sync_specs_for_tests( + name = "test_optimization_data_go", + service = "go-service", + runtime_version = "1.25.9", + module_path = "example.com/workspace", + enabled = False, + enabled_by_env = False, + runtime_arch = "arm64", + out_dir = "custom_topt", + http_connect_timeout_seconds = 11, + http_max_time_seconds = 22, + http_retry_attempts = 3, + http_retry_delay_seconds = 4, + http_execute_timeout_buffer_seconds = 5, + known_tests = False, + test_management = False, + flaky_tests = False, + require_git_metadata = True, + debug = True, + ) + asserts.equals(env, 1, len(result["sync_specs"])) + _assert_sync_spec(env, result["sync_specs"][0], "test_optimization_data_go", "go-service", False) + asserts.equals(env, None, result["aggregate_spec"]) + return unittest.end(env) + +def _go_workspace_multi_specs_test(ctx): + env = unittest.begin(ctx) + result = build_go_workspace_sync_specs_for_tests( + name = "test_optimization_data_go", + services = ["go-service-a", "go-service-a", "go-service-b"], + runtime_version = "1.25.9", + module_path = "example.com/workspace", + enabled = False, + enabled_by_env = False, + runtime_arch = "arm64", + out_dir = "custom_topt", + http_connect_timeout_seconds = 11, + http_max_time_seconds = 22, + http_retry_attempts = 3, + http_retry_delay_seconds = 4, + http_execute_timeout_buffer_seconds = 5, + known_tests = False, + test_management = False, + flaky_tests = False, + require_git_metadata = True, + debug = True, + ) + asserts.equals(env, ["go_service_a", "go_service_a_2", "go_service_b"], result["aggregate_spec"]["service_keys"]) + asserts.equals( + env, + [ + "test_optimization_data_go_go_service_a", + "test_optimization_data_go_go_service_a_2", + "test_optimization_data_go_go_service_b", + ], + result["aggregate_spec"]["repo_names"], + ) + for i in range(3): + _assert_sync_spec( + env, + result["sync_specs"][i], + result["aggregate_spec"]["repo_names"][i], + ["go-service-a", "go-service-a", "go-service-b"][i], + False, + ) + return unittest.end(env) + +def _go_workspace_specs_default_to_config_gated_test(ctx): + env = unittest.begin(ctx) + result = build_go_workspace_sync_specs_for_tests( + name = "test_optimization_data_go", + service = "go-service", + runtime_version = "1.25.9", + module_path = "example.com/workspace", + ) + asserts.equals(env, True, result["sync_specs"][0]["enabled_by_env"]) + return unittest.end(env) + +def _orchestrion_call_spec_test(ctx): + env = unittest.begin(ctx) + call = build_orchestrion_repo_call_for_tests( + dd_trace_go_version = "v2.9.0", + version = "v1.9.0", + go_sdk_root = "@go_sdk//:ROOT", + go_sdk_version = "1.25.0", + log_timing = True, + ) + asserts.equals( + env, + { + "name": "rules_go_orchestrion_tool", + "dd_trace_go_version": "v2.9.0", + "dd_trace_go_versions": {}, + "dd_trace_go_pin_files": [], + "enabled_by_env": True, + "version": "v1.9.0", + "go_sdk_root": "@go_sdk//:ROOT", + "go_sdk_version": "1.25.0", + "log_timing": True, + }, + call, + ) + asserts.false(env, "enabled" in call) + return unittest.end(env) + +def _orchestrion_pin_file_call_spec_test(ctx): + env = unittest.begin(ctx) + call = build_orchestrion_repo_call_for_tests( + dd_trace_go_pin_files = [ + "@//:go.mod", + "@//:go.sum", + ], + version = "v1.9.0", + go_sdk_root = "@go_sdk//:ROOT", + go_sdk_version = "1.25.0", + ) + asserts.equals( + env, + [ + "@//:go.mod", + "@//:go.sum", + ], + call["dd_trace_go_pin_files"], + ) + asserts.equals(env, "", call["dd_trace_go_version"]) + asserts.equals(env, {}, call["dd_trace_go_versions"]) + return unittest.end(env) + +go_workspace_single_specs_test = unittest.make(_go_workspace_single_specs_test) +go_workspace_multi_specs_test = unittest.make(_go_workspace_multi_specs_test) +go_workspace_specs_default_to_config_gated_test = unittest.make(_go_workspace_specs_default_to_config_gated_test) +orchestrion_call_spec_test = unittest.make(_orchestrion_call_spec_test) +orchestrion_pin_file_call_spec_test = unittest.make(_orchestrion_pin_file_call_spec_test) diff --git a/modules/go/tools/dd_topt_go_bootstrap/main.go b/modules/go/tools/dd_topt_go_bootstrap/main.go index 356ffe15..c9f9ce20 100644 --- a/modules/go/tools/dd_topt_go_bootstrap/main.go +++ b/modules/go/tools/dd_topt_go_bootstrap/main.go @@ -322,8 +322,8 @@ func parseFlags() config { flag.IntVar(&cfg.defaultJobs, "default-jobs", 0, "Default --jobs value added to generated Bazel test commands when greater than zero") flag.StringVar(&cfg.wrapperPackage, "wrapper-package", defaultWrapperPackage, "Workspace-relative Bazel package where --write-wrapper-template writes the wrapper") flag.StringVar(&cfg.wrapperFile, "wrapper-file", defaultWorkspaceWrapperFile, "Wrapper .bzl filename used with --write-wrapper-template") - flag.StringVar(&cfg.plainWrapperName, "plain-wrapper-name", defaultPlainWrapperName, "Plain repo-local Go test wrapper name used in the generated wrapper template") - flag.StringVar(&cfg.optimizedWrapperName, "optimized-wrapper-name", defaultOptimizedWrapperName, "Optimized repo-local Go test wrapper name used in the generated wrapper template") + flag.StringVar(&cfg.plainWrapperName, "plain-wrapper-name", defaultPlainWrapperName, "Central repo-local Go test wrapper name used in the generated wrapper template") + flag.StringVar(&cfg.optimizedWrapperName, "optimized-wrapper-name", defaultOptimizedWrapperName, "Compatibility alias for the central repo-local Go test wrapper") flag.StringVar(&cfg.orchestrionVersion, "orchestrion-version", defaultOrchestrionVersion, "Orchestrion version to configure") flag.StringVar(&cfg.ddTraceGoVersion, "dd-trace-go-version", defaultDDTraceGoVersion, "dd-trace-go version to pin for Orchestrion-backed instrumentation") flag.StringVar(&cfg.rulesGoRemote, "rules-go-remote", defaultRulesGoRemote, "rules_go fork remote used for Orchestrion support") @@ -848,14 +848,39 @@ git_override( strip_prefix = "%s", ) +%s orchestrion = use_extension("@rules_go//go:extensions.bzl", "orchestrion") orchestrion.from_source( version = "%s", %s +%s ) use_repo(orchestrion, "rules_go_orchestrion_tool") %s -`, managedBlockStart, cfg.rulesGoRemote, cfg.rulesGoCommit, stripPrefix, cfg.orchestrionVersion, managedTracerConfigBlock(cfg), managedBlockEnd), nil +`, managedBlockStart, cfg.rulesGoRemote, cfg.rulesGoCommit, stripPrefix, managedGoSDKBlock(cfg), cfg.orchestrionVersion, managedTracerConfigBlock(cfg), managedOrchestrionGoSDKAttrs(cfg), managedBlockEnd), nil +} + +func managedGoSDKBlock(cfg config) string { + version := strings.TrimSpace(cfg.runtimeVersion) + if version == "" { + return "" + } + return fmt.Sprintf(`test_optimization_go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +test_optimization_go_sdk.download( + name = "test_optimization_go_sdk", + version = %q, +) +use_repo(test_optimization_go_sdk, "test_optimization_go_sdk") +`, version) +} + +func managedOrchestrionGoSDKAttrs(cfg config) string { + version := strings.TrimSpace(cfg.runtimeVersion) + if version == "" { + return "" + } + return fmt.Sprintf(` go_sdk_root = "@test_optimization_go_sdk//:ROOT", + go_sdk_version = %q,`, version) } func validateRulesGoVariant(variant string) error { @@ -1363,6 +1388,17 @@ func bazelrcSnippet(cfg config) (string, error) { for _, key := range bazelrcRepoEnvKeys { fmt.Fprintf(&buf, "common:%s --repo_env=%s\n", cfg.bazelrcConfig, key) } + fmt.Fprintf(&buf, "common:%s --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1\n", cfg.bazelrcConfig) + rulesGoRepoName := cfg.rulesGoRepoName + if !cfg.workspaceMode { + // Bzlmod exposes rules_go under its module name. The WORKSPACE + // repository name is configurable because repository rules may + // remap it (the default there remains io_bazel_rules_go). + rulesGoRepoName = "rules_go" + } else if rulesGoRepoName == "" { + rulesGoRepoName = defaultRulesGoRepoName + } + fmt.Fprintf(&buf, "build:%s --@%s//go/private/orchestrion:enabled=true\n", cfg.bazelrcConfig, rulesGoRepoName) fmt.Fprintf(&buf, "test:%s --remote_download_minimal\n", cfg.bazelrcConfig) fmt.Fprintf(&buf, "test:%s --remote_download_regex=.*test[.]outputs.*\n", cfg.bazelrcConfig) fmt.Fprintf(&buf, "test:%s --zip_undeclared_test_outputs\n", cfg.bazelrcConfig) @@ -1371,6 +1407,17 @@ func bazelrcSnippet(cfg config) (string, error) { return buf.String(), nil } +func apparentRulesGoRepoName(cfg config) string { + rulesGoRepoName := cfg.rulesGoRepoName + if !cfg.workspaceMode { + return "rules_go" + } + if rulesGoRepoName == "" { + return defaultRulesGoRepoName + } + return rulesGoRepoName +} + // writeBazelrcBlock inserts or replaces the managed .bazelrc block. func writeBazelrcBlock(cfg config) error { snippet, err := bazelrcSnippet(cfg) @@ -1420,6 +1467,7 @@ func validationScript(cfg config) (string, error) { fmt.Fprintf(&buf, "SYNC_REPO=%s\n", shellQuote(cfg.syncRepoName)) fmt.Fprintf(&buf, "DOCTOR_TARGET=%s\n", shellQuote(cfg.validationDoctorTarget)) fmt.Fprintf(&buf, "UPLOAD_TARGET=%s\n", shellQuote(cfg.validationUploadTarget)) + fmt.Fprintf(&buf, "RULES_GO_ENABLED_LABEL=%s\n", shellQuote("@"+apparentRulesGoRepoName(cfg)+"//go/private/orchestrion:enabled")) buf.WriteString("WORKSPACE_DIR=\"$(pwd -P)\"\n") buf.WriteString("BEP_TMP_ROOT=\"\"\n") buf.WriteString("BEP_JSON_DIR=\"\"\n") @@ -1539,6 +1587,32 @@ run_step() { "$@" } +validate_disabled_bootstrap() { + local alias_files + log "validate ordinary no-config bootstrap" + if ! env -u DD_API_KEY -u DD_SITE -u DD_TEST_OPTIMIZATION_ENABLED \ + "${BAZEL}" query "@${SYNC_REPO}//:test_optimization_files"; then + warn "ordinary no-config metadata bootstrap failed" + return 1 + fi + alias_files="$( + env -u DD_API_KEY -u DD_SITE -u DD_TEST_OPTIMIZATION_ENABLED \ + "${BAZEL}" cquery \ + "${RULES_GO_ENABLED_LABEL%:enabled}:tool_binary" --output=files + )" || return $? + if [[ -n "${alias_files}" ]]; then + warn "ordinary no-config Orchestrion alias unexpectedly exposed files: ${alias_files}" + return 1 + fi + + log "validate explicit disabled precedence" + env -u DD_API_KEY -u DD_SITE -u DD_TEST_OPTIMIZATION_ENABLED \ + "${BAZEL}" query "--config=${BAZEL_CONFIG}" \ + --repo_env=DD_TEST_OPTIMIZATION_ENABLED=0 \ + "--${RULES_GO_ENABLED_LABEL}=false" \ + "@${SYNC_REPO}//:test_optimization_files" +} + upload=0 while (($#)); do case "$1" in @@ -1564,6 +1638,10 @@ done trap cleanup EXIT check_disk +if ! validate_disabled_bootstrap; then + warn "disabled bootstrap validation failed; skipping enabled validation" + exit 1 +fi run_step "sync ${SYNC_REPO}" "${BAZEL}" sync "${SYNC_FLAGS[@]}" "--repo_env=FETCH_SALT=$(date +%s)" "--only=${SYNC_REPO}" sync_status=$? if (( sync_status != 0 )); then @@ -1881,16 +1959,21 @@ datadog_go_test_optimization_workspace_repositories( } buf.WriteString(")\n\n") + goVersion := "" + if strings.TrimSpace(cfg.runtimeVersion) != "" { + goVersion = strings.TrimSpace(cfg.runtimeVersion) + } buf.WriteString(fmt.Sprintf(`load("@%s//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") -load("@%s//go:orchestrion_workspace.bzl", "go_orchestrion_tool_repo") +load("@datadog-rules-test-optimization-go//:topt_go_orchestrion_repository.bzl", "dd_topt_go_orchestrion_tool_repo") -go_rules_dependencies() -go_register_toolchains(version = "") -go_orchestrion_tool_repo( +dd_topt_go_orchestrion_tool_repo( version = "%s", %s +%s ) -`, cfg.rulesGoRepoName, cfg.rulesGoRepoName, cfg.orchestrionVersion, workspaceSnippetTracerConfig(cfg))) +go_rules_dependencies() +go_register_toolchains(version = "%s") +`, cfg.rulesGoRepoName, cfg.orchestrionVersion, workspaceSnippetTracerConfig(cfg), workspaceSnippetOrchestrionGoSDKAttrs(cfg), goVersion)) if cfg.workspaceMode || strings.TrimSpace(cfg.service) != "" || strings.TrimSpace(cfg.runtimeVersion) != "" { buf.WriteString("\n") buf.WriteString(workspaceSyncSnippet(cfg)) @@ -1901,16 +1984,19 @@ go_orchestrion_tool_repo( // workspaceSyncSnippet renders the repository-rule call that fetches Test // Optimization metadata during WORKSPACE repository resolution. func workspaceSyncSnippet(cfg config) string { - return fmt.Sprintf(`load("@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", "test_optimization_sync") + modulePathLine := "" + if cfg.goModulePath != "" { + modulePathLine = fmt.Sprintf(" module_path = %q,\n", cfg.goModulePath) + } + return fmt.Sprintf(`load("@datadog-rules-test-optimization-go//:topt_go_workspace.bzl", "dd_topt_go_workspace_sync_repositories") -test_optimization_sync( +dd_topt_go_workspace_sync_repositories( name = "%s", service = "%s", - runtime_name = "go", runtime_version = "%s", - require_git_metadata = True, +%s require_git_metadata = True, ) -`, cfg.syncRepoName, cfg.service, cfg.runtimeVersion) +`, cfg.syncRepoName, cfg.service, cfg.runtimeVersion, modulePathLine) } func workspaceSnippetTracerConfig(cfg config) string { @@ -1926,6 +2012,15 @@ func workspaceSnippetTracerConfig(cfg config) string { return fmt.Sprintf(" dd_trace_go_version = %q,", cfg.ddTraceGoVersion) } +func workspaceSnippetOrchestrionGoSDKAttrs(cfg config) string { + version := strings.TrimSpace(cfg.runtimeVersion) + if version == "" { + return "" + } + return fmt.Sprintf(` go_sdk_root = "@go_sdk//:ROOT", + go_sdk_version = %q,`, version) +} + func rulesGoStripPrefix(cfg config) (string, error) { variant := cfg.rulesGoVariant if variant == "" { @@ -2276,34 +2371,29 @@ func ensureGuidedRootBuild(cfg config) error { } } - text, err = ensureLoadStatement(text, `load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor")`) - if err != nil { - return err - } - text, err = ensureLoadStatement(text, `load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader")`) + text, err = ensureLoadStatement(text, `load("@datadog-rules-test-optimization//tools/core:test_optimization_targets.bzl", "dd_test_optimization_targets")`) if err != nil { return err } doctorBlock := fmt.Sprintf(`%s -dd_test_optimization_doctor( - name = "%s", - data = ["@%s//:test_optimization_context"], +dd_test_optimization_targets( + name = "test_optimization", + sync_repo_name = "%s", + doctor_name = "%s", + uploader_name = "%s", %s) %s -`, doctorBlockStart, cfg.doctorTargetName, cfg.syncRepoName, renderExpectedTargetsAttr(cfg.expectedTargets), doctorBlockEnd) +`, doctorBlockStart, cfg.syncRepoName, cfg.doctorTargetName, cfg.uploaderTargetName, renderExpectedTargetsAttr(cfg.expectedTargets), doctorBlockEnd) text, err = replaceManagedSection(text, doctorBlockStart, doctorBlockEnd, doctorBlock) if err != nil { return err } uploaderBlock := fmt.Sprintf(`%s -dd_payload_uploader( - name = "%s", - data = ["@%s//:test_optimization_context"], -) +# The doctor/uploader pair is generated by dd_test_optimization_targets above. %s -`, uploaderBlockStart, cfg.uploaderTargetName, cfg.syncRepoName, uploaderBlockEnd) +`, uploaderBlockStart, uploaderBlockEnd) text, err = replaceManagedSection(text, uploaderBlockStart, uploaderBlockEnd, uploaderBlock) if err != nil { return err @@ -2444,9 +2534,9 @@ def dd_go_test(name, **kwargs): return nil } -// ensureWorkspaceWrapperTemplate writes a generic split wrapper template for -// WORKSPACE monorepos. The template keeps repository policy in one local helper -// while Datadog-specific attributes stay in the optimized wrapper path. +// ensureWorkspaceWrapperTemplate writes a config-gated central wrapper template +// for WORKSPACE monorepos. The template keeps repository policy in one local +// helper while the public Test Optimization macro owns enabled/disabled dispatch. func ensureWorkspaceWrapperTemplate(cfg config) error { if strings.TrimSpace(cfg.wrapperPackage) == "" { return errors.New("--wrapper-package must be non-empty") @@ -2503,19 +2593,27 @@ func ensureWorkspaceWrapperTemplate(cfg config) error { return nil } -// workspaceWrapperTemplate renders a repo-local plain/optimized wrapper split. -// Consumers keep scheduling, tags, flaky handling, and platform policy inside +// workspaceWrapperTemplate renders one repo-local public wrapper. Consumers keep +// scheduling, tags, flaky handling, and platform policy inside // _apply_repo_go_test_policy instead of editing the public Datadog macro. func workspaceWrapperTemplate(cfg config, pinLabels []string) string { - return fmt.Sprintf(`"""Workspace-local Go test wrappers for Datadog Test Optimization. + compatibilityAlias := "" + if cfg.optimizedWrapperName != cfg.plainWrapperName { + compatibilityAlias = fmt.Sprintf(` +# Compatibility alias for repositories that still load the former optimized name. +%s = %s +`, cfg.optimizedWrapperName, cfg.plainWrapperName) + } + + return fmt.Sprintf(`"""Workspace-local Go test wrapper for Datadog Test Optimization. Keep repository-specific scheduling, tags, Docker, flaky, and platform policy -inside _apply_repo_go_test_policy. The optimized wrapper below owns only the -Datadog Test Optimization attributes. +inside _apply_repo_go_test_policy. Every test uses the same public wrapper; +--config=test-optimization selects enabled metadata and Orchestrion behavior, +while omitting the config preserves the normal go_test behavior. """ %s -load("@%s//go:def.bzl", _raw_go_test = "go_test") load("@datadog-rules-test-optimization-go//:topt_go_test.bzl", _raw_dd_topt_go_test = "dd_topt_go_test") load("@%s//:export.bzl", "topt_data") @@ -2528,11 +2626,7 @@ def _apply_repo_go_test_policy(go_test_macro, name, **kwargs): go_test_macro(name = name, **kwargs) def %s(name, **kwargs): - """Run a plain go_test with repository-local policy only.""" - _apply_repo_go_test_policy(_raw_go_test, name = name, **kwargs) - -def %s(name, **kwargs): - """Run an Orchestrion-enabled go_test with Datadog Test Optimization.""" + """Run a config-gated go_test with repository-local policy.""" if "topt_data" in kwargs: fail("%s injects topt_data from @%s; remove the explicit topt_data attr") if "orchestrion_pin_files" in kwargs: @@ -2546,7 +2640,8 @@ def %s(name, **kwargs): **kwargs ) %s -`, wrapperBlockStart, cfg.rulesGoRepoName, cfg.syncRepoName, strings.TrimRight(renderPinLabelLines(pinLabels), "\n"), cfg.plainWrapperName, cfg.optimizedWrapperName, cfg.optimizedWrapperName, cfg.syncRepoName, cfg.optimizedWrapperName, wrapperBlockEnd) +%s +`, wrapperBlockStart, cfg.syncRepoName, strings.TrimRight(renderPinLabelLines(pinLabels), "\n"), cfg.plainWrapperName, cfg.plainWrapperName, cfg.syncRepoName, cfg.plainWrapperName, strings.TrimRight(compatibilityAlias, "\n"), wrapperBlockEnd) } // resolveWorkspaceRelativeDir resolves a user-selected directory and rejects @@ -3066,10 +3161,22 @@ func bootstrapSyncCommands(cfg config) [][]string { switch mode { case "targeted": - commands = append(commands, - append([]string{"list", "-mod=mod", "-tags=tools"}, orchestrionToolPackages...), - append([]string{"list", "-mod=readonly", "-tags=tools"}, orchestrionToolPackages...), - ) + // Seed every selected module version explicitly before loading package + // roots. On a cold cache, go list may otherwise query @latest even + // though go.mod already contains the intended requirements. + commands = append(commands, []string{"mod", "download", "github.com/DataDog/orchestrion@" + cfg.orchestrionVersion}) + for _, modulePath := range ddTraceGoModules { + commands = append(commands, []string{"mod", "download", modulePath + "@" + versions[modulePath]}) + } + // Resolve package roots one at a time. A single go list spanning several + // module roots can ignore freshly edited requirements on a cold module + // cache and fall back to @latest for some roots. + for _, packagePath := range orchestrionToolPackages { + commands = append(commands, []string{"list", "-mod=mod", "-tags=tools", packagePath}) + } + for _, packagePath := range orchestrionToolPackages { + commands = append(commands, []string{"list", "-mod=readonly", "-tags=tools", packagePath}) + } case "tidy": commands = append(commands, []string{"get", "github.com/DataDog/dd-trace-go/v2/orchestrion@" + versions["github.com/DataDog/dd-trace-go/v2"]}, @@ -3350,17 +3457,22 @@ func normalizedGoEnv(env []string) []string { func setEnvValue(env []string, key, value string) []string { prefix := key + "=" + normalized := make([]string, 0, len(env)+1) replaced := false - for idx, entry := range env { + for _, entry := range env { if strings.HasPrefix(entry, prefix) { - env[idx] = prefix + value - replaced = true + if !replaced { + normalized = append(normalized, prefix+value) + replaced = true + } + continue } + normalized = append(normalized, entry) } if !replaced { - env = append(env, prefix+value) + normalized = append(normalized, prefix+value) } - return env + return normalized } func envValue(env []string, key string) string { @@ -3379,15 +3491,18 @@ func orchestrionBootstrapEnv() []string { goModCache := filepath.Join(cacheRoot, "pkg", "mod") goBuildCache := filepath.Join(cacheRoot, "cache") - env = append(env, - "GO111MODULE=on", - "GOWORK=off", - "GOPATH="+cacheRoot, - "GOMODCACHE="+goModCache, - "GOCACHE="+goBuildCache, - "GOPROXY=https://proxy.golang.org,direct", - "GOSUMDB=sum.golang.org", - ) + env = setEnvValue(env, "GO111MODULE", "on") + env = setEnvValue(env, "GOWORK", "off") + env = setEnvValue(env, "GOPATH", cacheRoot) + env = setEnvValue(env, "GOMODCACHE", goModCache) + env = setEnvValue(env, "GOCACHE", goBuildCache) + env = setEnvValue(env, "GOPROXY", "https://proxy.golang.org,direct") + env = setEnvValue(env, "GOSUMDB", "sum.golang.org") + // The Orchestrion and dd-trace-go pins are public modules. Do not let a + // developer's broad GOPRIVATE/GONOSUMDB settings bypass the public proxy + // and leave the isolated module cache with incomplete package metadata. + env = setEnvValue(env, "GOPRIVATE", "") + env = setEnvValue(env, "GONOSUMDB", "") return normalizedGoEnv(env) } diff --git a/modules/go/tools/dd_topt_go_bootstrap/main_test.go b/modules/go/tools/dd_topt_go_bootstrap/main_test.go index 0e1da47a..9161da61 100644 --- a/modules/go/tools/dd_topt_go_bootstrap/main_test.go +++ b/modules/go/tools/dd_topt_go_bootstrap/main_test.go @@ -82,6 +82,7 @@ func TestManagedModuleBlockIncludesRulesGoExtension(t *testing.T) { cfg := config{ orchestrionVersion: "v1.9.0", ddTraceGoVersion: "v2.5.0", + runtimeVersion: "1.25.0", rulesGoRemote: "https://github.com/example/repo.git", rulesGoCommit: "deadbeef", } @@ -95,12 +96,24 @@ func TestManagedModuleBlockIncludesRulesGoExtension(t *testing.T) { if !strings.Contains(got, `use_extension("@rules_go//go:extensions.bzl", "orchestrion")`) { t.Fatalf("expected rules_go orchestrion extension in managed block:\n%s", got) } + if !strings.Contains(got, `test_optimization_go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")`) { + t.Fatalf("expected managed Go SDK extension in managed block:\n%s", got) + } + if !strings.Contains(got, `name = "test_optimization_go_sdk"`) || + !strings.Contains(got, `version = "1.25.0"`) || + !strings.Contains(got, `go_sdk_root = "@test_optimization_go_sdk//:ROOT"`) || + !strings.Contains(got, `go_sdk_version = "1.25.0"`) { + t.Fatalf("expected managed Go SDK identity in managed block:\n%s", got) + } if !strings.Contains(got, `orchestrion.from_source(`) { t.Fatalf("expected orchestrion extension call in managed block:\n%s", got) } if !strings.Contains(got, `version = "v1.9.0"`) { t.Fatalf("expected orchestrion version in managed block:\n%s", got) } + if strings.Contains(got, `enabled_by_env`) { + t.Fatalf("expected managed block to rely on the config-gated extension default:\n%s", got) + } if !strings.Contains(got, `dd_trace_go_version = "v2.5.0"`) { t.Fatalf("expected dd-trace-go version in managed block:\n%s", got) } @@ -109,6 +122,21 @@ func TestManagedModuleBlockIncludesRulesGoExtension(t *testing.T) { } } +func TestManagedModuleBlockWithoutRuntimeVersionPreservesLegacyShape(t *testing.T) { + cfg := config{ + orchestrionVersion: "v1.9.0", + ddTraceGoVersion: "v2.5.0", + rulesGoRemote: "https://github.com/example/repo.git", + rulesGoCommit: "deadbeef", + } + got := managedModuleBlock(cfg) + if strings.Contains(got, `"go_sdk"`) || + strings.Contains(got, `go_sdk_root`) || + strings.Contains(got, `go_sdk_version`) { + t.Fatalf("expected a non-guided block without a runtime version to preserve legacy SDK discovery:\n%s", got) + } +} + func TestManagedModuleBlockCanSelectBaseRulesGoVariant(t *testing.T) { cfg := config{ orchestrionVersion: "v1.9.0", @@ -151,6 +179,7 @@ func TestWorkspaceSnippetSupportsMixedFetchModes(t *testing.T) { rtoArchiveType: "tar.gz", orchestrionVersion: "v1.9.0", ddTraceGoVersion: "v2.9.0", + runtimeVersion: "1.25.0", } got, err := workspaceSnippet(cfg) if err != nil { @@ -167,11 +196,19 @@ func TestWorkspaceSnippetSupportsMixedFetchModes(t *testing.T) { `rules_go_variant = "base"`, `go_orchestrion_tool_repo(`, `dd_trace_go_version = "v2.9.0"`, + `go_sdk_root = "@go_sdk//:ROOT"`, + `go_sdk_version = "1.25.0"`, + `go_register_toolchains(version = "1.25.0")`, } { if !strings.Contains(got, want) { t.Fatalf("workspace snippet missing %q:\n%s", want, got) } } + toolRepoCall := strings.Index(got, "\ndd_topt_go_orchestrion_tool_repo(") + dependenciesCall := strings.Index(got, "\ngo_rules_dependencies()\n") + if toolRepoCall < 0 || dependenciesCall < 0 || toolRepoCall > dependenciesCall { + t.Fatalf("workspace snippet must declare the real Orchestrion repository before rules_go installs its fallback:\n%s", got) + } } func TestWorkspaceSnippetFallsBackToRulesGoCommit(t *testing.T) { @@ -236,11 +273,16 @@ func TestWorkspaceModeSnippetIncludesSyncAndBaseVariant(t *testing.T) { for _, want := range []string{ `rules_go_variant = "base"`, `rules_go_repo_name = "io_bazel_rules_go"`, - `load("@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", "test_optimization_sync")`, + `load("@datadog-rules-test-optimization-go//:topt_go_workspace.bzl", "dd_topt_go_workspace_sync_repositories")`, + `load("@datadog-rules-test-optimization-go//:topt_go_orchestrion_repository.bzl", "dd_topt_go_orchestrion_tool_repo")`, + `dd_topt_go_workspace_sync_repositories(`, + `dd_topt_go_orchestrion_tool_repo(`, `name = "test_optimization_data_worker"`, `service = "worker"`, - `runtime_name = "go"`, `runtime_version = "1.25.9"`, + `go_sdk_root = "@go_sdk//:ROOT"`, + `go_sdk_version = "1.25.9"`, + `go_register_toolchains(version = "1.25.9")`, `require_git_metadata = True`, } { if !strings.Contains(got, want) { @@ -309,9 +351,8 @@ func TestRunWorkspaceModeWritesSelectedFilesWithoutModuleBazel(t *testing.T) { } wrapperText := string(wrapper) for _, want := range []string{ - `load("@io_bazel_rules_go//go:def.bzl", _raw_go_test = "go_test")`, `def dd_go_test(name, **kwargs):`, - `def dd_topt_go_test(name, **kwargs):`, + `dd_topt_go_test = dd_go_test`, `load("@test_optimization_data_worker//:export.bzl", "topt_data")`, `orchestrion_mode = "test_optimization"`, `orchestrion_pin_files = _ORCHESTRION_PIN_FILES`, @@ -320,11 +361,19 @@ func TestRunWorkspaceModeWritesSelectedFilesWithoutModuleBazel(t *testing.T) { t.Fatalf("workspace wrapper missing %q:\n%s", want, wrapperText) } } - for _, forbidden := range []string{"consumer-internal-name", "--test_env=DD_GIT_"} { + for _, forbidden := range []string{ + "consumer-internal-name", + "--test_env=DD_GIT_", + `load("@io_bazel_rules_go//go:def.bzl", _raw_go_test = "go_test")`, + `def dd_topt_go_test(name, **kwargs):`, + } { if strings.Contains(wrapperText, forbidden) { t.Fatalf("workspace wrapper contains forbidden %q:\n%s", forbidden, wrapperText) } } + if got := strings.Count(wrapperText, "_raw_dd_topt_go_test,"); got != 1 { + t.Fatalf("workspace wrapper should have one Test Optimization call path, got %d:\n%s", got, wrapperText) + } } func TestWorkspaceModeDoesNotRunGoModSyncByDefault(t *testing.T) { @@ -382,6 +431,17 @@ func TestEnsureWorkspaceWrapperTemplateIsIdempotent(t *testing.T) { if string(first) != string(second) { t.Fatalf("expected idempotent wrapper template:\nfirst:\n%s\nsecond:\n%s", first, second) } + for _, want := range []string{ + `def plain_go_test(name, **kwargs):`, + `optimized_go_test = plain_go_test`, + } { + if !strings.Contains(string(first), want) { + t.Fatalf("workspace wrapper missing %q:\n%s", want, first) + } + } + if strings.Contains(string(first), `_raw_go_test`) { + t.Fatalf("workspace wrapper must not bypass config-gated dispatch:\n%s", first) + } } func TestEnsureWorkspaceWrapperTemplateRejectsPathTraversal(t *testing.T) { @@ -412,6 +472,8 @@ func TestBazelrcSnippetUsesRepoEnvOnlyForSyncMetadata(t *testing.T) { `common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_AGENTLESS_URL`, `common:test-optimization --repo_env=DD_GIT_REPOSITORY_URL`, `common:test-optimization --repo_env=DD_PR_NUMBER`, + `common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1`, + `build:test-optimization --@rules_go//go/private/orchestrion:enabled=true`, `test:test-optimization --remote_download_minimal`, `test:test-optimization --remote_download_regex=.*test[.]outputs.*`, `test:test-optimization --zip_undeclared_test_outputs`, @@ -654,6 +716,7 @@ func TestValidationScriptUsesConfiguredFlowAndUploadOptIn(t *testing.T) { `SYNC_REPO='test_optimization_data_worker'`, `DOCTOR_TARGET='//:dd_test_optimization_doctor'`, `UPLOAD_TARGET='//:dd_upload_payloads'`, + `RULES_GO_ENABLED_LABEL='@rules_go//go/private/orchestrion:enabled'`, `WORKSPACE_DIR="$(pwd -P)"`, `BEP_TMP_ROOT=""`, `BEP_JSON_DIR=""`, @@ -682,6 +745,12 @@ func TestValidationScriptUsesConfiguredFlowAndUploadOptIn(t *testing.T) { `--report-json`, `mktemp -d "${tmp_parent%/}/dd-go-topt.XXXXXX"`, `sync -> controls -> instrumented tests -> doctor -> dry-run uploader -> optional upload`, + `validate ordinary no-config bootstrap`, + `validate explicit disabled precedence`, + `query "@${SYNC_REPO}//:test_optimization_files"`, + `"${BAZEL}" cquery \ + "${RULES_GO_ENABLED_LABEL%:enabled}:tool_binary"`, + `--repo_env=DD_TEST_OPTIMIZATION_ENABLED=0`, `upload skipped; rerun with --upload`, `${BAZEL}" shutdown`, } { @@ -799,6 +868,9 @@ func TestValidationScriptRunsWithNoControlTargets(t *testing.T) { } logText := string(logBytes) for _, want := range []string{ + "query @test_optimization_data//:test_optimization_files", + "cquery @rules_go//go/private/orchestrion:tool_binary --output=files", + "query --config=test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=0 --@rules_go//go/private/orchestrion:enabled=false @test_optimization_data//:test_optimization_files", "sync --config=test-optimization --repo_env=FETCH_SALT=", "test --config=test-optimization --build_event_json_file=", "//pkg:go_default_test", @@ -1176,6 +1248,14 @@ test:old --test_env=DD_GIT_BRANCH=main if strings.Contains(text, "--test_env=DD_GIT_BRANCH") || strings.Count(text, bazelrcBlockStart) != 1 { t.Fatalf("expected old managed block to be replaced:\n%s", text) } + for _, want := range []string{ + `common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1`, + `build:test-optimization --@rules_go//go/private/orchestrion:enabled=true`, + } { + if !strings.Contains(text, want) { + t.Fatalf("migrated managed block missing %q:\n%s", want, text) + } + } } func TestWriteBazelrcBlockRejectsPathTraversal(t *testing.T) { @@ -1538,6 +1618,9 @@ func TestManagedGuidedModuleBlockIncludesModulePath(t *testing.T) { if !strings.Contains(got, `module_path = "github.com/DataDog/example-service"`) { t.Fatalf("expected guided block to include explicit module_path:\n%s", got) } + if strings.Contains(got, `enabled_by_env`) { + t.Fatalf("expected guided block to rely on the config-gated extension default:\n%s", got) + } } func TestWriteStarterOrchestrionYML(t *testing.T) { @@ -1608,6 +1691,31 @@ func TestBootstrapSyncCommandsTargetedModeAvoidsGoModTidy(t *testing.T) { if !strings.Contains(joined, "list -mod=readonly -tags=tools github.com/DataDog/orchestrion") { t.Fatalf("targeted bootstrap sync must verify readonly module completeness:\n%s", joined) } + for _, mode := range []string{"-mod=mod", "-mod=readonly"} { + for _, packagePath := range orchestrionToolPackages { + want := "list " + mode + " -tags=tools " + packagePath + if !strings.Contains(joined, want) { + t.Fatalf("targeted bootstrap sync missing sequential package resolution %q:\n%s", want, joined) + } + } + } + expectedDownloads := []string{ + "github.com/DataDog/orchestrion@v1.9.0", + "github.com/DataDog/dd-trace-go/v2@v2.9.0", + "github.com/DataDog/dd-trace-go/contrib/net/http/v2@v2.9.0", + "github.com/DataDog/dd-trace-go/contrib/log/slog/v2@v2.9.0", + } + for _, moduleVersion := range expectedDownloads { + want := "mod download " + moduleVersion + if !strings.Contains(joined, want) { + t.Fatalf("targeted bootstrap sync missing exact module download %q:\n%s", want, joined) + } + } + for _, command := range got { + if len(command) > 5 && command[0] == "list" { + t.Fatalf("targeted bootstrap sync must resolve one package root per go list command: %#v", command) + } + } } func TestBootstrapSyncCommandsDefaultsToTargetedMode(t *testing.T) { @@ -2145,6 +2253,42 @@ func TestNormalizedGoEnvForcesGoWorkOff(t *testing.T) { } } +func TestOrchestrionBootstrapEnvUsesPublicModuleResolution(t *testing.T) { + got := orchestrionBootstrapEnv() + cacheRoot := filepath.Join(os.TempDir(), sharedOrchestrionCacheDirName) + for key, want := range map[string]string{ + "GOPATH": cacheRoot, + "GOMODCACHE": filepath.Join(cacheRoot, "pkg", "mod"), + "GOCACHE": filepath.Join(cacheRoot, "cache"), + } { + if value := envValue(got, key); value != want { + t.Fatalf("%s=%q, want %q", key, value, want) + } + prefix := key + "=" + count := 0 + for _, entry := range got { + if strings.HasPrefix(entry, prefix) { + count++ + } + } + if count != 1 { + t.Fatalf("%s appears %d times in bootstrap environment, want exactly once", key, count) + } + } + if envValue(got, "GOPROXY") != "https://proxy.golang.org,direct" { + t.Fatalf("GOPROXY=%q, want public proxy", envValue(got, "GOPROXY")) + } + if envValue(got, "GOSUMDB") != "sum.golang.org" { + t.Fatalf("GOSUMDB=%q, want public checksum database", envValue(got, "GOSUMDB")) + } + if envValue(got, "GOPRIVATE") != "" { + t.Fatalf("GOPRIVATE=%q, want empty for public bootstrap modules", envValue(got, "GOPRIVATE")) + } + if envValue(got, "GONOSUMDB") != "" { + t.Fatalf("GONOSUMDB=%q, want empty for public bootstrap modules", envValue(got, "GONOSUMDB")) + } +} + func TestNormalizeDDTraceGoVersionMutatesConfigBeforePersistence(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("shell-script based helper test is Unix-only") diff --git a/modules/go/tools/onboardingpins/rules_go_forks_gen.go b/modules/go/tools/onboardingpins/rules_go_forks_gen.go index 51b7efe2..5a05638b 100644 --- a/modules/go/tools/onboardingpins/rules_go_forks_gen.go +++ b/modules/go/tools/onboardingpins/rules_go_forks_gen.go @@ -11,4 +11,7 @@ var rulesGoForkStripPrefixes = map[string]map[string]string{ "v0_61_1": { "base": "third_party/rgo/v0_61_1/base", }, + "v0_62_0": { + "base": "third_party/rgo/v0_62_0/base", + }, } diff --git a/modules/go/topt_go_extension.bzl b/modules/go/topt_go_extension.bzl index 37056518..28fc3992 100644 --- a/modules/go/topt_go_extension.bzl +++ b/modules/go/topt_go_extension.bzl @@ -44,16 +44,106 @@ def _record_repo_owner_or_fail(seen_repo_owners, repo_name, owner, tag_name): ) seen_repo_owners[repo_name] = owner +def _build_go_single_repo_spec( + name, + service, + module_path = "", + runtime_version = "", + runtime_arch = "", + out_dir = "", + http_connect_timeout_seconds = HTTP_POLICY_ATTR_UNSET, + http_max_time_seconds = HTTP_POLICY_ATTR_UNSET, + http_retry_attempts = HTTP_POLICY_ATTR_UNSET, + http_retry_delay_seconds = HTTP_POLICY_ATTR_UNSET, + http_execute_timeout_buffer_seconds = HTTP_POLICY_ATTR_UNSET, + known_tests = True, + test_management = True, + flaky_tests = True, + enabled = True, + enabled_by_env = True, + require_git_metadata = False, + debug = False): + """Build the complete sync spec for one Go service repository.""" + return { + "name": name, + "repo_name": name, + "out_dir": out_dir, + "service": service, + "runtime_name": "go", + "runtime_version": runtime_version, + "runtime_arch": runtime_arch, + "runtime_module_path": module_path, + "http_connect_timeout_seconds": http_connect_timeout_seconds, + "http_max_time_seconds": http_max_time_seconds, + "http_retry_attempts": http_retry_attempts, + "http_retry_delay_seconds": http_retry_delay_seconds, + "http_execute_timeout_buffer_seconds": http_execute_timeout_buffer_seconds, + "known_tests": known_tests, + "test_management": test_management, + "flaky_tests": flaky_tests, + "enabled": enabled, + "enabled_by_env": enabled_by_env, + "require_git_metadata": require_git_metadata, + "debug": debug, + } + +def _build_go_multi_repo_specs( + name, + services, + module_path = "", + runtime_version = "", + runtime_arch = "", + out_dir = "", + http_connect_timeout_seconds = HTTP_POLICY_ATTR_UNSET, + http_max_time_seconds = HTTP_POLICY_ATTR_UNSET, + http_retry_attempts = HTTP_POLICY_ATTR_UNSET, + http_retry_delay_seconds = HTTP_POLICY_ATTR_UNSET, + http_execute_timeout_buffer_seconds = HTTP_POLICY_ATTR_UNSET, + known_tests = True, + test_management = True, + flaky_tests = True, + enabled = True, + enabled_by_env = True, + require_git_metadata = False, + debug = False): + """Build the per-service sync specs for a multi-service Go tag.""" + service_keys = _compute_service_keys(services) + repo_names = _compute_repo_names(name, service_keys) + specs = [] + for i in range(len(services)): + specs.append(_build_go_single_repo_spec( + name = repo_names[i], + service = services[i], + module_path = module_path, + runtime_version = runtime_version, + runtime_arch = runtime_arch, + out_dir = out_dir, + http_connect_timeout_seconds = http_connect_timeout_seconds, + http_max_time_seconds = http_max_time_seconds, + http_retry_attempts = http_retry_attempts, + http_retry_delay_seconds = http_retry_delay_seconds, + http_execute_timeout_buffer_seconds = http_execute_timeout_buffer_seconds, + known_tests = known_tests, + test_management = test_management, + flaky_tests = flaky_tests, + enabled = enabled, + enabled_by_env = enabled_by_env, + require_git_metadata = require_git_metadata, + debug = debug, + )) + return specs + +build_go_single_repo_spec_for_tests = _build_go_single_repo_spec +build_go_multi_repo_specs_for_tests = _build_go_multi_repo_specs + def _materialize_single_service_repo(call): - test_optimization_sync( + test_optimization_sync(**_build_go_single_repo_spec( name = call.name, - repo_name = call.name, - out_dir = call.out_dir, service = call.service, - runtime_name = "go", + module_path = call.module_path, runtime_version = call.runtime_version, runtime_arch = call.runtime_arch, - runtime_module_path = call.module_path, + out_dir = call.out_dir, http_connect_timeout_seconds = call.http_connect_timeout_seconds, http_max_time_seconds = call.http_max_time_seconds, http_retry_attempts = call.http_retry_attempts, @@ -61,34 +151,38 @@ def _materialize_single_service_repo(call): http_execute_timeout_buffer_seconds = call.http_execute_timeout_buffer_seconds, known_tests = call.known_tests, test_management = call.test_management, + flaky_tests = call.flaky_tests, + enabled = call.enabled, + enabled_by_env = call.enabled_by_env, require_git_metadata = call.require_git_metadata, debug = call.debug, - ) + )) def _materialize_multi_service_repos(call): service_keys = _compute_service_keys(call.services) repo_names = _compute_repo_names(call.name, service_keys) - for i in range(len(call.services)): - test_optimization_sync( - name = repo_names[i], - repo_name = repo_names[i], - out_dir = call.out_dir, - service = call.services[i], - runtime_name = "go", - runtime_version = call.runtime_version, - runtime_arch = call.runtime_arch, - runtime_module_path = call.module_path, - http_connect_timeout_seconds = call.http_connect_timeout_seconds, - http_max_time_seconds = call.http_max_time_seconds, - http_retry_attempts = call.http_retry_attempts, - http_retry_delay_seconds = call.http_retry_delay_seconds, - http_execute_timeout_buffer_seconds = call.http_execute_timeout_buffer_seconds, - known_tests = call.known_tests, - test_management = call.test_management, - require_git_metadata = call.require_git_metadata, - debug = call.debug, - ) + for spec in _build_go_multi_repo_specs( + name = call.name, + services = call.services, + module_path = call.module_path, + runtime_version = call.runtime_version, + runtime_arch = call.runtime_arch, + out_dir = call.out_dir, + http_connect_timeout_seconds = call.http_connect_timeout_seconds, + http_max_time_seconds = call.http_max_time_seconds, + http_retry_attempts = call.http_retry_attempts, + http_retry_delay_seconds = call.http_retry_delay_seconds, + http_execute_timeout_buffer_seconds = call.http_execute_timeout_buffer_seconds, + known_tests = call.known_tests, + test_management = call.test_management, + flaky_tests = call.flaky_tests, + enabled = call.enabled, + enabled_by_env = call.enabled_by_env, + require_git_metadata = call.require_git_metadata, + debug = call.debug, + ): + test_optimization_sync(**spec) test_optimization_multi_aggregate( name = call.name, @@ -137,6 +231,9 @@ test_optimization_go_extension = module_extension( "http_execute_timeout_buffer_seconds": attr.int(default = HTTP_POLICY_ATTR_UNSET), "known_tests": attr.bool(default = True), "test_management": attr.bool(default = True), + "flaky_tests": attr.bool(default = True), + "enabled": attr.bool(default = True), + "enabled_by_env": attr.bool(default = True), "require_git_metadata": attr.bool(default = False), "debug": attr.bool(default = False), }), diff --git a/modules/go/topt_go_infer.bzl b/modules/go/topt_go_infer.bzl index 995e359f..42407336 100644 --- a/modules/go/topt_go_infer.bzl +++ b/modules/go/topt_go_infer.bzl @@ -74,7 +74,12 @@ def _resolve_payload_selection(ctx): ctx.attr.fallback_importpath or "", ) - module_group_names = [m.label.name for m in ctx.attr.module_groups] + module_group_names = ctx.attr.module_group_names + if module_group_names: + if len(module_group_names) != len(ctx.attr.module_groups): + fail("module_group_names must contain one entry per module_groups entry") + else: + module_group_names = [m.label.name for m in ctx.attr.module_groups] strict_selection = ctx.attr.include_per_module and len(module_group_names) > 0 and ( bool(ctx.attr.explicit_importpath) or bool(ctx.attr.module_label_override) ) @@ -89,9 +94,9 @@ def _resolve_payload_selection(ctx): chosen = None if selected_name: - for module_group in ctx.attr.module_groups: - if module_group.label.name == selected_name: - chosen = module_group + for index in range(len(module_group_names)): + if module_group_names[index] == selected_name: + chosen = ctx.attr.module_groups[index] break if chosen != None: @@ -266,6 +271,9 @@ topt_go_payloads_selector = rule( # All per-module filegroups (e.g., @repo//:module_) "module_groups": attr.label_list(), + # Optional logical names parallel to module_groups for namespaced repos. + "module_group_names": attr.string_list(), + # Whether to prefer per-module files when available "include_per_module": attr.bool(default = True), @@ -280,6 +288,7 @@ topt_go_bazel_metadata = rule( "embeds": attr.label_list(aspects = [_importpath_aspect]), "explicit_importpath": attr.string(), "fallback_importpath": attr.string(), + "module_group_names": attr.string_list(), "module_groups": attr.label_list(), "include_per_module": attr.bool(default = True), "module_label_override": attr.string(), diff --git a/modules/go/topt_go_orchestrion.bzl b/modules/go/topt_go_orchestrion.bzl index bf33ce3e..a58363a4 100644 --- a/modules/go/topt_go_orchestrion.bzl +++ b/modules/go/topt_go_orchestrion.bzl @@ -6,13 +6,14 @@ """Internal Orchestrion wrapper rule for Go tests.""" +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") + _BAZEL_TARGET_METADATA_OUTPUT = "bazel_target_metadata.json" _ORCHESTRION_MODE_GENERAL = "general" _ORCHESTRION_MODE_TEST_OPTIMIZATION = "test_optimization" def _orch_transition_impl(_settings, _attr): return { - "@rules_go//go/private/orchestrion:enabled": True, "@rules_go//go/private/orchestrion:mode": _attr.orchestrion_mode, } @@ -21,10 +22,7 @@ orch_transition_impl_for_tests = _orch_transition_impl orch_transition = transition( implementation = _orch_transition_impl, inputs = [], - outputs = [ - "@rules_go//go/private/orchestrion:enabled", - "@rules_go//go/private/orchestrion:mode", - ], + outputs = ["@rules_go//go/private/orchestrion:mode"], ) def _first_target(dep): @@ -54,14 +52,17 @@ def _wrapped_actual_output_name(label_name, executable_basename): """Return the wrapper-owned sibling executable name used at test runtime.""" return label_name + "__wrapped_" + executable_basename -def _unix_wrapper_content(actual_filename): +def _wrapped_metadata_output_name(label_name, metadata_basename): + """Return the wrapper-owned sibling metadata name used at test runtime.""" + return label_name + "__wrapped_" + metadata_basename + +def _unix_wrapper_content(actual_filename, metadata_filename): """Render the Unix launcher used by the Orchestrion wrapper target.""" return """#!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "$0")" && pwd)" actual="$script_dir/%s" -metadata_basename="${DD_TEST_OPTIMIZATION_BAZEL_TARGET_METADATA_BASENAME:-}" undeclared_dir="${TEST_UNDECLARED_OUTPUTS_DIR:-}" if [[ ! -x "$actual" ]]; then @@ -69,23 +70,22 @@ if [[ ! -x "$actual" ]]; then exit 1 fi -if [[ -n "$metadata_basename" && -n "$undeclared_dir" ]]; then - metadata_source="$script_dir/$metadata_basename" +if [[ -n "$undeclared_dir" ]]; then + metadata_source="$script_dir/%s" if [[ -f "$metadata_source" ]]; then cp "$metadata_source" "$undeclared_dir/%s" fi fi "$actual" "$@" -""" % (actual_filename, _BAZEL_TARGET_METADATA_OUTPUT) +""" % (actual_filename, metadata_filename, _BAZEL_TARGET_METADATA_OUTPUT) -def _windows_wrapper_content(actual_filename): +def _windows_wrapper_content(actual_filename, metadata_filename): """Render the Windows launcher used by the Orchestrion wrapper target.""" return """@echo off setlocal set "SCRIPT_DIR=%%~dp0" set "ACTUAL=%%SCRIPT_DIR%%%s" -set "META_BASENAME=%%DD_TEST_OPTIMIZATION_BAZEL_TARGET_METADATA_BASENAME%%" set "UNDECLARED_DIR=%%TEST_UNDECLARED_OUTPUTS_DIR%%" if not exist "%%ACTUAL%%" ( @@ -93,36 +93,48 @@ if not exist "%%ACTUAL%%" ( exit /b 1 ) -if not "%%META_BASENAME%%"=="" if not "%%UNDECLARED_DIR%%"=="" ( - set "META_SOURCE=%%SCRIPT_DIR%%%%META_BASENAME%%" - if exist "%%META_SOURCE%%" copy /Y "%%META_SOURCE%%" "%%UNDECLARED_DIR%%\\%s" >nul +if not "%%UNDECLARED_DIR%%"=="" ( + if exist "%%SCRIPT_DIR%%%s" copy /Y "%%SCRIPT_DIR%%%s" "%%UNDECLARED_DIR%%\\%s" >nul ) "%%ACTUAL%%" %%* +exit /b %%ERRORLEVEL%% """ % ( actual_filename.replace("/", "\\"), + metadata_filename.replace("/", "\\"), + metadata_filename.replace("/", "\\"), _BAZEL_TARGET_METADATA_OUTPUT, ) def _orch_go_test_impl(ctx): + if ctx.attr.test_optimization_enabled and not ctx.attr._orchestrion_enabled[BuildSettingInfo].value: + fail( + "orch_go_test: Test Optimization metadata is enabled but Orchestrion is disabled; " + + "run with --config=test-optimization. Consumers upgrading an existing setup should " + + "rerun dd_topt_go_bootstrap with --write-bazelrc before building tests.", + ) + dep_exe, dep_runfiles = _dep_exec_and_runfiles(ctx.attr.actual) dep_run_environment = _dep_run_environment_info(ctx.attr.actual) + metadata_file = ctx.file.metadata is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]) out = ctx.actions.declare_file(_select_wrapper_output_name(ctx.label.name, dep_exe.basename, is_windows)) actual_out = ctx.actions.declare_file(_wrapped_actual_output_name(ctx.label.name, dep_exe.basename), sibling = out) + metadata_out = ctx.actions.declare_file(_wrapped_metadata_output_name(ctx.label.name, metadata_file.basename), sibling = out) - # Materialize the raw test binary next to the wrapper so the launcher does - # not have to guess which configuration-specific execroot path Bazel chose. + # Materialize transitioned inputs next to the wrapper so the launcher does + # not have to guess which configuration-specific execroot paths Bazel chose. ctx.actions.symlink(output = actual_out, target_file = dep_exe) + ctx.actions.symlink(output = metadata_out, target_file = metadata_file) ctx.actions.write( output = out, - content = _windows_wrapper_content(actual_out.basename) if is_windows else _unix_wrapper_content(actual_out.basename), + content = _windows_wrapper_content(actual_out.basename, metadata_out.basename) if is_windows else _unix_wrapper_content(actual_out.basename, metadata_out.basename), is_executable = True, ) providers = [DefaultInfo( - files = depset([out, actual_out]), - runfiles = dep_runfiles.merge(ctx.runfiles(files = [actual_out])), + files = depset([out, actual_out, metadata_out]), + runfiles = dep_runfiles.merge(ctx.runfiles(files = [actual_out, metadata_out])), executable = out, )] if dep_run_environment: @@ -138,6 +150,12 @@ orch_go_test = rule( cfg = orch_transition, doc = "The underlying raw go_test target built with Orchestrion enabled.", ), + "metadata": attr.label( + mandatory = True, + allow_single_file = True, + cfg = orch_transition, + doc = "Bazel-owned target metadata copied next to emitted test payloads.", + ), "orchestrion_mode": attr.string( default = _ORCHESTRION_MODE_GENERAL, values = [ @@ -146,9 +164,17 @@ orch_go_test = rule( ], doc = "Internal Orchestrion mode forwarded to the raw go_test target.", ), + "test_optimization_enabled": attr.bool( + default = False, + doc = "Whether the selected generated metadata repository is enabled.", + ), "_allowlist_function_transition": attr.label( default = "@bazel_tools//tools/allowlists/function_transition_allowlist", ), + "_orchestrion_enabled": attr.label( + default = "@rules_go//go/private/orchestrion:enabled", + providers = [BuildSettingInfo], + ), "_windows_constraint": attr.label(default = "@platforms//os:windows"), }, test = True, diff --git a/modules/go/topt_go_orchestrion_repository.bzl b/modules/go/topt_go_orchestrion_repository.bzl new file mode 100644 index 00000000..b0f10ec1 --- /dev/null +++ b/modules/go/topt_go_orchestrion_repository.bzl @@ -0,0 +1,73 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under +# the Apache 2.0 License. +# +# This product includes software developed at Datadog +# (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. + +"""Thin WORKSPACE wrapper around rules_go's public Orchestrion repository API.""" + +load( + "@rules_go//go:orchestrion_workspace.bzl", + "go_orchestrion_tool_repo", +) + +_DEFAULT_TOOL_REPO_NAME = "rules_go_orchestrion_tool" + +def _configured_version_modes(dd_trace_go_version, dd_trace_go_versions, dd_trace_go_pin_files): + return len([ + value + for value in [ + dd_trace_go_version, + dd_trace_go_versions, + dd_trace_go_pin_files, + ] + if value + ]) + +def _build_orchestrion_repo_call( + dd_trace_go_version = "", + dd_trace_go_versions = {}, + dd_trace_go_pin_files = [], + version = "", + go_sdk_root = "", + go_sdk_version = "", + log_timing = False): + """Build the fixed-name public rules_go repository call.""" + if _configured_version_modes(dd_trace_go_version, dd_trace_go_versions, dd_trace_go_pin_files) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") + + call = { + "name": _DEFAULT_TOOL_REPO_NAME, + "dd_trace_go_version": dd_trace_go_version, + "dd_trace_go_versions": dd_trace_go_versions, + "dd_trace_go_pin_files": dd_trace_go_pin_files, + "enabled_by_env": True, + "version": version, + "log_timing": log_timing, + } + if go_sdk_root: + call["go_sdk_root"] = go_sdk_root + if go_sdk_version: + call["go_sdk_version"] = go_sdk_version + return call + +def dd_topt_go_orchestrion_tool_repo( + dd_trace_go_version = "", + dd_trace_go_versions = {}, + dd_trace_go_pin_files = [], + version = "", + go_sdk_root = "", + go_sdk_version = "", + log_timing = False): + """Declare the real Orchestrion repository through rules_go's public API.""" + go_orchestrion_tool_repo(**_build_orchestrion_repo_call( + dd_trace_go_version = dd_trace_go_version, + dd_trace_go_versions = dd_trace_go_versions, + dd_trace_go_pin_files = dd_trace_go_pin_files, + version = version, + go_sdk_root = go_sdk_root, + go_sdk_version = go_sdk_version, + log_timing = log_timing, + )) + +build_orchestrion_repo_call_for_tests = _build_orchestrion_repo_call diff --git a/modules/go/topt_go_test.bzl b/modules/go/topt_go_test.bzl index 069c153f..e4f5aea9 100644 --- a/modules/go/topt_go_test.bzl +++ b/modules/go/topt_go_test.bzl @@ -25,7 +25,8 @@ Notes: test_optimization_uploader.bzl) and run it via `bazel run` after tests. Macro design constraints: -- This macro creates a hidden raw `go_test` plus a public wrapper target. +- Enabled exports create a hidden raw `go_test` plus a public wrapper target. + Disabled exports create only the caller's public raw `go_test`. - It does not create upload targets and does not alter workspace-level upload behavior. - Runtime behavior must remain hermetic: tests write payloads to @@ -65,6 +66,10 @@ load( "merge_optional_env_defaults", "merge_user_env", "normalize_user_data", + "resolve_files_label", + "resolve_manifest_label", + "resolve_module_group_names", + "resolve_module_labels", "resolve_topt_service_key", "service_mapping_entries", "split_test_wrapper_kwargs", @@ -269,8 +274,9 @@ def dd_topt_go_test( **kwargs): """Define a Go test with Datadog Test Optimization support. - This macro creates a hidden raw go_test target plus a public - Orchestrion-enabled wrapper target. Payloads are written to Bazel's + For an enabled export, this macro creates a hidden raw go_test target plus a + public Orchestrion-enabled wrapper target. For a disabled export, it creates + only the caller's public raw go_test. Enabled payloads are written to Bazel's TEST_UNDECLARED_OUTPUTS_DIR and collected in bazel-testlogs//test.outputs/. After running tests, use a single workspace-level uploader target to upload @@ -326,13 +332,8 @@ def dd_topt_go_test( if topt_data == None or not _is_dict(topt_data): fail_with_prefix("dd_topt_go_test", "topt_data is required and must be the dict from @//:export.bzl (single-service) or the aggregator mapping") _validate_orchestrion_mode(orchestrion_mode) - test_binary_linker_optimization_requested = ( - orchestrion_mode == _ORCHESTRION_MODE_TEST_OPTIMIZATION and - enable_test_binary_linker_optimization - ) - test_binary_linker_optimization_applied = ( - _TEST_BINARY_LINKER_OPTIMIZATION_APPLIED if test_binary_linker_optimization_requested else False - ) + if go_test_rule == None: + fail_with_prefix("dd_topt_go_test", "go_test_rule override cannot be None") # Support both shapes: # 1) Single-service dict with keys: repo_name, labels, set, runtimes @@ -352,6 +353,20 @@ def dd_topt_go_test( selected_key = _resolve_topt_service_key(service_entries, topt_service) _svc = service_entries[selected_key] + if not bool(_svc.get("enabled", True)): + go_test_rule( + name = name, + **kwargs + ) + return + + test_binary_linker_optimization_requested = ( + orchestrion_mode == _ORCHESTRION_MODE_TEST_OPTIMIZATION and + enable_test_binary_linker_optimization + ) + test_binary_linker_optimization_applied = ( + _TEST_BINARY_LINKER_OPTIMIZATION_APPLIED if test_binary_linker_optimization_requested else False + ) wrapper_kwargs, raw_passthrough = split_test_wrapper_kwargs(kwargs) # ------------------------------------------------------------------ @@ -412,7 +427,7 @@ def dd_topt_go_test( # Build labels for files/context based on (possibly derived) sync_repo_name. # These labels remain stable public contracts of the generated sync repo. - files_label = "@%s//:test_optimization_files" % sync_repo_name + files_label = resolve_files_label(_svc, sync_repo_name, macro_name = "dd_topt_go_test") # ------------------------------------------------------------------ # Phase 4: Build environment and selector inputs for analysis-time mapping. @@ -432,7 +447,12 @@ def dd_topt_go_test( # Build the list of per-module groups once (if any were exported) # Use exported sanitized labels directly to avoid re-deriving naming policy # in the macro and drifting from sync-side label generation. - module_labels = _build_module_labels(sync_repo_name, _svc.get("labels")) + module_labels = resolve_module_labels(_svc, sync_repo_name, macro_name = "dd_topt_go_test") + module_group_names = resolve_module_group_names( + _svc, + module_labels, + macro_name = "dd_topt_go_test", + ) # Fallback importpath when providers are unavailable: go_module_path + Bazel package pkg_path = native.package_name() @@ -463,6 +483,7 @@ def dd_topt_go_test( explicit_importpath = explicit_importpath, fallback_importpath = fallback_importpath, full_files = files_label, + module_group_names = module_group_names, module_groups = module_labels, include_per_module = include_per_module_files, module_label_override = module_label_override, @@ -479,6 +500,7 @@ def dd_topt_go_test( embeds = embed_labels, explicit_importpath = explicit_importpath or "", fallback_importpath = fallback_importpath or "", + module_group_names = module_group_names, module_groups = module_labels, include_per_module = include_per_module_files, module_label_override = module_label_override or "", @@ -550,16 +572,16 @@ def dd_topt_go_test( # manifest_path is emitted by sync metadata and may include slashes. # These paths are rooted at the sync repo package, so target syntax remains # @repo//: (for example @test_optimization_data//:.testoptimization/manifest.txt). - manifest_path = _svc.get("manifest_path") or ".testoptimization/manifest.txt" - manifest_label = "@%s//:%s" % (sync_repo_name, manifest_path) + manifest_label = resolve_manifest_label(_svc, sync_repo_name, macro_name = "dd_topt_go_test") data = _append_data_dependencies(data, [manifest_label]) required_env = { "DD_TEST_OPTIMIZATION_MANIFEST_FILE": "$(rlocationpath %s)" % manifest_label, # Signal to the library that payloads should be written to files # (TEST_UNDECLARED_OUTPUTS_DIR) regardless of caller input. "DD_TEST_OPTIMIZATION_PAYLOADS_IN_FILES": "true", - # The Orchestrion wrapper copies this file into test.outputs so the - # uploader can enrich payloads with target-specific Bazel metadata. + # Keep the target metadata basename available to the test runtime. The + # wrapper also receives the generated target directly and copies it + # into test.outputs for uploader enrichment. "DD_TEST_OPTIMIZATION_BAZEL_TARGET_METADATA_BASENAME": metadata_name + ".json", } if ci_visibility_enabled: @@ -570,9 +592,6 @@ def dd_topt_go_test( macro_name = "dd_topt_go_test", ) - if go_test_rule == None: - fail_with_prefix("dd_topt_go_test", "go_test_rule override cannot be None") - # Use the repository root when staged sources need repo-relative lookup. # Otherwise keep the package directory default to preserve existing tests. if "rundir" not in kwargs: @@ -602,6 +621,8 @@ def dd_topt_go_test( orch_go_test( name = name, actual = ":" + raw_name, + metadata = ":" + metadata_name, orchestrion_mode = orchestrion_mode, + test_optimization_enabled = bool(_svc.get("enabled", True)), **wrapper_kwargs ) diff --git a/modules/go/topt_go_workspace.bzl b/modules/go/topt_go_workspace.bzl new file mode 100644 index 00000000..49813080 --- /dev/null +++ b/modules/go/topt_go_workspace.bzl @@ -0,0 +1,139 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under +# the Apache 2.0 License. +# +# This product includes software developed at Datadog +# (https://www.datadoghq.com/) Copyright 2025-Present Datadog, Inc. + +"""WORKSPACE metadata bootstrap for Go consumers.""" + +load( + "@datadog-rules-test-optimization//tools/core:common_utils.bzl", + "dedup_keys", + "sanitize_label_fragment", +) +load( + "@datadog-rules-test-optimization//tools/core:test_optimization_multi_sync.bzl", + "test_optimization_multi_aggregate", +) +load( + "@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl", + "test_optimization_sync", +) + +def _service_keys(services): + return dedup_keys([sanitize_label_fragment(service) for service in services]) + +def _build_go_workspace_sync_specs( + name, + runtime_version, + module_path, + service = None, + services = [], + enabled = True, + enabled_by_env = True, + runtime_arch = "", + out_dir = "", + http_connect_timeout_seconds = -1, + http_max_time_seconds = -1, + http_retry_attempts = -1, + http_retry_delay_seconds = -1, + http_execute_timeout_buffer_seconds = -1, + known_tests = True, + test_management = True, + flaky_tests = True, + require_git_metadata = False, + debug = False): + """Build metadata sync calls and the optional aggregate call.""" + if service and services: + fail("set either service or services, not both") + if not service and not services: + fail("one of service or services is required") + + service_values = [service] if service else services + keys = [] if service else _service_keys(services) + repo_names = [name] if service else ["%s_%s" % (name, key) for key in keys] + sync_specs = [] + for i in range(len(service_values)): + sync_specs.append({ + "name": repo_names[i], + "repo_name": repo_names[i], + "service": service_values[i], + "runtime_name": "go", + "runtime_version": runtime_version, + "runtime_arch": runtime_arch, + "runtime_module_path": module_path, + "out_dir": out_dir, + "enabled": enabled, + "enabled_by_env": enabled_by_env, + "http_connect_timeout_seconds": http_connect_timeout_seconds, + "http_max_time_seconds": http_max_time_seconds, + "http_retry_attempts": http_retry_attempts, + "http_retry_delay_seconds": http_retry_delay_seconds, + "http_execute_timeout_buffer_seconds": http_execute_timeout_buffer_seconds, + "known_tests": known_tests, + "test_management": test_management, + "flaky_tests": flaky_tests, + "require_git_metadata": require_git_metadata, + "debug": debug, + }) + aggregate_spec = None + if not service: + aggregate_spec = { + "name": name, + "service_keys": keys, + "repo_names": repo_names, + "debug": debug, + } + return { + "sync_specs": sync_specs, + "aggregate_spec": aggregate_spec, + } + +build_go_workspace_sync_specs_for_tests = _build_go_workspace_sync_specs + +def dd_topt_go_workspace_sync_repositories( + name, + runtime_version, + module_path = "", + service = None, + services = [], + enabled = True, + enabled_by_env = True, + runtime_arch = "", + out_dir = "", + http_connect_timeout_seconds = -1, + http_max_time_seconds = -1, + http_retry_attempts = -1, + http_retry_delay_seconds = -1, + http_execute_timeout_buffer_seconds = -1, + known_tests = True, + test_management = True, + flaky_tests = True, + require_git_metadata = False, + debug = False): + specs = _build_go_workspace_sync_specs( + name = name, + runtime_version = runtime_version, + module_path = module_path, + service = service, + services = services, + enabled = enabled, + enabled_by_env = enabled_by_env, + runtime_arch = runtime_arch, + out_dir = out_dir, + http_connect_timeout_seconds = http_connect_timeout_seconds, + http_max_time_seconds = http_max_time_seconds, + http_retry_attempts = http_retry_attempts, + http_retry_delay_seconds = http_retry_delay_seconds, + http_execute_timeout_buffer_seconds = http_execute_timeout_buffer_seconds, + known_tests = known_tests, + test_management = test_management, + flaky_tests = flaky_tests, + require_git_metadata = require_git_metadata, + debug = debug, + ) + for sync_spec in specs["sync_specs"]: + test_optimization_sync(**sync_spec) + aggregate_spec = specs["aggregate_spec"] + if aggregate_spec: + test_optimization_multi_aggregate(**aggregate_spec) diff --git a/modules/java/MODULE.bazel.lock b/modules/java/MODULE.bazel.lock index c602cdda..6ed3a69d 100644 --- a/modules/java/MODULE.bazel.lock +++ b/modules/java/MODULE.bazel.lock @@ -140,8 +140,8 @@ "moduleExtensions": { "//tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "zC3aEdxLSUhPV6iwgCNk7hQr+1eO+rAQ5znCfGieX3g=", - "usagesDigest": "WUBevKMAOfvH9naco2wxzvnDbEMGelUuwm0wvsegGYc=", + "bzlTransitiveDigest": "8Z0dqG8n5A2E4sAbWxvij+vncAodaOVqDuvzF/sm6wE=", + "usagesDigest": "6NwGJ7RyhJOwtM7+EPNpuNyawB974PzmTqQARABaogw=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/modules/nodejs/MODULE.bazel.lock b/modules/nodejs/MODULE.bazel.lock index ce7dabff..fb767431 100644 --- a/modules/nodejs/MODULE.bazel.lock +++ b/modules/nodejs/MODULE.bazel.lock @@ -140,8 +140,8 @@ "moduleExtensions": { "//tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "zC3aEdxLSUhPV6iwgCNk7hQr+1eO+rAQ5znCfGieX3g=", - "usagesDigest": "irePOqLrnrDswqq6uNfKWfqwmNWA2wVLir9YmhV+HBw=", + "bzlTransitiveDigest": "8Z0dqG8n5A2E4sAbWxvij+vncAodaOVqDuvzF/sm6wE=", + "usagesDigest": "lqQSWgxAEY9YXf27tmAuYKvioDk6WYdJzSpQkWFpeTE=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/modules/python/MODULE.bazel b/modules/python/MODULE.bazel index e3740a5a..297c1ef7 100644 --- a/modules/python/MODULE.bazel +++ b/modules/python/MODULE.bazel @@ -22,6 +22,12 @@ example_stub_repo = use_extension( ) example_stub_repo.example_stub_repo( name = "test_optimization_data", + labels = [ + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_stub_tests", + "example_python_tests", + ], service_keys = [ "py_service", "ruby_service", diff --git a/modules/python/MODULE.bazel.lock b/modules/python/MODULE.bazel.lock index 3b4da633..ef5fb12a 100644 --- a/modules/python/MODULE.bazel.lock +++ b/modules/python/MODULE.bazel.lock @@ -148,8 +148,8 @@ "moduleExtensions": { "//tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "zC3aEdxLSUhPV6iwgCNk7hQr+1eO+rAQ5znCfGieX3g=", - "usagesDigest": "Njje2Mz52TKjSVkVkgxLXaZa/9f/0VBc5vCkeOpAhDE=", + "bzlTransitiveDigest": "NHlcGDHChvBcvl50+UhxkmlFTJUEj9A2ARhtKx4kY+0=", + "usagesDigest": "UDiAhPtQ9KsYnDQ8zl34syCpr+iVmZjdd5stUk67Umk=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -157,10 +157,16 @@ "test_optimization_data": { "repoRuleId": "@@datadog-rules-test-optimization+//tools/tests:example_stub_repo.bzl%example_stub_repo", "attributes": { + "enabled": true, "go_module_included": false, "go_module_path": "example.com/stub", "go_sanitized_module_path": "example_com_stub", - "labels": [], + "labels": [ + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_stub_tests", + "example_python_tests" + ], "out_dir": ".testoptimization", "repo_alias": "test_optimization_data", "service_name": "stub-service", diff --git a/modules/python/tests/BUILD.bazel b/modules/python/tests/BUILD.bazel index 54b30b41..75a79515 100644 --- a/modules/python/tests/BUILD.bazel +++ b/modules/python/tests/BUILD.bazel @@ -32,10 +32,19 @@ load( "py_macro_consumer_runner_with_main_target", "py_macro_default_rule_detection_target_rule", "py_macro_default_rule_detection_test", + "py_macro_disabled_consumer_runner_target", + "py_macro_disabled_consumer_runner_test", + "py_macro_disabled_managed_pytest_target", + "py_macro_disabled_managed_pytest_test", + "py_macro_dynamic_manifest_payloads_test", + "py_macro_dynamic_manifest_target", + "py_macro_dynamic_manifest_wiring_test", "py_macro_env_none_target", "py_macro_env_none_wiring_test", "py_macro_explicit_service_target", "py_macro_explicit_service_wiring_test", + "py_macro_fallback_payloads_target", + "py_macro_fallback_payloads_test", "py_macro_invalid_runner_mode_failure_test", "py_macro_invalid_runner_mode_target_rule", "py_macro_managed_pytest_kwargs_target", @@ -64,6 +73,7 @@ load( "selector_deps_precedence_test", "selector_explicit_miss_failure_target", "selector_explicit_miss_failure_test", + "selector_explicit_namespaced_test", "selector_explicit_precedence_target", "selector_explicit_precedence_test", "selector_fallback_target", @@ -81,6 +91,8 @@ load( "selector_override_target", "selector_override_test", "selector_payload_fixture_targets", + "selector_prefixed_fallback_target", + "selector_prefixed_fallback_test", ) load( ":test_selection_utils.bzl", @@ -93,11 +105,13 @@ load( "build_module_labels_unsanitized_entry_failure_test", "build_module_labels_unsanitized_entry_target_rule", "build_module_labels_valid_test", + "build_python_fallback_identifier_test", "normalize_python_identifier_edge_cases_test", "normalize_user_data_handles_none_test", "normalize_user_data_invalid_type_failure_test", "normalize_user_data_invalid_type_target_rule", "py_stub_includes_manifest_in_files_test", + "resolve_python_selector_inputs_test", "resolve_topt_service_key_prefers_exact_then_sanitized_test", "select_module_group_name_test", "service_mapping_entries_filters_non_service_test", @@ -149,6 +163,18 @@ build_module_labels_valid_test( timeout = "short", ) +build_python_fallback_identifier_test( + name = "build_python_fallback_identifier_test", + size = "small", + timeout = "short", +) + +resolve_python_selector_inputs_test( + name = "resolve_python_selector_inputs_test", + size = "small", + timeout = "short", +) + py_stub_includes_manifest_in_files_test( name = "py_stub_includes_manifest_in_files_test", size = "small", @@ -177,6 +203,18 @@ selector_explicit_precedence_test( target_under_test = ":selector_explicit_precedence_target", ) +selector_explicit_precedence_target( + name = "selector_explicit_namespaced_target", + module_group_names = ["module_example_python_explicit_pkg"], + module_groups = [":module_manifest_context_example_python_explicit_pkg"], + tags = ["manual"], +) + +selector_explicit_namespaced_test( + name = "selector_explicit_namespaced_test", + target_under_test = ":selector_explicit_namespaced_target", +) + selector_imports_precedence_target( name = "selector_imports_precedence_target", tags = ["manual"], @@ -227,6 +265,16 @@ selector_no_match_fallback_test( target_under_test = ":selector_no_match_fallback_target", ) +selector_prefixed_fallback_target( + name = "selector_prefixed_fallback_target", + tags = ["manual"], +) + +selector_prefixed_fallback_test( + name = "selector_prefixed_fallback_test", + target_under_test = ":selector_prefixed_fallback_target", +) + selector_include_disabled_target( name = "selector_include_disabled_target", tags = ["manual"], @@ -372,6 +420,26 @@ py_macro_managed_pytest_kwargs_test( target_under_test = ":py_macro_managed_pytest_kwargs_target__raw_python_test", ) +py_macro_disabled_consumer_runner_target( + name = "py_macro_disabled_consumer_runner_target", + tags = ["consumer_tag"], +) + +py_macro_disabled_consumer_runner_test( + name = "py_macro_disabled_consumer_runner_test", + target_under_test = ":py_macro_disabled_consumer_runner_target", +) + +py_macro_disabled_managed_pytest_target( + name = "py_macro_disabled_managed_pytest_target", + tags = ["consumer_tag"], +) + +py_macro_disabled_managed_pytest_test( + name = "py_macro_disabled_managed_pytest_test", + target_under_test = ":py_macro_disabled_managed_pytest_target", +) + py_macro_consumer_runner_no_rule_no_main_target_rule( name = "py_macro_consumer_runner_no_rule_no_main_target", tags = ["manual"], @@ -439,6 +507,16 @@ py_macro_public_wrapper_test( target_under_test = ":py_macro_single_service_target", ) +py_macro_fallback_payloads_target( + name = "py_macro_fallback_payloads_target", + tags = ["manual"], +) + +py_macro_fallback_payloads_test( + name = "py_macro_fallback_payloads_test", + target_under_test = ":py_macro_fallback_payloads_target_topt_payloads", +) + py_macro_multi_service_target( name = "py_macro_multi_service_target", tags = ["manual"], @@ -449,6 +527,21 @@ py_macro_multi_service_wiring_test( target_under_test = ":py_macro_multi_service_target__raw_python_test", ) +py_macro_dynamic_manifest_target( + name = "py_macro_dynamic_manifest_target", + tags = ["manual"], +) + +py_macro_dynamic_manifest_wiring_test( + name = "py_macro_dynamic_manifest_wiring_test", + target_under_test = ":py_macro_dynamic_manifest_target__raw_python_test", +) + +py_macro_dynamic_manifest_payloads_test( + name = "py_macro_dynamic_manifest_payloads_test", + target_under_test = ":py_macro_dynamic_manifest_target_topt_payloads", +) + py_macro_env_none_target( name = "py_macro_env_none_target", tags = ["manual"], @@ -567,6 +660,7 @@ test_suite( ":build_module_labels_invalid_shape_failure_test", ":build_module_labels_unsanitized_entry_failure_test", ":build_module_labels_valid_test", + ":build_python_fallback_identifier_test", ":normalize_python_identifier_edge_cases_test", ":normalize_user_data_handles_none_test", ":normalize_user_data_invalid_type_failure_test", @@ -583,14 +677,20 @@ test_suite( ":py_macro_consumer_runner_validation_helpers_test", ":py_macro_consumer_runner_wiring_test", ":py_macro_default_rule_detection_test", + ":py_macro_disabled_consumer_runner_test", + ":py_macro_disabled_managed_pytest_test", + ":py_macro_dynamic_manifest_payloads_test", + ":py_macro_dynamic_manifest_wiring_test", ":py_macro_env_none_wiring_test", ":py_macro_explicit_service_wiring_test", + ":py_macro_fallback_payloads_test", ":py_macro_invalid_runner_mode_failure_test", ":py_macro_managed_pytest_kwargs_test", ":py_macro_multi_service_wiring_test", ":py_macro_select_inputs_wiring_test", ":py_macro_single_service_wiring_test", ":py_stub_includes_manifest_in_files_test", + ":resolve_python_selector_inputs_test", ":resolve_topt_service_key_missing_failure_test", ":resolve_topt_service_key_prefers_exact_then_sanitized_test", ":resolve_topt_service_key_unknown_failure_test", @@ -600,6 +700,7 @@ test_suite( ":selector_attr_precedence_test", ":selector_deps_precedence_test", ":selector_explicit_miss_failure_test", + ":selector_explicit_namespaced_test", ":selector_explicit_precedence_test", ":selector_fallback_test", ":selector_imports_precedence_test", @@ -608,6 +709,7 @@ test_suite( ":selector_omits_flaky_tests_test", ":selector_override_miss_failure_test", ":selector_override_test", + ":selector_prefixed_fallback_test", ":service_mapping_entries_filters_non_service_test", ], ) diff --git a/modules/python/tests/test_macro.bzl b/modules/python/tests/test_macro.bzl index db065961..d31eb3bc 100644 --- a/modules/python/tests/test_macro.bzl +++ b/modules/python/tests/test_macro.bzl @@ -257,7 +257,11 @@ def _single_service_topt_data(): "repo_name": "test_optimization_data", "service_name": "py-service", "manifest_path": ".testoptimization/manifest.txt", - "labels": [], + "labels": [ + "example_python_modules_python_tests", + "example_python_pkg", + "example_python_tests", + ], "set": {}, "runtimes": { "go": { @@ -278,6 +282,11 @@ def _single_service_topt_data(): }, } +def _disabled_single_service_topt_data(): + disabled = dict(_single_service_topt_data()) + disabled["enabled"] = False + return disabled + def _multi_service_topt_data(): selected = _single_service_topt_data() not_selected = dict(selected) @@ -289,6 +298,20 @@ def _multi_service_topt_data(): "_meta": {"description": "non-service entry should be ignored"}, } +def _dynamic_manifest_topt_data(): + """Model one target entry exported by the manifest aggregate repository.""" + data = _single_service_topt_data() + data.update({ + "repo_name": "virtual_dynamic_repo_that_must_not_resolve", + "service_name": "dynamic-python-service", + "files_label": ":full_payload", + "manifest_label": ":test_macro.bzl", + "module_labels": [":module_example_python_explicit_pkg"], + "labels": ["ignored_static_label_that_must_not_resolve"], + "manifest_path": "ignored/static/manifest.txt", + }) + return data + def py_macro_single_service_target(name, tags = None): dd_topt_py_test( name = name, @@ -303,6 +326,16 @@ def py_macro_single_service_target(name, tags = None): tags = tags, ) +def py_macro_dynamic_manifest_target(name, tags = None): + """Target under test for explicit labels from one dynamic manifest entry.""" + dd_topt_py_test( + name = name, + topt_data = _dynamic_manifest_topt_data(), + py_test_rule = _py_test_capture_rule, + importpath = "example/python/explicit/pkg", + tags = tags, + ) + def py_macro_multi_service_target(name, tags = None): dd_topt_py_test( name = name, @@ -322,6 +355,15 @@ def py_macro_env_none_target(name, tags = None): tags = tags, ) +def py_macro_fallback_payloads_target(name, tags = None): + """Exercise package-derived fallback against the shared dev stub export.""" + dd_topt_py_test( + name = name, + topt_data = _single_service_topt_data(), + py_test_rule = _py_test_capture_rule, + tags = tags, + ) + def py_macro_explicit_service_target(name, tags = None): dd_topt_py_test( name = name, @@ -479,6 +521,36 @@ def py_macro_managed_pytest_kwargs_target(name, tags = None): tags = tags, ) +def py_macro_disabled_consumer_runner_target(name, tags = None): + """Disabled sync preserves the consumer runner without instrumentation.""" + dd_topt_py_test( + name = name, + topt_data = _disabled_single_service_topt_data(), + py_test_rule = _py_test_kwargs_capture_macro, + runner_mode = "consumer_runner", + srcs = ["consumer_runner_main.py"], + data = [":test_macro.bzl"], + dd_requirements = ["pytest"], + env = select({ + "//conditions:default": { + "CUSTOM_ENV": "preserved", + "DD_CIVISIBILITY_ENABLED": "true", + }, + }), + args = ["-k", "consumer"], + tags = tags, + ) + +def py_macro_disabled_managed_pytest_target(name, tags = None): + """Disabled sync keeps the managed pytest runner but omits instrumentation.""" + dd_topt_py_test( + name = name, + topt_data = _disabled_single_service_topt_data(), + py_test_rule = _py_test_kwargs_capture_macro, + srcs = ["consumer_runner_main.py"], + tags = tags, + ) + def _py_macro_consumer_runner_no_rule_no_main_target_impl(_ctx): dd_topt_py_test( name = "should_not_be_created", @@ -669,6 +741,41 @@ def _py_macro_managed_pytest_kwargs_test_impl(ctx): ) return analysistest.end(env) +def _assert_no_test_optimization_wiring(env, captured): + asserts.equals(env, "false", captured.env.get("DD_CIVISIBILITY_ENABLED")) + asserts.equals(env, None, captured.env.get("DD_SERVICE")) + asserts.equals(env, None, captured.env.get("DD_TEST_OPTIMIZATION_MANIFEST_FILE")) + asserts.equals(env, None, captured.env.get("DD_TEST_OPTIMIZATION_PAYLOADS_IN_FILES")) + asserts.equals(env, None, captured.env.get("DD_TEST_OPTIMIZATION_BAZEL_TARGET_METADATA_BASENAME")) + for label in captured.data_labels: + asserts.false(env, "topt_payloads" in label) + asserts.false(env, ".testoptimization" in label) + +def _py_macro_disabled_consumer_runner_test_impl(ctx): + env = analysistest.begin(ctx) + captured = analysistest.target_under_test(env)[ToptPyKwargsCaptureInfo] + _assert_no_test_optimization_wiring(env, captured) + asserts.equals(env, "preserved", captured.env.get("CUSTOM_ENV")) + asserts.true(env, captured.saw_args) + asserts.false(env, captured.saw_imports) + asserts.false(env, captured.saw_main) + asserts.false(env, captured.saw_run_pytest) + asserts.equals(env, ["pytest"], captured.dd_requirements) + asserts.true(env, _has_label_suffix(captured.data_labels, ":test_macro.bzl")) + asserts.false(env, "manual" in captured.tags) + return analysistest.end(env) + +def _py_macro_disabled_managed_pytest_test_impl(ctx): + env = analysistest.begin(ctx) + captured = analysistest.target_under_test(env)[ToptPyKwargsCaptureInfo] + _assert_no_test_optimization_wiring(env, captured) + asserts.true(env, captured.saw_args) + asserts.true(env, captured.saw_imports) + asserts.true(env, captured.saw_main) + asserts.true(env, captured.saw_run_pytest) + asserts.false(env, "manual" in captured.tags) + return analysistest.end(env) + def _py_macro_consumer_runner_no_rule_no_main_failure_test_impl(ctx): env = analysistest.begin(ctx) asserts.expect_failure(env, "requires a consumer-owned Python test runner") @@ -724,6 +831,12 @@ py_macro_consumer_runner_select_env_test = analysistest.make( py_macro_managed_pytest_kwargs_test = analysistest.make( _py_macro_managed_pytest_kwargs_test_impl, ) +py_macro_disabled_consumer_runner_test = analysistest.make( + _py_macro_disabled_consumer_runner_test_impl, +) +py_macro_disabled_managed_pytest_test = analysistest.make( + _py_macro_disabled_managed_pytest_test_impl, +) py_macro_consumer_runner_no_rule_no_main_failure_test = analysistest.make( _py_macro_consumer_runner_no_rule_no_main_failure_test_impl, expect_failure = True, @@ -791,6 +904,25 @@ def _py_macro_multi_service_wiring_test_impl(ctx): asserts.equals(env, ["example/python/multi"], captured.imports) return analysistest.end(env) +def _py_macro_dynamic_manifest_wiring_test_impl(ctx): + """Assert dynamic target entries avoid virtual-repository label fallback.""" + env = analysistest.begin(ctx) + captured = analysistest.target_under_test(env)[ToptPyMacroCaptureInfo] + asserts.true(env, _has_label_suffix(captured.data_labels, ":py_macro_dynamic_manifest_target_topt_payloads")) + asserts.true(env, _has_label_suffix(captured.data_labels, ":test_macro.bzl")) + asserts.false(env, _has_fragment(captured.data_labels, "virtual_dynamic_repo_that_must_not_resolve")) + asserts.equals(env, "dynamic-python-service", captured.env.get("DD_SERVICE")) + return analysistest.end(env) + +def _py_macro_dynamic_manifest_payloads_test_impl(ctx): + """Assert only the selected explicit module files reach the selector.""" + env = analysistest.begin(ctx) + files = analysistest.target_under_test(env)[DefaultInfo].files.to_list() + asserts.equals(env, 1, len(files)) + asserts.true(env, _has_file_basename(files, "module_example_python_explicit_pkg.payload")) + asserts.false(env, _has_file_basename(files, "full_payload.payload")) + return analysistest.end(env) + def _py_macro_env_none_wiring_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) @@ -867,6 +999,33 @@ def _py_macro_public_wrapper_test_impl(ctx): asserts.equals(env, "1", run_env.get("CUSTOM_ENV")) return analysistest.end(env) +def _py_macro_fallback_payloads_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + paths = [file.short_path for file in target[DefaultInfo].files.to_list()] + package_suffix = ctx.label.package.replace("/", "_") + expected_module_name = "module_example_python_%s" % package_suffix + + expected_module_known_tests = False + full_bundle_known_tests = False + for path in paths: + if path.endswith("/.testoptimization/%s/known_tests.json" % expected_module_name): + expected_module_known_tests = True + if path.endswith("/.testoptimization/cache/http/known_tests.json"): + full_bundle_known_tests = True + + asserts.true( + env, + expected_module_known_tests, + msg = "macro-generated selector must expose %s: %s" % (expected_module_name, paths), + ) + asserts.false( + env, + full_bundle_known_tests, + msg = "macro-generated selector must not fall back to the full known-tests bundle: %s" % paths, + ) + return analysistest.end(env) + def _resolve_topt_service_key_missing_target_impl(_ctx): resolve_topt_service_key_for_tests( { @@ -939,6 +1098,12 @@ py_macro_single_service_wiring_test = analysistest.make( py_macro_multi_service_wiring_test = analysistest.make( _py_macro_multi_service_wiring_test_impl, ) +py_macro_dynamic_manifest_wiring_test = analysistest.make( + _py_macro_dynamic_manifest_wiring_test_impl, +) +py_macro_dynamic_manifest_payloads_test = analysistest.make( + _py_macro_dynamic_manifest_payloads_test_impl, +) py_macro_env_none_wiring_test = analysistest.make( _py_macro_env_none_wiring_test_impl, ) @@ -951,6 +1116,9 @@ py_macro_explicit_service_wiring_test = analysistest.make( py_macro_public_wrapper_test = analysistest.make( _py_macro_public_wrapper_test_impl, ) +py_macro_fallback_payloads_test = analysistest.make( + _py_macro_fallback_payloads_test_impl, +) resolve_topt_service_key_missing_failure_test = analysistest.make( _resolve_topt_service_key_missing_failure_test_impl, expect_failure = True, diff --git a/modules/python/tests/test_payloads_selector.bzl b/modules/python/tests/test_payloads_selector.bzl index 570981c6..61b86ba6 100644 --- a/modules/python/tests/test_payloads_selector.bzl +++ b/modules/python/tests/test_payloads_selector.bzl @@ -73,6 +73,10 @@ def selector_payload_fixture_targets(): name = "module_example_python_explicit_pkg", marker = "module:explicit", ) + _payload_marker( + name = "module_manifest_context_example_python_explicit_pkg", + marker = "module:explicit-namespaced", + ) _payload_marker( name = "module_example_python_imports_pkg", marker = "module:imports", @@ -89,6 +93,10 @@ def selector_payload_fixture_targets(): name = "module_example_python_fallback_pkg", marker = "module:fallback", ) + _payload_marker( + name = "module_domains_ffe_apps_apis_query_validator_internal_validator_tests", + marker = "module:dd-source-prefixed-fallback", + ) _payload_marker( name = "module_custom_override", marker = "module:override", @@ -109,7 +117,11 @@ def selector_payload_fixture_targets(): deps = [":deps_leaf"], ) -def selector_explicit_precedence_target(name, tags = None): +def selector_explicit_precedence_target( + name, + tags = None, + module_groups = None, + module_group_names = None): topt_py_payloads_selector( name = name, explicit_identifier = "example/python/explicit/pkg", @@ -118,7 +130,8 @@ def selector_explicit_precedence_target(name, tags = None): attribute_candidates = ["example/python/attr/pkg"], fallback_identifier = "example/python/fallback/pkg", full_files = ":full_payload", - module_groups = _COMMON_MODULE_GROUPS, + module_group_names = module_group_names or [], + module_groups = module_groups or _COMMON_MODULE_GROUPS, include_per_module = True, tags = tags, ) @@ -188,6 +201,20 @@ def selector_no_match_fallback_target(name, tags = None): tags = tags, ) +def selector_prefixed_fallback_target(name, tags = None): + """Select a dd-source-style module path without falling back to full files.""" + topt_py_payloads_selector( + name = name, + imports = [], + deps = [], + attribute_candidates = [], + fallback_identifier = "domains.ffe.apps.apis.query_validator.internal.validator.tests", + full_files = ":full_payload", + module_groups = [":module_domains_ffe_apps_apis_query_validator_internal_validator_tests"], + include_per_module = True, + tags = tags, + ) + def selector_include_disabled_target(name, tags = None): topt_py_payloads_selector( name = name, @@ -298,6 +325,12 @@ def _selector_explicit_precedence_test_impl(ctx): _assert_selected(env, target, "module_example_python_explicit_pkg") return analysistest.end(env) +def _selector_explicit_namespaced_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + _assert_selected(env, target, "module_manifest_context_example_python_explicit_pkg") + return analysistest.end(env) + def _selector_imports_precedence_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) @@ -328,6 +361,12 @@ def _selector_no_match_fallback_test_impl(ctx): _assert_selected(env, target, "full_payload") return analysistest.end(env) +def _selector_prefixed_fallback_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + _assert_selected(env, target, "module_domains_ffe_apps_apis_query_validator_internal_validator_tests") + return analysistest.end(env) + def _selector_include_disabled_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) @@ -367,6 +406,9 @@ def _selector_omits_flaky_tests_test_impl(ctx): selector_explicit_precedence_test = analysistest.make( _selector_explicit_precedence_test_impl, ) +selector_explicit_namespaced_test = analysistest.make( + _selector_explicit_namespaced_test_impl, +) selector_imports_precedence_test = analysistest.make( _selector_imports_precedence_test_impl, ) @@ -382,6 +424,9 @@ selector_fallback_test = analysistest.make( selector_no_match_fallback_test = analysistest.make( _selector_no_match_fallback_test_impl, ) +selector_prefixed_fallback_test = analysistest.make( + _selector_prefixed_fallback_test_impl, +) selector_include_disabled_test = analysistest.make( _selector_include_disabled_test_impl, ) diff --git a/modules/python/tests/test_selection_utils.bzl b/modules/python/tests/test_selection_utils.bzl index 0bce5e3d..ecd27cd7 100644 --- a/modules/python/tests/test_selection_utils.bzl +++ b/modules/python/tests/test_selection_utils.bzl @@ -15,7 +15,9 @@ load( load( "@datadog-rules-test-optimization-python//:topt_py_test.bzl", "build_module_labels_for_tests", + "build_python_fallback_identifier_for_tests", "normalize_user_data_for_tests", + "resolve_python_selector_inputs_for_tests", "resolve_topt_service_key_for_tests", "service_mapping_entries_for_tests", ) @@ -83,6 +85,83 @@ def _normalize_python_identifier_edge_cases_test(ctx): asserts.equals(env, "", normalize_python_identifier_for_tests(None)) return unittest.end(env) +def _build_python_fallback_identifier_test(ctx): + env = unittest.begin(ctx) + asserts.equals( + env, + "example.project.app", + build_python_fallback_identifier_for_tests("app", {"module_path": "example.project"}), + ) + asserts.equals( + env, + "domains.ffe.apps.apis.query_validator.internal.validator.tests", + build_python_fallback_identifier_for_tests( + "domains/ffe/apps/apis/query_validator/internal/validator/tests", + {"module_path": "domains.ffe.apps.apis.query_validator"}, + ), + ) + asserts.equals( + env, + "domains.ffe.apps.apis.query_validator", + build_python_fallback_identifier_for_tests( + "domains/ffe/apps/apis/query_validator", + {"module_path": "domains.ffe.apps.apis.query_validator"}, + ), + ) + asserts.equals( + env, + "app", + build_python_fallback_identifier_for_tests("app", {}), + ) + asserts.equals( + env, + "example.project.app.tests", + build_python_fallback_identifier_for_tests("example//project\\app//tests", {"module_path": "example.project"}), + ) + return unittest.end(env) + +def _resolve_python_selector_inputs_test(ctx): + env = unittest.begin(ctx) + derived = resolve_python_selector_inputs_for_tests( + module_identifier = None, + imports_candidates = [], + deps_labels = [], + importpath_candidate = None, + module_path_candidate = None, + fallback_identifier = "example.project.tests", + module_groups = ["@repo//:module_example_project_tests"], + module_included = False, + ) + asserts.equals(env, "", derived["explicit_identifier"]) + asserts.equals(env, "example.project.tests", derived["fallback_identifier"]) + asserts.equals(env, True, derived["include_per_module"]) + + explicit = resolve_python_selector_inputs_for_tests( + module_identifier = "explicit.module", + imports_candidates = [], + deps_labels = [], + importpath_candidate = None, + module_path_candidate = None, + fallback_identifier = "fallback.module", + module_groups = ["@repo//:module_explicit_module"], + module_included = False, + ) + asserts.equals(env, "explicit.module", explicit["explicit_identifier"]) + asserts.equals(env, True, explicit["include_per_module"]) + + no_groups = resolve_python_selector_inputs_for_tests( + module_identifier = None, + imports_candidates = [], + deps_labels = [], + importpath_candidate = None, + module_path_candidate = None, + fallback_identifier = "example.project.tests", + module_groups = [], + module_included = False, + ) + asserts.equals(env, False, no_groups["include_per_module"]) + return unittest.end(env) + def _normalize_user_data_handles_none_test(ctx): env = unittest.begin(ctx) asserts.equals(env, [], normalize_user_data_for_tests(None)) @@ -202,6 +281,8 @@ service_mapping_entries_filters_non_service_test = unittest.make(_service_mappin resolve_topt_service_key_prefers_exact_then_sanitized_test = unittest.make(_resolve_topt_service_key_prefers_exact_then_sanitized_test) select_module_group_name_test = unittest.make(_select_module_group_name_test) normalize_python_identifier_edge_cases_test = unittest.make(_normalize_python_identifier_edge_cases_test) +build_python_fallback_identifier_test = unittest.make(_build_python_fallback_identifier_test) +resolve_python_selector_inputs_test = unittest.make(_resolve_python_selector_inputs_test) normalize_user_data_handles_none_test = unittest.make(_normalize_user_data_handles_none_test) build_module_labels_valid_test = unittest.make(_build_module_labels_valid_test) py_stub_includes_manifest_in_files_test = unittest.make(_py_stub_includes_manifest_in_files_test) diff --git a/modules/python/tools/dd_topt_py_bootstrap/main.py b/modules/python/tools/dd_topt_py_bootstrap/main.py index 6baf58d0..b2be07a9 100644 --- a/modules/python/tools/dd_topt_py_bootstrap/main.py +++ b/modules/python/tools/dd_topt_py_bootstrap/main.py @@ -164,6 +164,7 @@ def render_bazelrc_snippet(args: argparse.Namespace) -> str: lines = [ "# Datadog metadata is resolved during repository/module analysis.", "# These values are repo_env, not test_env, so tests do not receive secrets.", + f"common:{args.bazelrc_config} --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1", ] lines.extend(f"common:{args.bazelrc_config} --repo_env={key}" for key in SYNC_REPO_ENV_KEYS) lines.append(f"test:{args.bazelrc_config} --remote_download_minimal") @@ -249,6 +250,7 @@ def render_workspace_snippet(args: argparse.Namespace) -> str: ' runtime_name = "python",', f" runtime_version = {_quote(args.runtime_version)},", f" runtime_module_path = {_quote(args.runtime_module_path)},", + " enabled_by_env = True,", ")", ] ) @@ -310,6 +312,7 @@ def render_bzlmod_snippet(args: argparse.Namespace) -> str: ' runtime_name = "python",', f" runtime_version = {_quote(args.runtime_version)},", f" runtime_module_path = {_quote(args.runtime_module_path)},", + " enabled_by_env = True,", ")", f"use_repo(test_optimization_sync, {_quote(args.sync_repo_name)})", ] @@ -346,9 +349,12 @@ def render_test_snippet(args: argparse.Namespace) -> str: if args.runner_mode == "consumer_runner": load_line = "# load(\"//path/to:python_rules.bzl\", \"your_py_test_rule\")" rule_ref = "your_py_test_rule" + module_identifier_line = "" if args.py_test_rule_load_label and args.py_test_rule_symbol: load_line = f"load({_quote(args.py_test_rule_load_label)}, {_quote(args.py_test_rule_symbol)})" rule_ref = args.py_test_rule_symbol + if args.module_identifier: + module_identifier_line = f" module_identifier = {_quote(args.module_identifier)},\n" return dedent( f""" load("@datadog-rules-test-optimization-python//:topt_py_test.bzl", "dd_topt_py_test") @@ -360,8 +366,7 @@ def render_test_snippet(args: argparse.Namespace) -> str: topt_data = topt_data, runner_mode = "consumer_runner", py_test_rule = {rule_ref}, - module_identifier = {_quote(args.module_identifier or args.runtime_module_path)}, - srcs = ["test_example.py"], + {module_identifier_line} srcs = ["test_example.py"], deps = [ requirement("ddtrace"), requirement("pytest"), diff --git a/modules/python/tools/dd_topt_py_bootstrap/main_test.py b/modules/python/tools/dd_topt_py_bootstrap/main_test.py index 43d5ec73..7d0f6364 100644 --- a/modules/python/tools/dd_topt_py_bootstrap/main_test.py +++ b/modules/python/tools/dd_topt_py_bootstrap/main_test.py @@ -45,6 +45,8 @@ def test_workspace_snippet_contains_helper(self) -> None: snippet = main.render_workspace_snippet(args) self.assertIn("datadog_python_test_optimization_workspace_repositories", snippet) self.assertIn("test_optimization_sync", snippet) + self.assertIn("enabled_by_env = True", snippet) + self.assertNotIn("rules_go", snippet) self.assertNotRegex(snippet, r"(?m)^ (load|# Declare|datadog_python_test_optimization_workspace_repositories|test_optimization_sync)") def test_bzlmod_snippet_contains_bazel_dep(self) -> None: @@ -54,6 +56,8 @@ def test_bzlmod_snippet_contains_bazel_dep(self) -> None: snippet = main.render_bzlmod_snippet(args) self.assertIn('bazel_dep(name = "datadog-rules-test-optimization"', snippet) self.assertIn('bazel_dep(name = "datadog-rules-test-optimization-python"', snippet) + self.assertIn("enabled_by_env = True", snippet) + self.assertNotIn("rules_go", snippet) self.assertNotRegex(snippet, r"(?m)^ (bazel_dep|archive_override|git_override|test_optimization_sync|use_repo)") def test_bzlmod_archive_snippet_emits_sha256_pin(self) -> None: @@ -86,7 +90,9 @@ def test_bazelrc_has_no_forbidden_test_env_or_fetch_salt(self) -> None: """Generated .bazelrc keeps secrets and git metadata out of test_env.""" args = _args() snippet = main.render_bazelrc_snippet(args) + self.assertIn("common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1", snippet) self.assertIn("common:test-optimization --repo_env=DD_API_KEY", snippet) + self.assertNotIn("orchestrion:enabled", snippet) self.assertIn("test:test-optimization --remote_download_minimal", snippet) self.assertIn("test:test-optimization --remote_download_regex=.*test[.]outputs.*", snippet) self.assertIn("test:test-optimization --zip_undeclared_test_outputs", snippet) @@ -182,7 +188,7 @@ def test_managed_pytest_snippet_lists_consumer_dependencies(self) -> None: self.assertIn('requirement("pytest")', snippet) def test_consumer_runner_snippet_contains_module_identifier(self) -> None: - """Consumer runner examples preserve module selection guidance.""" + """An explicit module-selection exception is preserved in output.""" args = _args( "--runner-mode=consumer_runner", "--module-identifier=example.python.app", @@ -194,6 +200,17 @@ def test_consumer_runner_snippet_contains_module_identifier(self) -> None: self.assertIn('module_identifier = "example.python.app"', snippet) self.assertIn("py_test_rule = dd_py_test", snippet) + def test_consumer_runner_snippet_uses_derived_module_identifier_by_default(self) -> None: + """The normal onboarding path does not require per-target identifiers.""" + args = _args( + "--runner-mode=consumer_runner", + "--py-test-rule-load-label=//tools:python.bzl", + "--py-test-rule-symbol=dd_py_test", + ) + snippet = main.render_test_snippet(args) + self.assertNotIn("module_identifier", snippet) + self.assertIn('srcs = ["test_example.py"]', snippet) + def test_write_modes_are_idempotent_and_preserve_user_content(self) -> None: """Managed block writes preserve unmanaged content and replace only generated content.""" with tempfile.TemporaryDirectory() as tmp: @@ -209,6 +226,28 @@ def test_write_modes_are_idempotent_and_preserve_user_content(self) -> None: self.assertIn("# user content", second) self.assertEqual(1, second.count(main.BEGIN_MARKER)) + def test_write_bazelrc_upgrades_an_older_managed_block(self) -> None: + """Re-running onboarding upgrades managed config without touching user content.""" + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / ".bazelrc" + path.write_text( + "# user content\n" + f"{main.BEGIN_MARKER}\n" + "common:test-optimization --repo_env=DD_API_KEY\n" + f"{main.END_MARKER}\n", + encoding="utf-8", + ) + args = _args("--write-bazelrc", f"--bazelrc-path={path}") + main._validate_args(args) + main.write_outputs(args) + content = path.read_text(encoding="utf-8") + self.assertIn("# user content", content) + self.assertEqual(1, content.count(main.BEGIN_MARKER)) + self.assertIn( + "common:test-optimization --repo_env=DD_TEST_OPTIMIZATION_ENABLED=1", + content, + ) + def test_write_targets_creates_parent_directories(self) -> None: """Target write mode creates lightweight packages on demand.""" with tempfile.TemporaryDirectory() as tmp: diff --git a/modules/python/topt_py_infer.bzl b/modules/python/topt_py_infer.bzl index 44e82bbb..f9bf0bd3 100644 --- a/modules/python/topt_py_infer.bzl +++ b/modules/python/topt_py_infer.bzl @@ -94,7 +94,12 @@ def _select_from_candidates(candidates, module_group_names, include_per_module, return "" def _topt_py_payloads_selector_impl(ctx): - module_group_names = [m.label.name for m in ctx.attr.module_groups] + module_group_names = ctx.attr.module_group_names + if module_group_names: + if len(module_group_names) != len(ctx.attr.module_groups): + fail("module_group_names must contain one entry per module_groups entry") + else: + module_group_names = [m.label.name for m in ctx.attr.module_groups] explicit_identifier = _normalize_python_identifier(ctx.attr.explicit_identifier) selected_name = "" @@ -143,9 +148,9 @@ def _topt_py_payloads_selector_impl(ctx): chosen = None if selected_name: - for m in ctx.attr.module_groups: - if m.label.name == selected_name: - chosen = m + for index in range(len(module_group_names)): + if module_group_names[index] == selected_name: + chosen = ctx.attr.module_groups[index] break source = chosen if chosen != None else ctx.attr.full_files @@ -170,6 +175,7 @@ topt_py_payloads_selector = rule( "explicit_identifier": attr.string(), "fallback_identifier": attr.string(), "full_files": attr.label(), + "module_group_names": attr.string_list(), "module_groups": attr.label_list(), "include_per_module": attr.bool(default = True), "module_label_override": attr.string(), diff --git a/modules/python/topt_py_test.bzl b/modules/python/topt_py_test.bzl index fef4d0ff..6d414387 100644 --- a/modules/python/topt_py_test.bzl +++ b/modules/python/topt_py_test.bzl @@ -22,6 +22,10 @@ load( "merge_optional_env_defaults", "merge_user_env", "normalize_user_data", + "resolve_files_label", + "resolve_manifest_label", + "resolve_module_group_names", + "resolve_module_labels", "resolve_topt_service_key", "select_service_entry_or_fail", "service_mapping_entries", @@ -69,12 +73,22 @@ def _build_module_labels(sync_repo_name, labels): build_module_labels_for_tests = _build_module_labels +def _normalize_python_fallback_part(value): + """Normalize a workspace package or runtime module path to dotted form.""" + dotted = (value or "").replace("\\", ".").replace("/", ".") + return ".".join([part for part in dotted.split(".") if part]) + def _build_python_fallback_identifier(package_path, runtime_info): - pkg_dotted = (package_path or "").replace("/", ".") - module_path = ((runtime_info or {}).get("module_path") or "") - if module_path: - return (module_path + "." + pkg_dotted) if pkg_dotted else module_path - return pkg_dotted + """Build a generic prefix-aware Python module fallback identifier.""" + package_dotted = _normalize_python_fallback_part(package_path) + module_path = _normalize_python_fallback_part((runtime_info or {}).get("module_path")) + if not module_path: + return package_dotted + if not package_dotted: + return module_path + if package_dotted == module_path or package_dotted.startswith(module_path + "."): + return package_dotted + return module_path + "." + package_dotted def _has_non_empty_value(value): """Return True when a macro input is present and materially non-empty.""" @@ -86,6 +100,40 @@ def _has_non_empty_value(value): return len(value) > 0 return True +def _resolve_python_selector_inputs( + module_identifier, + imports_candidates, + deps_labels, + importpath_candidate, + module_path_candidate, + fallback_identifier, + module_groups, + module_included): + """Resolve selector inputs once so production and tests share the contract.""" + module_groups = module_groups or [] + uses_explicit_inference = ( + _has_non_empty_value(module_identifier) or + _has_non_empty_value(imports_candidates) or + _has_non_empty_value(deps_labels) or + _has_non_empty_value(importpath_candidate) or + _has_non_empty_value(module_path_candidate) + ) + uses_derived_fallback = _has_non_empty_value(fallback_identifier) and len(module_groups) > 0 + if uses_explicit_inference or uses_derived_fallback: + include_per_module = True + elif module_included != None: + include_per_module = bool(module_included) + else: + include_per_module = len(module_groups) > 0 + return { + "explicit_identifier": module_identifier or "", + "fallback_identifier": fallback_identifier or "", + "include_per_module": include_per_module, + } + +build_python_fallback_identifier_for_tests = _build_python_fallback_identifier +resolve_python_selector_inputs_for_tests = _resolve_python_selector_inputs + def _is_default_py_test_rule(py_test_rule): """Return True when a py_test_rule value is the rules_python base py_test macro.""" return py_test_rule == _default_py_test @@ -118,6 +166,25 @@ def _validate_consumer_runner_inputs(py_test_rule_was_explicit, py_test_rule_is_ "for the built-in pytest runner.", ) +def _define_uninstrumented_py_test(name, py_test_rule, runner_mode, kwargs): + """Define the consumer test without Datadog wiring when sync is disabled.""" + test_kwargs = dict(kwargs) + test_kwargs["env"] = _merge_user_env( + test_kwargs.get("env"), + {"DD_CIVISIBILITY_ENABLED": "false"}, + macro_name = "dd_topt_py_test", + ) + if runner_mode == _RUNNER_MODE_MANAGED_PYTEST and test_kwargs.get("main") == None: + pkg_path = native.package_name() + test_kwargs["srcs"] = _append_data_dependencies(test_kwargs.get("srcs"), [_RUN_PYTEST]) + test_kwargs["main"] = _RUN_PYTEST + if "args" not in test_kwargs: + test_kwargs["args"] = [pkg_path] if pkg_path else [] + if "imports" not in test_kwargs: + test_kwargs["imports"] = [pkg_path] if pkg_path else [] + test_kwargs["name"] = name + py_test_rule(**test_kwargs) + # Public aliases for unit tests. validate_runner_mode_for_tests = _validate_runner_mode validate_consumer_runner_inputs_for_tests = _validate_consumer_runner_inputs @@ -158,6 +225,20 @@ def dd_topt_py_test( py_test_rule_is_default = _is_default_py_test_rule(py_test_rule) _svc = _select_service_entry_or_fail(topt_data, topt_service) + if runner_mode == _RUNNER_MODE_CONSUMER_RUNNER: + _validate_consumer_runner_inputs( + py_test_rule_was_explicit, + py_test_rule_is_default, + kwargs.get("main"), + ) + + # A disabled sync repository exports the same schema with enabled = False. + # Keep the consumer's test runnable, but do not create selectors, wrappers, + # metadata targets, Datadog env, or payload-producing instrumentation. + if not _svc.get("enabled", True): + _define_uninstrumented_py_test(name, py_test_rule, runner_mode, kwargs) + return + wrapper_kwargs, raw_passthrough = split_test_wrapper_kwargs(kwargs) user_data = kwargs.pop("data", None) @@ -178,9 +259,6 @@ def dd_topt_py_test( user_srcs = kwargs.pop("srcs", None) user_main = kwargs.pop("main", None) - if runner_mode == _RUNNER_MODE_CONSUMER_RUNNER: - _validate_consumer_runner_inputs(py_test_rule_was_explicit, py_test_rule_is_default, user_main) - # args is a wrapper-only attr; split_test_wrapper_kwargs already moved it to wrapper_kwargs. user_args = wrapper_kwargs.pop("args", None) @@ -195,25 +273,24 @@ def dd_topt_py_test( if type(module_path_candidate) == type("") and module_path_candidate: attribute_candidates.append(module_path_candidate) - uses_inference = ( - _has_non_empty_value(module_identifier) or - _has_non_empty_value(imports_candidates) or - _has_non_empty_value(deps_labels) or - _has_non_empty_value(importpath_candidate) or - _has_non_empty_value(module_path_candidate) + files_label = resolve_files_label(_svc, sync_repo_name, macro_name = "dd_topt_py_test") + module_labels = resolve_module_labels(_svc, sync_repo_name, macro_name = "dd_topt_py_test") + module_group_names = resolve_module_group_names( + _svc, + module_labels, + macro_name = "dd_topt_py_test", ) - if uses_inference: - include_per_module_files = True - else: - module_included = _python.get("module_included") if _is_dict(_python) else None - if module_included != None: - include_per_module_files = bool(module_included) - else: - include_per_module_files = bool(_svc.get("labels")) - - files_label = "@%s//:test_optimization_files" % sync_repo_name - module_labels = _build_module_labels(sync_repo_name, _svc.get("labels")) fallback_identifier = _build_python_fallback_identifier(native.package_name(), _python) + selector_inputs = _resolve_python_selector_inputs( + module_identifier = module_identifier, + imports_candidates = imports_candidates, + deps_labels = deps_labels, + importpath_candidate = importpath_candidate, + module_path_candidate = module_path_candidate, + fallback_identifier = fallback_identifier, + module_groups = module_labels, + module_included = _python.get("module_included") if _is_dict(_python) else None, + ) selector_name = name + "_topt_payloads" metadata_name = name + "_topt_bazel_metadata" @@ -222,11 +299,12 @@ def dd_topt_py_test( deps = deps_labels, imports = imports_candidates, attribute_candidates = attribute_candidates, - explicit_identifier = module_identifier or "", - fallback_identifier = fallback_identifier, + explicit_identifier = selector_inputs["explicit_identifier"], + fallback_identifier = selector_inputs["fallback_identifier"], full_files = files_label, + module_group_names = module_group_names, module_groups = module_labels, - include_per_module = include_per_module_files, + include_per_module = selector_inputs["include_per_module"], module_label_override = module_label_override, importpath = importpath_candidate if importpath_candidate != None else "", module_path = module_path_candidate if module_path_candidate != None else "", @@ -269,8 +347,7 @@ def dd_topt_py_test( data = _append_data_dependencies(data, [":" + selector_name]) - manifest_path = _svc.get("manifest_path") or ".testoptimization/manifest.txt" - manifest_label = "@%s//:%s" % (sync_repo_name, manifest_path) + manifest_label = resolve_manifest_label(_svc, sync_repo_name, macro_name = "dd_topt_py_test") data = _append_data_dependencies(data, [manifest_label]) env = _merge_user_env( user_env, diff --git a/modules/ruby/MODULE.bazel.lock b/modules/ruby/MODULE.bazel.lock index 7299adf2..b9ec6196 100644 --- a/modules/ruby/MODULE.bazel.lock +++ b/modules/ruby/MODULE.bazel.lock @@ -140,8 +140,8 @@ "moduleExtensions": { "//tests:example_stub_repo.bzl%example_stub_repo_extension": { "general": { - "bzlTransitiveDigest": "zC3aEdxLSUhPV6iwgCNk7hQr+1eO+rAQ5znCfGieX3g=", - "usagesDigest": "gJmZLd6nd/xMP9rApCY4mVIpVZPOzoIiqCGWDFbM4VA=", + "bzlTransitiveDigest": "8Z0dqG8n5A2E4sAbWxvij+vncAodaOVqDuvzF/sm6wE=", + "usagesDigest": "D5EtmFTCTKSRH5kAymUIV/dmXm5DQEi4R3poqsT00uw=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/third_party/rgo/BUILD.bazel b/third_party/rgo/BUILD.bazel index 3eb29ea6..12cfa8aa 100644 --- a/third_party/rgo/BUILD.bazel +++ b/third_party/rgo/BUILD.bazel @@ -9,4 +9,6 @@ exports_files([ "v0_60_0/base.CHANGED_FILES.md", "v0_61_1/base.METADATA.json", "v0_61_1/base.CHANGED_FILES.md", + "v0_62_0/base.METADATA.json", + "v0_62_0/base.CHANGED_FILES.md", ], visibility = ["//visibility:public"]) diff --git a/third_party/rgo/v0_60_0/base.CHANGED_FILES.md b/third_party/rgo/v0_60_0/base.CHANGED_FILES.md index f11018e0..f8068104 100644 --- a/third_party/rgo/v0_60_0/base.CHANGED_FILES.md +++ b/third_party/rgo/v0_60_0/base.CHANGED_FILES.md @@ -12,8 +12,8 @@ This file is generated. Do not edit by hand. ## Summary -- Total changed paths: `52` -- Modified files: `28` +- Total changed paths: `54` +- Modified files: `30` - Added files: `24` - Removed files: `0` @@ -24,11 +24,13 @@ This file is generated. Do not edit by hand. - `docs/doc_helpers.bzl` - `go/extensions.bzl` - `go/private/BUILD.bazel` +- `go/private/actions/BUILD.bazel` - `go/private/actions/archive.bzl` - `go/private/actions/compilepkg.bzl` - `go/private/actions/link.bzl` - `go/private/actions/stdlib.bzl` - `go/private/context.bzl` +- `go/private/repositories.bzl` - `go/private/rules/library.bzl` - `go/private/rules/stdlib.bzl` - `go/private/rules/test.bzl` diff --git a/third_party/rgo/v0_60_0/base/go/orchestrion_workspace.bzl b/third_party/rgo/v0_60_0/base/go/orchestrion_workspace.bzl index 8d85b877..ce443892 100644 --- a/third_party/rgo/v0_60_0/base/go/orchestrion_workspace.bzl +++ b/third_party/rgo/v0_60_0/base/go/orchestrion_workspace.bzl @@ -8,11 +8,26 @@ load( _DEFAULT_TOOL_REPO_NAME = "rules_go_orchestrion_tool" +def _configured_version_modes(dd_trace_go_version, dd_trace_go_versions, dd_trace_go_pin_files): + return len([ + value + for value in [ + dd_trace_go_version, + dd_trace_go_versions, + dd_trace_go_pin_files, + ] + if value + ]) + def go_orchestrion_tool_repo( name = _DEFAULT_TOOL_REPO_NAME, version = "", dd_trace_go_version = "", dd_trace_go_versions = None, + dd_trace_go_pin_files = None, + enabled_by_env = False, + go_sdk_root = "", + go_sdk_version = "", log_timing = False): """Create the `rules_go_orchestrion_tool` repository in WORKSPACE mode. @@ -25,6 +40,18 @@ def go_orchestrion_tool_repo( target module when instrumentation is enabled. dd_trace_go_versions: Optional per-module dd-trace-go version mapping. Mutually exclusive with `dd_trace_go_version`. + dd_trace_go_pin_files: Optional `[go.mod, go.sum]` labels used to derive + the selected direct and transitive dd-trace-go module versions. + Mutually exclusive with explicit version fields. + enabled_by_env: Gate repository materialization on the Test Optimization + repository environment. Generic Orchestrion callers should keep the + default. + go_sdk_root: Optional label string for a hermetic Go SDK ROOT marker. + When set, the enabled repository builds Orchestrion with that SDK + instead of searching for Go on the host. + go_sdk_version: Optional declared version for `go_sdk_root`. When set, + bootstrap can restore an existing cache entry before materializing the + SDK and verifies the declared value on cache miss. log_timing: Emit structured bootstrap timing probes while building the Orchestrion tool repository. """ @@ -35,14 +62,16 @@ def go_orchestrion_tool_repo( if dd_trace_go_versions == None: dd_trace_go_versions = {} + if dd_trace_go_pin_files == None: + dd_trace_go_pin_files = [] - if dd_trace_go_version and dd_trace_go_versions: - fail("go_orchestrion_tool_repo: dd_trace_go_version and dd_trace_go_versions cannot both be set") + if _configured_version_modes(dd_trace_go_version, dd_trace_go_versions, dd_trace_go_pin_files) > 1: + fail("go_orchestrion_tool_repo: dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") if not version: fail("go_orchestrion_tool_repo: version is required in WORKSPACE mode") - if not dd_trace_go_version and not dd_trace_go_versions: + if not dd_trace_go_version and not dd_trace_go_versions and not dd_trace_go_pin_files: dd_trace_go_version = DEFAULT_DD_TRACE_GO_VERSION orchestrion_build_repository( @@ -50,5 +79,9 @@ def go_orchestrion_tool_repo( version = version, dd_trace_go_version = dd_trace_go_version, dd_trace_go_versions = dd_trace_go_versions, + dd_trace_go_pin_files = dd_trace_go_pin_files, + enabled_by_env = enabled_by_env, + go_sdk_root = go_sdk_root, + go_sdk_version = go_sdk_version, log_timing = log_timing, ) diff --git a/third_party/rgo/v0_60_0/base/go/private/actions/BUILD.bazel b/third_party/rgo/v0_60_0/base/go/private/actions/BUILD.bazel index 3bd3d155..439d4f21 100644 --- a/third_party/rgo/v0_60_0/base/go/private/actions/BUILD.bazel +++ b/third_party/rgo/v0_60_0/base/go/private/actions/BUILD.bazel @@ -43,6 +43,7 @@ bzl_library( deps = [ ":utils", "//go/private:mode", + "//go/private/orchestrion:pin_files", "@bazel_skylib//lib:shell", ], ) @@ -54,6 +55,7 @@ bzl_library( deps = [ "//go/private:common", "//go/private:mode", + "//go/private/orchestrion:pin_files", "//go/private:rpath", "@bazel_skylib//lib:collections", ], @@ -66,6 +68,7 @@ bzl_library( deps = [ ":utils", "//go/private:mode", + "//go/private/orchestrion:pin_files", "//go/private:providers", "//go/private:sdk", ], diff --git a/third_party/rgo/v0_60_0/base/go/private/orchestrion/BUILD b/third_party/rgo/v0_60_0/base/go/private/orchestrion/BUILD index 488d4adf..31a01c33 100644 --- a/third_party/rgo/v0_60_0/base/go/private/orchestrion/BUILD +++ b/third_party/rgo/v0_60_0/base/go/private/orchestrion/BUILD @@ -1,3 +1,4 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag") filegroup( @@ -13,6 +14,12 @@ filegroup( visibility = ["//visibility:public"], ) +bzl_library( + name = "pin_files", + srcs = ["pin_files.bzl"], + visibility = ["//go:__subpackages__"], +) + bool_flag( name = "enabled", build_setting_default = False, @@ -29,37 +36,80 @@ string_flag( visibility = ["//visibility:public"], ) -# Proxy target for the orchestrion tool binary. -# This always points to the rules_go_orchestrion_tool repo. -# The repo provides an empty filegroup by default, or the actual orchestrion -# binary when configured via module extension. -# go_context_data checks the :enabled flag to determine whether to use this. +config_setting( + name = "enabled_config", + flag_values = {":enabled": "true"}, +) + +filegroup( + name = "disabled_tool_binary", + srcs = [], +) + +filegroup( + name = "disabled_dd_trace_go_version_file", + srcs = [], +) + +filegroup( + name = "disabled_dd_trace_go_module_proxy_files", + srcs = [], +) + +filegroup( + name = "disabled_dd_trace_go_module_proxy_root_marker", + srcs = [], +) + +filegroup( + name = "disabled_orchestrion_tool_version_file", + srcs = [], +) + +# Stable Orchestrion aliases select package-local empty targets by default and +# only reference the real tool repository when the public :enabled flag is set. +# go_context_data also checks :enabled before consuming these files. alias( name = "tool_binary", - actual = "@rules_go_orchestrion_tool//:orchestrion", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:orchestrion", + "//conditions:default": ":disabled_tool_binary", + }), visibility = ["//visibility:public"], ) alias( name = "dd_trace_go_version_file", - actual = "@rules_go_orchestrion_tool//:dd_trace_go_version_file", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:dd_trace_go_version_file", + "//conditions:default": ":disabled_dd_trace_go_version_file", + }), visibility = ["//visibility:public"], ) alias( name = "dd_trace_go_module_proxy_files", - actual = "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_files", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_files", + "//conditions:default": ":disabled_dd_trace_go_module_proxy_files", + }), visibility = ["//visibility:public"], ) alias( name = "dd_trace_go_module_proxy_root_marker", - actual = "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_root_marker", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_root_marker", + "//conditions:default": ":disabled_dd_trace_go_module_proxy_root_marker", + }), visibility = ["//visibility:public"], ) alias( name = "orchestrion_tool_version_file", - actual = "@rules_go_orchestrion_tool//:orchestrion_tool_version_file", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:orchestrion_tool_version_file", + "//conditions:default": ":disabled_orchestrion_tool_version_file", + }), visibility = ["//visibility:public"], ) diff --git a/third_party/rgo/v0_60_0/base/go/private/orchestrion/extensions.bzl b/third_party/rgo/v0_60_0/base/go/private/orchestrion/extensions.bzl index 05652331..db1f149f 100644 --- a/third_party/rgo/v0_60_0/base/go/private/orchestrion/extensions.bzl +++ b/third_party/rgo/v0_60_0/base/go/private/orchestrion/extensions.bzl @@ -33,6 +33,15 @@ _DD_TRACE_GO_PREFLIGHT_PACKAGES = [ ] def _find_go_binary(ctx): + go_sdk_root = ctx.attr.go_sdk_root.strip() + if go_sdk_root: + root_file = ctx.path(Label(go_sdk_root)) + binary_name = "go.exe" if _is_windows(ctx) else "go" + go_path = root_file.dirname.get_child("bin").get_child(binary_name) + if not go_path.exists: + fail("Configured hermetic Go SDK does not expose %s next to %s" % (go_path, root_file)) + return go_path + go_path = ctx.which("go") if go_path: return go_path @@ -95,24 +104,42 @@ def _bootstrap_cache_root(ctx): def _bootstrap_go_cache_root(ctx): return _path_join(ctx, _bootstrap_cache_root(ctx), "go") +def _git_env(ctx): + # GOPROXY=direct may invoke Git. Keep that fallback independent from host + # rewrites, credential helpers, and interactive prompts. + return { + "GIT_CONFIG_GLOBAL": "NUL" if _is_windows(ctx) else "/dev/null", + "GIT_CONFIG_NOSYSTEM": "1", + "GIT_TERMINAL_PROMPT": "0", + } + +def _go_module_fetch_env(ctx): + host_env = ctx.os.environ + return { + # Allow consumers to provide an internal or authenticated module proxy, + # while keeping private-module resolution on that proxy instead of + # falling back to host Git configuration. + "GOPRIVATE": "", + "GONOPROXY": "", + "GONOSUMDB": (host_env.get("GONOSUMDB") or "").strip(), + "GOPROXY": (host_env.get("GOPROXY") or "").strip() or "https://proxy.golang.org,direct", + # Use the public checksum database directly. Some internal module + # proxies expose SumDB endpoints that are reachable only inside CI. + "GOSUMDB": "sum.golang.org https://sum.golang.org", + } + def _go_env(ctx): go_cache_root = _bootstrap_go_cache_root(ctx) - return { + env = { "GO111MODULE": "on", "GOWORK": "off", - "GOTOOLCHAIN": "go1.25.0+auto", - # Repository resolution only needs public modules. Clear host-specific - # private-module settings so bootstrap does not silently fall back to - # direct VCS fetches based on the developer environment. - "GOPRIVATE": "", - "GONOPROXY": "", - "GONOSUMDB": "", - "GOPROXY": "https://proxy.golang.org,direct", - "GOSUMDB": "sum.golang.org", - "GIT_TERMINAL_PROMPT": "0", + "GOTOOLCHAIN": "local" if ctx.attr.go_sdk_root.strip() else "go1.25.0+auto", "GOMODCACHE": _path_join(ctx, go_cache_root, "pkg", "mod"), "GOCACHE": _path_join(ctx, go_cache_root, "cache"), } + env.update(_go_module_fetch_env(ctx)) + env.update(_git_env(ctx)) + return env def _probe_enabled(ctx): return getattr(ctx.attr, "log_timing", False) @@ -196,6 +223,20 @@ def _fallback_go_tool_identity(ctx): goarch = _normalize_host_goarch(ctx.os.arch), ) +def _declared_go_tool_identity(ctx, go_sdk_version): + version = go_sdk_version.strip() + if not version: + return None + if not version.startswith("go"): + version = "go" + version + goos = _normalize_host_goos(ctx.os.name) + goarch = _normalize_host_goarch(ctx.os.arch) + return struct( + version = "go version %s %s/%s" % (version, goos, goarch), + goos = goos, + goarch = goarch, + ) + def _go_tool_identity(ctx, go_path): # Some integration tests and bootstrap environments intentionally wrap # `go` with a narrow shim that supports only the commands needed to build @@ -282,6 +323,22 @@ def _bootstrap_cache_required_entries(paths): module_proxy_root_marker = paths.module_proxy_root_marker, ) +def _bootstrap_manifest_content(paths, version, version_map, go_identity, binary_name, binary_sha256): + return json.encode({ + "abi": ORCHESTRION_BOOTSTRAP_CACHE_ABI, + "patchset_id": ORCHESTRION_PATCHSET_ID, + "cache_key": paths.key, + "orchestrion_version": version, + "go_identity": { + "version": go_identity.version, + "goos": go_identity.goos, + "goarch": go_identity.goarch, + }, + "dd_trace_go_versions": version_map, + "binary_name": binary_name, + "binary_sha256": binary_sha256, + }) + "\n" + def _module_proxy_tree_has_payload(ctx, module_proxy_dir, root_marker): if not ctx.path(module_proxy_dir).exists or not ctx.path(root_marker).exists: return False @@ -314,12 +371,23 @@ def _module_proxy_tree_has_payload(ctx, module_proxy_dir, root_marker): ) return result.return_code == 0 and bool(result.stdout.strip()) -def _bootstrap_cache_entry_ready(ctx, paths): +def _bootstrap_cache_entry_ready(ctx, paths, version, version_map, go_identity, binary_name): required = _bootstrap_cache_required_entries(paths) for required_path in required.files: if not ctx.path(required_path).exists: return False - return _module_proxy_tree_has_payload(ctx, required.module_proxy_dir, required.module_proxy_root_marker) + if not _module_proxy_tree_has_payload(ctx, required.module_proxy_dir, required.module_proxy_root_marker): + return False + binary_sha256 = _binary_sha256(ctx, paths.binary_path) + expected_manifest = _bootstrap_manifest_content( + paths, + version, + version_map, + go_identity, + binary_name, + binary_sha256, + ) + return ctx.read(ctx.path(paths.manifest_path)) == expected_manifest def _dd_trace_go_versions_from_shared(version): version_map = {} @@ -389,7 +457,9 @@ def _should_append_go_toolchain_hint(args): return True return "mod" in argv and "download" in argv -def _go_toolchain_hint(): +def _go_toolchain_hint(ctx): + if ctx.attr.go_sdk_root.strip(): + return "Bootstrap uses the configured hermetic Go SDK with GOTOOLCHAIN=local. Ensure go_sdk_root and go_sdk_version identify the same SDK." return "Bootstrap uses GOTOOLCHAIN=go1.25.0+auto. If Go 1.25.0 is not already installed, the Go tool may try to download it during repository resolution. In restricted environments, preinstall Go 1.25.0 or allow fetch-time egress, then rerun bazel sync." def _ctx_execute_or_fail(ctx, args, env, error_prefix): @@ -397,7 +467,7 @@ def _ctx_execute_or_fail(ctx, args, env, error_prefix): if result.return_code != 0: details = "%s: %s\n%s" % (error_prefix, result.stdout, result.stderr) if _should_append_go_toolchain_hint(args): - details += "\n" + _go_toolchain_hint() + details += "\n" + _go_toolchain_hint(ctx) fail(details) return result @@ -533,15 +603,119 @@ def _validated_per_module_dd_trace_go_versions(ctx, go_path, version_map): _run_dd_trace_go_package_preflight(ctx, go_path, version_map) return _copy_dd_trace_go_versions(version_map) -def _validated_dd_trace_go_versions(ctx, go_path, shared_query, version_map): - if shared_query and version_map: - fail("dd_trace_go_version and dd_trace_go_versions cannot both be set") +def _configured_version_modes(shared_query, version_map, pin_files): + return len([ + value + for value in [ + shared_query, + version_map, + pin_files, + ] + if value + ]) + +def _pin_file_by_basename(ctx, pin_files, basename): + matches = [pin_file for pin_file in pin_files if ctx.path(pin_file).basename == basename] + if len(matches) != 1: + fail("dd_trace_go_pin_files must contain exactly one %s label" % basename) + return matches[0] + +def _validated_pin_file_dd_trace_go_versions(ctx, go_path, pin_files): + if not ctx.attr.go_sdk_root.strip(): + fail("dd_trace_go_pin_files requires go_sdk_root so version resolution never depends on host Go") + if len(pin_files) != 2: + fail("dd_trace_go_pin_files must contain exactly one go.mod label and one go.sum label") + go_mod = _pin_file_by_basename(ctx, pin_files, "go.mod") + go_sum = _pin_file_by_basename(ctx, pin_files, "go.sum") + check_dir = ".ddtrace_pin_check" + ctx.file(check_dir + "/go.mod", ctx.read(ctx.path(go_mod))) + ctx.file(check_dir + "/go.sum", ctx.read(ctx.path(go_sum))) + env = _go_env(ctx) + pin_cache_root = str(ctx.path(".ddtrace_pin_check_go")) + env["GOMODCACHE"] = _path_join(ctx, pin_cache_root, "pkg", "mod") + env["GOCACHE"] = _path_join(ctx, pin_cache_root, "cache") + env["GOFLAGS"] = "-mod=readonly" + format_expr = "{{if .Path}}{{.Path}}={{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}{{end}}" + result = ctx.execute( + [ + str(go_path), + "-C", + check_dir, + "list", + "-m", + "-mod=readonly", + "-f", + format_expr, + ] + _DD_TRACE_GO_MODULES, + timeout = 600, + environment = env, + ) + if result.return_code != 0: + fail( + ( + "Failed to derive dd-trace-go versions from dd_trace_go_pin_files: %s\n%s\n" + + "Ensure go.mod/go.sum select every supported tracer module, including transitive contrib modules. " + + "For unsupported module graphs, configure dd_trace_go_versions explicitly." + ) % (result.stdout, result.stderr), + ) + resolved = _parse_key_value_lines( + result.stdout, + _DD_TRACE_GO_MODULES, + "Failed to derive dd-trace-go versions from dd_trace_go_pin_files", + ) + for module_path in _DD_TRACE_GO_MODULES: + version = resolved[module_path] + if not _looks_like_canonical_dd_trace_go_version(version): + fail( + ( + "dd_trace_go_pin_files resolved %s to non-canonical version %r; " + + "configure dd_trace_go_versions explicitly" + ) % (module_path, version), + ) + _run_dd_trace_go_package_preflight(ctx, go_path, resolved) + return resolved + +def _merge_pin_file_module_proxy(ctx): + pin_cache_root = str(ctx.path(".ddtrace_pin_check_go")) + download_root = _path_join(ctx, pin_cache_root, "pkg", "mod", "cache", "download") + if not ctx.path(download_root).exists: + fail("dd_trace_go_pin_files resolution produced no module metadata to stage") + _host_merge_tree( + ctx, + download_root, + "module_proxy", + "Failed to stage dd_trace_go_pin_files module metadata", + ) + _host_remove_path_if_exists(ctx, "module_proxy/sumdb", "Failed to prune pin-file module proxy sumdb cache") + _host_remove_path_if_exists(ctx, "module_proxy/golang.org/toolchain", "Failed to prune pin-file module proxy toolchain module") + +def _validated_dd_trace_go_versions(ctx, go_path, shared_query, version_map, pin_files): + if _configured_version_modes(shared_query, version_map, pin_files) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") + if pin_files: + return _validated_pin_file_dd_trace_go_versions(ctx, go_path, pin_files) if version_map: return _validated_per_module_dd_trace_go_versions(ctx, go_path, version_map) if shared_query: return _validated_shared_dd_trace_go_versions(ctx, go_path, shared_query) return _dd_trace_go_versions_from_shared(DEFAULT_DD_TRACE_GO_VERSION) +def _declared_dd_trace_go_versions(shared_query, version_map, pin_files = []): + if _configured_version_modes(shared_query, version_map, pin_files) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") + if pin_files: + return None + if version_map: + _validate_dd_trace_go_versions_keys(version_map) + if all([_looks_like_canonical_dd_trace_go_version(version_map[module_path]) for module_path in _DD_TRACE_GO_MODULES]): + return _copy_dd_trace_go_versions(version_map) + return None + if shared_query: + if _looks_like_canonical_dd_trace_go_version(shared_query): + return _dd_trace_go_versions_from_shared(shared_query) + return None + return _dd_trace_go_versions_from_shared(DEFAULT_DD_TRACE_GO_VERSION) + def _dd_trace_go_versions_json(version_map): entries = [] for module_path in _DD_TRACE_GO_MODULES: @@ -692,6 +866,33 @@ def _host_copy_tree(ctx, src, dst, error_prefix): if not copied: fail("%s: %s\n%s" % (error_prefix, stdout, stderr)) +def _host_merge_tree(ctx, src, dst, error_prefix): + src_path = str(ctx.path(src)) + dst_path = str(ctx.path(dst)) + if _is_windows(ctx): + powershell = ctx.which("powershell.exe") or ctx.which("pwsh") or ctx.which("powershell") + if not powershell: + fail("%s: could not find PowerShell" % error_prefix) + command = "$ErrorActionPreference = 'Stop'; New-Item -ItemType Directory -Force -Path %s | Out-Null; Get-ChildItem -LiteralPath %s -Force | Copy-Item -Destination %s -Recurse -Force" % ( + _powershell_single_quoted_literal(dst_path), + _powershell_single_quoted_literal(src_path), + _powershell_single_quoted_literal(dst_path), + ) + result = _ctx_execute_checked( + ctx, + [str(powershell), "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", command], + timeout = 180, + ) + else: + shell = ctx.which("sh") or "/bin/sh" + result = _ctx_execute_checked( + ctx, + [str(shell), "-c", "mkdir -p \"$2\" && cp -R \"$1/.\" \"$2\"", "bootstrap-merge-tree", src_path, dst_path], + timeout = 180, + ) + if result.return_code != 0: + fail("%s: %s\n%s" % (error_prefix, result.stdout, result.stderr)) + def _host_remove_path_if_exists(ctx, path, error_prefix): removed, stdout, stderr = _host_remove_path_if_exists_result(ctx, path) if not removed: @@ -961,22 +1162,17 @@ def _write_orchestrion_repo_files(ctx, binary_name, dd_trace_go_versions, versio def _write_bootstrap_cache(ctx, paths, version, version_map, go_identity, binary_name): manifest_repo_path = ".orchestrion_bootstrap_manifest.json" ready_repo_path = ".orchestrion_bootstrap_ready" - manifest = json.encode({ - "abi": ORCHESTRION_BOOTSTRAP_CACHE_ABI, - "patchset_id": ORCHESTRION_PATCHSET_ID, - "cache_key": paths.key, - "orchestrion_version": version, - "go_identity": { - "version": go_identity.version, - "goos": go_identity.goos, - "goarch": go_identity.goarch, - }, - "dd_trace_go_versions": version_map, - "binary_name": binary_name, - "binary_sha256": _binary_sha256(ctx, binary_name), - }) - ctx.file(manifest_repo_path, manifest + "\n") + manifest = _bootstrap_manifest_content( + paths, + version, + version_map, + go_identity, + binary_name, + _binary_sha256(ctx, binary_name), + ) + ctx.file(manifest_repo_path, manifest) ctx.file(ready_repo_path, "ready\n") + _host_remove_path_if_exists(ctx, paths.ready_path, "Failed to invalidate Orchestrion bootstrap cache") _host_copy_file(ctx, binary_name, paths.binary_path, "Failed to persist cached Orchestrion binary") _host_copy_file(ctx, "dd_trace_go_versions.json", paths.version_file_path, "Failed to persist cached Orchestrion version file") _host_copy_file(ctx, "orchestrion_version.txt", paths.tool_version_file_path, "Failed to persist cached Orchestrion tool version file") @@ -986,8 +1182,8 @@ def _write_bootstrap_cache(ctx, paths, version, version_map, go_identity, binary _host_copy_file(ctx, manifest_repo_path, paths.manifest_path, "Failed to persist Orchestrion bootstrap manifest") _host_copy_file(ctx, ready_repo_path, paths.ready_path, "Failed to persist Orchestrion bootstrap ready sentinel") -def _restore_bootstrap_cache(ctx, paths, binary_name): - if not _bootstrap_cache_entry_ready(ctx, paths): +def _restore_bootstrap_cache(ctx, paths, version, version_map, go_identity, binary_name): + if not _bootstrap_cache_entry_ready(ctx, paths, version, version_map, go_identity, binary_name): return False binary_restored, _, _ = _host_copy_file_result(ctx, paths.binary_path, binary_name) if not binary_restored: @@ -1012,9 +1208,14 @@ def _restore_bootstrap_cache(ctx, paths, binary_name): orchestrion_extension_test_helpers = struct( bootstrap_cache_key = _bootstrap_cache_key, + bootstrap_manifest_content = _bootstrap_manifest_content, bootstrap_cache_paths = _bootstrap_cache_paths_with_root, bootstrap_cache_required_entries = _bootstrap_cache_required_entries, + declared_dd_trace_go_versions = _declared_dd_trace_go_versions, + declared_go_tool_identity = _declared_go_tool_identity, fallback_go_tool_identity = _fallback_go_tool_identity, + git_env = _git_env, + go_module_fetch_env = _go_module_fetch_env, host_path_is_writable = _host_path_is_writable, module_proxy_resolved_modules_json = _module_proxy_resolved_modules_json, module_proxy_seed_go_mod = _module_proxy_seed_go_mod, @@ -1024,24 +1225,121 @@ orchestrion_extension_test_helpers = struct( powershell_single_quoted_literal = _powershell_single_quoted_literal, ) +_TEST_OPTIMIZATION_ENABLED_ENV = "DD_TEST_OPTIMIZATION_ENABLED" +_TEST_OPTIMIZATION_ENABLED_VALUES = ["1", "true", "yes", "on"] + +def _orchestrion_repository_enabled(ctx): + if not ctx.attr.enabled_by_env: + return True + value = ctx.os.environ.get(_TEST_OPTIMIZATION_ENABLED_ENV, "") + return value.strip().lower() in _TEST_OPTIMIZATION_ENABLED_VALUES + +def _write_empty_orchestrion_repository(ctx): + ctx.file("BUILD.bazel", """# Generated by rules_go orchestrion extension +# Orchestrion is disabled +filegroup( + name = "orchestrion", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "dd_trace_go_version_file", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "dd_trace_go_module_proxy_files", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "dd_trace_go_module_proxy_root_marker", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "orchestrion_tool_version_file", + srcs = [], + visibility = ["//visibility:public"], +) +""") + def _orchestrion_build_impl(ctx): """Build orchestrion from source.""" + if not _orchestrion_repository_enabled(ctx): + _write_empty_orchestrion_repository(ctx) + return + if ctx.attr.dd_trace_go_pin_files and not ctx.attr.go_sdk_root.strip(): + fail("dd_trace_go_pin_files requires go_sdk_root so version resolution never depends on host Go") + total_start_ms = _probe_now_ms(ctx) version = ctx.attr.version + binary_name = "orchestrion.exe" if _is_windows(ctx) else "orchestrion_bin" + declared_go_identity = _declared_go_tool_identity(ctx, ctx.attr.go_sdk_version) + declared_dd_trace_go_versions = _declared_dd_trace_go_versions( + ctx.attr.dd_trace_go_version, + ctx.attr.dd_trace_go_versions, + ctx.attr.dd_trace_go_pin_files, + ) + if declared_go_identity != None and declared_dd_trace_go_versions != None: + declared_bootstrap_cache = _bootstrap_cache_paths(ctx, version, declared_dd_trace_go_versions, declared_go_identity, binary_name) + if _restore_bootstrap_cache( + ctx, + declared_bootstrap_cache, + version, + declared_dd_trace_go_versions, + declared_go_identity, + binary_name, + ): + _probe_emit( + ctx, + "extensions.bootstrap_cache_hit", + extra = { + "cache_key": declared_bootstrap_cache.key, + "cache_root": declared_bootstrap_cache.cache_root, + "identity_source": "declared_sdk", + }, + ) + _probe_emit( + ctx, + "extensions.orchestrion_build_total", + start_ms = total_start_ms, + extra = {"dd_trace_go_version": declared_dd_trace_go_versions["github.com/DataDog/dd-trace-go/v2"]}, + ) + return + go_path = _find_go_binary(ctx) version_start_ms = _probe_now_ms(ctx) - dd_trace_go_versions = _validated_dd_trace_go_versions(ctx, go_path, ctx.attr.dd_trace_go_version, ctx.attr.dd_trace_go_versions) + dd_trace_go_versions = _validated_dd_trace_go_versions( + ctx, + go_path, + ctx.attr.dd_trace_go_version, + ctx.attr.dd_trace_go_versions, + ctx.attr.dd_trace_go_pin_files, + ) _probe_emit(ctx, "extensions.validate_dd_trace_go_versions", start_ms = version_start_ms) - binary_name = "orchestrion.exe" if _is_windows(ctx) else "orchestrion_bin" go_identity = _go_tool_identity(ctx, go_path) + if declared_go_identity != None and ( + go_identity.version != declared_go_identity.version or + go_identity.goos != declared_go_identity.goos or + go_identity.goarch != declared_go_identity.goarch + ): + fail("Configured go_sdk_version %r does not match the hermetic Go SDK identity %r" % (ctx.attr.go_sdk_version, go_identity.version)) bootstrap_cache = _bootstrap_cache_paths(ctx, version, dd_trace_go_versions, go_identity, binary_name) - if _restore_bootstrap_cache(ctx, bootstrap_cache, binary_name): + if _restore_bootstrap_cache(ctx, bootstrap_cache, version, dd_trace_go_versions, go_identity, binary_name): + if ctx.attr.dd_trace_go_pin_files: + _merge_pin_file_module_proxy(ctx) _probe_emit( ctx, "extensions.bootstrap_cache_hit", extra = { "cache_key": bootstrap_cache.key, "cache_root": bootstrap_cache.cache_root, + "identity_source": "resolved_sdk", }, ) _probe_emit( @@ -1285,7 +1583,7 @@ func fallbackLookup(primary func(string) (io.ReadCloser, error)) func(string) (i if result.return_code == 0: _probe_emit(ctx, "extensions.go_build", start_ms = build_start_ms, status = "ok") else: - fail("Failed to build orchestrion from upstream module graph: %s\n%s\n%s" % (result.stdout, result.stderr, _go_toolchain_hint())) + fail("Failed to build orchestrion from upstream module graph: %s\n%s\n%s" % (result.stdout, result.stderr, _go_toolchain_hint(ctx))) proxy_start_ms = _probe_now_ms(ctx) _write_orchestrion_module_proxy(ctx, go_path, version, dd_trace_go_versions) @@ -1294,6 +1592,8 @@ func fallbackLookup(primary func(string) (io.ReadCloser, error)) func(string) (i _write_orchestrion_repo_files(ctx, binary_name, dd_trace_go_versions, version) cache_write_start_ms = _probe_now_ms(ctx) _write_bootstrap_cache(ctx, bootstrap_cache, version, dd_trace_go_versions, go_identity, binary_name) + if ctx.attr.dd_trace_go_pin_files: + _merge_pin_file_module_proxy(ctx) _probe_emit( ctx, "extensions.bootstrap_cache_write", @@ -1311,44 +1611,22 @@ _orchestrion_build = repository_rule( "version": attr.string(mandatory = True, doc = "Orchestrion version to build"), "dd_trace_go_version": attr.string(default = "", doc = "dd-trace-go version to validate against the target module for Orchestrion-backed instrumentation"), "dd_trace_go_versions": attr.string_dict(doc = "Per-module dd-trace-go versions to validate against the target module for Orchestrion-backed instrumentation"), + "dd_trace_go_pin_files": attr.label_list(allow_files = True, doc = "Optional go.mod and go.sum labels used to derive selected dd-trace-go module versions"), + "enabled_by_env": attr.bool(default = False, doc = "Gate repository materialization on the Test Optimization repository environment"), + "go_sdk_root": attr.string(default = "", doc = "Optional label string for a hermetic Go SDK ROOT marker used to build Orchestrion"), + "go_sdk_version": attr.string(default = "", doc = "Optional declared version for go_sdk_root; enables cache lookup before materializing the SDK and is verified on cache miss"), "log_timing": attr.bool(default = False, doc = "Emit structured timing probes while building Orchestrion"), }, + environ = [ + _TEST_OPTIMIZATION_ENABLED_ENV, + "GONOSUMDB", + "GOPROXY", + ], ) def _orchestrion_empty_impl(ctx): """Create an empty placeholder repo.""" - ctx.file("BUILD.bazel", """# Generated by rules_go orchestrion extension -# No orchestrion configured -filegroup( - name = "orchestrion", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "dd_trace_go_version_file", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "dd_trace_go_module_proxy_files", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "dd_trace_go_module_proxy_root_marker", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "orchestrion_tool_version_file", - srcs = [], - visibility = ["//visibility:public"], -) -""") + _write_empty_orchestrion_repository(ctx) _orchestrion_empty = repository_rule( implementation = _orchestrion_empty_impl, @@ -1365,18 +1643,31 @@ def _orchestrion_ext_impl(module_ctx): version = "" dd_trace_go_version = "" dd_trace_go_versions = {} + dd_trace_go_pin_files = [] + enabled_by_env = True + go_sdk_root = "" + go_sdk_version = "" log_timing = False for mod in module_ctx.modules: for from_source in mod.tags.from_source: if from_source.version: - if from_source.dd_trace_go_version and from_source.dd_trace_go_versions: - fail("dd_trace_go_version and dd_trace_go_versions cannot both be set in orchestrion.from_source()") + if _configured_version_modes( + from_source.dd_trace_go_version, + from_source.dd_trace_go_versions, + from_source.dd_trace_go_pin_files, + ) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive in orchestrion.from_source()") version = from_source.version + enabled_by_env = from_source.enabled_by_env + go_sdk_root = str(from_source.go_sdk_root) if from_source.go_sdk_root else "" + go_sdk_version = from_source.go_sdk_version log_timing = from_source.log_timing if from_source.dd_trace_go_version: dd_trace_go_version = from_source.dd_trace_go_version if from_source.dd_trace_go_versions: dd_trace_go_versions = from_source.dd_trace_go_versions + if from_source.dd_trace_go_pin_files: + dd_trace_go_pin_files = from_source.dd_trace_go_pin_files break if version: break @@ -1387,6 +1678,10 @@ def _orchestrion_ext_impl(module_ctx): version = version, dd_trace_go_version = dd_trace_go_version, dd_trace_go_versions = dd_trace_go_versions, + dd_trace_go_pin_files = dd_trace_go_pin_files, + enabled_by_env = enabled_by_env, + go_sdk_root = go_sdk_root, + go_sdk_version = go_sdk_version, log_timing = log_timing, ) else: @@ -1407,6 +1702,21 @@ _from_source = tag_class( "dd_trace_go_versions": attr.string_dict( doc = "Per-module dd-trace-go versions to validate against the target module for Orchestrion-backed instrumentation.", ), + "dd_trace_go_pin_files": attr.label_list( + allow_files = True, + doc = "Optional go.mod and go.sum labels used to derive selected dd-trace-go module versions.", + ), + "enabled_by_env": attr.bool( + default = True, + doc = "Gate repository materialization on the Test Optimization repository environment.", + ), + "go_sdk_root": attr.label( + doc = "Optional hermetic Go SDK ROOT marker used to build Orchestrion.", + ), + "go_sdk_version": attr.string( + default = "", + doc = "Optional declared version for go_sdk_root; enables cache lookup before SDK materialization.", + ), "log_timing": attr.bool( default = False, doc = "Emit structured timing probes while building the Orchestrion tool repository.", diff --git a/third_party/rgo/v0_60_0/base/go/private/repositories.bzl b/third_party/rgo/v0_60_0/base/go/private/repositories.bzl index 94adead5..27895206 100644 --- a/third_party/rgo/v0_60_0/base/go/private/repositories.bzl +++ b/third_party/rgo/v0_60_0/base/go/private/repositories.bzl @@ -17,6 +17,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("//go/private:common.bzl", "MINIMUM_BAZEL_VERSION") load("//go/private:nogo.bzl", "DEFAULT_NOGO", "go_register_nogo") +load("//go/private/orchestrion:extensions.bzl", "orchestrion_empty_repository") load("//go/private:polyfill_bazel_features.bzl", "polyfill_bazel_features") load("//go/private/skylib/lib:versions.bzl", "versions") load("//proto:gogo.bzl", "gogo_special_proto") @@ -39,6 +40,15 @@ def go_rules_dependencies(force = False): if getattr(native, "bazel_version", None): versions.check(MINIMUM_BAZEL_VERSION, bazel_version = native.bazel_version) + # Keep the stable Orchestrion repository mapping available to ordinary + # WORKSPACE consumers. Test Optimization consumers declare the real tool + # repository before calling go_rules_dependencies(), so this fallback does + # not replace or fetch it. + _maybe( + orchestrion_empty_repository, + name = "rules_go_orchestrion_tool", + ) + if force: wrapper = _always else: diff --git a/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg.go b/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg.go index dab85cb8..02e5b2ee 100644 --- a/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg.go +++ b/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg.go @@ -1201,8 +1201,10 @@ func modulePackageCommandEnv(goenv *env, exportRoot string) ([]string, error) { env = setEnv(env, "GOWORK", "off") env = setEnv(env, orchestrionJobserverURLEnvVar, "") env = setEnv(env, orchestrionSkipPinEnvVar, "") - if goenv.goroot != "" { - env = setEnv(env, "GOROOT", abs(goenv.goroot)) + if goenv.sdk != "" { + // Module `go list` commands need the complete SDK root so Go can find + // its tools. The woven stdlib remains available through GOCACHE. + env = setEnv(env, "GOROOT", abs(goenv.sdk)) } goBin := filepath.Join(abs(goenv.sdk), "bin") diff --git a/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg_test.go b/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg_test.go index 9f7a1b02..3de12ac1 100644 --- a/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg_test.go +++ b/third_party/rgo/v0_60_0/base/go/tools/builders/compilepkg_test.go @@ -381,19 +381,26 @@ func TestSeedSyntheticTestmainModuleFilesFallsBack(t *testing.T) { // Orchestrion cache paths that break Windows subprocesses. func TestModulePackageCommandEnvUsesShortExportModuleCache(t *testing.T) { sdkRoot := filepath.Join(t.TempDir(), "sdk") + wovenGoRoot := filepath.Join(t.TempDir(), "woven-goroot") exportRoot := filepath.Join(t.TempDir(), "exports") if err := os.MkdirAll(filepath.Join(sdkRoot, "bin"), 0o755); err != nil { t.Fatalf("mkdir fake sdk bin: %v", err) } + if err := os.MkdirAll(wovenGoRoot, 0o755); err != nil { + t.Fatalf("mkdir fake woven goroot: %v", err) + } if err := os.MkdirAll(exportRoot, 0o755); err != nil { t.Fatalf("mkdir export root: %v", err) } - envv, err := modulePackageCommandEnv(&env{sdk: sdkRoot}, exportRoot) + envv, err := modulePackageCommandEnv(&env{sdk: sdkRoot, goroot: wovenGoRoot}, exportRoot) if err != nil { t.Fatalf("modulePackageCommandEnv error: %v", err) } + if got := getEnv(envv, "GOROOT"); got != sdkRoot { + t.Fatalf("GOROOT = %q, want complete SDK root %q", got, sdkRoot) + } wantGoPath := moduleExportModuleCacheRoot(exportRoot) if got := getEnv(envv, "GOPATH"); got != wantGoPath { t.Fatalf("GOPATH = %q, want %q", got, wantGoPath) @@ -504,6 +511,14 @@ func TestLoadModulePackageMetadataBatchSkipsBrokenTransitiveDeps(t *testing.T) { if err != nil { t.Skipf("go binary not on PATH: %v", err) } + goRootOutput, err := exec.Command(goExe, "env", "GOROOT").Output() + if err != nil { + t.Fatalf("resolve Go SDK root: %v", err) + } + sdkRoot := strings.TrimSpace(string(goRootOutput)) + if sdkRoot == "" { + t.Fatal("go env GOROOT returned an empty SDK root") + } root := t.TempDir() depDir := filepath.Join(root, "dep") @@ -542,7 +557,7 @@ func TestLoadModulePackageMetadataBatchSkipsBrokenTransitiveDeps(t *testing.T) { t.Fatalf("mkdir export root: %v", err) } metaCache, err := loadModulePackageMetadataBatch( - &env{sdk: filepath.Dir(filepath.Dir(goExe))}, + &env{sdk: sdkRoot}, mainDir, exportRoot, []string{"example.com/dep"}, diff --git a/third_party/rgo/v0_60_0/base/go/tools/builders/orchestrion_cache.go b/third_party/rgo/v0_60_0/base/go/tools/builders/orchestrion_cache.go index fa743275..e4768cfc 100644 --- a/third_party/rgo/v0_60_0/base/go/tools/builders/orchestrion_cache.go +++ b/third_party/rgo/v0_60_0/base/go/tools/builders/orchestrion_cache.go @@ -17,9 +17,9 @@ const ( // logic changes. The prepared cache snapshot only keys off the copied module // files plus selected toolchain metadata, so code-only changes would // otherwise keep restoring stale synthetic go.mod state. - syntheticModuleCacheABIVersion = "v4" - helperDecisionCacheABIVersion = "v6" - helperExportCacheABIVersion = "v5" + syntheticModuleCacheABIVersion = "v5" + helperDecisionCacheABIVersion = "v8" + helperExportCacheABIVersion = "v7" helperArchiveCacheABIVersion = "v12" // Bump the helper source-set version whenever the synthetic testmain source // compile closure changes. The helper decision and archive caches both key diff --git a/third_party/rgo/v0_60_0/base/tests/core/starlark/orchestrion_extension_tests.bzl b/third_party/rgo/v0_60_0/base/tests/core/starlark/orchestrion_extension_tests.bzl index 42c5d5a7..48b94524 100644 --- a/third_party/rgo/v0_60_0/base/tests/core/starlark/orchestrion_extension_tests.bzl +++ b/third_party/rgo/v0_60_0/base/tests/core/starlark/orchestrion_extension_tests.bzl @@ -22,8 +22,12 @@ def _bootstrap_cache_key_stability_test(ctx): ordered_key = orchestrion_extension_test_helpers.bootstrap_cache_key("v1.6.0", ordered_versions, go_identity) reordered_key = orchestrion_extension_test_helpers.bootstrap_cache_key("v1.6.0", reordered_versions, go_identity) + changed_versions = dict(ordered_versions) + changed_versions["github.com/DataDog/dd-trace-go/v2"] = "v2.8.0" + changed_key = orchestrion_extension_test_helpers.bootstrap_cache_key("v1.6.0", changed_versions, go_identity) asserts.equals(env, ordered_key, reordered_key) + asserts.false(env, ordered_key == changed_key, "a selected module version change must invalidate the bootstrap cache") return unittest.end(env) @@ -48,6 +52,38 @@ def _bootstrap_cache_paths_contract_test(ctx): bootstrap_cache_paths_contract_test = unittest.make(_bootstrap_cache_paths_contract_test) +def _bootstrap_manifest_content_test(ctx): + env = unittest.begin(ctx) + + paths = struct(key = "cache-key") + versions = { + "github.com/DataDog/dd-trace-go/contrib/log/slog/v2": "v2.7.0", + "github.com/DataDog/dd-trace-go/contrib/net/http/v2": "v2.7.0", + "github.com/DataDog/dd-trace-go/v2": "v2.7.0", + } + identity = struct( + version = "go version go1.25.0 linux/amd64", + goos = "linux", + goarch = "amd64", + ) + manifest = json.decode(orchestrion_extension_test_helpers.bootstrap_manifest_content( + paths, + "v1.6.0", + versions, + identity, + "orchestrion_bin", + "0123456789abcdef", + )) + + asserts.equals(env, "cache-key", manifest["cache_key"]) + asserts.equals(env, identity.version, manifest["go_identity"]["version"]) + asserts.equals(env, versions, manifest["dd_trace_go_versions"]) + asserts.equals(env, "0123456789abcdef", manifest["binary_sha256"]) + + return unittest.end(env) + +bootstrap_manifest_content_test = unittest.make(_bootstrap_manifest_content_test) + def _module_proxy_seed_go_mod_test(ctx): env = unittest.begin(ctx) @@ -128,6 +164,55 @@ def _host_platform_normalization_test(ctx): host_platform_normalization_test = unittest.make(_host_platform_normalization_test) +def _git_env_test(ctx): + env = unittest.begin(ctx) + + linux_env = orchestrion_extension_test_helpers.git_env(struct(os = struct(name = "linux"))) + asserts.equals(env, "/dev/null", linux_env["GIT_CONFIG_GLOBAL"]) + asserts.equals(env, "1", linux_env["GIT_CONFIG_NOSYSTEM"]) + asserts.equals(env, "0", linux_env["GIT_TERMINAL_PROMPT"]) + + windows_env = orchestrion_extension_test_helpers.git_env(struct(os = struct(name = "windows_nt"))) + asserts.equals(env, "NUL", windows_env["GIT_CONFIG_GLOBAL"]) + asserts.equals(env, "1", windows_env["GIT_CONFIG_NOSYSTEM"]) + asserts.equals(env, "0", windows_env["GIT_TERMINAL_PROMPT"]) + + return unittest.end(env) + +git_env_test = unittest.make(_git_env_test) + +def _go_module_fetch_env_test(ctx): + env = unittest.begin(ctx) + + default_env = orchestrion_extension_test_helpers.go_module_fetch_env( + struct(os = struct(environ = {})), + ) + asserts.equals(env, "https://proxy.golang.org,direct", default_env["GOPROXY"]) + asserts.equals(env, "", default_env["GONOSUMDB"]) + asserts.equals(env, "", default_env["GOPRIVATE"]) + asserts.equals(env, "", default_env["GONOPROXY"]) + asserts.equals(env, "sum.golang.org https://sum.golang.org", default_env["GOSUMDB"]) + + configured_env = orchestrion_extension_test_helpers.go_module_fetch_env( + struct( + os = struct( + environ = { + "GONOSUMDB": "github.com/DataDog", + "GOPROXY": "https://proxy.example.test,direct", + }, + ), + ), + ) + asserts.equals(env, "https://proxy.example.test,direct", configured_env["GOPROXY"]) + asserts.equals(env, "github.com/DataDog", configured_env["GONOSUMDB"]) + asserts.equals(env, "", configured_env["GOPRIVATE"]) + asserts.equals(env, "", configured_env["GONOPROXY"]) + asserts.equals(env, "sum.golang.org https://sum.golang.org", configured_env["GOSUMDB"]) + + return unittest.end(env) + +go_module_fetch_env_test = unittest.make(_go_module_fetch_env_test) + def _fallback_go_tool_identity_test(ctx): env = unittest.begin(ctx) @@ -147,12 +232,56 @@ def _fallback_go_tool_identity_test(ctx): fallback_go_tool_identity_test = unittest.make(_fallback_go_tool_identity_test) +def _declared_go_tool_identity_test(ctx): + env = unittest.begin(ctx) + fake_ctx = struct( + os = struct( + name = "mac os x", + arch = "aarch64", + ), + ) + + identity = orchestrion_extension_test_helpers.declared_go_tool_identity(fake_ctx, "1.25.0") + asserts.equals(env, "go version go1.25.0 darwin/arm64", identity.version) + asserts.equals(env, "darwin", identity.goos) + asserts.equals(env, "arm64", identity.goarch) + asserts.equals(env, identity.version, orchestrion_extension_test_helpers.declared_go_tool_identity(fake_ctx, "go1.25.0").version) + asserts.equals(env, None, orchestrion_extension_test_helpers.declared_go_tool_identity(fake_ctx, "")) + + return unittest.end(env) + +declared_go_tool_identity_test = unittest.make(_declared_go_tool_identity_test) + +def _declared_dd_trace_go_versions_test(ctx): + env = unittest.begin(ctx) + canonical = orchestrion_extension_test_helpers.declared_dd_trace_go_versions("v2.9.0", {}) + asserts.equals(env, "v2.9.0", canonical["github.com/DataDog/dd-trace-go/v2"]) + asserts.equals(env, None, orchestrion_extension_test_helpers.declared_dd_trace_go_versions("main", {})) + asserts.equals( + env, + None, + orchestrion_extension_test_helpers.declared_dd_trace_go_versions( + "", + {}, + ["//:go.mod", "//:go.sum"], + ), + ) + + return unittest.end(env) + +declared_dd_trace_go_versions_test = unittest.make(_declared_dd_trace_go_versions_test) + def orchestrion_extension_test_suite(): unittest.suite( "orchestrion_extension_tests", bootstrap_cache_key_stability_test, + bootstrap_manifest_content_test, bootstrap_cache_paths_contract_test, + declared_dd_trace_go_versions_test, + declared_go_tool_identity_test, fallback_go_tool_identity_test, + git_env_test, + go_module_fetch_env_test, host_platform_normalization_test, module_proxy_resolved_modules_json_test, module_proxy_seed_go_mod_test, diff --git a/third_party/rgo/v0_61_1/base.CHANGED_FILES.md b/third_party/rgo/v0_61_1/base.CHANGED_FILES.md index cab689be..bed6af76 100644 --- a/third_party/rgo/v0_61_1/base.CHANGED_FILES.md +++ b/third_party/rgo/v0_61_1/base.CHANGED_FILES.md @@ -12,8 +12,8 @@ This file is generated. Do not edit by hand. ## Summary -- Total changed paths: `53` -- Modified files: `29` +- Total changed paths: `54` +- Modified files: `30` - Added files: `24` - Removed files: `0` @@ -30,6 +30,7 @@ This file is generated. Do not edit by hand. - `go/private/actions/link.bzl` - `go/private/actions/stdlib.bzl` - `go/private/context.bzl` +- `go/private/repositories.bzl` - `go/private/rules/library.bzl` - `go/private/rules/stdlib.bzl` - `go/private/rules/test.bzl` diff --git a/third_party/rgo/v0_61_1/base/go/orchestrion_workspace.bzl b/third_party/rgo/v0_61_1/base/go/orchestrion_workspace.bzl index 8d85b877..ce443892 100644 --- a/third_party/rgo/v0_61_1/base/go/orchestrion_workspace.bzl +++ b/third_party/rgo/v0_61_1/base/go/orchestrion_workspace.bzl @@ -8,11 +8,26 @@ load( _DEFAULT_TOOL_REPO_NAME = "rules_go_orchestrion_tool" +def _configured_version_modes(dd_trace_go_version, dd_trace_go_versions, dd_trace_go_pin_files): + return len([ + value + for value in [ + dd_trace_go_version, + dd_trace_go_versions, + dd_trace_go_pin_files, + ] + if value + ]) + def go_orchestrion_tool_repo( name = _DEFAULT_TOOL_REPO_NAME, version = "", dd_trace_go_version = "", dd_trace_go_versions = None, + dd_trace_go_pin_files = None, + enabled_by_env = False, + go_sdk_root = "", + go_sdk_version = "", log_timing = False): """Create the `rules_go_orchestrion_tool` repository in WORKSPACE mode. @@ -25,6 +40,18 @@ def go_orchestrion_tool_repo( target module when instrumentation is enabled. dd_trace_go_versions: Optional per-module dd-trace-go version mapping. Mutually exclusive with `dd_trace_go_version`. + dd_trace_go_pin_files: Optional `[go.mod, go.sum]` labels used to derive + the selected direct and transitive dd-trace-go module versions. + Mutually exclusive with explicit version fields. + enabled_by_env: Gate repository materialization on the Test Optimization + repository environment. Generic Orchestrion callers should keep the + default. + go_sdk_root: Optional label string for a hermetic Go SDK ROOT marker. + When set, the enabled repository builds Orchestrion with that SDK + instead of searching for Go on the host. + go_sdk_version: Optional declared version for `go_sdk_root`. When set, + bootstrap can restore an existing cache entry before materializing the + SDK and verifies the declared value on cache miss. log_timing: Emit structured bootstrap timing probes while building the Orchestrion tool repository. """ @@ -35,14 +62,16 @@ def go_orchestrion_tool_repo( if dd_trace_go_versions == None: dd_trace_go_versions = {} + if dd_trace_go_pin_files == None: + dd_trace_go_pin_files = [] - if dd_trace_go_version and dd_trace_go_versions: - fail("go_orchestrion_tool_repo: dd_trace_go_version and dd_trace_go_versions cannot both be set") + if _configured_version_modes(dd_trace_go_version, dd_trace_go_versions, dd_trace_go_pin_files) > 1: + fail("go_orchestrion_tool_repo: dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") if not version: fail("go_orchestrion_tool_repo: version is required in WORKSPACE mode") - if not dd_trace_go_version and not dd_trace_go_versions: + if not dd_trace_go_version and not dd_trace_go_versions and not dd_trace_go_pin_files: dd_trace_go_version = DEFAULT_DD_TRACE_GO_VERSION orchestrion_build_repository( @@ -50,5 +79,9 @@ def go_orchestrion_tool_repo( version = version, dd_trace_go_version = dd_trace_go_version, dd_trace_go_versions = dd_trace_go_versions, + dd_trace_go_pin_files = dd_trace_go_pin_files, + enabled_by_env = enabled_by_env, + go_sdk_root = go_sdk_root, + go_sdk_version = go_sdk_version, log_timing = log_timing, ) diff --git a/third_party/rgo/v0_61_1/base/go/private/orchestrion/BUILD b/third_party/rgo/v0_61_1/base/go/private/orchestrion/BUILD index 488d4adf..177eeaf2 100644 --- a/third_party/rgo/v0_61_1/base/go/private/orchestrion/BUILD +++ b/third_party/rgo/v0_61_1/base/go/private/orchestrion/BUILD @@ -29,37 +29,80 @@ string_flag( visibility = ["//visibility:public"], ) -# Proxy target for the orchestrion tool binary. -# This always points to the rules_go_orchestrion_tool repo. -# The repo provides an empty filegroup by default, or the actual orchestrion -# binary when configured via module extension. -# go_context_data checks the :enabled flag to determine whether to use this. +config_setting( + name = "enabled_config", + flag_values = {":enabled": "true"}, +) + +filegroup( + name = "disabled_tool_binary", + srcs = [], +) + +filegroup( + name = "disabled_dd_trace_go_version_file", + srcs = [], +) + +filegroup( + name = "disabled_dd_trace_go_module_proxy_files", + srcs = [], +) + +filegroup( + name = "disabled_dd_trace_go_module_proxy_root_marker", + srcs = [], +) + +filegroup( + name = "disabled_orchestrion_tool_version_file", + srcs = [], +) + +# Stable Orchestrion aliases select package-local empty targets by default and +# only reference the real tool repository when the public :enabled flag is set. +# go_context_data also checks :enabled before consuming these files. alias( name = "tool_binary", - actual = "@rules_go_orchestrion_tool//:orchestrion", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:orchestrion", + "//conditions:default": ":disabled_tool_binary", + }), visibility = ["//visibility:public"], ) alias( name = "dd_trace_go_version_file", - actual = "@rules_go_orchestrion_tool//:dd_trace_go_version_file", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:dd_trace_go_version_file", + "//conditions:default": ":disabled_dd_trace_go_version_file", + }), visibility = ["//visibility:public"], ) alias( name = "dd_trace_go_module_proxy_files", - actual = "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_files", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_files", + "//conditions:default": ":disabled_dd_trace_go_module_proxy_files", + }), visibility = ["//visibility:public"], ) alias( name = "dd_trace_go_module_proxy_root_marker", - actual = "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_root_marker", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:dd_trace_go_module_proxy_root_marker", + "//conditions:default": ":disabled_dd_trace_go_module_proxy_root_marker", + }), visibility = ["//visibility:public"], ) alias( name = "orchestrion_tool_version_file", - actual = "@rules_go_orchestrion_tool//:orchestrion_tool_version_file", + actual = select({ + ":enabled_config": "@rules_go_orchestrion_tool//:orchestrion_tool_version_file", + "//conditions:default": ":disabled_orchestrion_tool_version_file", + }), visibility = ["//visibility:public"], ) diff --git a/third_party/rgo/v0_61_1/base/go/private/orchestrion/extensions.bzl b/third_party/rgo/v0_61_1/base/go/private/orchestrion/extensions.bzl index 05652331..db1f149f 100644 --- a/third_party/rgo/v0_61_1/base/go/private/orchestrion/extensions.bzl +++ b/third_party/rgo/v0_61_1/base/go/private/orchestrion/extensions.bzl @@ -33,6 +33,15 @@ _DD_TRACE_GO_PREFLIGHT_PACKAGES = [ ] def _find_go_binary(ctx): + go_sdk_root = ctx.attr.go_sdk_root.strip() + if go_sdk_root: + root_file = ctx.path(Label(go_sdk_root)) + binary_name = "go.exe" if _is_windows(ctx) else "go" + go_path = root_file.dirname.get_child("bin").get_child(binary_name) + if not go_path.exists: + fail("Configured hermetic Go SDK does not expose %s next to %s" % (go_path, root_file)) + return go_path + go_path = ctx.which("go") if go_path: return go_path @@ -95,24 +104,42 @@ def _bootstrap_cache_root(ctx): def _bootstrap_go_cache_root(ctx): return _path_join(ctx, _bootstrap_cache_root(ctx), "go") +def _git_env(ctx): + # GOPROXY=direct may invoke Git. Keep that fallback independent from host + # rewrites, credential helpers, and interactive prompts. + return { + "GIT_CONFIG_GLOBAL": "NUL" if _is_windows(ctx) else "/dev/null", + "GIT_CONFIG_NOSYSTEM": "1", + "GIT_TERMINAL_PROMPT": "0", + } + +def _go_module_fetch_env(ctx): + host_env = ctx.os.environ + return { + # Allow consumers to provide an internal or authenticated module proxy, + # while keeping private-module resolution on that proxy instead of + # falling back to host Git configuration. + "GOPRIVATE": "", + "GONOPROXY": "", + "GONOSUMDB": (host_env.get("GONOSUMDB") or "").strip(), + "GOPROXY": (host_env.get("GOPROXY") or "").strip() or "https://proxy.golang.org,direct", + # Use the public checksum database directly. Some internal module + # proxies expose SumDB endpoints that are reachable only inside CI. + "GOSUMDB": "sum.golang.org https://sum.golang.org", + } + def _go_env(ctx): go_cache_root = _bootstrap_go_cache_root(ctx) - return { + env = { "GO111MODULE": "on", "GOWORK": "off", - "GOTOOLCHAIN": "go1.25.0+auto", - # Repository resolution only needs public modules. Clear host-specific - # private-module settings so bootstrap does not silently fall back to - # direct VCS fetches based on the developer environment. - "GOPRIVATE": "", - "GONOPROXY": "", - "GONOSUMDB": "", - "GOPROXY": "https://proxy.golang.org,direct", - "GOSUMDB": "sum.golang.org", - "GIT_TERMINAL_PROMPT": "0", + "GOTOOLCHAIN": "local" if ctx.attr.go_sdk_root.strip() else "go1.25.0+auto", "GOMODCACHE": _path_join(ctx, go_cache_root, "pkg", "mod"), "GOCACHE": _path_join(ctx, go_cache_root, "cache"), } + env.update(_go_module_fetch_env(ctx)) + env.update(_git_env(ctx)) + return env def _probe_enabled(ctx): return getattr(ctx.attr, "log_timing", False) @@ -196,6 +223,20 @@ def _fallback_go_tool_identity(ctx): goarch = _normalize_host_goarch(ctx.os.arch), ) +def _declared_go_tool_identity(ctx, go_sdk_version): + version = go_sdk_version.strip() + if not version: + return None + if not version.startswith("go"): + version = "go" + version + goos = _normalize_host_goos(ctx.os.name) + goarch = _normalize_host_goarch(ctx.os.arch) + return struct( + version = "go version %s %s/%s" % (version, goos, goarch), + goos = goos, + goarch = goarch, + ) + def _go_tool_identity(ctx, go_path): # Some integration tests and bootstrap environments intentionally wrap # `go` with a narrow shim that supports only the commands needed to build @@ -282,6 +323,22 @@ def _bootstrap_cache_required_entries(paths): module_proxy_root_marker = paths.module_proxy_root_marker, ) +def _bootstrap_manifest_content(paths, version, version_map, go_identity, binary_name, binary_sha256): + return json.encode({ + "abi": ORCHESTRION_BOOTSTRAP_CACHE_ABI, + "patchset_id": ORCHESTRION_PATCHSET_ID, + "cache_key": paths.key, + "orchestrion_version": version, + "go_identity": { + "version": go_identity.version, + "goos": go_identity.goos, + "goarch": go_identity.goarch, + }, + "dd_trace_go_versions": version_map, + "binary_name": binary_name, + "binary_sha256": binary_sha256, + }) + "\n" + def _module_proxy_tree_has_payload(ctx, module_proxy_dir, root_marker): if not ctx.path(module_proxy_dir).exists or not ctx.path(root_marker).exists: return False @@ -314,12 +371,23 @@ def _module_proxy_tree_has_payload(ctx, module_proxy_dir, root_marker): ) return result.return_code == 0 and bool(result.stdout.strip()) -def _bootstrap_cache_entry_ready(ctx, paths): +def _bootstrap_cache_entry_ready(ctx, paths, version, version_map, go_identity, binary_name): required = _bootstrap_cache_required_entries(paths) for required_path in required.files: if not ctx.path(required_path).exists: return False - return _module_proxy_tree_has_payload(ctx, required.module_proxy_dir, required.module_proxy_root_marker) + if not _module_proxy_tree_has_payload(ctx, required.module_proxy_dir, required.module_proxy_root_marker): + return False + binary_sha256 = _binary_sha256(ctx, paths.binary_path) + expected_manifest = _bootstrap_manifest_content( + paths, + version, + version_map, + go_identity, + binary_name, + binary_sha256, + ) + return ctx.read(ctx.path(paths.manifest_path)) == expected_manifest def _dd_trace_go_versions_from_shared(version): version_map = {} @@ -389,7 +457,9 @@ def _should_append_go_toolchain_hint(args): return True return "mod" in argv and "download" in argv -def _go_toolchain_hint(): +def _go_toolchain_hint(ctx): + if ctx.attr.go_sdk_root.strip(): + return "Bootstrap uses the configured hermetic Go SDK with GOTOOLCHAIN=local. Ensure go_sdk_root and go_sdk_version identify the same SDK." return "Bootstrap uses GOTOOLCHAIN=go1.25.0+auto. If Go 1.25.0 is not already installed, the Go tool may try to download it during repository resolution. In restricted environments, preinstall Go 1.25.0 or allow fetch-time egress, then rerun bazel sync." def _ctx_execute_or_fail(ctx, args, env, error_prefix): @@ -397,7 +467,7 @@ def _ctx_execute_or_fail(ctx, args, env, error_prefix): if result.return_code != 0: details = "%s: %s\n%s" % (error_prefix, result.stdout, result.stderr) if _should_append_go_toolchain_hint(args): - details += "\n" + _go_toolchain_hint() + details += "\n" + _go_toolchain_hint(ctx) fail(details) return result @@ -533,15 +603,119 @@ def _validated_per_module_dd_trace_go_versions(ctx, go_path, version_map): _run_dd_trace_go_package_preflight(ctx, go_path, version_map) return _copy_dd_trace_go_versions(version_map) -def _validated_dd_trace_go_versions(ctx, go_path, shared_query, version_map): - if shared_query and version_map: - fail("dd_trace_go_version and dd_trace_go_versions cannot both be set") +def _configured_version_modes(shared_query, version_map, pin_files): + return len([ + value + for value in [ + shared_query, + version_map, + pin_files, + ] + if value + ]) + +def _pin_file_by_basename(ctx, pin_files, basename): + matches = [pin_file for pin_file in pin_files if ctx.path(pin_file).basename == basename] + if len(matches) != 1: + fail("dd_trace_go_pin_files must contain exactly one %s label" % basename) + return matches[0] + +def _validated_pin_file_dd_trace_go_versions(ctx, go_path, pin_files): + if not ctx.attr.go_sdk_root.strip(): + fail("dd_trace_go_pin_files requires go_sdk_root so version resolution never depends on host Go") + if len(pin_files) != 2: + fail("dd_trace_go_pin_files must contain exactly one go.mod label and one go.sum label") + go_mod = _pin_file_by_basename(ctx, pin_files, "go.mod") + go_sum = _pin_file_by_basename(ctx, pin_files, "go.sum") + check_dir = ".ddtrace_pin_check" + ctx.file(check_dir + "/go.mod", ctx.read(ctx.path(go_mod))) + ctx.file(check_dir + "/go.sum", ctx.read(ctx.path(go_sum))) + env = _go_env(ctx) + pin_cache_root = str(ctx.path(".ddtrace_pin_check_go")) + env["GOMODCACHE"] = _path_join(ctx, pin_cache_root, "pkg", "mod") + env["GOCACHE"] = _path_join(ctx, pin_cache_root, "cache") + env["GOFLAGS"] = "-mod=readonly" + format_expr = "{{if .Path}}{{.Path}}={{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}{{end}}" + result = ctx.execute( + [ + str(go_path), + "-C", + check_dir, + "list", + "-m", + "-mod=readonly", + "-f", + format_expr, + ] + _DD_TRACE_GO_MODULES, + timeout = 600, + environment = env, + ) + if result.return_code != 0: + fail( + ( + "Failed to derive dd-trace-go versions from dd_trace_go_pin_files: %s\n%s\n" + + "Ensure go.mod/go.sum select every supported tracer module, including transitive contrib modules. " + + "For unsupported module graphs, configure dd_trace_go_versions explicitly." + ) % (result.stdout, result.stderr), + ) + resolved = _parse_key_value_lines( + result.stdout, + _DD_TRACE_GO_MODULES, + "Failed to derive dd-trace-go versions from dd_trace_go_pin_files", + ) + for module_path in _DD_TRACE_GO_MODULES: + version = resolved[module_path] + if not _looks_like_canonical_dd_trace_go_version(version): + fail( + ( + "dd_trace_go_pin_files resolved %s to non-canonical version %r; " + + "configure dd_trace_go_versions explicitly" + ) % (module_path, version), + ) + _run_dd_trace_go_package_preflight(ctx, go_path, resolved) + return resolved + +def _merge_pin_file_module_proxy(ctx): + pin_cache_root = str(ctx.path(".ddtrace_pin_check_go")) + download_root = _path_join(ctx, pin_cache_root, "pkg", "mod", "cache", "download") + if not ctx.path(download_root).exists: + fail("dd_trace_go_pin_files resolution produced no module metadata to stage") + _host_merge_tree( + ctx, + download_root, + "module_proxy", + "Failed to stage dd_trace_go_pin_files module metadata", + ) + _host_remove_path_if_exists(ctx, "module_proxy/sumdb", "Failed to prune pin-file module proxy sumdb cache") + _host_remove_path_if_exists(ctx, "module_proxy/golang.org/toolchain", "Failed to prune pin-file module proxy toolchain module") + +def _validated_dd_trace_go_versions(ctx, go_path, shared_query, version_map, pin_files): + if _configured_version_modes(shared_query, version_map, pin_files) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") + if pin_files: + return _validated_pin_file_dd_trace_go_versions(ctx, go_path, pin_files) if version_map: return _validated_per_module_dd_trace_go_versions(ctx, go_path, version_map) if shared_query: return _validated_shared_dd_trace_go_versions(ctx, go_path, shared_query) return _dd_trace_go_versions_from_shared(DEFAULT_DD_TRACE_GO_VERSION) +def _declared_dd_trace_go_versions(shared_query, version_map, pin_files = []): + if _configured_version_modes(shared_query, version_map, pin_files) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive") + if pin_files: + return None + if version_map: + _validate_dd_trace_go_versions_keys(version_map) + if all([_looks_like_canonical_dd_trace_go_version(version_map[module_path]) for module_path in _DD_TRACE_GO_MODULES]): + return _copy_dd_trace_go_versions(version_map) + return None + if shared_query: + if _looks_like_canonical_dd_trace_go_version(shared_query): + return _dd_trace_go_versions_from_shared(shared_query) + return None + return _dd_trace_go_versions_from_shared(DEFAULT_DD_TRACE_GO_VERSION) + def _dd_trace_go_versions_json(version_map): entries = [] for module_path in _DD_TRACE_GO_MODULES: @@ -692,6 +866,33 @@ def _host_copy_tree(ctx, src, dst, error_prefix): if not copied: fail("%s: %s\n%s" % (error_prefix, stdout, stderr)) +def _host_merge_tree(ctx, src, dst, error_prefix): + src_path = str(ctx.path(src)) + dst_path = str(ctx.path(dst)) + if _is_windows(ctx): + powershell = ctx.which("powershell.exe") or ctx.which("pwsh") or ctx.which("powershell") + if not powershell: + fail("%s: could not find PowerShell" % error_prefix) + command = "$ErrorActionPreference = 'Stop'; New-Item -ItemType Directory -Force -Path %s | Out-Null; Get-ChildItem -LiteralPath %s -Force | Copy-Item -Destination %s -Recurse -Force" % ( + _powershell_single_quoted_literal(dst_path), + _powershell_single_quoted_literal(src_path), + _powershell_single_quoted_literal(dst_path), + ) + result = _ctx_execute_checked( + ctx, + [str(powershell), "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", command], + timeout = 180, + ) + else: + shell = ctx.which("sh") or "/bin/sh" + result = _ctx_execute_checked( + ctx, + [str(shell), "-c", "mkdir -p \"$2\" && cp -R \"$1/.\" \"$2\"", "bootstrap-merge-tree", src_path, dst_path], + timeout = 180, + ) + if result.return_code != 0: + fail("%s: %s\n%s" % (error_prefix, result.stdout, result.stderr)) + def _host_remove_path_if_exists(ctx, path, error_prefix): removed, stdout, stderr = _host_remove_path_if_exists_result(ctx, path) if not removed: @@ -961,22 +1162,17 @@ def _write_orchestrion_repo_files(ctx, binary_name, dd_trace_go_versions, versio def _write_bootstrap_cache(ctx, paths, version, version_map, go_identity, binary_name): manifest_repo_path = ".orchestrion_bootstrap_manifest.json" ready_repo_path = ".orchestrion_bootstrap_ready" - manifest = json.encode({ - "abi": ORCHESTRION_BOOTSTRAP_CACHE_ABI, - "patchset_id": ORCHESTRION_PATCHSET_ID, - "cache_key": paths.key, - "orchestrion_version": version, - "go_identity": { - "version": go_identity.version, - "goos": go_identity.goos, - "goarch": go_identity.goarch, - }, - "dd_trace_go_versions": version_map, - "binary_name": binary_name, - "binary_sha256": _binary_sha256(ctx, binary_name), - }) - ctx.file(manifest_repo_path, manifest + "\n") + manifest = _bootstrap_manifest_content( + paths, + version, + version_map, + go_identity, + binary_name, + _binary_sha256(ctx, binary_name), + ) + ctx.file(manifest_repo_path, manifest) ctx.file(ready_repo_path, "ready\n") + _host_remove_path_if_exists(ctx, paths.ready_path, "Failed to invalidate Orchestrion bootstrap cache") _host_copy_file(ctx, binary_name, paths.binary_path, "Failed to persist cached Orchestrion binary") _host_copy_file(ctx, "dd_trace_go_versions.json", paths.version_file_path, "Failed to persist cached Orchestrion version file") _host_copy_file(ctx, "orchestrion_version.txt", paths.tool_version_file_path, "Failed to persist cached Orchestrion tool version file") @@ -986,8 +1182,8 @@ def _write_bootstrap_cache(ctx, paths, version, version_map, go_identity, binary _host_copy_file(ctx, manifest_repo_path, paths.manifest_path, "Failed to persist Orchestrion bootstrap manifest") _host_copy_file(ctx, ready_repo_path, paths.ready_path, "Failed to persist Orchestrion bootstrap ready sentinel") -def _restore_bootstrap_cache(ctx, paths, binary_name): - if not _bootstrap_cache_entry_ready(ctx, paths): +def _restore_bootstrap_cache(ctx, paths, version, version_map, go_identity, binary_name): + if not _bootstrap_cache_entry_ready(ctx, paths, version, version_map, go_identity, binary_name): return False binary_restored, _, _ = _host_copy_file_result(ctx, paths.binary_path, binary_name) if not binary_restored: @@ -1012,9 +1208,14 @@ def _restore_bootstrap_cache(ctx, paths, binary_name): orchestrion_extension_test_helpers = struct( bootstrap_cache_key = _bootstrap_cache_key, + bootstrap_manifest_content = _bootstrap_manifest_content, bootstrap_cache_paths = _bootstrap_cache_paths_with_root, bootstrap_cache_required_entries = _bootstrap_cache_required_entries, + declared_dd_trace_go_versions = _declared_dd_trace_go_versions, + declared_go_tool_identity = _declared_go_tool_identity, fallback_go_tool_identity = _fallback_go_tool_identity, + git_env = _git_env, + go_module_fetch_env = _go_module_fetch_env, host_path_is_writable = _host_path_is_writable, module_proxy_resolved_modules_json = _module_proxy_resolved_modules_json, module_proxy_seed_go_mod = _module_proxy_seed_go_mod, @@ -1024,24 +1225,121 @@ orchestrion_extension_test_helpers = struct( powershell_single_quoted_literal = _powershell_single_quoted_literal, ) +_TEST_OPTIMIZATION_ENABLED_ENV = "DD_TEST_OPTIMIZATION_ENABLED" +_TEST_OPTIMIZATION_ENABLED_VALUES = ["1", "true", "yes", "on"] + +def _orchestrion_repository_enabled(ctx): + if not ctx.attr.enabled_by_env: + return True + value = ctx.os.environ.get(_TEST_OPTIMIZATION_ENABLED_ENV, "") + return value.strip().lower() in _TEST_OPTIMIZATION_ENABLED_VALUES + +def _write_empty_orchestrion_repository(ctx): + ctx.file("BUILD.bazel", """# Generated by rules_go orchestrion extension +# Orchestrion is disabled +filegroup( + name = "orchestrion", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "dd_trace_go_version_file", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "dd_trace_go_module_proxy_files", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "dd_trace_go_module_proxy_root_marker", + srcs = [], + visibility = ["//visibility:public"], +) + +filegroup( + name = "orchestrion_tool_version_file", + srcs = [], + visibility = ["//visibility:public"], +) +""") + def _orchestrion_build_impl(ctx): """Build orchestrion from source.""" + if not _orchestrion_repository_enabled(ctx): + _write_empty_orchestrion_repository(ctx) + return + if ctx.attr.dd_trace_go_pin_files and not ctx.attr.go_sdk_root.strip(): + fail("dd_trace_go_pin_files requires go_sdk_root so version resolution never depends on host Go") + total_start_ms = _probe_now_ms(ctx) version = ctx.attr.version + binary_name = "orchestrion.exe" if _is_windows(ctx) else "orchestrion_bin" + declared_go_identity = _declared_go_tool_identity(ctx, ctx.attr.go_sdk_version) + declared_dd_trace_go_versions = _declared_dd_trace_go_versions( + ctx.attr.dd_trace_go_version, + ctx.attr.dd_trace_go_versions, + ctx.attr.dd_trace_go_pin_files, + ) + if declared_go_identity != None and declared_dd_trace_go_versions != None: + declared_bootstrap_cache = _bootstrap_cache_paths(ctx, version, declared_dd_trace_go_versions, declared_go_identity, binary_name) + if _restore_bootstrap_cache( + ctx, + declared_bootstrap_cache, + version, + declared_dd_trace_go_versions, + declared_go_identity, + binary_name, + ): + _probe_emit( + ctx, + "extensions.bootstrap_cache_hit", + extra = { + "cache_key": declared_bootstrap_cache.key, + "cache_root": declared_bootstrap_cache.cache_root, + "identity_source": "declared_sdk", + }, + ) + _probe_emit( + ctx, + "extensions.orchestrion_build_total", + start_ms = total_start_ms, + extra = {"dd_trace_go_version": declared_dd_trace_go_versions["github.com/DataDog/dd-trace-go/v2"]}, + ) + return + go_path = _find_go_binary(ctx) version_start_ms = _probe_now_ms(ctx) - dd_trace_go_versions = _validated_dd_trace_go_versions(ctx, go_path, ctx.attr.dd_trace_go_version, ctx.attr.dd_trace_go_versions) + dd_trace_go_versions = _validated_dd_trace_go_versions( + ctx, + go_path, + ctx.attr.dd_trace_go_version, + ctx.attr.dd_trace_go_versions, + ctx.attr.dd_trace_go_pin_files, + ) _probe_emit(ctx, "extensions.validate_dd_trace_go_versions", start_ms = version_start_ms) - binary_name = "orchestrion.exe" if _is_windows(ctx) else "orchestrion_bin" go_identity = _go_tool_identity(ctx, go_path) + if declared_go_identity != None and ( + go_identity.version != declared_go_identity.version or + go_identity.goos != declared_go_identity.goos or + go_identity.goarch != declared_go_identity.goarch + ): + fail("Configured go_sdk_version %r does not match the hermetic Go SDK identity %r" % (ctx.attr.go_sdk_version, go_identity.version)) bootstrap_cache = _bootstrap_cache_paths(ctx, version, dd_trace_go_versions, go_identity, binary_name) - if _restore_bootstrap_cache(ctx, bootstrap_cache, binary_name): + if _restore_bootstrap_cache(ctx, bootstrap_cache, version, dd_trace_go_versions, go_identity, binary_name): + if ctx.attr.dd_trace_go_pin_files: + _merge_pin_file_module_proxy(ctx) _probe_emit( ctx, "extensions.bootstrap_cache_hit", extra = { "cache_key": bootstrap_cache.key, "cache_root": bootstrap_cache.cache_root, + "identity_source": "resolved_sdk", }, ) _probe_emit( @@ -1285,7 +1583,7 @@ func fallbackLookup(primary func(string) (io.ReadCloser, error)) func(string) (i if result.return_code == 0: _probe_emit(ctx, "extensions.go_build", start_ms = build_start_ms, status = "ok") else: - fail("Failed to build orchestrion from upstream module graph: %s\n%s\n%s" % (result.stdout, result.stderr, _go_toolchain_hint())) + fail("Failed to build orchestrion from upstream module graph: %s\n%s\n%s" % (result.stdout, result.stderr, _go_toolchain_hint(ctx))) proxy_start_ms = _probe_now_ms(ctx) _write_orchestrion_module_proxy(ctx, go_path, version, dd_trace_go_versions) @@ -1294,6 +1592,8 @@ func fallbackLookup(primary func(string) (io.ReadCloser, error)) func(string) (i _write_orchestrion_repo_files(ctx, binary_name, dd_trace_go_versions, version) cache_write_start_ms = _probe_now_ms(ctx) _write_bootstrap_cache(ctx, bootstrap_cache, version, dd_trace_go_versions, go_identity, binary_name) + if ctx.attr.dd_trace_go_pin_files: + _merge_pin_file_module_proxy(ctx) _probe_emit( ctx, "extensions.bootstrap_cache_write", @@ -1311,44 +1611,22 @@ _orchestrion_build = repository_rule( "version": attr.string(mandatory = True, doc = "Orchestrion version to build"), "dd_trace_go_version": attr.string(default = "", doc = "dd-trace-go version to validate against the target module for Orchestrion-backed instrumentation"), "dd_trace_go_versions": attr.string_dict(doc = "Per-module dd-trace-go versions to validate against the target module for Orchestrion-backed instrumentation"), + "dd_trace_go_pin_files": attr.label_list(allow_files = True, doc = "Optional go.mod and go.sum labels used to derive selected dd-trace-go module versions"), + "enabled_by_env": attr.bool(default = False, doc = "Gate repository materialization on the Test Optimization repository environment"), + "go_sdk_root": attr.string(default = "", doc = "Optional label string for a hermetic Go SDK ROOT marker used to build Orchestrion"), + "go_sdk_version": attr.string(default = "", doc = "Optional declared version for go_sdk_root; enables cache lookup before materializing the SDK and is verified on cache miss"), "log_timing": attr.bool(default = False, doc = "Emit structured timing probes while building Orchestrion"), }, + environ = [ + _TEST_OPTIMIZATION_ENABLED_ENV, + "GONOSUMDB", + "GOPROXY", + ], ) def _orchestrion_empty_impl(ctx): """Create an empty placeholder repo.""" - ctx.file("BUILD.bazel", """# Generated by rules_go orchestrion extension -# No orchestrion configured -filegroup( - name = "orchestrion", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "dd_trace_go_version_file", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "dd_trace_go_module_proxy_files", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "dd_trace_go_module_proxy_root_marker", - srcs = [], - visibility = ["//visibility:public"], -) - -filegroup( - name = "orchestrion_tool_version_file", - srcs = [], - visibility = ["//visibility:public"], -) -""") + _write_empty_orchestrion_repository(ctx) _orchestrion_empty = repository_rule( implementation = _orchestrion_empty_impl, @@ -1365,18 +1643,31 @@ def _orchestrion_ext_impl(module_ctx): version = "" dd_trace_go_version = "" dd_trace_go_versions = {} + dd_trace_go_pin_files = [] + enabled_by_env = True + go_sdk_root = "" + go_sdk_version = "" log_timing = False for mod in module_ctx.modules: for from_source in mod.tags.from_source: if from_source.version: - if from_source.dd_trace_go_version and from_source.dd_trace_go_versions: - fail("dd_trace_go_version and dd_trace_go_versions cannot both be set in orchestrion.from_source()") + if _configured_version_modes( + from_source.dd_trace_go_version, + from_source.dd_trace_go_versions, + from_source.dd_trace_go_pin_files, + ) > 1: + fail("dd_trace_go_version, dd_trace_go_versions, and dd_trace_go_pin_files are mutually exclusive in orchestrion.from_source()") version = from_source.version + enabled_by_env = from_source.enabled_by_env + go_sdk_root = str(from_source.go_sdk_root) if from_source.go_sdk_root else "" + go_sdk_version = from_source.go_sdk_version log_timing = from_source.log_timing if from_source.dd_trace_go_version: dd_trace_go_version = from_source.dd_trace_go_version if from_source.dd_trace_go_versions: dd_trace_go_versions = from_source.dd_trace_go_versions + if from_source.dd_trace_go_pin_files: + dd_trace_go_pin_files = from_source.dd_trace_go_pin_files break if version: break @@ -1387,6 +1678,10 @@ def _orchestrion_ext_impl(module_ctx): version = version, dd_trace_go_version = dd_trace_go_version, dd_trace_go_versions = dd_trace_go_versions, + dd_trace_go_pin_files = dd_trace_go_pin_files, + enabled_by_env = enabled_by_env, + go_sdk_root = go_sdk_root, + go_sdk_version = go_sdk_version, log_timing = log_timing, ) else: @@ -1407,6 +1702,21 @@ _from_source = tag_class( "dd_trace_go_versions": attr.string_dict( doc = "Per-module dd-trace-go versions to validate against the target module for Orchestrion-backed instrumentation.", ), + "dd_trace_go_pin_files": attr.label_list( + allow_files = True, + doc = "Optional go.mod and go.sum labels used to derive selected dd-trace-go module versions.", + ), + "enabled_by_env": attr.bool( + default = True, + doc = "Gate repository materialization on the Test Optimization repository environment.", + ), + "go_sdk_root": attr.label( + doc = "Optional hermetic Go SDK ROOT marker used to build Orchestrion.", + ), + "go_sdk_version": attr.string( + default = "", + doc = "Optional declared version for go_sdk_root; enables cache lookup before SDK materialization.", + ), "log_timing": attr.bool( default = False, doc = "Emit structured timing probes while building the Orchestrion tool repository.", diff --git a/third_party/rgo/v0_61_1/base/go/private/repositories.bzl b/third_party/rgo/v0_61_1/base/go/private/repositories.bzl index 865c41fd..c57f7198 100644 --- a/third_party/rgo/v0_61_1/base/go/private/repositories.bzl +++ b/third_party/rgo/v0_61_1/base/go/private/repositories.bzl @@ -17,6 +17,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("//go/private:common.bzl", "MINIMUM_BAZEL_VERSION") load("//go/private:nogo.bzl", "DEFAULT_NOGO", "go_register_nogo") +load("//go/private/orchestrion:extensions.bzl", "orchestrion_empty_repository") load("//go/private:polyfill_bazel_features.bzl", "polyfill_bazel_features") load("//go/private/skylib/lib:versions.bzl", "versions") load("//proto:gogo.bzl", "gogo_special_proto") @@ -39,6 +40,15 @@ def go_rules_dependencies(force = False): if getattr(native, "bazel_version", None): versions.check(MINIMUM_BAZEL_VERSION, bazel_version = native.bazel_version) + # Keep the stable Orchestrion repository mapping available to ordinary + # WORKSPACE consumers. Test Optimization consumers declare the real tool + # repository before calling go_rules_dependencies(), so this fallback does + # not replace or fetch it. + _maybe( + orchestrion_empty_repository, + name = "rules_go_orchestrion_tool", + ) + if force: wrapper = _always else: diff --git a/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg.go b/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg.go index dab85cb8..02e5b2ee 100644 --- a/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg.go +++ b/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg.go @@ -1201,8 +1201,10 @@ func modulePackageCommandEnv(goenv *env, exportRoot string) ([]string, error) { env = setEnv(env, "GOWORK", "off") env = setEnv(env, orchestrionJobserverURLEnvVar, "") env = setEnv(env, orchestrionSkipPinEnvVar, "") - if goenv.goroot != "" { - env = setEnv(env, "GOROOT", abs(goenv.goroot)) + if goenv.sdk != "" { + // Module `go list` commands need the complete SDK root so Go can find + // its tools. The woven stdlib remains available through GOCACHE. + env = setEnv(env, "GOROOT", abs(goenv.sdk)) } goBin := filepath.Join(abs(goenv.sdk), "bin") diff --git a/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg_test.go b/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg_test.go index 9f7a1b02..3de12ac1 100644 --- a/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg_test.go +++ b/third_party/rgo/v0_61_1/base/go/tools/builders/compilepkg_test.go @@ -381,19 +381,26 @@ func TestSeedSyntheticTestmainModuleFilesFallsBack(t *testing.T) { // Orchestrion cache paths that break Windows subprocesses. func TestModulePackageCommandEnvUsesShortExportModuleCache(t *testing.T) { sdkRoot := filepath.Join(t.TempDir(), "sdk") + wovenGoRoot := filepath.Join(t.TempDir(), "woven-goroot") exportRoot := filepath.Join(t.TempDir(), "exports") if err := os.MkdirAll(filepath.Join(sdkRoot, "bin"), 0o755); err != nil { t.Fatalf("mkdir fake sdk bin: %v", err) } + if err := os.MkdirAll(wovenGoRoot, 0o755); err != nil { + t.Fatalf("mkdir fake woven goroot: %v", err) + } if err := os.MkdirAll(exportRoot, 0o755); err != nil { t.Fatalf("mkdir export root: %v", err) } - envv, err := modulePackageCommandEnv(&env{sdk: sdkRoot}, exportRoot) + envv, err := modulePackageCommandEnv(&env{sdk: sdkRoot, goroot: wovenGoRoot}, exportRoot) if err != nil { t.Fatalf("modulePackageCommandEnv error: %v", err) } + if got := getEnv(envv, "GOROOT"); got != sdkRoot { + t.Fatalf("GOROOT = %q, want complete SDK root %q", got, sdkRoot) + } wantGoPath := moduleExportModuleCacheRoot(exportRoot) if got := getEnv(envv, "GOPATH"); got != wantGoPath { t.Fatalf("GOPATH = %q, want %q", got, wantGoPath) @@ -504,6 +511,14 @@ func TestLoadModulePackageMetadataBatchSkipsBrokenTransitiveDeps(t *testing.T) { if err != nil { t.Skipf("go binary not on PATH: %v", err) } + goRootOutput, err := exec.Command(goExe, "env", "GOROOT").Output() + if err != nil { + t.Fatalf("resolve Go SDK root: %v", err) + } + sdkRoot := strings.TrimSpace(string(goRootOutput)) + if sdkRoot == "" { + t.Fatal("go env GOROOT returned an empty SDK root") + } root := t.TempDir() depDir := filepath.Join(root, "dep") @@ -542,7 +557,7 @@ func TestLoadModulePackageMetadataBatchSkipsBrokenTransitiveDeps(t *testing.T) { t.Fatalf("mkdir export root: %v", err) } metaCache, err := loadModulePackageMetadataBatch( - &env{sdk: filepath.Dir(filepath.Dir(goExe))}, + &env{sdk: sdkRoot}, mainDir, exportRoot, []string{"example.com/dep"}, diff --git a/third_party/rgo/v0_61_1/base/go/tools/builders/orchestrion_cache.go b/third_party/rgo/v0_61_1/base/go/tools/builders/orchestrion_cache.go index fa743275..e4768cfc 100644 --- a/third_party/rgo/v0_61_1/base/go/tools/builders/orchestrion_cache.go +++ b/third_party/rgo/v0_61_1/base/go/tools/builders/orchestrion_cache.go @@ -17,9 +17,9 @@ const ( // logic changes. The prepared cache snapshot only keys off the copied module // files plus selected toolchain metadata, so code-only changes would // otherwise keep restoring stale synthetic go.mod state. - syntheticModuleCacheABIVersion = "v4" - helperDecisionCacheABIVersion = "v6" - helperExportCacheABIVersion = "v5" + syntheticModuleCacheABIVersion = "v5" + helperDecisionCacheABIVersion = "v8" + helperExportCacheABIVersion = "v7" helperArchiveCacheABIVersion = "v12" // Bump the helper source-set version whenever the synthetic testmain source // compile closure changes. The helper decision and archive caches both key diff --git a/third_party/rgo/v0_61_1/base/tests/core/starlark/orchestrion_extension_tests.bzl b/third_party/rgo/v0_61_1/base/tests/core/starlark/orchestrion_extension_tests.bzl index 42c5d5a7..48b94524 100644 --- a/third_party/rgo/v0_61_1/base/tests/core/starlark/orchestrion_extension_tests.bzl +++ b/third_party/rgo/v0_61_1/base/tests/core/starlark/orchestrion_extension_tests.bzl @@ -22,8 +22,12 @@ def _bootstrap_cache_key_stability_test(ctx): ordered_key = orchestrion_extension_test_helpers.bootstrap_cache_key("v1.6.0", ordered_versions, go_identity) reordered_key = orchestrion_extension_test_helpers.bootstrap_cache_key("v1.6.0", reordered_versions, go_identity) + changed_versions = dict(ordered_versions) + changed_versions["github.com/DataDog/dd-trace-go/v2"] = "v2.8.0" + changed_key = orchestrion_extension_test_helpers.bootstrap_cache_key("v1.6.0", changed_versions, go_identity) asserts.equals(env, ordered_key, reordered_key) + asserts.false(env, ordered_key == changed_key, "a selected module version change must invalidate the bootstrap cache") return unittest.end(env) @@ -48,6 +52,38 @@ def _bootstrap_cache_paths_contract_test(ctx): bootstrap_cache_paths_contract_test = unittest.make(_bootstrap_cache_paths_contract_test) +def _bootstrap_manifest_content_test(ctx): + env = unittest.begin(ctx) + + paths = struct(key = "cache-key") + versions = { + "github.com/DataDog/dd-trace-go/contrib/log/slog/v2": "v2.7.0", + "github.com/DataDog/dd-trace-go/contrib/net/http/v2": "v2.7.0", + "github.com/DataDog/dd-trace-go/v2": "v2.7.0", + } + identity = struct( + version = "go version go1.25.0 linux/amd64", + goos = "linux", + goarch = "amd64", + ) + manifest = json.decode(orchestrion_extension_test_helpers.bootstrap_manifest_content( + paths, + "v1.6.0", + versions, + identity, + "orchestrion_bin", + "0123456789abcdef", + )) + + asserts.equals(env, "cache-key", manifest["cache_key"]) + asserts.equals(env, identity.version, manifest["go_identity"]["version"]) + asserts.equals(env, versions, manifest["dd_trace_go_versions"]) + asserts.equals(env, "0123456789abcdef", manifest["binary_sha256"]) + + return unittest.end(env) + +bootstrap_manifest_content_test = unittest.make(_bootstrap_manifest_content_test) + def _module_proxy_seed_go_mod_test(ctx): env = unittest.begin(ctx) @@ -128,6 +164,55 @@ def _host_platform_normalization_test(ctx): host_platform_normalization_test = unittest.make(_host_platform_normalization_test) +def _git_env_test(ctx): + env = unittest.begin(ctx) + + linux_env = orchestrion_extension_test_helpers.git_env(struct(os = struct(name = "linux"))) + asserts.equals(env, "/dev/null", linux_env["GIT_CONFIG_GLOBAL"]) + asserts.equals(env, "1", linux_env["GIT_CONFIG_NOSYSTEM"]) + asserts.equals(env, "0", linux_env["GIT_TERMINAL_PROMPT"]) + + windows_env = orchestrion_extension_test_helpers.git_env(struct(os = struct(name = "windows_nt"))) + asserts.equals(env, "NUL", windows_env["GIT_CONFIG_GLOBAL"]) + asserts.equals(env, "1", windows_env["GIT_CONFIG_NOSYSTEM"]) + asserts.equals(env, "0", windows_env["GIT_TERMINAL_PROMPT"]) + + return unittest.end(env) + +git_env_test = unittest.make(_git_env_test) + +def _go_module_fetch_env_test(ctx): + env = unittest.begin(ctx) + + default_env = orchestrion_extension_test_helpers.go_module_fetch_env( + struct(os = struct(environ = {})), + ) + asserts.equals(env, "https://proxy.golang.org,direct", default_env["GOPROXY"]) + asserts.equals(env, "", default_env["GONOSUMDB"]) + asserts.equals(env, "", default_env["GOPRIVATE"]) + asserts.equals(env, "", default_env["GONOPROXY"]) + asserts.equals(env, "sum.golang.org https://sum.golang.org", default_env["GOSUMDB"]) + + configured_env = orchestrion_extension_test_helpers.go_module_fetch_env( + struct( + os = struct( + environ = { + "GONOSUMDB": "github.com/DataDog", + "GOPROXY": "https://proxy.example.test,direct", + }, + ), + ), + ) + asserts.equals(env, "https://proxy.example.test,direct", configured_env["GOPROXY"]) + asserts.equals(env, "github.com/DataDog", configured_env["GONOSUMDB"]) + asserts.equals(env, "", configured_env["GOPRIVATE"]) + asserts.equals(env, "", configured_env["GONOPROXY"]) + asserts.equals(env, "sum.golang.org https://sum.golang.org", configured_env["GOSUMDB"]) + + return unittest.end(env) + +go_module_fetch_env_test = unittest.make(_go_module_fetch_env_test) + def _fallback_go_tool_identity_test(ctx): env = unittest.begin(ctx) @@ -147,12 +232,56 @@ def _fallback_go_tool_identity_test(ctx): fallback_go_tool_identity_test = unittest.make(_fallback_go_tool_identity_test) +def _declared_go_tool_identity_test(ctx): + env = unittest.begin(ctx) + fake_ctx = struct( + os = struct( + name = "mac os x", + arch = "aarch64", + ), + ) + + identity = orchestrion_extension_test_helpers.declared_go_tool_identity(fake_ctx, "1.25.0") + asserts.equals(env, "go version go1.25.0 darwin/arm64", identity.version) + asserts.equals(env, "darwin", identity.goos) + asserts.equals(env, "arm64", identity.goarch) + asserts.equals(env, identity.version, orchestrion_extension_test_helpers.declared_go_tool_identity(fake_ctx, "go1.25.0").version) + asserts.equals(env, None, orchestrion_extension_test_helpers.declared_go_tool_identity(fake_ctx, "")) + + return unittest.end(env) + +declared_go_tool_identity_test = unittest.make(_declared_go_tool_identity_test) + +def _declared_dd_trace_go_versions_test(ctx): + env = unittest.begin(ctx) + canonical = orchestrion_extension_test_helpers.declared_dd_trace_go_versions("v2.9.0", {}) + asserts.equals(env, "v2.9.0", canonical["github.com/DataDog/dd-trace-go/v2"]) + asserts.equals(env, None, orchestrion_extension_test_helpers.declared_dd_trace_go_versions("main", {})) + asserts.equals( + env, + None, + orchestrion_extension_test_helpers.declared_dd_trace_go_versions( + "", + {}, + ["//:go.mod", "//:go.sum"], + ), + ) + + return unittest.end(env) + +declared_dd_trace_go_versions_test = unittest.make(_declared_dd_trace_go_versions_test) + def orchestrion_extension_test_suite(): unittest.suite( "orchestrion_extension_tests", bootstrap_cache_key_stability_test, + bootstrap_manifest_content_test, bootstrap_cache_paths_contract_test, + declared_dd_trace_go_versions_test, + declared_go_tool_identity_test, fallback_go_tool_identity_test, + git_env_test, + go_module_fetch_env_test, host_platform_normalization_test, module_proxy_resolved_modules_json_test, module_proxy_seed_go_mod_test, diff --git a/third_party/rgo/v0_62_0/base.CHANGED_FILES.md b/third_party/rgo/v0_62_0/base.CHANGED_FILES.md new file mode 100644 index 00000000..8eb573a4 --- /dev/null +++ b/third_party/rgo/v0_62_0/base.CHANGED_FILES.md @@ -0,0 +1,84 @@ +# rules_go fork delta + +This file is generated. Do not edit by hand. + +## Upstream base + +- Repository: `https://github.com/bazel-contrib/rules_go.git` +- Commit: `c6b35c2367d164f27af4825422d5c70c3365f6fb` +- Tag: `v0.62.0` +- Vendored fork: `third_party/rgo/v0_62_0/base` +- Regenerate: `python3 tools/dev/diff_rules_go_fork.py --upstream v0_62_0 --variant base --write-report` + +## Summary + +- Total changed paths: `54` +- Modified files: `30` +- Added files: `24` +- Removed files: `0` + +## Modified files + +- `BUILD.bazel` +- `MODULE.bazel` +- `MODULE.bazel.lock` +- `docs/doc_helpers.bzl` +- `go/extensions.bzl` +- `go/private/BUILD.bazel` +- `go/private/actions/archive.bzl` +- `go/private/actions/compilepkg.bzl` +- `go/private/actions/link.bzl` +- `go/private/actions/stdlib.bzl` +- `go/private/context.bzl` +- `go/private/repositories.bzl` +- `go/private/rules/library.bzl` +- `go/private/rules/stdlib.bzl` +- `go/private/rules/test.bzl` +- `go/private/rules/transition.bzl` +- `go/tools/builders/BUILD.bazel` +- `go/tools/builders/ar.go` +- `go/tools/builders/builder.go` +- `go/tools/builders/compilepkg.go` +- `go/tools/builders/env.go` +- `go/tools/builders/env_test.go` +- `go/tools/builders/filter_buildid.go` +- `go/tools/builders/importcfg.go` +- `go/tools/builders/link.go` +- `go/tools/builders/nogo.go` +- `go/tools/builders/stdlib.go` +- `go/tools/builders/stdliblist.go` +- `tests/core/starlark/BUILD.bazel` +- `tests/core/starlark/context_tests.bzl` + +## Added files + +- `go/orchestrion_workspace.bzl` +- `go/private/orchestrion/BUILD` +- `go/private/orchestrion/extensions.bzl` +- `go/private/orchestrion/pin_files.bzl` +- `go/tools/builders/compilepkg_test.go` +- `go/tools/builders/env_orchestrion.go` +- `go/tools/builders/importcfg_test.go` +- `go/tools/builders/module_proxy.go` +- `go/tools/builders/orchestrion.go` +- `go/tools/builders/orchestrion_cache.go` +- `go/tools/builders/orchestrion_cache_test.go` +- `go/tools/builders/orchestrion_mode.go` +- `go/tools/builders/orchestrion_mode_test.go` +- `go/tools/builders/orchestrion_skip_test.go` +- `go/tools/builders/orchestrion_synthetic_tool.go` +- `go/tools/builders/orchestrion_test.go` +- `go/tools/builders/orchestrion_test_helpers_test.go` +- `go/tools/builders/orchestrion_version.go` +- `go/tools/builders/orchestrion_version_test.go` +- `go/tools/builders/probe.go` +- `go/tools/builders/probe_test.go` +- `go/tools/builders/stdlib_test.go` +- `go/tools/builders/tool_version.go` +- `tests/core/starlark/orchestrion_extension_tests.bzl` + +## Removed files + +- None + +_Generated from `third_party/rgo/v0_62_0/base.METADATA.json` using `tools/dev/diff_rules_go_fork.py`._ diff --git a/third_party/rgo/v0_62_0/base.METADATA.json b/third_party/rgo/v0_62_0/base.METADATA.json new file mode 100644 index 00000000..6c325e6f --- /dev/null +++ b/third_party/rgo/v0_62_0/base.METADATA.json @@ -0,0 +1,11 @@ +{ + "upstream": { + "repository": "https://github.com/bazel-contrib/rules_go.git", + "commit": "c6b35c2367d164f27af4825422d5c70c3365f6fb", + "tag": "v0.62.0", + "archive_sha256": "dba960adb5b746d02176f7c3a74340820eaa35ac3474565d43ec16e3f73797ee" + }, + "fork_path": "third_party/rgo/v0_62_0/base", + "generated_report": "third_party/rgo/v0_62_0/base.CHANGED_FILES.md", + "generator": "python3 tools/dev/diff_rules_go_fork.py --upstream v0_62_0 --variant base --write-report" +} diff --git a/third_party/rgo/v0_62_0/base/.bazelci/presubmit.yml b/third_party/rgo/v0_62_0/base/.bazelci/presubmit.yml new file mode 100644 index 00000000..f2012db9 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bazelci/presubmit.yml @@ -0,0 +1,286 @@ +--- +matrix: + platform: + - ubuntu2404 + - ubuntu2004_arm64 + - macos_arm64 + - windows + # Only BCR tests use all Bazel versions. Others use the default. + bazel: + - 7.* + - 8.* + - 9.* + +tasks: + debian11_bazel6: + platform: debian11 + bazel: 7.2.1 # test minimum supported version of bazel that works with our bzlmod setup + build_targets: + - "//..." + - "-//tests/core/go_binary:goos_pure_bin" + - "-//tests/core/cross:go_cross_binary_test" + build_flags: + - "--per_file_copt=external/.*@-w" + - "--host_per_file_copt=external/.*@-w" + test_targets: + - "//..." + # Nogo includes/excludes doesn't work before bazel 7 + - "-//tests/core/nogo/includes_excludes:includes_exclude_test" + - "-//tests/core/nogo/bzlmod:includes_exclude_test" + # _repo_mapping is missing + - "-//tests/runfiles:runfiles_test" + # TODO: Investigate why this fails. + - "-//tests/core/starlark/cgo:missing_cc_toolchain_explicit_pure_off_test" + # TODO: Bzlmod setup requires at least Bazel 7. + - "-//tests/core/cross:proto_test" + - "-//tests/core/from_go_mod_file:from_go_mod_file_test" + - "-//tests/core/from_go_work_file:from_go_work_file_test" + - "-//tests/core/transition:hermeticity_test" + - "-//tests/integration/gazelle:gazelle_test" + # Requires https://github.com/bazelbuild/bazel/commit/ceddfb1ece1f8ed7ff81558fa1751e6526df031b. + - "-//tests/core/go_binary:configurable_attribute_good_test" + - "-//tests/core/go_binary:goos_pure_bin" + - "-//tests/core/cross:go_cross_binary_test" + test_flags: + - "--per_file_copt=external/.*@-w" + - "--host_per_file_copt=external/.*@-w" + ubuntu2404: + # enable some unflipped incompatible flags on this platform to ensure we don't regress. + build_flags: + - "--config=incompatible" + test_flags: + - "--config=incompatible" + build_targets: + - "//..." + test_targets: + - "//..." + debian11_zig_cc: + platform: debian11 + build_flags: + - "--config=incompatible" + - "--extra_toolchains=@zig_sdk//toolchain:linux_amd64_gnu.2.31" + test_flags: + - "--config=incompatible" + - "--extra_toolchains=@zig_sdk//toolchain:linux_amd64_gnu.2.31" + - "--test_env=ZIG_CC=1" + build_targets: + - "//..." + test_targets: + - "//..." + bcr_tests: + name: BCR test module + platform: ${{ platform }} + bazel: ${{ bazel }} + working_directory: tests/bcr + build_flags: + - "--allow_yanked_versions=all" + test_flags: + - "--allow_yanked_versions=all" + build_targets: + - "//..." + - "@go_default_sdk//..." + test_targets: + - "//..." + bcr_tests_proto: + name: BCR test module (--incompatible_enable_proto_toolchain_resolution) + platform: ${{ platform }} + working_directory: tests/bcr + build_flags: + - "--allow_yanked_versions=all" + - "--incompatible_enable_proto_toolchain_resolution" + test_flags: + - "--allow_yanked_versions=all" + - "--incompatible_enable_proto_toolchain_resolution" + build_targets: + - "//..." + - "@go_default_sdk//..." + test_targets: + - "//..." + macos_arm64: + build_flags: + - "--apple_crosstool_top=@local_config_apple_cc//:toolchain" + - "--crosstool_top=@local_config_apple_cc//:toolchain" + - "--host_crosstool_top=@local_config_apple_cc//:toolchain" + build_targets: + - "//..." + - "--" + test_flags: + - "--apple_crosstool_top=@local_config_apple_cc//:toolchain" + - "--crosstool_top=@local_config_apple_cc//:toolchain" + - "--host_crosstool_top=@local_config_apple_cc//:toolchain" + test_targets: + - "//..." + rbe_ubuntu2404: + build_flags: + - "--per_file_copt=external/.*@-w" + - "--host_per_file_copt=external/.*@-w" + build_targets: + - "//..." + test_flags: + - "--per_file_copt=external/.*@-w" + - "--host_per_file_copt=external/.*@-w" + # Some tests depend on this feature being disabled. However, because it's + # enabled by default in the rbe_ubuntu2404 platform, we cannot simply remove + # this flag here, we have to explicitly override it with 0. + - "--repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=0" + # go_bazel_test rules are marked local, since the executors don't have bazel + # installed. It appears bazel is no longer in PATH on the host machines + # in this configuration either. + - "--test_tag_filters=-local" + test_targets: + - "--" + - "//..." + - "-//tests/core/stdlib:buildid_test" + # Source directories in runfiles are not supported with RBE. + - "-//tests/runfiles:runfiles_test" + windows: + build_flags: + - '--action_env=PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\bin;C:\tools\msys64\mingw64\bin;C:\python3\Scripts\;C:\python3;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\ProgramData\GooGet;C:\Program Files\Google\Compute Engine\metadata_scripts;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\tools\msys64\usr\bin;c:\openjdk\bin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\CMake\bin;c:\ninja;c:\bazel;c:\buildkite' + build_targets: + - "//..." + - "-//tests/core/cgo:generated_dylib_client" + - "-//tests/core/cgo:generated_dylib_test" + - "-//tests/core/cgo:generated_versioned_dylib_test" + - "-//tests/legacy/examples/cgo:generate_go_src" + - "-//tests/legacy/examples/cgo:cgo_lib_test" + - "-//tests/legacy/examples/cgo:go_default_library" + - "-//tests/legacy/examples/cgo:sub" + - "-//tests/legacy/examples/cgo/cc_dependency:version" + - "-//tests/legacy/examples/cgo/cc_dependency:c_version_so" + - "-//tests/legacy/examples/cgo/example_command:example_command" + - "-//tests/legacy/examples/cgo/example_command:example_command_script" + - "-//tests/legacy/examples/cgo/example_command:example_command_test" + # Plugins aren't supported on Windows. + - "-//tests/core/go_plugin/..." + - "-//tests/core/go_plugin_with_proto_library/..." + test_flags: + - '--action_env=PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\bin;C:\tools\msys64\mingw64\bin;C:\python3\Scripts\;C:\python3;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\ProgramData\GooGet;C:\Program Files\Google\Compute Engine\metadata_scripts;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\tools\msys64\usr\bin;c:\openjdk\bin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\CMake\bin;c:\ninja;c:\bazel;c:\buildkite' + # On Windows CI, bazel (bazelisk) needs %LocalAppData% to find the cache directory. + # We invoke bazel in tests, so the tests need this, too. + - "--test_env=LOCALAPPDATA" + # go_bazel_test runs bazel in a test workspace. It needs the same flags as above. + - "--test_env=GO_BAZEL_TEST_BAZELFLAGS=--cpu=x64_windows --compiler=mingw-gcc --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows_mingw --action_env=PATH --host_platform=@io_bazel_rules_go//go/toolchain:windows_amd64_cgo --incompatible_enable_cc_toolchain_resolution" + - "--test_env=PATH" + test_targets: + - "//..." + - "-//go/tools/builders:stdliblist_test" + - "-//tests:buildifier_test" + - "-//tests/core/cgo:generated_dylib_client" + - "-//tests/core/cgo:generated_dylib_test" + - "-//tests/core/cgo:generated_versioned_dylib_test" + - "-//tests/core/coverage:coverage_test" + - "-//tests/core/coverage:issue3017_test" + - "-//tests/core/coverage:issue4414_test" + - "-//tests/core/coverage:reassign_flag_commandline_test" + - "-//tests/core/go_binary:go_default_test" + - "-//tests/core/go_path:go_path_test" + - "-//tests/core/go_test:data_test" + - "-//tests/core/go_test:pwd_test" + - "-//tests/core/nogo/coverage:coverage_cgo_test" + - "-//tests/core/nogo/coverage:coverage_test" + - "-//tests/core/nogo/coverage:gen_code_test" + - "-//tests/core/stdlib:buildid_test" + - "-//tests/examples/executable_name:executable_name" + - "-//tests/integration/gazelle:gazelle_test" # exceeds command line length limit + - "-//tests/integration/reproducibility:reproducibility_test" + - "-//tests/legacy/examples/cgo:generate_go_src" + - "-//tests/legacy/examples/cgo:cgo_lib_test" + - "-//tests/legacy/examples/cgo:go_default_library" + - "-//tests/legacy/examples/cgo:sub" + - "-//tests/legacy/examples/cgo/cc_dependency:version" + - "-//tests/legacy/examples/cgo/cc_dependency:c_version_so" + - "-//tests/legacy/examples/cgo/example_command:example_command" + - "-//tests/legacy/examples/cgo/example_command:example_command_script" + - "-//tests/legacy/examples/cgo/example_command:example_command_test" + - "-//tests/legacy/extldflags_rpath:extldflags_rpath_test" + - "-//tests/legacy/info:info" + - "-//tests/legacy/test_chdir:go_default_test" + - "-//tests/legacy/test_rundir:go_default_test" + - "-//tests/legacy/transitive_data:go_default_test" + - "-@org_golang_x_crypto//sha3:sha3_test" + - "-@org_golang_x_sys//windows/svc:svc_test" + - "-@org_golang_x_text//language:language_test" + - "-@org_golang_x_tools//cmd/splitdwarf/internal/macho:macho_test" + - "-@test_chdir_remote//sub:go_default_test" + # Plugins aren't supported on Windows. + - "-//tests/core/go_plugin/..." + - "-//tests/core/go_plugin_with_proto_library/..." + # TODO: Update stardoc for consistent line endings. + - "-//docs:all" + # The following configurations test a seperate WORKSPACE under the examples folder + ubuntu_hello_example: + name: Hello example on Ubuntu + platform: ubuntu2404 + working_directory: examples/hello + build_targets: + - "//..." + test_targets: + - "//..." + macos_hello_example: + name: Hello example on macOS + platform: macos_arm64 + working_directory: examples/hello + build_targets: + - "//..." + test_targets: + - "//..." + windows_examples: + name: Hello example on Windows + platform: windows + working_directory: examples/hello + build_flags: + # Go requires a C toolchain that accepts options and emits errors like + # gcc or clang. The Go SDK does not support MSVC. + - '--action_env=PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\bin;C:\tools\msys64\mingw64\bin;C:\python3\Scripts\;C:\python3;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\ProgramData\GooGet;C:\Program Files\Google\Compute Engine\metadata_scripts;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\tools\msys64\usr\bin;c:\openjdk\bin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\CMake\bin;c:\ninja;c:\bazel;c:\buildkite' + # NOTE(bazelbuild/bazel#10529): bazel doesn't register the mingw toolchain automatically. + # We also need the host and target platforms to have the mingw constraint value. + build_targets: + - "//..." + test_targets: + - "//..." + test_flags: + - '--action_env=PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\bin;C:\tools\msys64\mingw64\bin;C:\python3\Scripts\;C:\python3;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\ProgramData\GooGet;C:\Program Files\Google\Compute Engine\metadata_scripts;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\tools\msys64\usr\bin;c:\openjdk\bin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\CMake\bin;c:\ninja;c:\bazel;c:\buildkite' + # On Windows CI, bazel (bazelisk) needs %LocalAppData% to find the cache directory. + # We invoke bazel in tests, so the tests need this, too. + - "--test_env=LOCALAPPDATA" + # go_bazel_test runs bazel in a test workspace. It needs the same flags as above. + - "--test_env=GO_BAZEL_TEST_BAZELFLAGS=--cpu=x64_windows --compiler=mingw-gcc --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows_mingw --action_env=PATH --host_platform=@io_bazel_rules_go//go/toolchain:windows_amd64_cgo --incompatible_enable_cc_toolchain_resolution" + - "--test_env=PATH" + ubuntu_basic_gazelle_example: + name: Basic Gazelle example on Ubuntu + platform: ubuntu2404 + working_directory: examples/basic_gazelle + build_targets: + - "//..." + test_targets: + - "//..." + macos_basic_gazelle_example: + name: Basic Gazelle example on macOS + platform: macos_arm64 + working_directory: examples/basic_gazelle + build_targets: + - "//..." + test_targets: + - "//..." + windows_basic_gazelle_example: + name: Basic Gazelle example on Windows + platform: windows + working_directory: examples/basic_gazelle + build_flags: + # Go requires a C toolchain that accepts options and emits errors like + # gcc or clang. The Go SDK does not support MSVC. + - '--action_env=PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\bin;C:\tools\msys64\mingw64\bin;C:\python3\Scripts\;C:\python3;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\ProgramData\GooGet;C:\Program Files\Google\Compute Engine\metadata_scripts;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\tools\msys64\usr\bin;c:\openjdk\bin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\CMake\bin;c:\ninja;c:\bazel;c:\buildkite' + # NOTE(bazelbuild/bazel#10529): bazel doesn't register the mingw toolchain automatically. + # We also need the host and target platforms to have the mingw constraint value. + build_targets: + - "//..." + test_targets: + - "//..." + test_flags: + - '--action_env=PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\bin;C:\tools\msys64\mingw64\bin;C:\python3\Scripts\;C:\python3;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\ProgramData\GooGet;C:\Program Files\Google\Compute Engine\metadata_scripts;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\tools\msys64\usr\bin;c:\openjdk\bin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\CMake\bin;c:\ninja;c:\bazel;c:\buildkite' + # On Windows CI, bazel (bazelisk) needs %LocalAppData% to find the cache directory. + # We invoke bazel in tests, so the tests need this, too. + - "--test_env=LOCALAPPDATA" + # go_bazel_test runs bazel in a test workspace. It needs the same flags as above. + - "--test_env=GO_BAZEL_TEST_BAZELFLAGS=--cpu=x64_windows --compiler=mingw-gcc --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows_mingw --action_env=PATH --host_platform=@io_bazel_rules_go//go/toolchain:windows_amd64_cgo --incompatible_enable_cc_toolchain_resolution" + - "--test_env=PATH" diff --git a/third_party/rgo/v0_62_0/base/.bazelignore b/third_party/rgo/v0_62_0/base/.bazelignore new file mode 100644 index 00000000..397609d1 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bazelignore @@ -0,0 +1,2 @@ +tests/bcr +examples diff --git a/third_party/rgo/v0_62_0/base/.bazelrc b/third_party/rgo/v0_62_0/base/.bazelrc new file mode 100644 index 00000000..5c76be5a --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bazelrc @@ -0,0 +1,47 @@ +startup --host_jvm_args=-DBAZEL_TRACK_SOURCE_DIRECTORIES=1 + +common --enable_platform_specific_config +# Improve caching, but allow integration tests to find `bazel` in PATH. +# Doesn't work on Windows as protoc requires DLLs outside the default PATH. +common:macos --incompatible_strict_action_env +common:linux --incompatible_strict_action_env +common --test_env=PATH +test --test_output=errors + +# Workaround for https://github.com/bazelbuild/continuous-integration/issues/2269. +build:macos --copt=-Dfdopen=fdopen +build:macos --host_copt=-Dfdopen=fdopen + +# Go requires a C toolchain that accepts options and emits errors like +# gcc or clang. The Go SDK does not support MSVC. +build:windows --cpu=x64_windows +build:windows --compiler=mingw-gcc + +# NOTE(bazelbuild/bazel#10529): bazel doesn't register the mingw toolchain automatically. +# We also need the host and target platforms to have the mingw constraint value. +build:windows --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows_mingw +build:windows --host_platform=@io_bazel_rules_go//go/toolchain:windows_amd64_cgo +build:windows --platforms=@io_bazel_rules_go//go/toolchain:windows_amd64_cgo +build:windows --incompatible_enable_cc_toolchain_resolution + +build:check --all_incompatible_changes + +common:ci --color=no +build:ci --verbose_failures +build:ci --sandbox_debug +build:ci --spawn_strategy=standalone +build:ci --genrule_strategy=standalone +test:ci --test_strategy=standalone + +# Incompatible flags to test in a dedicated CI pipeline. +build:incompatible --incompatible_load_proto_rules_from_bzl +build:incompatible --incompatible_enable_cc_toolchain_resolution +build:incompatible --incompatible_config_setting_private_default_visibility +build:incompatible --incompatible_enforce_config_setting_visibility +build:incompatible --incompatible_disallow_empty_glob +build:incompatible --incompatible_disable_starlark_host_transitions +build:incompatible --nolegacy_external_runfiles +build:incompatible --incompatible_enable_proto_toolchain_resolution +build:incompatible --incompatible_auto_exec_groups +# Also enable all incompatible flags in go_bazel_test by default. +test:incompatible --test_env=GO_BAZEL_TEST_BAZELFLAGS='--incompatible_disallow_empty_glob --incompatible_load_proto_rules_from_bzl --incompatible_enable_cc_toolchain_resolution --incompatible_config_setting_private_default_visibility --incompatible_enforce_config_setting_visibility --incompatible_disable_starlark_host_transitions --nolegacy_external_runfiles --incompatible_enable_proto_toolchain_resolution --incompatible_auto_exec_groups' diff --git a/third_party/rgo/v0_62_0/base/.bazelversion b/third_party/rgo/v0_62_0/base/.bazelversion new file mode 100644 index 00000000..1985849f --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bazelversion @@ -0,0 +1 @@ +7.7.0 diff --git a/third_party/rgo/v0_62_0/base/.bcr/config.yml b/third_party/rgo/v0_62_0/base/.bcr/config.yml new file mode 100644 index 00000000..4225f4fe --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bcr/config.yml @@ -0,0 +1,3 @@ +fixedReleaser: + login: fmeum + email: fabian@meumertzhe.im diff --git a/third_party/rgo/v0_62_0/base/.bcr/metadata.template.json b/third_party/rgo/v0_62_0/base/.bcr/metadata.template.json new file mode 100644 index 00000000..aadaf778 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bcr/metadata.template.json @@ -0,0 +1,35 @@ +{ + "homepage": "https://github.com/bazelbuild/rules_go", + "maintainers": [ + { + "email": "fabian@meumertzhe.im", + "github": "fmeum", + "name": "Fabian Meumertzheim" + }, + { + "email": "zplin@uber.com", + "github": "linzhp", + "name": "Zhongpeng Lin" + }, + { + "email": "french.tyler.d@gmail.com", + "github": "tyler-french", + "name": "Tyler French" + }, + { + "email": "jay@engflow.com", + "github": "jayconrod", + "name": "Jay Conrod" + }, + { + "email": "dzbarsky@gmail.com", + "github": "dzbarsky", + "name": "David Zbarsky" + } + ], + "repository": [ + "github:bazel-contrib/rules_go" + ], + "versions": [], + "yanked_versions": {} +} diff --git a/third_party/rgo/v0_62_0/base/.bcr/presubmit.yml b/third_party/rgo/v0_62_0/base/.bcr/presubmit.yml new file mode 100644 index 00000000..6ce55a70 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bcr/presubmit.yml @@ -0,0 +1,33 @@ +matrix: + platform: + - debian11 + - ubuntu2004_arm64 + - macos_arm64 + - windows + bazel: [7.*, 8.*, 9.*] +tasks: + verify_targets: + name: Verify build targets + platform: ${{ platform }} + bazel: ${{ bazel }} + build_targets: + - "@rules_go//go/tools/bzltestutil/..." +bcr_test_module: + module_path: tests/bcr + matrix: + platform: + - debian11 + - ubuntu2004_arm64 + - macos_arm64 + - windows + bazel: [7.*, 8.*, 9.*] + tasks: + run_test_module: + name: Run test module + platform: ${{ platform }} + bazel: ${{ bazel }} + build_targets: + - //... + - "@go_default_sdk//..." + test_targets: + - //... diff --git a/third_party/rgo/v0_62_0/base/.bcr/source.template.json b/third_party/rgo/v0_62_0/base/.bcr/source.template.json new file mode 100644 index 00000000..cfd7e71e --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.bcr/source.template.json @@ -0,0 +1,5 @@ +{ + "integrity": "", + "strip_prefix": "", + "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/{REPO}-{TAG}.zip" +} diff --git a/third_party/rgo/v0_62_0/base/.github/ISSUE_TEMPLATE/config.yaml b/third_party/rgo/v0_62_0/base/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 00000000..61cd62f6 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1,55 @@ +name: Issue +description: New issue template +body: + - type: textarea + attributes: + label: What version of rules_go are you using? + description: Check io_bazel_rules_go in WORKSPACE if you're not sure + validations: + required: true + - type: textarea + attributes: + label: What version of gazelle are you using? + description: Check bazel_gazelle in WORKSPACE if you're not sure + validations: + required: true + - type: textarea + attributes: + label: What version of Bazel are you using? + description: Run "bazel version" to find out + validations: + required: true + - type: textarea + attributes: + label: Does this issue reproduce with the latest releases of all the above? + validations: + required: true + - type: textarea + attributes: + label: What operating system and processor architecture are you using? + validations: + required: true + - type: textarea + attributes: + label: Any other potentially useful information about your toolchain? + description: C/C++ compiler, custom CROSSTOOL, remote execution? + validations: + required: false + - type: textarea + attributes: + label: What did you do? + description: If possible, provide a minimal recipe for reproducing the error. + validations: + required: false + - type: textarea + attributes: + label: What did you expect to see? + description: + validations: + required: false + - type: textarea + attributes: + label: What did you see instead? + description: + validations: + required: false diff --git a/third_party/rgo/v0_62_0/base/.github/PULL_REQUEST_TEMPLATE.md b/third_party/rgo/v0_62_0/base/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..9241c611 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,30 @@ + + +**What type of PR is this?** + +> Uncomment one line below and remove others. +> +> Bug fix +> Feature +> Documentation +> Other + +**What does this PR do? Why is it needed?** + +**Which issues(s) does this PR fix?** + +Fixes # + +**Other notes for review** diff --git a/third_party/rgo/v0_62_0/base/.gitignore b/third_party/rgo/v0_62_0/base/.gitignore new file mode 100644 index 00000000..2e51ff90 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/.gitignore @@ -0,0 +1,8 @@ +/bazel-* +/tests/core/cgo/libimported.* +/tests/core/cgo/libversioned.* +/tests/bcr/bazel-* +/examples/*/bazel-* +/.ijwb/ +/tests/bcr/.ijwb/ +.vscode \ No newline at end of file diff --git a/third_party/rgo/v0_62_0/base/AUTHORS b/third_party/rgo/v0_62_0/base/AUTHORS new file mode 100644 index 00000000..22f94638 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/AUTHORS @@ -0,0 +1,16 @@ +# This the official list of Bazel authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. + +Benjamin Staffin +Brian Silverman +David Santiago +David Zbarsky +Google Inc. +Jake Voytko +Tyler French +Yuki Yugui Sonoda diff --git a/third_party/rgo/v0_62_0/base/BUILD.bazel b/third_party/rgo/v0_62_0/base/BUILD.bazel new file mode 100644 index 00000000..b8a5ebb8 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/BUILD.bazel @@ -0,0 +1,163 @@ +load( + "//go:def.bzl", + "TOOLS_NOGO", +) +load( + "//go/private:context.bzl", + "go_config", + "go_context_data", +) +load( + "//go/private/rules:info.bzl", + "go_info", +) +load( + "//go/private/rules:nogo.bzl", + "nogo", +) +load( + "//go/private/rules:stdlib.bzl", + "stdlib", +) +load( + "//go/private/tools:lines_sorted_test.bzl", + "lines_sorted_test", +) + +# gazelle:prefix github.com/bazelbuild/rules_go +# gazelle:exclude tests +# gazelle:exclude third_party +# gazelle:exclude go/tools/builders +# gazelle:exclude go/tools/coverdata +# gazelle:exclude go/tools/fetch_repo +# gazelle:exclude go/tools/windows-testrunner +# gazelle:go_naming_convention import_alias + +# TODO(jayconrod): add a gazelle rule so gazelle can be run automatically. +# It can't go here though, because it would break anything that depends on +# rules_go but not Gazelle, including our own go_bazel_tests. + +stdlib( + name = "stdlib", + visibility = ["//visibility:public"], +) + +# default_nogo is the nogo target that nogo references by default. It +# does not analyze anything, which means no binary is built or run +# at compile time. +filegroup( + name = "default_nogo", + visibility = ["//visibility:public"], +) + +# tools_nogo includes all of the analysis passes in +# golang.org/x/tools/go/analysis/passes. +# This is not backward compatible, so use caution when depending on this -- +# new analyses may discover issues in existing builds. +nogo( + name = "tools_nogo", + visibility = ["//visibility:public"], + deps = TOOLS_NOGO, +) + +# go_context_data collects build options and is depended on by all Go targets. +go_context_data( + name = "go_context_data", + coverdata = "//go/tools/coverdata", + go_config = ":go_config", + nogo = "@io_bazel_rules_nogo//:nogo", + stdlib = ":stdlib", + visibility = ["//visibility:public"], +) + +# go_config collects information about build settings in the current +# configuration. go_context_data depends on this so that rules don't need +# to depend on all build settings directly. +go_config( + name = "go_config", + amd64 = select({ + "//go/constraints/amd64:v2": "v2", + "//go/constraints/amd64:v3": "v3", + "//go/constraints/amd64:v4": "v4", + # The default is v1. + "//conditions:default": None, + }), + arm = select({ + "//go/constraints/arm:5": "5", + "//go/constraints/arm:6": "6", + "//go/constraints/arm:7": "7", + "//conditions:default": None, + }), + cover_format = "//go/config:cover_format", + # Always include debug symbols with -c dbg. + debug = select({ + "//go/private:is_compilation_mode_dbg": "//go/private:always_true", + "//conditions:default": "//go/config:debug", + }), + export_stdlib = "//go/config:export_stdlib", + force_pic = select({ + "//go/private:force_pic": True, + "//conditions:default": False, + }), + gc_goopts = "//go/config:gc_goopts", + gc_linkopts = "//go/config:gc_linkopts", + gotags = "//go/config:tags", + linkmode = "//go/config:linkmode", + msan = "//go/config:msan", + pgoprofile = "//go/config:pgoprofile", + pure = "//go/config:pure", + race = "//go/config:race", + stamp = select({ + "//go/private:stamp": True, + "//conditions:default": False, + }), + static = "//go/config:static", + strip = select({ + "//go/private:is_strip_always": True, + "//go/private:is_strip_sometimes_fastbuild": True, + "//conditions:default": False, + }), + visibility = ["//visibility:public"], +) + +lines_sorted_test( + name = "contributors_sorted_test", + size = "small", + cmd = "grep -v '^#' $< | grep -v '^$$' >$@", + error_message = "Contributors must be sorted by first name", + file = "CONTRIBUTORS", +) + +lines_sorted_test( + name = "authors_sorted_test", + size = "small", + cmd = "grep -v '^#' $< | grep -v '^$$' >$@", + error_message = "Authors must be sorted by first name", + file = "AUTHORS", +) + +# AUTHORS is used as an anchor point for the directory in tests and the +# license can be consumed by depending projects. +exports_files([ + "AUTHORS", + "LICENSE.txt", +]) + +go_info() + +filegroup( + name = "all_files", + testonly = True, + srcs = [ + "BUILD.bazel", + "MODULE.bazel", + "WORKSPACE", + "go.mod", + "go.sum", + "//extras:all_files", + "//go:all_files", + "//proto:all_files", + "//third_party:all_files", + ], + visibility = ["//visibility:public"], +) diff --git a/third_party/rgo/v0_62_0/base/CODEOWNERS b/third_party/rgo/v0_62_0/base/CODEOWNERS new file mode 100644 index 00000000..1950b862 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/CODEOWNERS @@ -0,0 +1 @@ +* @go-maintainers diff --git a/third_party/rgo/v0_62_0/base/CONTRIBUTING.md b/third_party/rgo/v0_62_0/base/CONTRIBUTING.md new file mode 100644 index 00000000..fb0f8581 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/CONTRIBUTING.md @@ -0,0 +1,41 @@ +Want to contribute? Great! First, read this page (including the small print at +the end). + +### Before you contribute + +**Before we can use your code, you must sign the +[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) +(CLA)**, which you can do online. + +The CLA is necessary mainly because you own the copyright to your changes, +even after your contribution becomes part of our codebase, so we need your +permission to use and distribute your code. We also need to be sure of +various other things — for instance that you'll tell us if you know that +your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. + +### The small print + +Contributions made by corporations are covered by a different agreement than +the one above, the +[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). + +### Contribution process + +1. Explain your idea and discuss your plan with members of the team. The best + way to do this is to create + an [issue](https://github.com/bazelbuild/rules_go/issues) or comment on an + existing issue. +1. Prepare a git commit with your change. Don't forget to + add [tests](https://github.com/bazelbuild/rules_go/tree/master/tests). + Run the existing tests with `bazel test //...`. Update + [README.rst](https://github.com/bazelbuild/rules_go/blob/master/README.rst) + if appropriate. +1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request/). + This will start the code review process. **All submissions, including + submissions by project members, require review.** +1. You may be asked to make some changes. You'll also need to sign the CLA at + this point, if you haven't done so already. Our continuous integration bots + will test your change automatically on supported platforms. Once everything + looks good, your change will be merged. diff --git a/third_party/rgo/v0_62_0/base/CONTRIBUTORS b/third_party/rgo/v0_62_0/base/CONTRIBUTORS new file mode 100644 index 00000000..87f122d2 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/CONTRIBUTORS @@ -0,0 +1,28 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name + +Benjamin Staffin +Brian Silverman +Damien Martin-Guillerez +David Chen +David Santiago +David Zbarsky +Fabian Meumertzheim +Han-Wen Nienhuys +Ian Cottrell +Jake Voytko +Jay Conrod +Josh Powell +Justine Alexandra Roberts Tunney +Kristina Chodorow +Lukacs Berki +Tyler French +Yuki Yugui Sonoda diff --git a/third_party/rgo/v0_62_0/base/LICENSE.txt b/third_party/rgo/v0_62_0/base/LICENSE.txt new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/rgo/v0_62_0/base/MODULE.bazel b/third_party/rgo/v0_62_0/base/MODULE.bazel new file mode 100644 index 00000000..6b8514b2 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/MODULE.bazel @@ -0,0 +1,111 @@ +module( + name = "rules_go", + compatibility_level = 0, + repo_name = "io_bazel_rules_go", +) + +# The custom repo_name is used to prevent our bazel_features polyfill for WORKSPACE builds from +# conflicting with the real bazel_features repo. +bazel_dep(name = "bazel_features", version = "1.36.0", repo_name = "io_bazel_rules_go_bazel_features") +bazel_dep(name = "bazel_skylib", version = "1.8.1") +bazel_dep(name = "platforms", version = "1.1.0") +bazel_dep(name = "rules_proto", version = "7.0.2") +bazel_dep(name = "protobuf", version = "29.0", repo_name = "com_google_protobuf") +bazel_dep(name = "rules_shell", version = "0.3.0") +bazel_dep(name = "rules_cc", version = "0.1.5") + +go_sdk = use_extension("//go:extensions.bzl", "go_sdk") + +# Don't depend on this repo by name, use toolchains instead. +# See https://github.com/bazel-contrib/rules_go/blob/master/go/toolchains.rst +go_sdk.from_file( + name = "go_default_sdk", + go_mod = "//:go.mod", +) +use_repo( + go_sdk, + "go_host_compatible_sdk_label", + "go_toolchains", + # This name is ugly on purpose to avoid a conflict with a user-named SDK. + "io_bazel_rules_nogo", +) + +register_toolchains("@go_toolchains//:all") + +# Orchestrion extension for compile-time instrumentation. +# By default, this creates an empty rules_go_orchestrion_tool repo. +# Projects that want orchestrion can provide their own repo with the same name. +orchestrion = use_extension("//go:extensions.bzl", "orchestrion") +use_repo(orchestrion, "rules_go_orchestrion_tool") + +bazel_dep(name = "gazelle", version = "0.51.3") + +go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") +go_deps.from_file(go_mod = "//:go.mod") +use_repo( + go_deps, + "com_github_aymanbagabas_go_udiff", + "com_github_gogo_protobuf", + "com_github_golang_mock", + "com_github_golang_protobuf", + "org_golang_google_genproto", + "org_golang_google_grpc", + "org_golang_google_grpc_cmd_protoc_gen_go_grpc", + "org_golang_google_protobuf", + "org_golang_x_net", + "org_golang_x_tools", + # Exported by gazelle specifically for rules_go. + "bazel_gazelle_go_repository_config", + "org_golang_google_genproto_googleapis_bytestream", + "org_golang_google_genproto_googleapis_rpc", + "org_golang_x_crypto", +) + +### Dev dependencies + +bazel_dep(name = "stardoc", version = "0.8.0", dev_dependency = True) + +dev_go_sdk = use_extension("//go:extensions.bzl", "go_sdk", dev_dependency = True) +dev_go_sdk.download( + name = "rules_go_internal_compatibility_sdk", + version = "1.22.12", +) + +bazel_dep(name = "toolchains_protoc", version = "0.6.0", dev_dependency = True) + +protoc = use_extension("@toolchains_protoc//protoc:extensions.bzl", "protoc", dev_dependency = True) +protoc.toolchain( + name = "protoc_toolchains", + version = "v25.3", +) +use_repo(protoc, "protoc_toolchains") + +register_toolchains( + "@protoc_toolchains//...", + dev_dependency = True, +) + +# Used to transition binaries in rules_go's test suite to different configurations. +bazel_dep(name = "with_cfg.bzl", version = "0.14.1", dev_dependency = True) +bazel_dep(name = "runfiles_remote_test", version = "0.0.0", dev_dependency = True) +local_path_override( + module_name = "runfiles_remote_test", + path = "tests/core/runfiles/runfiles_remote_test", +) + +bazel_dep(name = "googleapis", version = "0.0.0-20241220-5e258e33", dev_dependency = True) + +# Used for both testing objc interop and building on Apple platforms. +bazel_dep(name = "apple_support", version = "1.24.3", dev_dependency = True, repo_name = "build_bazel_apple_support") + +# For manual testing against an LLVM toolchain. +# Use --extra_toolchains=@llvm_toolchain//:cc-toolchain-linux,@llvm_toolchain//:cc-toolchain-darwin +bazel_dep(name = "toolchains_llvm", version = "0.10.3", dev_dependency = True) + +llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm", dev_dependency = True) +llvm.toolchain( + name = "llvm_toolchain", + llvm_version = "8.0.0", +) + +bazel_dep(name = "bazel_ci_rules", version = "1.0.0", dev_dependency = True) diff --git a/third_party/rgo/v0_62_0/base/MODULE.bazel.lock b/third_party/rgo/v0_62_0/base/MODULE.bazel.lock new file mode 100644 index 00000000..372cbf5e --- /dev/null +++ b/third_party/rgo/v0_62_0/base/MODULE.bazel.lock @@ -0,0 +1,2299 @@ +{ + "lockFileVersion": 13, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442", + "https://bcr.bazel.build/modules/apple_support/1.24.3/MODULE.bazel": "f490627de467ca6de2bc313482d8890584673142b811c7ac20329a57191cc7a3", + "https://bcr.bazel.build/modules/apple_support/1.24.3/source.json": "d86580223e2e89ec48313489e2212b3a302c75e3196e8f49f5e497078072986f", + "https://bcr.bazel.build/modules/bazel_ci_rules/1.0.0/MODULE.bazel": "0f92c944b9c466066ed484cfc899cf43fca765df78caca18984c62479f7925eb", + "https://bcr.bazel.build/modules/bazel_ci_rules/1.0.0/source.json": "3405a2a7f9f827a44934b01470faeac1b56fb1304955c98ee9fcd03ad2ca5dcc", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.24.0/MODULE.bazel": "4796b4c25b47053e9bbffa792b3792d07e228ff66cd0405faef56a978708acd4", + "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", + "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", + "https://bcr.bazel.build/modules/bazel_features/1.36.0/MODULE.bazel": "596cb62090b039caf1cad1d52a8bc35cf188ca9a4e279a828005e7ee49a1bec3", + "https://bcr.bazel.build/modules/bazel_features/1.36.0/source.json": "279625cafa5b63cc0a8ee8448d93bc5ac1431f6000c50414051173fd22a6df3c", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/source.json": "7ebaefba0b03efe59cac88ed5bbc67bcf59a3eff33af937345ede2a38b2d368a", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/gazelle/0.51.3/MODULE.bazel": "618a729142f66de1e2cb776d026413763be5b80d5e3d29ffb9d3d90c5defde90", + "https://bcr.bazel.build/modules/gazelle/0.51.3/source.json": "fbe5312a01fb4a2a58caff4a0d40dcf384b6f0bda75e85546663360da1d7538a", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googleapis-rules-registry/1.0.0/MODULE.bazel": "97c6a4d413b373d4cc97065da3de1b2166e22cbbb5f4cc9f05760bfa83619e24", + "https://bcr.bazel.build/modules/googleapis-rules-registry/1.0.0/source.json": "cf611c836a60e98e2e2ab2de8004f119e9f06878dcf4ea2d95a437b1b7a89fe9", + "https://bcr.bazel.build/modules/googleapis/0.0.0-20241220-5e258e33/MODULE.bazel": "571b018644920302f5a69520b91dae189c17d566e730a1b87c9dbeefe39bd6a5", + "https://bcr.bazel.build/modules/googleapis/0.0.0-20241220-5e258e33/source.json": "2172f9bad88838c509e92489545b6ec41d99fb0de8cf7b2a2da61dae7587a0e4", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/MODULE.bazel": "ef4f9439e3270fdd6b9fd4dbc3d2f29d13888e44c529a1b243f7a31dfbc2e8e4", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/source.json": "2326db2f6592578177751c3e1f74786b79382cd6008834c9d01ec865b9126a85", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/1.1.0/MODULE.bazel": "1c0c09f5bdcf4b3f924720d2478a3711cb39f4977019ca5988685e5b7e18b3d2", + "https://bcr.bazel.build/modules/platforms/1.1.0/source.json": "fcf351c47596c939140ab0d333dfdd08ed1ea6ce33c2fe70c12493a301cf1344", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95", + "https://bcr.bazel.build/modules/protobuf/29.1/source.json": "04cca85dce26b895ed037d98336d860367fe09919208f2ad383f0df1aff63199", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.11/MODULE.bazel": "9f249c5624a4788067b96b8b896be10c7e8b4375dc46f6d8e1e51100113e0992", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", + "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", + "https://bcr.bazel.build/modules/rules_cc/0.2.8/source.json": "85087982aca15f31307bd52698316b28faa31bd2c3095a41f456afec0131344c", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", + "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71", + "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", + "https://bcr.bazel.build/modules/rules_java/8.6.1/source.json": "f18d9ad3c4c54945bf422ad584fa6c5ca5b3116ff55a5b1bc77e5c1210be5960", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.6/MODULE.bazel": "153042249c7060536dc95b6bb9f9bb8063b8a0b0cb7acdb381bddbc2374aed55", + "https://bcr.bazel.build/modules/rules_jvm_external/6.6/source.json": "b1d7ffc3877e5a76e6e48e6bce459cbb1712c90eba14861b112bd299587a534d", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.31.0/source.json": "a41c836d4065888eef4377f2f27b6eea0fedb9b5adb1bab1970437373fe90dc7", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.8.0/MODULE.bazel": "bbad4298d7ba185684f5fcd71b049c95b0575d1248891fd80b8d7077d647c9d8", + "https://bcr.bazel.build/modules/stardoc/0.8.0/source.json": "7321db37080ee8a445dc60e8516a98ab3a27884d1457b892485d73759ccb7f4d", + "https://bcr.bazel.build/modules/toolchains_llvm/0.10.3/MODULE.bazel": "d4bae4c78eeea299c8acb374a86cb4f321977bed73d973ec3e795107082d02b8", + "https://bcr.bazel.build/modules/toolchains_llvm/0.10.3/source.json": "0e0533c5714c52de0c82ef774b4c56bccb992aa07bd7908735ab158da85460b4", + "https://bcr.bazel.build/modules/toolchains_protoc/0.6.0/MODULE.bazel": "bb8da2b2ccee5fde3142d237afe049239da114b56dd4a566fadeb937a30b33b4", + "https://bcr.bazel.build/modules/toolchains_protoc/0.6.0/source.json": "7617b931b9de333cada607ad11c74f3770fe7231e56f2166eb12181365cf1278", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/with_cfg.bzl/0.14.1/MODULE.bazel": "aa0ef3f6c67dd35db7ac38c76785dc02f48b53f34e16b20487e70f51b5324d0a", + "https://bcr.bazel.build/modules/with_cfg.bzl/0.14.1/source.json": "4666d3035f69063ecd136f3f0c68e424f1b1dd97ffc9cceb679522c0be38761b", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "//go:extensions.bzl%orchestrion": { + "general": { + "bzlTransitiveDigest": "OjZHk3iIvwEd6R/xIcrcb654JOnGoTcX3A/wbenuqBY=", + "usagesDigest": "uzG4j+dPOAh/T8fqRnNWcwaH4INbm74AsvyHGrBh/Go=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "rules_go_orchestrion_tool": { + "bzlFile": "@@//go/private/orchestrion:extensions.bzl", + "ruleClassName": "_orchestrion_empty", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "", + "bazel_tools", + "bazel_tools" + ], + [ + "", + "io_bazel_rules_go", + "" + ], + [ + "", + "io_bazel_rules_go_bazel_features", + "bazel_features~" + ], + [ + "bazel_features~", + "bazel_features_globals", + "bazel_features~~version_extension~bazel_features_globals" + ], + [ + "bazel_features~", + "bazel_features_version", + "bazel_features~~version_extension~bazel_features_version" + ] + ] + } + }, + "@@pybind11_bazel~//:python_configure.bzl%extension": { + "general": { + "bzlTransitiveDigest": "dFd3A3f+jPCss+EDKMp/jxjcUhfMku130eT1KGxSCwA=", + "usagesDigest": "gNvOHVcAlwgDsNXD0amkv2CC96mnaCThPQoE44y8K+w=", + "recordedFileInputs": { + "@@pybind11_bazel~//MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e" + }, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_python": { + "bzlFile": "@@pybind11_bazel~//:python_configure.bzl", + "ruleClassName": "python_configure", + "attributes": {} + }, + "pybind11": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file": "@@pybind11_bazel~//:pybind11.BUILD", + "strip_prefix": "pybind11-2.11.1", + "urls": [ + "https://github.com/pybind/pybind11/archive/v2.11.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "pybind11_bazel~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_fuzzing~//fuzzing/private:extensions.bzl%non_module_dependencies": { + "general": { + "bzlTransitiveDigest": "VMhyxXtdJvrNlLts7afAymA+pOatXuh5kLdxzVAZ/04=", + "usagesDigest": "YnIrdgwnf3iCLfChsltBdZ7yOJh706lpa2vww/i2pDI=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "platforms": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz" + ], + "sha256": "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74" + } + }, + "rules_python": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8", + "strip_prefix": "rules_python-0.28.0", + "url": "https://github.com/bazelbuild/rules_python/releases/download/0.28.0/rules_python-0.28.0.tar.gz" + } + }, + "bazel_skylib": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94", + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz" + ] + } + }, + "com_google_absl": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/abseil/abseil-cpp/archive/refs/tags/20240116.1.zip" + ], + "strip_prefix": "abseil-cpp-20240116.1", + "integrity": "sha256-7capMWOvWyoYbUaHF/b+I2U6XLMaHmky8KugWvfXYuk=" + } + }, + "rules_fuzzing_oss_fuzz": { + "bzlFile": "@@rules_fuzzing~//fuzzing/private/oss_fuzz:repository.bzl", + "ruleClassName": "oss_fuzz_repository", + "attributes": {} + }, + "honggfuzz": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file": "@@rules_fuzzing~//:honggfuzz.BUILD", + "sha256": "6b18ba13bc1f36b7b950c72d80f19ea67fbadc0ac0bb297ec89ad91f2eaa423e", + "url": "https://github.com/google/honggfuzz/archive/2.5.zip", + "strip_prefix": "honggfuzz-2.5" + } + }, + "rules_fuzzing_jazzer": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_jar", + "attributes": { + "sha256": "ee6feb569d88962d59cb59e8a31eb9d007c82683f3ebc64955fd5b96f277eec2", + "url": "https://repo1.maven.org/maven2/com/code-intelligence/jazzer/0.20.1/jazzer-0.20.1.jar" + } + }, + "rules_fuzzing_jazzer_api": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_jar", + "attributes": { + "sha256": "f5a60242bc408f7fa20fccf10d6c5c5ea1fcb3c6f44642fec5af88373ae7aa1b", + "url": "https://repo1.maven.org/maven2/com/code-intelligence/jazzer-api/0.20.1/jazzer-api-0.20.1.jar" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_fuzzing~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_java~//java:rules_java_deps.bzl%compatibility_proxy": { + "general": { + "bzlTransitiveDigest": "wz/gaA3xHNx01lt9KMTpLRTOGQHRWnTsAPhRfjdk21k=", + "usagesDigest": "I6+CGVbSrNp2QwSmF31WrXKCF4JkXIiGHgmLdJ7jzeQ=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "compatibility_proxy": { + "bzlFile": "@@rules_java~//java:rules_java_deps.bzl", + "ruleClassName": "_compatibility_proxy_repo_rule", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_java~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "eecmTsmdIQveoA97hPtH3/Ej/kugbdCI24bhXIXaly8=", + "usagesDigest": "aJF6fLy82rR95Ff5CZPAqxNoFgOMLMN5ImfBS0nhnkg=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", + "ruleClassName": "kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", + "ruleClassName": "kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl", + "ruleClassName": "ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_python~//python/extensions:pip.bzl%pip": { + "os:osx,arch:aarch64": { + "bzlTransitiveDigest": "5MUx+3y7/AkrYKnErq4h92RhZF18Bu4/s3T7ciotuac=", + "usagesDigest": "VV/m9hcGpYNYqWuAClm1Zln5+P89fWXgpmx0PpSPWDY=", + "recordedFileInputs": { + "@@rules_fuzzing~//fuzzing/requirements.txt": "ab04664be026b632a0d2a2446c4f65982b7654f5b6851d2f9d399a19b7242a5b", + "@@protobuf~//python/requirements.txt": "983be60d3cec4b319dcab6d48aeb3f5b2f7c3350f26b3a9e97486c37967c73c5" + }, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "pip_deps_38__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "pip_deps_38_", + "groups": {} + } + }, + "pip_deps_38_numpy": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "numpy<=1.26.1", + "repo": "pip_deps_38", + "repo_prefix": "pip_deps_38_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_38_setuptools": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "setuptools<=70.3.0", + "repo": "pip_deps_38", + "repo_prefix": "pip_deps_38_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_39__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "pip_deps_39_", + "groups": {} + } + }, + "pip_deps_39_numpy": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "numpy<=1.26.1", + "repo": "pip_deps_39", + "repo_prefix": "pip_deps_39_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_39_setuptools": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "setuptools<=70.3.0", + "repo": "pip_deps_39", + "repo_prefix": "pip_deps_39_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_310__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "pip_deps_310_", + "groups": {} + } + }, + "pip_deps_310_numpy": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "numpy<=1.26.1", + "repo": "pip_deps_310", + "repo_prefix": "pip_deps_310_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_310_setuptools": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "setuptools<=70.3.0", + "repo": "pip_deps_310", + "repo_prefix": "pip_deps_310_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_311__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "pip_deps_311_", + "groups": {} + } + }, + "pip_deps_311_numpy": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "numpy<=1.26.1", + "repo": "pip_deps_311", + "repo_prefix": "pip_deps_311_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_311_setuptools": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "setuptools<=70.3.0", + "repo": "pip_deps_311", + "repo_prefix": "pip_deps_311_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_312__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "pip_deps_312_", + "groups": {} + } + }, + "pip_deps_312_numpy": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "numpy<=1.26.1", + "repo": "pip_deps_312", + "repo_prefix": "pip_deps_312_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps_312_setuptools": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "setuptools<=70.3.0", + "repo": "pip_deps_312", + "repo_prefix": "pip_deps_312_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_38__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "rules_fuzzing_py_deps_38_", + "groups": {} + } + }, + "rules_fuzzing_py_deps_38_absl_py": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3", + "repo": "rules_fuzzing_py_deps_38", + "repo_prefix": "rules_fuzzing_py_deps_38_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_38_six": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "repo": "rules_fuzzing_py_deps_38", + "repo_prefix": "rules_fuzzing_py_deps_38_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_39__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "rules_fuzzing_py_deps_39_", + "groups": {} + } + }, + "rules_fuzzing_py_deps_39_absl_py": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3", + "repo": "rules_fuzzing_py_deps_39", + "repo_prefix": "rules_fuzzing_py_deps_39_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_39_six": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "repo": "rules_fuzzing_py_deps_39", + "repo_prefix": "rules_fuzzing_py_deps_39_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_310__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "rules_fuzzing_py_deps_310_", + "groups": {} + } + }, + "rules_fuzzing_py_deps_310_absl_py": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3", + "repo": "rules_fuzzing_py_deps_310", + "repo_prefix": "rules_fuzzing_py_deps_310_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_310_six": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "repo": "rules_fuzzing_py_deps_310", + "repo_prefix": "rules_fuzzing_py_deps_310_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_311__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "rules_fuzzing_py_deps_311_", + "groups": {} + } + }, + "rules_fuzzing_py_deps_311_absl_py": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3", + "repo": "rules_fuzzing_py_deps_311", + "repo_prefix": "rules_fuzzing_py_deps_311_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_311_six": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "repo": "rules_fuzzing_py_deps_311", + "repo_prefix": "rules_fuzzing_py_deps_311_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_312__groups": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "group_library", + "attributes": { + "repo_prefix": "rules_fuzzing_py_deps_312_", + "groups": {} + } + }, + "rules_fuzzing_py_deps_312_absl_py": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3", + "repo": "rules_fuzzing_py_deps_312", + "repo_prefix": "rules_fuzzing_py_deps_312_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "rules_fuzzing_py_deps_312_six": { + "bzlFile": "@@rules_python~//python/pip_install:pip_repository.bzl", + "ruleClassName": "whl_library", + "attributes": { + "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "repo": "rules_fuzzing_py_deps_312", + "repo_prefix": "rules_fuzzing_py_deps_312_", + "whl_patches": {}, + "experimental_target_platforms": [], + "python_interpreter": "", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "quiet": true, + "timeout": 600, + "isolated": true, + "extra_pip_args": [ + "--require-hashes" + ], + "download_only": false, + "pip_data_exclude": [], + "enable_implicit_namespace_pkgs": false, + "environment": {}, + "envsubst": [], + "group_name": "", + "group_deps": [] + } + }, + "pip_deps": { + "bzlFile": "@@rules_python~//python/private/bzlmod:pip_repository.bzl", + "ruleClassName": "pip_repository", + "attributes": { + "repo_name": "pip_deps", + "whl_map": { + "numpy": [ + "3.8", + "3.9", + "3.10", + "3.11", + "3.12" + ], + "setuptools": [ + "3.8", + "3.9", + "3.10", + "3.11", + "3.12" + ] + }, + "default_version": "3.11" + } + }, + "rules_fuzzing_py_deps": { + "bzlFile": "@@rules_python~//python/private/bzlmod:pip_repository.bzl", + "ruleClassName": "pip_repository", + "attributes": { + "repo_name": "rules_fuzzing_py_deps", + "whl_map": { + "absl_py": [ + "3.8", + "3.9", + "3.10", + "3.11", + "3.12" + ], + "six": [ + "3.8", + "3.9", + "3.10", + "3.11", + "3.12" + ] + }, + "default_version": "3.11" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "bazel_features~", + "bazel_features_globals", + "bazel_features~~version_extension~bazel_features_globals" + ], + [ + "bazel_features~", + "bazel_features_version", + "bazel_features~~version_extension~bazel_features_version" + ], + [ + "rules_python~", + "bazel_features", + "bazel_features~" + ], + [ + "rules_python~", + "bazel_skylib", + "bazel_skylib~" + ], + [ + "rules_python~", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_python~", + "pypi__build", + "rules_python~~internal_deps~pypi__build" + ], + [ + "rules_python~", + "pypi__click", + "rules_python~~internal_deps~pypi__click" + ], + [ + "rules_python~", + "pypi__colorama", + "rules_python~~internal_deps~pypi__colorama" + ], + [ + "rules_python~", + "pypi__importlib_metadata", + "rules_python~~internal_deps~pypi__importlib_metadata" + ], + [ + "rules_python~", + "pypi__installer", + "rules_python~~internal_deps~pypi__installer" + ], + [ + "rules_python~", + "pypi__more_itertools", + "rules_python~~internal_deps~pypi__more_itertools" + ], + [ + "rules_python~", + "pypi__packaging", + "rules_python~~internal_deps~pypi__packaging" + ], + [ + "rules_python~", + "pypi__pep517", + "rules_python~~internal_deps~pypi__pep517" + ], + [ + "rules_python~", + "pypi__pip", + "rules_python~~internal_deps~pypi__pip" + ], + [ + "rules_python~", + "pypi__pip_tools", + "rules_python~~internal_deps~pypi__pip_tools" + ], + [ + "rules_python~", + "pypi__pyproject_hooks", + "rules_python~~internal_deps~pypi__pyproject_hooks" + ], + [ + "rules_python~", + "pypi__setuptools", + "rules_python~~internal_deps~pypi__setuptools" + ], + [ + "rules_python~", + "pypi__tomli", + "rules_python~~internal_deps~pypi__tomli" + ], + [ + "rules_python~", + "pypi__wheel", + "rules_python~~internal_deps~pypi__wheel" + ], + [ + "rules_python~", + "pypi__zipp", + "rules_python~~internal_deps~pypi__zipp" + ], + [ + "rules_python~", + "pythons_hub", + "rules_python~~python~pythons_hub" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_10_aarch64-apple-darwin", + "rules_python~~python~python_3_10_aarch64-apple-darwin" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_10_host", + "rules_python~~python~python_3_10_host" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_11_aarch64-apple-darwin", + "rules_python~~python~python_3_11_aarch64-apple-darwin" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_11_host", + "rules_python~~python~python_3_11_host" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_12_aarch64-apple-darwin", + "rules_python~~python~python_3_12_aarch64-apple-darwin" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_12_host", + "rules_python~~python~python_3_12_host" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_8_aarch64-apple-darwin", + "rules_python~~python~python_3_8_aarch64-apple-darwin" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_8_host", + "rules_python~~python~python_3_8_host" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_9_aarch64-apple-darwin", + "rules_python~~python~python_3_9_aarch64-apple-darwin" + ], + [ + "rules_python~~python~pythons_hub", + "python_3_9_host", + "rules_python~~python~python_3_9_host" + ] + ] + } + }, + "@@rules_python~//python/extensions:python.bzl%python": { + "general": { + "bzlTransitiveDigest": "NKPsijGE1IrFTzT0W0yfAohwWNIZt6eB23MGn2bM1OU=", + "usagesDigest": "ATOseWU5EE5A0RV+r4ACrYJ9g+Rp7OdaFygles1jsNk=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": { + "RULES_PYTHON_BZLMOD_DEBUG": null + }, + "generatedRepoSpecs": { + "python_3_8_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "1825b1f7220bc93ff143f2e70b5c6a79c6469e0eeb40824e07a7277f59aabfda", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "236a300f386ead02ca98dbddbc026ff4ef4de6701a394106e291ff8b75445ee1", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fcf04532e644644213977242cd724fe5e84c0a5ac92ae038e07f1b01b474fca3", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "a9d203e78caed94de368d154e841610cef6f6b484738573f4ae9059d37e898a5", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "1e8a3babd1500111359b0f5675d770984bcbcb2cc8890b117394f0ed342fb9ec", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.8.18", + "user_repository_name": "python_3_8", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_8": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.8.18", + "user_repository_name": "python_3_8", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_9_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fdc4054837e37b69798c2ef796222a480bc1f80e8ad3a01a95d0168d8282a007", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "1e0a3e8ce8e58901a259748c0ab640d2b8294713782d14229e882c6898b2fb36", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "101c38b22fb2f5a0945156da4259c8e9efa0c08de9d7f59afa51e7ce6e22a1cc", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "eee31e55ffbc1f460d7b17f05dd89e45a2636f374a6f8dc29ea13d0497f7f586", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "82231cb77d4a5c8081a1a1d5b8ae440abe6993514eb77a926c826e9a69a94fb1", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "02ea7bb64524886bd2b05d6b6be4401035e4ba4319146f274f0bcd992822cd75", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "f3ff38b1ccae7dcebd8bbf2e533c9a984fac881de0ffd1636fbb61842bd924de", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.9.18", + "user_repository_name": "python_3_9", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_9": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.9.18", + "user_repository_name": "python_3_9", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_10_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fd027b1dedf1ea034cdaa272e91771bdf75ddef4c8653b05d224a0645aa2ca3c", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "8675915ff454ed2f1597e27794bc7df44f5933c26b94aa06af510fe91b58bb97", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "f3f9c43eec1a0c3f72845d0b705da17a336d3906b7df212d2640b8f47e8ff375", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "859f6cfe9aedb6e8858892fdc124037e83ab05f28d42a7acd314c6a16d6bd66c", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "be0b19b6af1f7d8c667e5abef5505ad06cf72e5a11bb5844970c395a7e5b1275", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b8d930ce0d04bda83037ad3653d7450f8907c88e24bb8255a29b8dab8930d6f1", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "5d0429c67c992da19ba3eb58b3acd0b35ec5e915b8cae9a4aa8ca565c423847a", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.10.13", + "user_repository_name": "python_3_10", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_10": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.10.13", + "user_repository_name": "python_3_10", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_11_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b042c966920cf8465385ca3522986b12d745151a72c060991088977ca36d3883", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b102eaf865eb715aa98a8a2ef19037b6cc3ae7dfd4a632802650f29de635aa13", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b44e1b74afe75c7b19143413632c4386708ae229117f8f950c2094e9681d34c7", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "49520e3ff494708020f306e30b0964f079170be83e956be4504f850557378a22", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "a0e615eef1fafdc742da0008425a9030b7ea68a4ae4e73ac557ef27b112836d4", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "67077e6fa918e4f4fd60ba169820b00be7c390c497bf9bc9cab2c255ea8e6f3e", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "4a51ce60007a6facf64e5495f4cf322e311ba9f39a8cd3f3e4c026eae488e140", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.11.7", + "user_repository_name": "python_3_11", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_11": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.11.7", + "user_repository_name": "python_3_11", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_12_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "f93f8375ca6ac0a35d58ff007043cbd3a88d9609113f1cb59cf7c8d215f064af", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "236533ef20e665007a111c2f36efb59c87ae195ad7dca223b6dc03fb07064f0b", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "78051f0d1411ee62bc2af5edfccf6e8400ac4ef82887a2affc19a7ace6a05267", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "60631211c701f8d2c56e5dd7b154e68868128a019b9db1d53a264f56c0d4aee2", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "eca96158c1568dedd9a0b3425375637a83764d1fa74446438293089a8bfac1f8", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fd5a9e0f41959d0341246d3643f2b8794f638adc0cec8dd5e1b6465198eae08a", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "74e330b8212ca22fd4d9a2003b9eec14892155566738febc8e5e572f267b9472", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.12.1", + "user_repository_name": "python_3_12", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_12": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.12.1", + "user_repository_name": "python_3_12", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "pythons_hub": { + "bzlFile": "@@rules_python~//python/private/bzlmod:pythons_hub.bzl", + "ruleClassName": "hub_repo", + "attributes": { + "default_python_version": "3.11", + "toolchain_prefixes": [ + "_0000_python_3_8_", + "_0001_python_3_9_", + "_0002_python_3_10_", + "_0003_python_3_12_", + "_0004_python_3_11_" + ], + "toolchain_python_versions": [ + "3.8", + "3.9", + "3.10", + "3.12", + "3.11" + ], + "toolchain_set_python_version_constraints": [ + "True", + "True", + "True", + "True", + "False" + ], + "toolchain_user_repository_names": [ + "python_3_8", + "python_3_9", + "python_3_10", + "python_3_12", + "python_3_11" + ] + } + }, + "python_versions": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "multi_toolchain_aliases", + "attributes": { + "python_versions": { + "3.8": "python_3_8", + "3.9": "python_3_9", + "3.10": "python_3_10", + "3.11": "python_3_11", + "3.12": "python_3_12" + } + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python~", + "bazel_skylib", + "bazel_skylib~" + ], + [ + "rules_python~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_python~//python/private/bzlmod:internal_deps.bzl%internal_deps": { + "general": { + "bzlTransitiveDigest": "5gQYH7IOUlRNgdc7jspILfMHm3iqMl3ZPlJvONOn1/o=", + "usagesDigest": "r7vtlnQfWxEwrL+QFXux06yzeWEkq/hrcwAssoCoSLY=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "rules_python_internal": { + "bzlFile": "@@rules_python~//python/private:internal_config_repo.bzl", + "ruleClassName": "internal_config_repo", + "attributes": {} + }, + "pypi__build": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/58/91/17b00d5fac63d3dca605f1b8269ba3c65e98059e1fd99d00283e42a454f0/build-0.10.0-py3-none-any.whl", + "sha256": "af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__click": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", + "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__colorama": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__importlib_metadata": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl", + "sha256": "3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__installer": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl", + "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__more_itertools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/5a/cb/6dce742ea14e47d6f565589e859ad225f2a5de576d7696e0623b784e226b/more_itertools-10.1.0-py3-none-any.whl", + "sha256": "64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__packaging": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl", + "sha256": "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pep517": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/ee/2f/ef63e64e9429111e73d3d6cbee80591672d16f2725e648ebc52096f3d323/pep517-0.13.0-py3-none-any.whl", + "sha256": "4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/50/c2/e06851e8cc28dcad7c155f4753da8833ac06a5c704c109313b8d5a62968a/pip-23.2.1-py3-none-any.whl", + "sha256": "7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip_tools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/e8/df/47e6267c6b5cdae867adbdd84b437393e6202ce4322de0a5e0b92960e1d6/pip_tools-7.3.0-py3-none-any.whl", + "sha256": "8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pyproject_hooks": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/d5/ea/9ae603de7fbb3df820b23a70f6aff92bf8c7770043254ad8d2dc9d6bcba4/pyproject_hooks-1.0.0-py3-none-any.whl", + "sha256": "283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__setuptools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/4f/ab/0bcfebdfc3bfa8554b2b2c97a555569c4c1ebc74ea288741ea8326c51906/setuptools-68.1.2-py3-none-any.whl", + "sha256": "3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__tomli": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", + "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__wheel": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/b8/8b/31273bf66016be6ad22bb7345c37ff350276cfd46e389a0c2ac5da9d9073/wheel-0.41.2-py3-none-any.whl", + "sha256": "75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__zipp": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/8c/08/d3006317aefe25ea79d3b76c9650afabaf6d63d1c8443b236e7405447503/zipp-3.16.2-py3-none-any.whl", + "sha256": "679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@toolchains_llvm~//toolchain/extensions:llvm.bzl%llvm": { + "general": { + "bzlTransitiveDigest": "B9PVPLh42j2FSNQnarwLwKswlOvjaVMKAq4tl8gqb5E=", + "usagesDigest": "VV3O38TSG8zGIHzPWKMHYCOSl8yjTWPg1zorDb0O2cc=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "llvm_toolchain_llvm": { + "bzlFile": "@@toolchains_llvm~//toolchain:rules.bzl", + "ruleClassName": "llvm", + "attributes": { + "alternative_llvm_sources": [], + "auth_patterns": {}, + "distribution": "auto", + "llvm_mirror": "", + "llvm_version": "8.0.0", + "llvm_versions": {}, + "netrc": "", + "sha256": {}, + "strip_prefix": {}, + "urls": {} + } + }, + "llvm_toolchain": { + "bzlFile": "@@toolchains_llvm~//toolchain:rules.bzl", + "ruleClassName": "toolchain", + "attributes": { + "absolute_paths": false, + "compile_flags": {}, + "coverage_compile_flags": {}, + "coverage_link_flags": {}, + "cxx_builtin_include_directories": {}, + "cxx_flags": {}, + "cxx_standard": {}, + "dbg_compile_flags": {}, + "link_flags": {}, + "link_libs": {}, + "llvm_versions": { + "": "8.0.0" + }, + "opt_compile_flags": {}, + "opt_link_flags": {}, + "stdlib": {}, + "sysroot": {}, + "target_settings": {}, + "toolchain_roots": {}, + "unfiltered_compile_flags": {} + } + } + }, + "recordedRepoMappingEntries": [ + [ + "toolchains_llvm~", + "bazel_tools", + "bazel_tools" + ], + [ + "toolchains_llvm~", + "toolchains_llvm", + "toolchains_llvm~" + ] + ] + } + } + } +} diff --git a/third_party/rgo/v0_62_0/base/README.rst b/third_party/rgo/v0_62_0/base/README.rst new file mode 100644 index 00000000..e1b5bc8d --- /dev/null +++ b/third_party/rgo/v0_62_0/base/README.rst @@ -0,0 +1,457 @@ +Go rules for Bazel_ +===================== + +.. Links to external sites and pages +.. _//tests/core/cross: https://github.com/bazelbuild/rules_go/blob/master/tests/core/cross/BUILD.bazel +.. _Avoiding conflicts: proto/core.rst#avoiding-conflicts +.. _Bazel labels: https://docs.bazel.build/versions/master/build-ref.html#labels +.. _Bazel: https://bazel.build/ +.. _Bazel Tutorial\: Build a Go Project: https://bazel.build/start/go +.. _Build modes: go/modes.rst +.. _Bzlmod: https://bazel.build/external/overview#bzlmod +.. _Go with Bzlmod: docs/go/core/bzlmod.md +.. _Go with WORKSPACE: docs/go/core/workspace.md +.. _Core rules: docs/go/core/rules.md +.. _Coverage: https://bazel.build/configure/coverage +.. _Dependencies: go/dependencies.rst +.. _Deprecation schedule: https://github.com/bazelbuild/rules_go/wiki/Deprecation-schedule +.. _Editor setup instructions: docs/editors.md +.. _examples/basic_gazelle: examples/basic_gazelle +.. _examples/hello: examples/hello +.. _Gopher Slack: https://invite.slack.golangbridge.org/ +.. _gopls integration: docs/editors.md +.. _Overriding dependencies: go/dependencies.rst#overriding-dependencies +.. _Proto rules: proto/core.rst +.. _Protocol buffers: proto/core.rst +.. _Toolchains: go/toolchains.rst +.. _Using rules_go on Windows: windows.rst +.. _bazel-go-discuss: https://groups.google.com/forum/#!forum/bazel-go-discuss +.. _configuration transition: https://docs.bazel.build/versions/master/skylark/lib/transition.html +.. _gazelle update-repos: https://github.com/bazelbuild/bazel-gazelle#update-repos +.. _gazelle: https://github.com/bazelbuild/bazel-gazelle +.. _github.com/bazelbuild/bazel-gazelle: https://github.com/bazelbuild/bazel-gazelle +.. _github.com/bazelbuild/rules_go/go/tools/bazel: https://pkg.go.dev/github.com/bazelbuild/rules_go/go/tools/bazel?tab=doc +.. _nogo build-time static analysis: go/nogo.rst +.. _nogo: go/nogo.rst +.. _rules_go and Gazelle roadmap: https://github.com/bazelbuild/rules_go/wiki/Roadmap +.. _#bazel on Go Slack: https://gophers.slack.com/archives/C1SCQE54N +.. _#go on Bazel Slack: https://bazelbuild.slack.com/archives/CDBP88Z0D + +.. Go rules +.. _go_binary: docs/go/core/rules.md#go_binary +.. _go_context: go/toolchains.rst#go_context +.. _go_deps: https://github.com/bazel-contrib/bazel-gazelle/blob/master/extensions.md#go_deps +.. _go_download_sdk: go/toolchains.rst#go_download_sdk +.. _go_host_sdk: go/toolchains.rst#go_host_sdk +.. _go_library: docs/go/core/rules.md#go_library +.. _go_local_sdk: go/toolchains.rst#go_local_sdk +.. _go_path: docs/go/core/rules.md#go_path +.. _go_proto_compiler: proto/core.rst#go_proto_compiler +.. _go_proto_library: proto/core.rst#go_proto_library +.. _go_register_toolchains: go/toolchains.rst#go_register_toolchains +.. _go_repository: https://github.com/bazelbuild/bazel-gazelle/blob/master/reference.md#go_repository +.. _go_rules_dependencies: go/dependencies.rst#go_rules_dependencies +.. _go_source: docs/go/core/rules.md#go_source +.. _go_test: docs/go/core/rules.md#go_test +.. _go_cross_binary: docs/go/core/rules.md#go_cross_binary +.. _go_toolchain: go/toolchains.rst#go_toolchain +.. _go_wrap_sdk: go/toolchains.rst#go_wrap_sdk +.. _gomock: docs/go/extras/extras.md#gomock + +.. External rules +.. _git_repository: https://docs.bazel.build/versions/master/repo/git.html +.. _http_archive: https://docs.bazel.build/versions/master/repo/http.html#http_archive +.. _proto_library: https://github.com/bazelbuild/rules_proto + +.. Issues +.. _#265: https://github.com/bazelbuild/rules_go/issues/265 +.. _#721: https://github.com/bazelbuild/rules_go/issues/721 +.. _#889: https://github.com/bazelbuild/rules_go/issues/889 +.. _#1199: https://github.com/bazelbuild/rules_go/issues/1199 +.. _#2775: https://github.com/bazelbuild/rules_go/issues/2775 + + +Mailing list: `bazel-go-discuss`_ + +Slack: `#go on Bazel Slack`_, `#bazel on Go Slack`_ + +Contents +-------- + +* `Overview`_ +* `Setup`_ +* `FAQ`_ + +Documentation +~~~~~~~~~~~~~ + +* `Core rules`_ + + * `go_binary`_ + * `go_library`_ + * `go_test`_ + * `go_source`_ + * `go_path`_ + * `go_cross_binary`_ + +* `Proto rules`_ + + * `go_proto_library`_ + * `go_proto_compiler`_ + +* `Dependencies`_ + + * `go_rules_dependencies`_ + * `go_repository`_ (Gazelle) + +* `Toolchains`_ + + * `go_register_toolchains`_ + * `go_download_sdk`_ + * `go_host_sdk`_ + * `go_local_sdk`_ + * `go_wrap_sdk`_ + * `go_toolchain`_ + * `go_context`_ + +* `Extra rules `_ + + * `gomock`_ + +* `nogo build-time static analysis`_ +* `Build modes `_ + +Quick links +~~~~~~~~~~~ + +* `Editor setup instructions`_ +* `rules_go and Gazelle roadmap`_ +* `Deprecation schedule`_ +* `Using rules_go on Windows`_ + +Overview +-------- + +These rules support: + +* Building libraries, binaries, and tests (`go_library`_, `go_binary`_, + `go_test`_) +* Go modules via `go_deps`_. +* Vendoring +* cgo +* Cross-compilation +* Generating BUILD files via gazelle_ +* Build-time static code analysis via nogo_ +* `Protocol buffers`_ +* Remote execution +* `Coverage`_ +* `gopls integration`_ for editor support +* Debugging + +They currently do not support or have limited support for: + +* C/C++ integration other than cgo (SWIG) + +The Go rules are tested and supported on the following host platforms: + +* Linux, macOS, Windows +* amd64, arm64 + +Users have reported success on several other platforms, but the rules are +only tested on those listed above. + +Note: Since version v0.51.0, rules_go requires Bazel ≥ 6.5.0 to work. + +The ``master`` branch is only guaranteed to work with the latest version of Bazel. + + +Setup +----- + +To build Go code with Bazel, you will need: + +* A recent version of Bazel. +* A C/C++ toolchain (if using cgo). Bazel will attempt to configure the + toolchain automatically. +* Bash, ``patch``, ``cat``, and a handful of other Unix tools in ``PATH``. + +You normally won't need a Go toolchain installed. Bazel will download one. + +See `Using rules_go on Windows`_ for Windows-specific setup instructions. +Several additional tools need to be installed and configured. + +If you're new to Bazel, read `Bazel Tutorial: Build a Go Project`_, which +introduces Bazel concepts and shows you how to set up a small Go workspace to +be built with Bazel. + +For a quicker "hello world" example, see `examples/hello`_. + +For an example that generates build files and retrieves external dependencies +using Gazelle, see `examples/basic_gazelle`_. + +For more detailed `Bzlmod`_ documentation, see `Go with Bzlmod`_. + +For legacy ``WORKSPACE`` instructions, see `Go with WORKSPACE`_. + +FAQ +--- + +**Go** + +* `Can I still use the go command?`_ +* `Does this work with Go modules?`_ +* `What's up with the go_default_library name?`_ +* `How do I cross-compile?`_ +* `How do I access testdata?`_ +* `How do I access go_binary executables from go_test?`_ + +**Protocol buffers** + +* `How do I avoid conflicts with protocol buffers?`_ +* `Can I use a vendored gRPC with go_proto_library?`_ + +**Dependencies and testing** + +* `How do I use different versions of dependencies?`_ +* `How do I test a beta version of the Go SDK?`_ + +Can I still use the go command? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Yes, but not directly. + +rules_go invokes the Go compiler and linker directly, based on the targets +described with `go_binary`_ and other rules. Bazel and rules_go together +fill the same role as the ``go`` command, so it's not necessary to use the +``go`` command in a Bazel workspace. + +That said, it's usually still a good idea to follow conventions required by +the ``go`` command (e.g., one package per directory, package paths match +directory paths). Tools that aren't compatible with Bazel will still work, +and your project can be depended on by non-Bazel projects. + +If you need to use the ``go`` command to perform tasks that Bazel doesn't cover +(such as adding a new dependency to ``go.mod``), you can use the following Bazel +invocation to run the ``go`` binary of the Bazel-configured Go SDK: + +.. code:: bash + + bazel run @io_bazel_rules_go//go -- + +Prefer this to running ``go`` directly since it ensures that the version of Go +is identical to the one used by rules_go. + +Does this work with Go modules? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Yes, but not directly. Bazel ignores ``go.mod`` files, and all package +dependencies must be expressed through ``deps`` attributes in targets +described with `go_library`_ and other rules. + +You can download a Go module at a specific version as an external repository +using `go_repository`_, a workspace rule provided by gazelle_. This will also +generate build files using gazelle_. + +You can import `go_repository`_ rules from a ``go.mod`` file using +`gazelle update-repos`_. + +What's up with the go_default_library name? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This was used to keep import paths consistent in libraries that can be built +with ``go build`` before the ``importpath`` attribute was available. + +In order to compile and link correctly, rules_go must know the Go import path +(the string by which a package can be imported) for each library. This is now +set explicitly with the ``importpath`` attribute. Before that attribute existed, +the import path was inferred by concatenating a string from a special +``go_prefix`` rule and the library's package and label name. For example, if +``go_prefix`` was ``github.com/example/project``, for a library +``//foo/bar:bar``, rules_go would infer the import path as +``github.com/example/project/foo/bar/bar``. The stutter at the end is +incompatible with ``go build``, so if the label name was ``go_default_library``, +the import path would not include it. So for the library +``//foo/bar:go_default_library``, the import path would be +``github.com/example/project/foo/bar``. + +Since ``go_prefix`` was removed and the ``importpath`` attribute became +mandatory (see `#721`_), the ``go_default_library`` name no longer serves any +purpose. We may decide to stop using it in the future (see `#265`_). + +How do I cross-compile? +~~~~~~~~~~~~~~~~~~~~~~~ + +You can cross-compile by setting the ``--platforms`` flag on the command line. +For example: + +.. code:: + + $ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 //cmd + +By default, cgo is disabled when cross-compiling. To cross-compile with cgo, +add a ``_cgo`` suffix to the target platform. You must register a +cross-compiling C/C++ toolchain with Bazel for this to work. + +.. code:: + + $ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64_cgo //cmd + +Platform-specific sources with build tags or filename suffixes are filtered +automatically at compile time. You can selectively include platform-specific +dependencies with ``select`` expressions (Gazelle does this automatically). + +.. code:: bzl + + go_library( + name = "foo", + srcs = [ + "foo_linux.go", + "foo_windows.go", + ], + deps = select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "//bar_linux", + ], + "@io_bazel_rules_go//go/platform:windows_amd64": [ + "//bar_windows", + ], + "//conditions:default": [], + }), + ) + +To build a specific `go_binary`_ target for a target platform or using a +specific golang SDK version, use the `go_cross_binary`_ rule. This is useful +for producing multiple binaries for different platforms in a single build. + +To build a specific `go_test`_ target for a target platform, set the +``goos`` and ``goarch`` attributes on that rule. + +You can equivalently depend on a `go_binary`_ or `go_test`_ rule through +a Bazel `configuration transition`_ on ``//command_line_option:platforms`` +(there are problems with this approach prior to rules_go 0.23.0). + +How do I access testdata? +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bazel executes tests in a sandbox, which means tests don't automatically have +access to files. You must include test files using the ``data`` attribute. +For example, if you want to include everything in the ``testdata`` directory: + +.. code:: bzl + + go_test( + name = "foo_test", + srcs = ["foo_test.go"], + data = glob(["testdata/**"]), + importpath = "github.com/example/project/foo", + ) + +By default, tests are run in the directory of the build file that defined them. +Note that this follows the Go testing convention, not the Bazel convention +followed by other languages, which run in the repository root. This means +that you can access test files using relative paths. You can change the test +directory using the ``rundir`` attribute. See go_test_. + +Gazelle will automatically add a ``data`` attribute like the one above if you +have a ``testdata`` directory *unless* it contains buildable .go files or +build files, in which case, ``testdata`` is treated as a normal package. + +Note that on Windows, data files are not directly available to tests, since test +data files rely on symbolic links, and by default, Windows doesn't let +unprivileged users create symbolic links. You can use the +`github.com/bazelbuild/rules_go/go/tools/bazel`_ library to access data files. + +How do I access go_binary executables from go_test? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The location where ``go_binary`` writes its executable file is not stable across +rules_go versions and should not be depended upon. The parent directory includes +some configuration data in its name. This prevents Bazel's cache from being +poisoned when the same binary is built in different configurations. The binary +basename may also be platform-dependent: on Windows, we add an .exe extension. + +To depend on an executable in a ``go_test`` rule, reference the executable +in the ``data`` attribute (to make it visible), then expand the location +in ``args``. The real location will be passed to the test on the command line. +For example: + +.. code:: bzl + + go_binary( + name = "cmd", + srcs = ["cmd.go"], + ) + + go_test( + name = "cmd_test", + srcs = ["cmd_test.go"], + args = ["$(location :cmd)"], + data = [":cmd"], + ) + +See `//tests/core/cross`_ for a full example of a test that +accesses a binary. + +Alternatively, you can set the ``out`` attribute of `go_binary`_ to a specific +filename. Note that when ``out`` is set, the binary won't be cached when +changing configurations. + +.. code:: bzl + + go_binary( + name = "cmd", + srcs = ["cmd.go"], + out = "cmd", + ) + + go_test( + name = "cmd_test", + srcs = ["cmd_test.go"], + data = [":cmd"], + ) + +How do I avoid conflicts with protocol buffers? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `Avoiding conflicts`_ in the proto documentation. + +Can I use a vendored gRPC with go_proto_library? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is not supported. When using `go_proto_library`_ with the +``@io_bazel_rules_go//proto:go_grpc`` compiler, an implicit dependency is added +on ``@org_golang_google_grpc//:go_default_library``. If you link another copy of +the same package from ``//vendor/google.golang.org/grpc:go_default_library`` +or anywhere else, you may experience conflicts at compile or run-time. + +If you're using Gazelle with proto rule generation enabled, imports of +``google.golang.org/grpc`` will be automatically resolved to +``@org_golang_google_grpc//:go_default_library`` to avoid conflicts. The +vendored gRPC should be ignored in this case. + +If you specifically need to use a vendored gRPC package, it's best to avoid +using ``go_proto_library`` altogether. You can check in pre-generated .pb.go +files and build them with ``go_library`` rules. Gazelle will generate these +rules when proto rule generation is disabled (add ``# gazelle:proto +disable_global`` to your root build file). + +How do I use different versions of dependencies? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `Overriding dependencies`_ for instructions on overriding repositories +declared in `go_rules_dependencies`_. + +How do I test a beta version of the Go SDK? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +rules_go only supports official releases of the Go SDK. However, you can still +test beta and RC versions by passing a ``version`` like ``"1.16beta1"`` to +`go_register_toolchains`_. See also `go_download_sdk`_. + +.. code:: bzl + + load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") + + go_rules_dependencies() + + go_register_toolchains(version = "1.17beta1") diff --git a/third_party/rgo/v0_62_0/base/WORKSPACE b/third_party/rgo/v0_62_0/base/WORKSPACE new file mode 100644 index 00000000..92a7c246 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/WORKSPACE @@ -0,0 +1,111 @@ +workspace(name = "io_bazel_rules_go") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@io_bazel_rules_go//go:deps.bzl", "go_register_nogo", "go_register_toolchains", "go_rules_dependencies") + +# The non-polyfill version of this is needed by rules_proto below. +http_archive( + name = "bazel_features", + sha256 = "9390b391a68d3b24aef7966bce8556d28003fe3f022a5008efc7807e8acaaf1a", + strip_prefix = "bazel_features-1.36.0", + url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.36.0/bazel_features-v1.36.0.tar.gz", +) + +load("@bazel_features//:deps.bzl", "bazel_features_deps") + +bazel_features_deps() + +go_rules_dependencies() + +go_register_toolchains(version = "1.24.12") + +go_register_nogo( + nogo = "@//internal:nogo", +) + +# Used by //tests:buildifier_test. +http_archive( + name = "com_github_bazelbuild_buildtools", + sha256 = "05c3c3602d25aeda1e9dbc91d3b66e624c1f9fdadf273e5480b489e744ca7269", + strip_prefix = "buildtools-6.4.0", + # latest, as of 2023-11-17 + urls = ["https://github.com/bazelbuild/buildtools/archive/refs/tags/v6.4.0.tar.gz"], +) + +load("@bazel_ci_rules//:rbe_repo.bzl", "rbe_preconfig") + +# Creates a default toolchain config for RBE. +# Use this as is if you are using the rbe_ubuntu16_04 container, +# otherwise refer to RBE docs. +rbe_preconfig( + name = "buildkite_config", + toolchain = "ubuntu2204", +) + +http_archive( + name = "bazel_gazelle", + sha256 = "49d9eba309b0b695824ff417d734242824ad9ab5edb56063b9d3400df1a61a56", + urls = [ + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.51.3/bazel-gazelle-v0.51.3.tar.gz", + ], +) + +load("@gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") + +gazelle_dependencies(go_sdk = "go_sdk") + +go_repository( + name = "com_github_google_go_github_v36", + importpath = "github.com/google/go-github/v36", + sum = "h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs=", + version = "v36.0.0", +) + +go_repository( + name = "com_github_google_go_querystring", + importpath = "github.com/google/go-querystring", + sum = "h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=", + version = "v1.1.0", +) + +go_repository( + name = "org_golang_x_oauth2", + importpath = "golang.org/x/oauth2", + sum = "h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=", + version = "v0.6.0", +) + +load("@io_bazel_rules_go//tests/legacy/test_chdir:remote.bzl", "test_chdir_remote") + +test_chdir_remote() + +load("@io_bazel_rules_go//tests/integration/popular_repos:popular_repos.bzl", "popular_repos") + +popular_repos() + +load( + "@build_bazel_apple_support//lib:repositories.bzl", + "apple_support_dependencies", +) + +apple_support_dependencies() + +# For testing the compatibility with a hermetic cc toolchain. Users should not have to enable it. +http_archive( + name = "hermetic_cc_toolchain", + sha256 = "bd2234acd0837251361be3270d7d3ce599b418be123d902d84762302e31a3014", + strip_prefix = "hermetic_cc_toolchain-13c904dce0cb9b6d07f0d557e6ce3cf7013a562e", + urls = ["https://github.com/uber/hermetic_cc_toolchain/archive/13c904dce0cb9b6d07f0d557e6ce3cf7013a562e.zip"], +) + +load("@hermetic_cc_toolchain//toolchain:defs.bzl", zig_toolchains = "toolchains") + +zig_toolchains( + host_platform_sha256 = { + "linux-aarch64": "12be476ed53c219507e77737dbb7f2a77b280760b8acbc6ba2eaaeb42b7d145e", + "linux-x86_64": "1b1c115c4ccbdc215cc3b07833c7957336d9f5fff816f97e5cafee556a9d8be8", + "macos-aarch64": "3943612c560dd066fba5698968317a146a0f585f6cdaa1e7c1df86685c7c4eaf", + "macos-x86_64": "0c89e5d934ecbf9f4d2dea6e3b8dfcc548a3d4184a856178b3db74e361031a2b", + }, + version = "0.11.0-dev.3886+0c1bfe271", +) diff --git a/third_party/rgo/v0_62_0/base/docs/BUILD.bazel b/third_party/rgo/v0_62_0/base/docs/BUILD.bazel new file mode 100644 index 00000000..d4742ad5 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/BUILD.bazel @@ -0,0 +1,17 @@ +load("//docs:doc_helpers.bzl", "stardoc_with_diff_test", "update_docs") + +# For each doc file, generate MD from bzl_library, then perform diff test +stardoc_with_diff_test( + bzl_library_target = "//docs/go/extras:extras", + out_label = "//docs/go/extras:extras.md", +) + +stardoc_with_diff_test( + bzl_library_target = "//docs/go/core:rules", + out_label = "//docs/go/core:rules.md", +) + +# Update MD in local source tree +update_docs( + name = "update", +) diff --git a/third_party/rgo/v0_62_0/base/docs/doc_helpers.bzl b/third_party/rgo/v0_62_0/base/docs/doc_helpers.bzl new file mode 100644 index 00000000..53ab9eb0 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/doc_helpers.bzl @@ -0,0 +1,96 @@ +# Copyright 2023 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("@stardoc//stardoc:stardoc.bzl", "stardoc") + +def stardoc_with_diff_test( + bzl_library_target, + out_label): + """Creates a stardoc target coupled with a diff_test for a given bzl_library. + + This is helpful for minimizing boilerplate when lots of stardoc targets are to be generated. + + Args: + bzl_library_target: the label of the bzl_library target to generate documentation for + out_label: the label of the output MD file + """ + + out_file = out_label.replace("//", "").replace(":", "/") + + # Generate MD from .bzl + stardoc( + name = out_file.replace("/", "_").replace(".md", "-docgen"), + out = out_file.replace(".md", "-docgen.md"), + input = bzl_library_target + ".bzl", + deps = [bzl_library_target], + ) + + # Ensure that the generated MD has been updated in the local source tree + diff_test( + name = out_file.replace("/", "_").replace(".md", "-difftest"), + failure_message = "Please run \"bazel run //docs:update\"", + # Source file + file1 = out_label, + # Output from stardoc rule above + file2 = out_file.replace(".md", "-docgen.md"), + ) + +def update_docs( + name = "update", + docs_folder = "docs"): + """Creates a sh_binary target which copies over generated doc files to the local source tree. + + This is to be used in tandem with `stardoc_with_diff_test()` to produce a convenient workflow + for generating, testing, and updating all doc files as follows: + + ``` bash + bazel build //{docs_folder}/... && bazel test //{docs_folder}/... && bazel run //{docs_folder}:update + ``` + + eg. + + ``` bash + bazel build //docs/... && bazel test //docs/... && bazel run //docs:update + ``` + + Args: + name: the name of the sh_binary target + docs_folder: the name of the folder containing the doc files in the local source tree + """ + content = ["#!/usr/bin/env bash", "cd ${BUILD_WORKSPACE_DIRECTORY}"] + data = [] + for r in native.existing_rules().values(): + if r["kind"] == "stardoc_markdown_renderer": + doc_gen = r["out"] + if doc_gen.startswith(":"): + doc_gen = doc_gen[1:] + doc_dest = doc_gen.replace("-docgen.md", ".md") + data.append(doc_gen) + content.append("cp -fv bazel-bin/{0}/{1} {2}".format(docs_folder, doc_gen, doc_dest)) + + update_script = name + ".sh" + write_file( + name = "gen_" + name, + out = update_script, + content = content, + ) + + sh_binary( + name = name, + srcs = [update_script], + data = data, + ) diff --git a/third_party/rgo/v0_62_0/base/docs/editors.md b/third_party/rgo/v0_62_0/base/docs/editors.md new file mode 100644 index 00000000..7c49df85 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/editors.md @@ -0,0 +1,347 @@ +# General setup + +The `GOPACKAGESDRIVER` allows `gopls` and any package using `x/tools/packages` to +expose package data. Configuring the rules_go's packages driver is simple. + +## 1. `gopls` +`gopls >= v0.6.10` ([released on Apr 13th 2021](https://github.com/golang/tools/releases/tag/gopls%2Fv0.6.10)) is required. + +Install it in your path. If you have $GOBIN in your PATH, this should do the trick: +``` +$ go install golang.org/x/tools/gopls@latest +``` + +If you are using Visual Studio Code, it should have been automatically updated by now. + +## 2. Launcher script +Create a launcher script, say `tools/gopackagesdriver.sh`. If your repo is loading `rules_go` in its MODULE.bazel, give it these contents: + +```bash +#!/usr/bin/env bash +exec bazel run -- @rules_go//go/tools/gopackagesdriver "${@}" +``` + +If your repo is still loading `rules_go` in the WORKSPACE file: + +```bash +#!/usr/bin/env bash +exec bazel run -- @io_bazel_rules_go//go/tools/gopackagesdriver "${@}" +``` + +## 3. Editor Setup + +You might want to replace `github.com/my/mypkg` with your package. When first opening +a file in the workspace, give the driver some time to load. + +### Visual Studio Code +In the `.vscode/settings.json` of your workspace, you'll need to one of the two following JSON blobs, depending on if your repo is using MODULE.bazel or WORKSPACE to load rules_go (the difference is in the `go.goroot`). Also, for both of these, you'll need to edit some of the lines. + +#### Bzlmod (MODULE.bazel file) +If you're using MODULE.bazel, use a JSON blob like this, after editing the following three lines: + +1. In `build.directoryFilters` replace `mypkg` in `bazel-mypkg` with your repo's workspace name. +2. In `formatting.local` replace the import path there with the import path of your repo's code. +3. In `go.goroot`, replace `mymodule` with the name of your root module. + +**NOTE:** The example below assumes you are using Bazel v8.0.0 or greater (or have the `--incompatible_use_plus_in_repo_names` flag enabled). If you are using an earlier version of Bazel (without that flag enabled), use this value for `go.goroot` instead: `${workspaceFolder}/bazel-${workspaceFolderBasename}/external/rules_go~~go_sdk~mymodule__download_0/`. + +```jsonc +{ + // Settings for go/bazel are based on editor setup instructions at + // https://github.com/bazelbuild/rules_go/wiki/Editor-setup#visual-studio-code + "go.goroot": "${workspaceFolder}/bazel-${workspaceFolderBasename}/external/rules_go++go_sdk+mymodule__download_0/", + "go.toolsEnvVars": { + "GOPACKAGESDRIVER": "${workspaceFolder}/tools/gopackagesdriver.sh" + }, + "go.enableCodeLens": { + "runtest": false + }, + "gopls": { + "build.workspaceFiles": [ + "**/BUILD", + "**/WORKSPACE", + "**/*.{bzl,bazel}", + ], + "build.directoryFilters": [ + "-bazel-bin", + "-bazel-out", + "-bazel-testlogs", + "-bazel-mypkg", + ], + "formatting.gofumpt": true, + "formatting.local": "github.com/my/mypkg", + "ui.completion.usePlaceholders": true, + "ui.semanticTokens": true, + "ui.codelenses": { + "gc_details": false, + "regenerate_cgo": false, + "generate": false, + "test": false, + "tidy": false, + "upgrade_dependency": false, + "vendor": false + }, + }, + "go.useLanguageServer": true, + "go.buildOnSave": "off", + "go.lintOnSave": "off", + "go.vetOnSave": "off", +} +``` + +#### Pre-Bzlmod (WORKSPACE file) +If your repo is using WORKSPACE to load `rules_go`, use a JSON blob like this, after editing the following two lines: + +1. In `build.directoryFilters` replace `mypkg` in `bazel-mypkg` with your repo's workspace name. +2. In `formatting.local` replace the import path there with the import path of your repo's code. + +```jsonc +{ + // Settings for go/bazel are based on editor setup instructions at + // https://github.com/bazelbuild/rules_go/wiki/Editor-setup#visual-studio-code + "go.goroot": "${workspaceFolder}/bazel-${workspaceFolderBasename}/external/rules_go++go_sdk+go_sdk/", + "go.toolsEnvVars": { + "GOPACKAGESDRIVER": "${workspaceFolder}/tools/gopackagesdriver.sh" + }, + "go.enableCodeLens": { + "runtest": false + }, + "gopls": { + "build.workspaceFiles": [ + "**/BUILD", + "**/WORKSPACE", + "**/*.{bzl,bazel}", + ], + "build.directoryFilters": [ + "-bazel-bin", + "-bazel-out", + "-bazel-testlogs", + "-bazel-mypkg", + ], + "formatting.gofumpt": true, + "formatting.local": "github.com/my/mypkg", + "ui.completion.usePlaceholders": true, + "ui.semanticTokens": true, + "ui.codelenses": { + "gc_details": false, + "regenerate_cgo": false, + "generate": false, + "test": false, + "tidy": false, + "upgrade_dependency": false, + "vendor": false + }, + }, + "go.useLanguageServer": true, + "go.buildOnSave": "off", + "go.lintOnSave": "off", + "go.vetOnSave": "off", +} +``` + +### Neovim + +```lua +nvim_lsp.gopls.setup { + on_attach = on_attach, + settings = { + gopls = { + workspaceFiles = { + "**/BUILD", + "**/WORKSPACE", + "**/*.{bzl,bazel}", + }, + env = { + GOPACKAGESDRIVER = './tools/gopackagesdriver.sh' + }, + directoryFilters = { + "-bazel-bin", + "-bazel-out", + "-bazel-testlogs", + "-bazel-mypkg", + }, + ... + }, + }, +} +``` + +### Vim + +1. Install [vim-go](https://github.com/fatih/vim-go), a Vim plugin for Go + development with support for `gopls`. + +2. Follow the instructions from [Editor + setup](https://github.com/bazelbuild/rules_go/wiki/Editor-setup#3-editor-setup) + for installing `gopls` and adding a launcher script. + * Note that `gopls` should already be installed as part of installing `vim-go`. + +3. Add the following to your `.vimrc`: + + ```vim + function! MaybeSetGoPackagesDriver() + " Start at the current directory and see if there's a WORKSPACE file in the + " current directory or any parent. If we find one, check if there's a + " gopackagesdriver.sh in a tools/ directory, and point our + " GOPACKAGESDRIVER env var at it. + let l:dir = getcwd() + while l:dir != "/" + if filereadable(simplify(join([l:dir, 'WORKSPACE'], '/'))) + let l:maybe_driver_path = simplify(join([l:dir, 'tools/gopackagesdriver.sh'], '/')) + if filereadable(l:maybe_driver_path) + let $GOPACKAGESDRIVER = l:maybe_driver_path + break + end + end + let l:dir = fnamemodify(l:dir, ':h') + endwhile + endfunction + + call MaybeSetGoPackagesDriver() + + " See https://github.com/golang/tools/blob/master/gopls/doc/settings.md + let g:go_gopls_settings = { + \ 'build.workspaceFiles': [ + \ '**/BUILD', + \ '**/WORKSPACE', + \ '**/*.{bzl,bazel}', + \ ], + \ 'build.directoryFilters': [ + \ '-bazel-bin', + \ '-bazel-out', + \ '-bazel-testlogs', + \ '-bazel-mypkg', + \ ], + \ 'ui.completion.usePlaceholders': v:true, + \ 'ui.semanticTokens': v:true, + \ 'ui.codelenses': { + \ 'gc_details': v:false, + \ 'regenerate_cgo': v:false, + \ 'generate': v:false, + \ 'test': v:false, + \ 'tidy': v:false, + \ 'upgrade_dependency': v:false, + \ 'vendor': v:false, + \ }, + \ } + ``` + + * You'll want to replace `-bazel-mypkg` with your package. + * If you've put your `gopackagesdriver.sh` script somewhere other than + `tools/gopackagesdriver.sh`, you'll need to update + `MaybeSetGoPackagesDriver` accordingly. + +### Sublime Text +Here is a sample `.sublime-project`: +```json +{ + "folders": [ + { + "path": ".", + "folder_exclude_patterns": ["bazel-*"] + } + ], + "settings": { + "lsp_format_on_save": true, + "LSP": { + "gopls": { + "enabled": true, + "command": ["~/go/bin/gopls"], + "selector": "source.go", + "settings": { + "gopls.workspaceFiles": [ + "**/BUILD", + "**/WORKSPACE", + "**/*.{bzl,bazel}", + ], + "gopls.directoryFilters": [ + "-bazel-bin", + "-bazel-out", + "-bazel-testlogs", + "-bazel-mypkg", + ], + "gopls.allowImplicitNetworkAccess": false, + "gopls.usePlaceholders": true, + "gopls.gofumpt": true, + "gopls.local": "github.com/my/mypkg", + "gopls.semanticTokens": true, + "gopls.codelenses": { + "gc_details": false, + "regenerate_cgo": false, + "generate": false, + "test": false, + "tidy": false, + "upgrade_dependency": false, + "vendor": false + } + }, + "env": { + "GOPACKAGESDRIVER": "./tools/gopackagesdriver.sh" + } + } + } + } +} +``` + +### Helix Editor +Here is a sample `.helix/languages.toml`: +```toml +[language-server.gopls.config] +"build.workspaceFiles" = ["**/BUILD", "**/WORKSPACE", "**/*.{bzl,bazel}"] +"build.directoryFilters" = [ + "-bazel-bin", + "-bazel-out", + "-bazel-testlogs", + "-bazel-mypkg", +] +"formatting.gofumpt" = true +"formatting.local" = "github.com/my/mypkg" +"ui.completion.usePlaceholders" = true +"ui.semanticTokens" = true +"ui.codelenses" = { gc_details = false, generate = false, regenerate_cgo = false, test = false, tidy = false, upgrade_dependency = false, vendor = false } +``` + +### Zed + +In `.zed/settings.json` (top right-hand hamburger menu -> "Open Project Settings") + +```jsonc +{ + "lsp": { + "gopls": { + "binary": { + "env": { + // See https://github.com/bazel-contrib/rules_go/wiki/Editor-setup + "GOPACKAGESDRIVER": "./tools/gopackagesdriver.sh" + } + } + } + } +} +``` + +Other Go-related settings at https://zed.dev/docs/languages/go + +## Environment variables +The package driver has a few environment configuration variables, although most won't +need to configure them: +- `GOPACKAGESDRIVER_BAZEL`: bazel binary, defaults to `bazel` +- `BUILD_WORKSPACE_DIRECTORY`: directory of the bazel workspace (auto detected when using a launcher script because it invokes `bazel run`) +- `GOPACKAGESDRIVER_BAZEL_FLAGS` which will be passed to `bazel` invocations +- `GOPACKAGESDRIVER_BAZEL_QUERY_FLAGS` which will be passed to `bazel query` + invocations +- `GOPACKAGESDRIVER_BAZEL_QUERY_SCOPE` which specifies the scope for `importpath` queries (since `gopls` only issues `file=` queries, so **use if you know what you're doing!**) +- `GOPACKAGESDRIVER_BAZEL_BUILD_FLAGS` which will be passed to `bazel build` + invocations + +## Debugging +It is possible to debug driver issues by calling it directly and looking at the errors +in the outputs: +``` +$ echo {} | ./tools/gopackagesdriver.sh file=relative/path.go +``` + +## Limitations +- CGo completion may not work, but at least it's not explicitly supported. +- Errors are not handled diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/BUILD.bazel b/third_party/rgo/v0_62_0/base/docs/go/core/BUILD.bazel new file mode 100644 index 00000000..b43a6d9e --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/BUILD.bazel @@ -0,0 +1,22 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +exports_files([ + "rules.md", + "rules.bzl", +]) + +bzl_library( + name = "rules", + srcs = ["rules.bzl"], + visibility = ["//visibility:public"], + deps = [ + "//go/private:rpath", + "//go/private/rules:binary", + "//go/private/rules:cross", + "//go/private/rules:library", + "//go/private/rules:library.bzl", + "//go/private/rules:source", + "//go/private/rules:test", + "//go/private/tools:path", + ], +) diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/buildgraph.excalidraw b/third_party/rgo/v0_62_0/base/docs/go/core/buildgraph.excalidraw new file mode 100644 index 00000000..60250523 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/buildgraph.excalidraw @@ -0,0 +1,2260 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "line", + "version": 715, + "versionNonce": 1588502918, + "isDeleted": false, + "id": "y8btfe8aNxR4U0rku_mYn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 40, + "angle": 0, + "x": 1132.107421875, + "y": 236.83398437500003, + "strokeColor": "#000000", + "backgroundColor": "#fd7e14", + "width": 856.15234375, + "height": 307.21875, + "seed": 661091153, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1648705107325, + "link": null, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -100.4296875, + 127.29296875 + ], + [ + -183.92578125, + 159.54296875 + ], + [ + -667.21484375, + 167.625 + ], + [ + -628.08203125, + 301.1796875 + ], + [ + -78.0703125, + 307.21875 + ], + [ + 188.9375, + 73.36328125 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "rectangle", + "version": 423, + "versionNonce": 1905005330, + "isDeleted": false, + "id": "_Yn448UDpyk8bgZY0fA9l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 526.61328125, + "y": 160.484375, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 135.75390625, + "height": 68.09375, + "seed": 860180077, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "aFKsLgjkb7lO7X9odAH4Z", + "type": "arrow" + } + ], + "updated": 1645713106334, + "link": null + }, + { + "type": "rectangle", + "version": 400, + "versionNonce": 2122489170, + "isDeleted": false, + "id": "HzjwDEtdpACOtsMXQz4qR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 515.8046875, + "y": -23.1875, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 188, + "height": 69, + "seed": 1527037778, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "aFKsLgjkb7lO7X9odAH4Z", + "type": "arrow" + }, + { + "type": "text", + "id": "XdeK36TNlGK4oDnK0QljI" + }, + { + "id": "gg8sTvMlfTEUCsO1BcBVQ", + "type": "arrow" + } + ], + "updated": 1645713058816, + "link": null + }, + { + "type": "rectangle", + "version": 450, + "versionNonce": 377362638, + "isDeleted": false, + "id": "nG82Pemyxdap8-2WgkNKA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 517, + "y": -110.83984375, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 188, + "height": 69, + "seed": 1392990674, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "aFKsLgjkb7lO7X9odAH4Z", + "type": "arrow" + }, + { + "id": "iI9z1qPn6RQpZWPzVundB", + "type": "text" + }, + { + "id": "gg8sTvMlfTEUCsO1BcBVQ", + "type": "arrow" + }, + { + "type": "text", + "id": "iI9z1qPn6RQpZWPzVundB" + } + ], + "updated": 1645713058816, + "link": null + }, + { + "type": "text", + "version": 272, + "versionNonce": 1262477070, + "isDeleted": false, + "id": "DbWhovpUmSW3P2ULquXGH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 547.859375, + "y": 182.69140625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 101, + "height": 25, + "seed": 906895950, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713106334, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "foo/foo.go", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "foo/foo.go" + }, + { + "type": "rectangle", + "version": 463, + "versionNonce": 1887166674, + "isDeleted": false, + "id": "_xbH0JhODNrj71g2D9gkP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 523.83203125, + "y": 278.546875, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 135.75390625, + "height": 68.09375, + "seed": 2061882962, + "groupIds": [ + "4kSMwuKzk3B7ostEFiZq2" + ], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "RenCmXsoXx0fGBRKi5_26", + "type": "arrow" + } + ], + "updated": 1645713106334, + "link": null + }, + { + "type": "text", + "version": 300, + "versionNonce": 1313656142, + "isDeleted": false, + "id": "iqePQyDoLs8KfvrRwplFb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 542.70703125, + "y": 299.05859375, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 102, + "height": 25, + "seed": 1875308494, + "groupIds": [ + "4kSMwuKzk3B7ostEFiZq2" + ], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713106334, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "bar/bar.go", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "bar/bar.go" + }, + { + "type": "rectangle", + "version": 589, + "versionNonce": 2132796058, + "isDeleted": false, + "id": "0pqTrsCrwG6n6wgsz7SgC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 526.15234375, + "y": 416.25, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 135.75390625, + "height": 68.09375, + "seed": 377700942, + "groupIds": [ + "eCCem_f9xwDhl8kXZowGD" + ], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "4LKhA3K_w1H2L003EIMw2", + "type": "arrow" + } + ], + "updated": 1648705120553, + "link": null + }, + { + "type": "text", + "version": 381, + "versionNonce": 1832430598, + "isDeleted": false, + "id": "dJOSRocJhisFxXPfh3dF7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 559.0859375, + "y": 436.62890625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 67, + "height": 25, + "seed": 2013483410, + "groupIds": [ + "eCCem_f9xwDhl8kXZowGD" + ], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1648705120554, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "main.go", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "main.go" + }, + { + "type": "rectangle", + "version": 327, + "versionNonce": 598472338, + "isDeleted": false, + "id": "ktywT8Qylp8edNPAyJ97P", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 826.0078125, + "y": 159.49609375, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 158, + "height": 75.1640625, + "seed": 205846418, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "text", + "id": "Dzp14kB83qtIZDUQDD5SD" + }, + { + "id": "aFKsLgjkb7lO7X9odAH4Z", + "type": "arrow" + }, + { + "id": "gfz01PbwrOcATNOv4UJYH", + "type": "arrow" + }, + { + "id": "JzL3QRbsha0aBVxbGukeT", + "type": "arrow" + } + ], + "updated": 1645713106334, + "link": null + }, + { + "type": "rectangle", + "version": 803, + "versionNonce": 1314669006, + "isDeleted": false, + "id": "96rPjdc8UZN-YzZFtZKgl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 834.0000000000002, + "y": 31.3125, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 158, + "height": 75.1640625, + "seed": 523095310, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "E-9hQ7N5qrOcGvUNiQiKh", + "type": "text" + }, + { + "id": "02WhVqVlyTmahvSW4ProQ", + "type": "arrow" + }, + { + "id": "gfz01PbwrOcATNOv4UJYH", + "type": "arrow" + }, + { + "id": "JzL3QRbsha0aBVxbGukeT", + "type": "arrow" + }, + { + "type": "text", + "id": "E-9hQ7N5qrOcGvUNiQiKh" + } + ], + "updated": 1645713058816, + "link": null + }, + { + "type": "rectangle", + "version": 403, + "versionNonce": 98306578, + "isDeleted": false, + "id": "-UZKzAkD5QFkhlYnkmn_1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 869.734375, + "y": -103.796875, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 190, + "height": 76, + "seed": 5847762, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "SozLW7ytDBjhY_zbGCVlc", + "type": "text" + }, + { + "id": "aFKsLgjkb7lO7X9odAH4Z", + "type": "arrow" + }, + { + "id": "gfz01PbwrOcATNOv4UJYH", + "type": "arrow" + }, + { + "id": "JzL3QRbsha0aBVxbGukeT", + "type": "arrow" + }, + { + "type": "text", + "id": "SozLW7ytDBjhY_zbGCVlc" + }, + { + "id": "gg8sTvMlfTEUCsO1BcBVQ", + "type": "arrow" + }, + { + "id": "02WhVqVlyTmahvSW4ProQ", + "type": "arrow" + } + ], + "updated": 1645713058816, + "link": null + }, + { + "type": "rectangle", + "version": 325, + "versionNonce": 754471374, + "isDeleted": false, + "id": "1hsA_FOvShESw1vZOfRki", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 823.0390625, + "y": 280.15625, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 158, + "height": 75.1640625, + "seed": 1605551566, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "mk113WrHJaj6g3-UUKDH7", + "type": "text" + }, + { + "id": "RenCmXsoXx0fGBRKi5_26", + "type": "arrow" + }, + { + "type": "text", + "id": "mk113WrHJaj6g3-UUKDH7" + } + ], + "updated": 1645713106334, + "link": null + }, + { + "type": "rectangle", + "version": 265, + "versionNonce": 1793939098, + "isDeleted": false, + "id": "IssDOZSbCLaPJjJ4_ILh0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 823.2265625, + "y": 413.234375, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 158, + "height": 75.1640625, + "seed": 261187278, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "HTOlHr-Ui1zDseI3sfY9K", + "type": "text" + }, + { + "id": "4LKhA3K_w1H2L003EIMw2", + "type": "arrow" + }, + { + "id": "HTOlHr-Ui1zDseI3sfY9K", + "type": "text" + }, + { + "type": "text", + "id": "HTOlHr-Ui1zDseI3sfY9K" + } + ], + "updated": 1648705117196, + "link": null + }, + { + "type": "text", + "version": 276, + "versionNonce": 908194702, + "isDeleted": false, + "id": "Dzp14kB83qtIZDUQDD5SD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 831.0078125, + "y": 184.578125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 148, + "height": 25, + "seed": 173132430, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713106334, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "foo_archive", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ktywT8Qylp8edNPAyJ97P", + "originalText": "foo_archive" + }, + { + "type": "text", + "version": 758, + "versionNonce": 2141859218, + "isDeleted": false, + "id": "E-9hQ7N5qrOcGvUNiQiKh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 839.0000000000002, + "y": 56.39453125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 148, + "height": 25, + "seed": 220975826, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058816, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "test_archive", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "96rPjdc8UZN-YzZFtZKgl", + "originalText": "test_archive" + }, + { + "type": "text", + "version": 363, + "versionNonce": 1233562766, + "isDeleted": false, + "id": "SozLW7ytDBjhY_zbGCVlc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 874.734375, + "y": -78.296875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180, + "height": 25, + "seed": 956961614, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058816, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "test_source.go", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "-UZKzAkD5QFkhlYnkmn_1", + "originalText": "test_source.go" + }, + { + "type": "text", + "version": 288, + "versionNonce": 2059991570, + "isDeleted": false, + "id": "mk113WrHJaj6g3-UUKDH7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 828.0390625, + "y": 305.23828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 148, + "height": 25, + "seed": 1042269714, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713106334, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "bar_archive", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "1hsA_FOvShESw1vZOfRki", + "originalText": "bar_archive" + }, + { + "type": "text", + "version": 186, + "versionNonce": 1163782862, + "isDeleted": false, + "id": "HTOlHr-Ui1zDseI3sfY9K", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 828.2265625, + "y": 438.31640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 148, + "height": 25, + "seed": 2042082578, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058816, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "main_archive", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "IssDOZSbCLaPJjJ4_ILh0", + "originalText": "main_archive" + }, + { + "type": "arrow", + "version": 768, + "versionNonce": 383410450, + "isDeleted": false, + "id": "aFKsLgjkb7lO7X9odAH4Z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 671.875, + "y": 192.01815773762468, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 146.4375, + "height": 4.775870872813329, + "seed": 1274321422, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713106864, + "link": null, + "startBinding": { + "elementId": "y92Fllrdc8UjAmzlSayru", + "focus": 1.5333143038068908, + "gap": 7.619720237624676 + }, + "endBinding": { + "elementId": "ktywT8Qylp8edNPAyJ97P", + "focus": -0.06333301495760145, + "gap": 7.6953125 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 146.4375, + 4.775870872813329 + ] + ] + }, + { + "type": "arrow", + "version": 1836, + "versionNonce": 942891278, + "isDeleted": false, + "id": "02WhVqVlyTmahvSW4ProQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 953.1035887473417, + "y": -13.566406249999774, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 20.944314879108333, + "height": 37.18359374999977, + "seed": 172817230, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713058816, + "link": null, + "startBinding": { + "elementId": "-UZKzAkD5QFkhlYnkmn_1", + "focus": -0.15324622745821068, + "gap": 14.230468750000227 + }, + "endBinding": { + "elementId": "96rPjdc8UZN-YzZFtZKgl", + "focus": -0.06333301495760137, + "gap": 7.6953125 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -20.944314879108333, + 37.18359374999977 + ] + ] + }, + { + "type": "arrow", + "version": 781, + "versionNonce": 591753486, + "isDeleted": false, + "id": "RenCmXsoXx0fGBRKi5_26", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 668.7734375, + "y": 312.67688026346684, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 146.5703125, + "height": 4.778341675082629, + "seed": 154459150, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713106864, + "link": null, + "startBinding": { + "elementId": "OWV5oGIX-s5xyq6g_m2zZ", + "focus": 1.4490929667636174, + "gap": 7.15234375 + }, + "endBinding": { + "elementId": "1hsA_FOvShESw1vZOfRki", + "focus": -0.06333301495760026, + "gap": 7.6953125 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 146.5703125, + 4.778341675082629 + ] + ] + }, + { + "type": "arrow", + "version": 385, + "versionNonce": 78116890, + "isDeleted": false, + "id": "4LKhA3K_w1H2L003EIMw2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 669.2109375, + "y": 445.7575776527482, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 146.3203125, + "height": 4.7737708541606025, + "seed": 1721195790, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1648705118191, + "link": null, + "startBinding": { + "elementId": "0pqTrsCrwG6n6wgsz7SgC", + "focus": -0.19283711924306857, + "gap": 7.3046875 + }, + "endBinding": { + "elementId": "IssDOZSbCLaPJjJ4_ILh0", + "focus": -0.06333301495760026, + "gap": 7.6953125 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 146.3203125, + 4.7737708541606025 + ] + ] + }, + { + "type": "text", + "version": 350, + "versionNonce": 13085330, + "isDeleted": false, + "id": "y92Fllrdc8UjAmzlSayru", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 676.77734375, + "y": 159.3984375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 25, + "seed": 1522598802, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "aFKsLgjkb7lO7X9odAH4Z", + "type": "arrow" + }, + { + "id": "D1sm8V-f_lwosorRMX2Pj", + "type": "arrow" + } + ], + "updated": 1645713127078, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "GoCompilePkg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoCompilePkg" + }, + { + "type": "text", + "version": 430, + "versionNonce": 2040329614, + "isDeleted": false, + "id": "AVQpPcZ2l6tF482laHpQm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 958.4257812500002, + "y": -14.23046875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 25, + "seed": 1234020498, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058816, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "GoCompilePkg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoCompilePkg" + }, + { + "type": "text", + "version": 373, + "versionNonce": 1338350418, + "isDeleted": false, + "id": "OWV5oGIX-s5xyq6g_m2zZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 675.92578125, + "y": 281.359375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 25, + "seed": 1981887442, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "RenCmXsoXx0fGBRKi5_26", + "type": "arrow" + } + ], + "updated": 1645713106334, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "GoCompilePkg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoCompilePkg" + }, + { + "type": "text", + "version": 263, + "versionNonce": 230888398, + "isDeleted": false, + "id": "XFDzOG61LR012x-J2LGIJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 675.609375, + "y": 418.51953125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 25, + "seed": 1994605266, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "GoCompilePkg", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoCompilePkg" + }, + { + "type": "line", + "version": 1696, + "versionNonce": 1947902610, + "isDeleted": false, + "id": "CCr_7bBDw6qxEnXcYPkhb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 984.40625, + "y": 176.43359375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 106.10546875, + "height": 313.45703125, + "seed": 1367735442, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 34.70703125, + 59.4140625 + ], + [ + 7.453125, + 145.83984375 + ], + [ + 106.10546875, + 141.45703125 + ], + [ + 3.32421875, + 148.296875 + ], + [ + 35.30859375, + 220.953125 + ], + [ + 7.41796875, + 313.45703125 + ] + ] + }, + { + "type": "line", + "version": 1423, + "versionNonce": 164157838, + "isDeleted": false, + "id": "rSS_NGIY9mXlKvJ6zEKcS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 698.2108315925065, + "y": -124.59268454085958, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 163.09322505611044, + "height": 177.3724073101255, + "seed": 1859243538, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713136400, + "link": null, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 32.08840700592511, + 30.81405958552382 + ], + [ + 18.23841960974691, + 71.9505372729384 + ], + [ + 163.09322505611044, + 62.79260616948538 + ], + [ + 19.635544337568465, + 76.75792430959316 + ], + [ + 31.990871883416816, + 131.85248366531474 + ], + [ + 2.2395418237075546, + 177.3724073101255 + ] + ] + }, + { + "type": "line", + "version": 2422, + "versionNonce": 1368162386, + "isDeleted": false, + "id": "Adp4I3kUZ5DVOnLF_mvH-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1004.0975503425063, + "y": 42.05965920914046, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135.13493323240277, + "height": 110.7669385601255, + "seed": 830365522, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 6.061063255925092, + 30.10702833552382 + ], + [ + 47.98060710974687, + 63.634131022938405 + ], + [ + 118.47213130611044, + 61.53479366948538 + ], + [ + 61.26445058756849, + 63.09386180959315 + ], + [ + 7.69009063341673, + 78.96576491531472 + ], + [ + -16.66280192629233, + 110.7669385601255 + ] + ] + }, + { + "type": "text", + "version": 211, + "versionNonce": 1752999442, + "isDeleted": false, + "id": "jqwxeTyV2H4FXh6iMTzld", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1014.41015625, + "y": 282.78125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 63, + "height": 25, + "seed": 417199122, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "GoLink", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoLink" + }, + { + "type": "text", + "version": 239, + "versionNonce": 1737882638, + "isDeleted": false, + "id": "QU_adpXt889Ir2oimAKco", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1048.234375, + "y": 120.48828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 63, + "height": 25, + "seed": 1994591822, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "GoLink", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoLink" + }, + { + "type": "rectangle", + "version": 311, + "versionNonce": 31593426, + "isDeleted": false, + "id": "3Fs-7jrpoFZjkiFhKyXwJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1104.68359375, + "y": 278.453125, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 145, + "height": 87, + "seed": 459479182, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "text", + "id": "U_khjX5LJoOf7oHa3yvmX" + } + ], + "updated": 1645713058817, + "link": null + }, + { + "type": "rectangle", + "version": 433, + "versionNonce": 332876366, + "isDeleted": false, + "id": "lAKw58pfZT2qHbLfCcLdZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1132.86328125, + "y": 62.6171875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 145, + "height": 87, + "seed": 766158926, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "XAa15ht9hRV0nmyVPWns_", + "type": "text" + }, + { + "type": "text", + "id": "XAa15ht9hRV0nmyVPWns_" + }, + { + "id": "FCxo6QVHjz9QekO1fdHyI", + "type": "arrow" + } + ], + "updated": 1645713058817, + "link": null + }, + { + "type": "rectangle", + "version": 642, + "versionNonce": 802408850, + "isDeleted": false, + "id": "CIn87cWj794-yqk1m35z0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1320.8125, + "y": 185.6171875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 145, + "height": 87, + "seed": 494767758, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "8UX-ttDyvCivRUrnxdAX9", + "type": "text" + }, + { + "id": "8UX-ttDyvCivRUrnxdAX9", + "type": "text" + }, + { + "id": "FCxo6QVHjz9QekO1fdHyI", + "type": "arrow" + }, + { + "type": "text", + "id": "8UX-ttDyvCivRUrnxdAX9" + } + ], + "updated": 1645713058817, + "link": null + }, + { + "type": "text", + "version": 206, + "versionNonce": 1062523022, + "isDeleted": false, + "id": "U_khjX5LJoOf7oHa3yvmX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1109.68359375, + "y": 309.453125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135, + "height": 25, + "seed": 606262286, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "go binary", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "3Fs-7jrpoFZjkiFhKyXwJ", + "originalText": "go binary" + }, + { + "type": "text", + "version": 332, + "versionNonce": 696829778, + "isDeleted": false, + "id": "XAa15ht9hRV0nmyVPWns_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1137.86328125, + "y": 93.6171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135, + "height": 25, + "seed": 1441614738, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "test binary", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lAKw58pfZT2qHbLfCcLdZ", + "originalText": "test binary" + }, + { + "type": "text", + "version": 554, + "versionNonce": 633835214, + "isDeleted": false, + "id": "8UX-ttDyvCivRUrnxdAX9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1325.8125, + "y": 216.6171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135, + "height": 25, + "seed": 768797010, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "test result", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "CIn87cWj794-yqk1m35z0", + "originalText": "test result" + }, + { + "type": "text", + "version": 125, + "versionNonce": 660081938, + "isDeleted": false, + "id": "XdeK36TNlGK4oDnK0QljI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 520.8046875, + "y": -1.1875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 178, + "height": 25, + "seed": 1057364558, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "foo/foo2_test.go", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HzjwDEtdpACOtsMXQz4qR", + "originalText": "foo/foo2_test.go" + }, + { + "type": "text", + "version": 173, + "versionNonce": 600343822, + "isDeleted": false, + "id": "iI9z1qPn6RQpZWPzVundB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 522, + "y": -88.83984375, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 178, + "height": 25, + "seed": 1192322126, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "foo/foo_test.go", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "nG82Pemyxdap8-2WgkNKA", + "originalText": "foo/foo_test.go" + }, + { + "type": "text", + "version": 268, + "versionNonce": 449885006, + "isDeleted": false, + "id": "YXVK7QXRiUHU6OoO9Za9x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 726.36328125, + "y": -42.26171875, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 130, + "height": 20, + "seed": 1377802510, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 16, + "fontFamily": 1, + "text": "GoTestGenTest", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GoTestGenTest" + }, + { + "type": "arrow", + "version": 1022, + "versionNonce": 1044476050, + "isDeleted": false, + "id": "FCxo6QVHjz9QekO1fdHyI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1289.5767145302918, + "y": 137.09954174565226, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 43.02415574638144, + "height": 37.753945950207225, + "seed": 789481298, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "startBinding": { + "elementId": "lAKw58pfZT2qHbLfCcLdZ", + "focus": -0.4006325045780303, + "gap": 11.713433280291838 + }, + "endBinding": { + "elementId": "CIn87cWj794-yqk1m35z0", + "focus": 0.009231708544778436, + "gap": 10.763699804140515 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 43.02415574638144, + 37.753945950207225 + ] + ] + }, + { + "type": "text", + "version": 76, + "versionNonce": 1792110098, + "isDeleted": false, + "id": "vfq9_DBY27vVxH1CzgHiN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1297.51171875, + "y": 122.25390625, + "strokeColor": "#000000", + "backgroundColor": "#82c91e", + "width": 113, + "height": 25, + "seed": 1564226382, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "T25vTTdMzWQ99VJDhDnIr", + "type": "arrow" + } + ], + "updated": 1645713173348, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "TestRunner", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "TestRunner" + }, + { + "type": "rectangle", + "version": 85, + "versionNonce": 451071506, + "isDeleted": false, + "id": "1LuXAqePsPIRHC1KSeWe6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 679.86328125, + "y": -263.30078125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 128.14453125, + "height": 71.30859375, + "seed": 2134387474, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "type": "text", + "id": "dwSuTduGarUxTROMpgTP0" + }, + { + "id": "w_ofYLqxsnoxd7X07Ob-e", + "type": "arrow" + }, + { + "id": "vKbHoIFobYKpPbfLap6ot", + "type": "arrow" + }, + { + "id": "D1sm8V-f_lwosorRMX2Pj", + "type": "arrow" + } + ], + "updated": 1645713113412, + "link": null + }, + { + "type": "rectangle", + "version": 188, + "versionNonce": 1893353554, + "isDeleted": false, + "id": "r9bJymnryIHCkuEfO52Bs", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1405.390625, + "y": -51.140625, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 128.14453125, + "height": 71.30859375, + "seed": 1928682574, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [ + { + "id": "yboxncedTfOgppKE1YKqS", + "type": "text" + }, + { + "id": "w_ofYLqxsnoxd7X07Ob-e", + "type": "arrow" + }, + { + "id": "vKbHoIFobYKpPbfLap6ot", + "type": "arrow" + }, + { + "id": "D1sm8V-f_lwosorRMX2Pj", + "type": "arrow" + }, + { + "type": "text", + "id": "yboxncedTfOgppKE1YKqS" + }, + { + "id": "T25vTTdMzWQ99VJDhDnIr", + "type": "arrow" + } + ], + "updated": 1645713173348, + "link": null + }, + { + "type": "text", + "version": 15, + "versionNonce": 613654994, + "isDeleted": false, + "id": "dwSuTduGarUxTROMpgTP0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 684.86328125, + "y": -240.146484375, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 118, + "height": 25, + "seed": 346104078, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713058817, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "rules_go", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "1LuXAqePsPIRHC1KSeWe6", + "originalText": "rules_go" + }, + { + "type": "text", + "version": 121, + "versionNonce": 1757596366, + "isDeleted": false, + "id": "yboxncedTfOgppKE1YKqS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1410.390625, + "y": -27.986328125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 118, + "height": 25, + "seed": 1725421458, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713148919, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "bazel", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "r9bJymnryIHCkuEfO52Bs", + "originalText": "bazel" + }, + { + "type": "arrow", + "version": 258, + "versionNonce": 1238989906, + "isDeleted": false, + "id": "w_ofYLqxsnoxd7X07Ob-e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 755.69140625, + "y": -178.3203125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 59.74609375, + "height": 105.75, + "seed": 1707389710, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713086452, + "link": null, + "startBinding": { + "elementId": "1LuXAqePsPIRHC1KSeWe6", + "focus": -0.010816189231700723, + "gap": 13.671875 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 34.55078125, + 35.0859375 + ], + [ + 59.74609375, + 105.75 + ] + ] + }, + { + "type": "arrow", + "version": 317, + "versionNonce": 2104161234, + "isDeleted": false, + "id": "vKbHoIFobYKpPbfLap6ot", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 823.015625, + "y": -236.16796875, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 336.3125, + "height": 212.578125, + "seed": 569428686, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713082596, + "link": null, + "startBinding": { + "elementId": "1LuXAqePsPIRHC1KSeWe6", + "focus": -0.43784332036864043, + "gap": 15.0078125 + }, + "endBinding": { + "elementId": "AVQpPcZ2l6tF482laHpQm", + "focus": 0.6528077547726024, + "gap": 9.359375 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 336.3125, + 46.7265625 + ], + [ + 261.6328125, + 212.578125 + ] + ] + }, + { + "type": "arrow", + "version": 378, + "versionNonce": 11265870, + "isDeleted": false, + "id": "EhfI59NuUjCxo0OQ-WWmc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 827.53125, + "y": -236.5078125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 356.58984375, + "height": 335.14453125, + "seed": 831391054, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713068336, + "link": null, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 356.58984375, + 64.0078125 + ], + [ + 257.359375, + 335.14453125 + ] + ] + }, + { + "type": "arrow", + "version": 332, + "versionNonce": 1017082894, + "isDeleted": false, + "id": "D1sm8V-f_lwosorRMX2Pj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 674.66015625, + "y": -215.19140625, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 321.421875, + "height": 365.08203125, + "seed": 138331282, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713128638, + "link": null, + "startBinding": { + "elementId": "1LuXAqePsPIRHC1KSeWe6", + "focus": 0.32892188879970596, + "gap": 5.203125 + }, + "endBinding": { + "elementId": "y92Fllrdc8UjAmzlSayru", + "focus": -0.15040918803524012, + "gap": 9.5078125 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -282.72265625, + 141.84375 + ], + [ + -206.94921875, + 313.4375 + ], + [ + -1.6015625, + 310.97265625 + ], + [ + 38.69921875, + 365.08203125 + ] + ] + }, + { + "type": "text", + "version": 8, + "versionNonce": 711435730, + "isDeleted": false, + "id": "KXmw08eClY3U80eoCvnKG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1014.6796875, + "y": -247.97265625, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 58, + "height": 25, + "seed": 221048654, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713156598, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "define", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "define" + }, + { + "type": "text", + "version": 54, + "versionNonce": 1449559442, + "isDeleted": false, + "id": "eAX_6DUdXn9173u5Un7rK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 807.55078125, + "y": -153.86328125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 58, + "height": 25, + "seed": 728211086, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713162666, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "define", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "define" + }, + { + "type": "text", + "version": 148, + "versionNonce": 1772837266, + "isDeleted": false, + "id": "dOH_fQDVLWiPkKb9Xa7dh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 493.55859375, + "y": -193.875, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 58, + "height": 25, + "seed": 224121998, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713166649, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "define", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "define" + }, + { + "type": "arrow", + "version": 60, + "versionNonce": 697733522, + "isDeleted": false, + "id": "T25vTTdMzWQ99VJDhDnIr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1418.390625, + "y": 29.76953125, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 65, + "height": 86.36328125, + "seed": 1643009874, + "groupIds": [], + "strokeSharpness": "round", + "boundElements": [], + "updated": 1645713175795, + "link": null, + "startBinding": { + "elementId": "r9bJymnryIHCkuEfO52Bs", + "focus": 0.18712696022442354, + "gap": 9.6015625 + }, + "endBinding": { + "elementId": "vfq9_DBY27vVxH1CzgHiN", + "focus": -0.22206696232341916, + "gap": 6.12109375 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -65, + 86.36328125 + ] + ] + }, + { + "type": "text", + "version": 8, + "versionNonce": 592105870, + "isDeleted": false, + "id": "_CGSnNAmoyvhmYlw0czhG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1403.6796875, + "y": 61.02734375, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 58, + "height": 25, + "seed": 1873973074, + "groupIds": [], + "strokeSharpness": "sharp", + "boundElements": [], + "updated": 1645713178113, + "link": null, + "fontSize": 20, + "fontFamily": 1, + "text": "define", + "baseline": 18, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "define" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/buildgraph.svg b/third_party/rgo/v0_62_0/base/docs/go/core/buildgraph.svg new file mode 100644 index 00000000..94f421cb --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/buildgraph.svg @@ -0,0 +1,16 @@ + + + + + + + foo/foo.gobar/bar.gomain.gofoo_archivetest_archivetest_source.gobar_archivemain_archiveGoCompilePkgGoCompilePkgGoCompilePkgGoCompilePkgGoLinkGoLinkgo binarytest binarytest resultfoo/foo2_test.gofoo/foo_test.goGoTestGenTestTestRunnerrules_gobazeldefinedefinedefinedefine \ No newline at end of file diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/bzlmod.md b/third_party/rgo/v0_62_0/base/docs/go/core/bzlmod.md new file mode 100644 index 00000000..c15d7644 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/bzlmod.md @@ -0,0 +1,379 @@ +# Go with Bzlmod + +This document describes how to use rules_go and Gazelle with Bazel's new external dependency subsystem [Bzlmod](https://bazel.build/external/overview#bzlmod), which is meant to replace `WORKSPACE` files eventually. +Usages of rules_go and Gazelle in `BUILD` files are not affected by this; refer to the existing documentation on rules and configuration options for them. + +## Setup + +Add the following lines to your `MODULE.bazel` file: + +```starlark +bazel_dep(name = "rules_go", version = "0.57.0") +bazel_dep(name = "gazelle", version = "0.45.0") +``` + +The latest versions are always listed on https://registry.bazel.build/. + +If you have WORKSPACE dependencies that reference rules_go and/or Gazelle, you can still use the legacy repository names for the two repositories: + +```starlark +bazel_dep(name = "rules_go", version = "0.57.0", repo_name = "io_bazel_rules_go") +bazel_dep(name = "gazelle", version = "0.45.0", repo_name = "bazel_gazelle") +``` + +## Go SDKs + +rules_go automatically downloads and registers a recent Go SDK, so unless a particular version is required, no manual steps are required. + +To register a particular version of the Go SDK, use the `go_sdk` module extension: + +```starlark +go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") + +# Download an SDK for the host OS & architecture as well as common remote execution +# platforms, using the version given from the `go.mod` file. +go_sdk.from_file(go_mod = "//:go.mod") + +# Alternatively, use the version from a `go.work` file. +go_sdk.from_file(go_work = "//:go.work") + +# Download an SDK for the host OS & architecture as well as common remote execution +# platforms, with a specific version. +go_sdk.download(version = "1.23.1") + +# Alternatively, download an SDK for a fixed OS/architecture. +go_sdk.download( + version = "1.23.1", + goarch = "amd64", + goos = "linux", +) + +# Another alternative is to register the Go SDK installed on the host (see the nota bene below). +go_sdk.host() +``` + +Nota bene: The use of `go_sdk.host()` [may break builds](https://github.com/enola-dev/enola/issues/713) whenever the host Go version is upgraded +(because many OS package managers, such as Debian/Ubuntu's `apt`, distribute Go into a directory which contains the version, such as `/usr/lib/go-1.22/`). +As package upgrades happen outside of Bazel's control, this will lead to non-reproducible builds. Due to this, use of `go_sdk.host()` is discouraged. + +When using `go_sdk.from_file()`, exactly one of `go_mod` or `go_work` must be specified. +Version extraction follows the same precedence for both file types: the `toolchain` directive takes precedence +over the `go` directive. If neither directive is present, `go.mod` has an implicit `go 1.16` line while +`go.work` has an implicit `go 1.18` line as per [Go Toolchains](https://go.dev/doc/toolchain#config) documentation. + +You can register multiple Go SDKs and select which one to use on a per-target basis using [`go_cross_binary`](rules.md#go_cross_binary). +As long as you specify the `version` of an SDK, it will be downloaded lazily, that is, only when it is actually needed during a particular build. +The usual rules of [toolchain resolution](https://bazel.build/extending/toolchains#toolchain-resolution) apply, with SDKs registered in the root module taking precedence over those registered in dependencies. + +### Using a Go SDK + +By default, Go SDK repositories are created with mangled names and are not expected to be referenced directly. + +For build actions, toolchain resolution is used to select the appropriate SDK for a given target. +[`go_cross_binary`](rules.md#go_cross_binary) can be used to influence the outcome of the resolution. + +The `go` tool of the SDK registered for the host is available via the `@rules_go//go` target. +Prefer running it via this target over running `go` directly to ensure that all developers use the same version. +The `@rules_go//go` target can be used in scripts executed via `bazel run`, but cannot be used in build actions. +Note that `go` command arguments starting with `-` require the use of the double dash separator with `bazel run`: + +```sh +bazel run @rules_go//go -- mod tidy -v +``` + +If you really do need direct access to a Go SDK, you can provide the `name` attribute on the `go_sdk.download` or `go_sdk.host` tag and then bring the repository with that name into scope via `use_repo`. +Note that modules using this attribute cannot be added to registries such as the Bazel Central Registry (BCR). +If you have a use case that would require this, please explain it in an issue. + +### Configuring `nogo` + +The `nogo` tool is a static analyzer for Go code that is run as part of compilation. +It is configured via an instance of the [`nogo`](/go/nogo.rst) rule, which can then be registered with the `go_sdk` extension: + +```starlark +go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +go_sdk.nogo(nogo = "//:my_nogo") +``` + +By default, the `nogo` tool is executed for all Go targets in the main repository, but not any external repositories. +Each module can only provide at most one `go_sdk.nogo` tag and only the tag of the root module is honored. + +It is also possible to include only or exclude particular packages from `nogo` analysis, using syntax that matches the `visibility` attribute on rules: + +```starlark +go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") +go_sdk.nogo( + nogo = "//:my_nogo", + includes = [ + "//:__subpackages__", + "@my_own_go_dep//logic:__pkg__", + ], + excludes = [ + "//third_party:__subpackages__", + ], +) +``` + +### Not yet supported + +- `go_local_sdk` + +## Generating BUILD files + +Add the following to your top-level BUILD file: + +```starlark +load("@gazelle//:def.bzl", "gazelle") + +gazelle(name = "gazelle") +``` + +If there is no `go.mod` file in the same directory as your top-level BUILD file, also add the following [Gazelle directive](https://github.com/bazelbuild/bazel-gazelle#directives) to that BUILD file to supply Gazelle with your Go module's path: + +```starlark +# gazelle:prefix github.com/example/project +``` + +Then, use `bazel run //:gazelle` to (re-)generate BUILD files. + +## External dependencies + +External Go dependencies are managed by the `go_deps` module extension provided by Gazelle. +`go_deps` performs [Minimal Version Selection](https://go.dev/ref/mod#minimal-version-selection) on all transitive Go dependencies of all Bazel modules, so compared to the old WORKSPACE setup, every Bazel module only needs to declare its own Go dependencies. +For every major version of a Go module, there will only ever be a single version in the entire build, just as in regular Go module builds. + +### Specifying external dependencies + +Even though this is not a strict requirement, for interoperability with Go tooling that isn't Bazel-aware, it is recommended to manage Go dependencies via `go.mod`. +The `go_deps` extension parses this file directly, so external tooling such as `gazelle update-repos` is no longer needed. + +Register the `go.mod` file with the `go_deps` extension as follows: + +```starlark +go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") +go_deps.from_file(go_mod = "//:go.mod") + +# All *direct* Go dependencies of the module have to be listed explicitly. +use_repo( + go_deps, + "com_github_gogo_protobuf", + "com_github_golang_mock", + "com_github_golang_protobuf", + "org_golang_x_net", +) +``` + +When using Bazel 7.1.1 or higher, the [`@rules_go//go` target](#using-a-go-sdk) automatically updates the `use_repo` call whenever the `go.mod` file changes, using `bazel mod tidy`. +With older versions of Bazel, a warning with a fixup command will be emitted during a build if the `use_repo` call is out of date or missing. + +Alternatively, you can specify a module extension tag to add an individual dependency: + +```starlark +go_deps.module( + path = "google.golang.org/grpc", + sum = "h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU=", + version = "v1.50.0", +) +``` + +#### Specifying Workspaces + +The `go.work` functionality is supported by the `go_deps` module extension in Gazelle. + +```starlark +go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") +go_deps.from_file(go_work = "//:go.work") + +# All *direct* Go dependencies of all `go.mod` files referenced by the `go.work` file have to be listed explicitly. +use_repo( + go_deps, + "com_github_gogo_protobuf", + "com_github_golang_mock", + "com_github_golang_protobuf", + "org_golang_x_net", +) +``` + +Limitations: + +- `go.work` is supported exclusively in the root module. +- Dependencies that are indirect and depend on a go module specified in `go.work` will have that dependency diverge from the one in `go.work`. More details can be found here: https://github.com/bazelbuild/bazel-gazelle/issues/1797. + +#### Depending on tools (Go 1.24+) + +Go 1.24 introduced the [`tool` directive](https://tip.golang.org/doc/go1.24#tools), allowing you to specify tool dependencies directly in your `go.mod` like so: +```sh +bazel run @rules_go//go -- get -tool golang.org/x/tools/cmd/stringer +``` + +This will add a `tool` section in your `go.mod`: +``` +tool golang.org/x/tools/cmd/stringer +``` +as well as adding that tool as a dependency. + +If you are using Gazelle >=0.47.0, then the tools you have added are exported as a dictionary named `GO_TOOLS` from `@gazelle//:go_tools.bzl`. This dictionary is in a suitable format for use by [`bazel_env.bzl`](https://github.com/buildbuddy-io/bazel_env.bzl), so you should be able to do the following to get all your repository’s tools into a `bazel_env` target: +```starlark +load("@bazel_env.bzl", "bazel_env") +load("@gazelle//:go_tools.bzl", "GO_TOOLS") +bazel_env( + name = "env", + tools = { + // […] + } | GO_TOOLS, +) +``` + +#### Depending on tools (pre Go 1.24) + +If you need to depend on Go modules that are only used as tools, you can use the [`tools.go` technique](https://github.com/golang/go/issues/25922#issuecomment-1038394599): + +1. In a new subdirectory of your repository, create a `tools.go` file that imports the tools' main packages: + + ```go + //go:build tools + // +build tools + + package my_tools + + import ( + _ "github.com/the/tool" + _ "golang.org/x/tools/cmd/stringer" + ) + ``` + +2. Run `bazel run @rules_go//go mod tidy` to populate the `go.mod` file with the dependencies of the tools. + +Instead, if you want the tools' dependencies to be resolved independently of the dependencies of your regular code ([experimental](https://github.com/bazelbuild/bazel/issues/20186)): + +2. Run `bazel run @rules_go//go mod init` in the directory containing the `tools.go` file to create a new `go.mod` file and then run `bazel run @rules_go//go mod tidy` in that directory. +3. Add `common --experimental_isolated_extension_usages` to your `.bazelrc` file to enable isolated usages of extensions. +4. Add an isolated usage of the `go_deps` extension to your module file: + + ```starlark + go_tool_deps = use_extension("@gazelle//:extensions.bzl", "go_deps", isolate = True) + go_tool_deps.from_file(go_mod = "//tools:go.mod") + ``` + +### Managing `go.mod` + +An initial `go.mod` file can be created via + +```sh +bazel run @rules_go//go mod init github.com/example/project +``` + +A dependency can be added via + +```sh +bazel run @rules_go//go get golang.org/x/text@v0.3.2 +``` + +### Environment variables + +Environment variables (such as `GOPROXY` and `GOPRIVATE`) required for fetching Go dependencies can be set as follows: + +```starlark +go_deps.config( + go_env = { + "GOPRIVATE": "...", + }, +) +``` + +Variables set in this way are used by `go_deps` as well as `@rules_go//go`, with other variables inheriting their value from the host environment. +`go_env` does **not** affect Go build actions. + +### Overrides + +The root module can override certain aspects of the dependency resolution performed by the `go_deps` extension. + +#### `replace` + +[`replace` directives](https://go.dev/ref/mod#go-mod-file-replace) in `go.mod` can be used to replace particular or all versions of dependencies with other versions or entirely different modules. + +``` +replace( + golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5 + golang.org/x/mod => example.com/my/mod v1.4.5 + example.org/hello => ../../../fixtures/hello +) +``` + +#### Gazelle directives + +Some external Go modules may require tweaking how Gazelle generates BUILD files for them via [Gazelle directives](https://github.com/bazelbuild/bazel-gazelle#directives). +The `go_deps` extension provides a dedicated `go_deps.gazelle_override` tag for this purpose: + +```starlark +go_deps.gazelle_override( + directives = [ + "gazelle:go_naming_convention go_default_library", + ], + path = "github.com/stretchr/testify", +) +``` + +If you need to use a `gazelle_override` to get a public Go module to build with Bazel, consider contributing the directives to the [public registry for default Gazelle overrides](https://github.com/bazelbuild/bazel-gazelle/blob/master/internal/bzlmod/default_gazelle_overrides.bzl) via a PR. +This will allow you to drop the `gazelle_override` tag and also makes the Go module usable in non-root Bazel modules. + +Users can apply custom default directives or extra args to **all** modules, these can be added via a `go_deps.gazelle_default_attributes`. These will +disable/overwrite the [public registry overrides](https://github.com/bazelbuild/bazel-gazelle/blob/master/internal/bzlmod/default_gazelle_overrides.bzl). + +```starlark +go_deps.gazelle_default_attributes( + build_extra_args = [ + "-go_naming_convention_external=go_default_library", + ], + build_file_generation = "on", + directives = [ + "gazelle:proto disable", + ], +) +``` + +Overrides are applied with precedence decreasing in this order:: + +1. Specific `go_deps.gazelle_override` overrides per module +2. `go_deps.gazelle_default_attributes`, which will overwrite #3 (which now must be applied manually by users). +3. [public registry for default Gazelle overrides](https://github.com/bazelbuild/bazel-gazelle/blob/master/internal/bzlmod/default_gazelle_overrides.bzl) + +It is recommended to avoid `go_deps.gazelle_default_attributes` and upstream the overrides to the [public registry for default Gazelle overrides](https://github.com/bazelbuild/bazel-gazelle/blob/master/internal/bzlmod/default_gazelle_overrides.bzl). + +#### `go_deps.module_override` + +A `go_deps.module_override` can be used to apply patches to a Go module: + +```starlark +go_deps.module_override( + patch_strip = 1, + patches = [ + "//patches:testify.patch", + ], + path = "github.com/stretchr/testify", +) +``` + +#### `go_deps.archive_override` + +A `go_deps.archive_override` can be used to replace a Go module with an archive fetched from a URL and is very similar to the `archive_override` for Bazel modules: + +```starlark +go_deps.archive_override( + urls = [ + "https://github.com/bazelbuild/buildtools/archive/ae8e3206e815d086269eb208b01f300639a4b194.tar.gz", + ], + patch_strip = 1, + patches = [ + "//patches:buildtools.patch", + ], + strip_prefix = "buildtools-ae8e3206e815d086269eb208b01f300639a4b194", + path = "github.com/bazelbuild/buildtools", + sha256 = "05d7c3d2bd3cc0b02d15672fefa0d6be48c7aebe459c1c99dced7ac5e598508f", +) +``` + +### Not yet supported + +- Fetching dependencies from Git repositories +- `go.mod` `exclude` directices diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/cross_compilation.md b/third_party/rgo/v0_62_0/base/docs/go/core/cross_compilation.md new file mode 100644 index 00000000..d4e24c0d --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/cross_compilation.md @@ -0,0 +1,27 @@ + +## Cross compilation + +rules_go can cross-compile Go projects to any platform the Go toolchain +supports. The simplest way to do this is by setting the `--platforms` flag on +the command line. + +``` bash +$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 //my/project +``` + +You can replace `linux_amd64` in the example above with any valid +GOOS / GOARCH pair. To list all platforms, run this command: + +``` bash +$ bazel query 'kind(platform, @io_bazel_rules_go//go/toolchain:all)' +``` + +By default, cross-compilation will cause Go targets to be built in "pure mode", +which disables cgo; cgo files will not be compiled, and C/C++ dependencies will +not be compiled or linked. + +Cross-compiling cgo code is possible, but not fully supported. You will need to +[define and register a C/C++ toolchain and platforms](https://bazel.build/extending/toolchains#toolchain-definitions). You'll need to ensure it +works by building `cc_binary` and `cc_library` targets with the `--platforms` +command line flag set. Then, to build a mixed Go / C / C++ project, add +`pure = "off"` to your `go_binary` target and run Bazel with `--platforms`. diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/defines_and_stamping.md b/third_party/rgo/v0_62_0/base/docs/go/core/defines_and_stamping.md new file mode 100644 index 00000000..9d616c5f --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/defines_and_stamping.md @@ -0,0 +1,94 @@ +## Defines and stamping + +In order to provide build time information to go code without data files, we +support the concept of stamping. + +Stamping asks the linker to substitute the value of a global variable with a +string determined at link time. Stamping only happens when linking a binary, not +when compiling a package. This means that changing a value results only in +re-linking, not re-compilation and thus does not cause cascading changes. + +Link values are set in the `x_defs` attribute of any Go rule. This is a +map of string to string, where keys are the names of variables to substitute, +and values are the string to use. Keys may be names of variables in the package +being compiled, or they may be fully qualified names of variables in another +package. + +These mappings are collected up across the entire transitive dependencies of a +binary. This means you can set a value using `x_defs` in a +`go_library`, and any binary that links that library will be stamped with that +value. You can also override stamp values from libraries using `x_defs` +on the `go_binary` rule if needed. The `--[no]stamp` option controls whether +stamping of workspace variables is enabled. + +The values of the `x_defs` dictionary are subject to +[location expansion](https://bazel.build/reference/be/make-variables#predefined_label_variables). + +**Example** + +Suppose we have a small library that contains the current version. + +``` go +package version + +var Version = "redacted" +``` + +We can set the version in the `go_library` rule for this library. + +``` bzl +go_library( + name = "version", + srcs = ["version.go"], + importpath = "example.com/repo/version", + x_defs = {"Version": "0.9"}, +) +``` + +Binaries that depend on this library may also set this value. + +``` bzl +go_binary( + name = "cmd", + srcs = ["main.go"], + deps = ["//version"], + x_defs = {"example.com/repo/version.Version": "0.9"}, +) +``` + +### Stamping with the workspace status script + +You can use values produced by the workspace status command in your link stamp. +To use this functionality, write a script that prints key-value pairs, separated +by spaces, one per line. For example: + +``` bash +#!/usr/bin/env bash + +echo STABLE_GIT_COMMIT $(git rev-parse HEAD) +``` + +***Note:*** stamping with keys that bazel designates as "stable" will trigger a +re-link when any stable key changes. Currently, in bazel, stable keys are +`BUILD_EMBED_LABEL`, `BUILD_USER`, `BUILD_HOST` and keys whose names start with +`STABLE_`. Stamping only with keys that are not stable keys will not trigger a +relink. + +You can reference these in `x_defs` using curly braces. + +``` bzl +go_binary( + name = "cmd", + srcs = ["main.go"], + deps = ["//version"], + x_defs = {"example.com/repo/version.Version": "{STABLE_GIT_COMMIT}"}, +) +``` + +You can build using the status script using the `--workspace_status_command` +argument on the command line: + +``` bash +$ bazel build --stamp --workspace_status_command=./status.sh //:cmd +``` + diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/embedding.md b/third_party/rgo/v0_62_0/base/docs/go/core/embedding.md new file mode 100644 index 00000000..cb24283e --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/embedding.md @@ -0,0 +1,86 @@ +## Embedding + +The sources, dependencies, and data of a `go_library` may be *embedded* +within another `go_library`, `go_binary`, or `go_test` using the `embed` +attribute. The embedding package will be compiled into a single archive +file. The embedded package may still be compiled as a separate target. + +A minimal example of embedding is below. In this example, the command `bazel +build :foo_and_bar` will compile `foo.go` and `bar.go` into a single +archive. `bazel build :bar` will compile only `bar.go`. Both libraries must +have the same `importpath`. + +``` bzl +go_library( + name = "foo_and_bar", + srcs = ["foo.go"], + embed = [":bar"], + importpath = "example.com/foo", +) + +go_library( + name = "bar", + srcs = ["bar.go"], + importpath = "example.com/foo", +) +``` + +Embedding is most frequently used for tests and binaries. Go supports two +different kinds of tests. *Internal tests* (e.g., `package foo`) are compiled +into the same archive as the library under test and can reference unexported +definitions in that library. *External tests* (e.g., `package foo_test`) are +compiled into separate archives and may depend on exported definitions from the +internal test archive. + +In order to compile the internal test archive, we *embed* the `go_library` +under test into a `go_test` that contains the test sources. The `go_test` +rule can automatically distinguish internal and external test sources, so they +can be listed together in `srcs`. The `go_library` under test does not +contain test sources. Other `go_binary` and `go_library` targets can depend +on it or embed it. + +``` bzl +go_library( + name = "foo_lib", + srcs = ["foo.go"], + importpath = "example.com/foo", +) + +go_binary( + name = "foo", + embed = [":foo_lib"], +) + +go_test( + name = "go_default_test", + srcs = [ + "foo_external_test.go", + "foo_internal_test.go", + ], + embed = [":foo_lib"], +) +``` + +Embedding may also be used to add extra sources to a +`go_proto_library`. + +``` bzl +proto_library( + name = "foo_proto", + srcs = ["foo.proto"], +) + +go_proto_library( + name = "foo_go_proto", + importpath = "example.com/foo", + proto = ":foo_proto", +) + +go_library( + name = "foo", + srcs = ["extra.go"], + embed = [":foo_go_proto"], + importpath = "example.com/foo", +) +``` + diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/examples.md b/third_party/rgo/v0_62_0/base/docs/go/core/examples.md new file mode 100644 index 00000000..99adb1a1 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/examples.md @@ -0,0 +1,70 @@ +## Examples + +### go_library +``` bzl +go_library( + name = "foo", + srcs = [ + "foo.go", + "bar.go", + ], + deps = [ + "//tools", + "@org_golang_x_utils//stuff", + ], + importpath = "github.com/example/project/foo", + visibility = ["//visibility:public"], +) +``` + +### go_test + +To write an internal test, reference the library being tested with the `embed` +instead of `deps`. This will compile the test sources into the same package as the library +sources. + +#### Internal test example + +This builds a test that can use the internal interface of the package being tested. + +In the normal go toolchain this would be the kind of tests formed by adding writing +`_test.go` files in the same package. + +It references the library being tested with `embed`. + + +``` bzl +go_library( + name = "lib", + srcs = ["lib.go"], +) + +go_test( + name = "lib_test", + srcs = ["lib_test.go"], + embed = [":lib"], +) +``` + +#### External test example + +This builds a test that can only use the public interface(s) of the packages being tested. + +In the normal go toolchain this would be the kind of tests formed by adding an `_test` +package. + +It references the library(s) being tested with `deps`. + +``` bzl +go_library( + name = "lib", + srcs = ["lib.go"], +) + +go_test( + name = "lib_xtest", + srcs = ["lib_x_test.go"], + deps = [":lib"], +) +``` + diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/platform-specific_dependencies.md b/third_party/rgo/v0_62_0/base/docs/go/core/platform-specific_dependencies.md new file mode 100644 index 00000000..92957fa0 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/platform-specific_dependencies.md @@ -0,0 +1,53 @@ + [build constraints]: https://golang.org/pkg/go/build/#hdr-Build_Constraints + [select]: https://docs.bazel.build/versions/master/be/functions.html#select + [config_setting]: https://docs.bazel.build/versions/master/be/general.html#config_setting + [Gazelle]: https://github.com/bazelbuild/bazel-gazelle + + +## Platform-specific dependencies + +When cross-compiling, you may have some platform-specific sources and +dependencies. Source files from all platforms can be mixed freely in a single +`srcs` list. Source files are filtered using [build constraints] (filename +suffixes and `+build` tags) before being passed to the compiler. + +Platform-specific dependencies are another story. For example, if you are +building a binary for Linux, and it has dependency that should only be built +when targeting Windows, you will need to filter it out using Bazel [select] +expressions: + +``` bzl +go_binary( + name = "cmd", + srcs = [ + "foo_linux.go", + "foo_windows.go", + ], + deps = [ + # platform agnostic dependencies + "//bar", + ] + select({ + # OS-specific dependencies + "@io_bazel_rules_go//go/platform:linux": [ + "//baz_linux", + ], + "@io_bazel_rules_go//go/platform:windows": [ + "//quux_windows", + ], + "//conditions:default": [], + }), +) +``` + +`select` accepts a dictionary argument. The keys are labels that reference [config_setting] rules. +The values are lists of labels. Exactly one of these +lists will be selected, depending on the target configuration. rules_go has +pre-declared `config_setting` rules for each OS, architecture, and +OS-architecture pair. For a full list, run this command: + +``` bash +$ bazel query 'kind(config_setting, @io_bazel_rules_go//go/platform:all)' +``` + +[Gazelle] will generate dependencies in this format automatically. + diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/rules.bzl b/third_party/rgo/v0_62_0/base/docs/go/core/rules.bzl new file mode 100644 index 00000000..8fdb90e2 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/rules.bzl @@ -0,0 +1,130 @@ +""" + ["Make variable"]: https://docs.bazel.build/versions/master/be/make-variables.html + [Bourne shell tokenization]: https://docs.bazel.build/versions/master/be/common-definitions.html#sh-tokenization + [Gazelle]: https://github.com/bazelbuild/bazel-gazelle + [GoArchive]: /go/providers.rst#GoArchive + [GoPath]: /go/providers.rst#GoPath + [GoInfo]: /go/providers.rst#GoInfo + [build constraints]: https://golang.org/pkg/go/build/#hdr-Build_Constraints + [cc_library deps]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_library.deps + [cgo]: http://golang.org/cmd/cgo/ + [config_setting]: https://docs.bazel.build/versions/master/be/general.html#config_setting + [data dependencies]: https://bazel.build/concepts/dependencies#data-dependencies + [goarch]: /go/modes.rst#goarch + [goos]: /go/modes.rst#goos + [mode attributes]: /go/modes.rst#mode-attributes + [nogo]: /go/nogo.rst#nogo + [pure]: /go/modes.rst#pure + [race]: /go/modes.rst#race + [msan]: /go/modes.rst#msan + [select]: https://docs.bazel.build/versions/master/be/functions.html#select + [shard_count]: https://docs.bazel.build/versions/master/be/common-definitions.html#test.shard_count + [static]: /go/modes.rst#static + [test_arg]: https://docs.bazel.build/versions/master/user-manual.html#flag--test_arg + [test_filter]: https://docs.bazel.build/versions/master/user-manual.html#flag--test_filter + [test_env]: https://docs.bazel.build/versions/master/user-manual.html#flag--test_env + [test_runner_fail_fast]: https://docs.bazel.build/versions/master/command-line-reference.html#flag--test_runner_fail_fast + [define and register a C/C++ toolchain and platforms]: https://bazel.build/extending/toolchains#toolchain-definitions + [bazel]: https://pkg.go.dev/github.com/bazelbuild/rules_go/go/tools/bazel?tab=doc + [go_library]: #go_library + [go_binary]: #go_binary + [go_test]: #go_test + [go_path]: #go_path + [go_source]: #go_source + [go_test]: #go_test + [go_reset_target]: #go_reset_target + [Examples]: examples.md#examples + [Defines and stamping]: defines_and_stamping.md#defines-and-stamping + [Stamping with the workspace status script]: defines_and_stamping.md#stamping-with-the-workspace-status-script + [Embedding]: embedding.md#embedding + [Cross compilation]: cross_compilation.md#cross-compilation + [Platform-specific dependencies]: platform-specific_dependencies.md#platform-specific-dependencies + +# Core Go rules + +These are the core go rules, required for basic operation. The intent is that these rules are +sufficient to match the capabilities of the normal go tools. + +## Additional resources +- ["Make variable"] +- [Bourne shell tokenization] +- [Gazelle] +- [GoArchive] +- [GoPath] +- [GoInfo] +- [build constraints]: +- [cc_library deps] +- [cgo] +- [config_setting] +- [data dependencies] +- [goarch] +- [goos] +- [mode attributes] +- [nogo] +- [pure] +- [race] +- [msan] +- [select]: +- [shard_count] +- [static] +- [test_arg] +- [test_filter] +- [test_env] +- [test_runner_fail_fast] +- [define and register a C/C++ toolchain and platforms] +- [bazel] + + +------------------------------------------------------------------------ + +Introduction +------------ + +Three core rules may be used to build most projects: [go_library], [go_binary], +and [go_test]. These rules reimplement the low level plumping commands of a normal +'go build' invocation: compiling package's source files to archives, then linking +archives into go binary. + +[go_library] builds a single package. It has a list of source files +(specified with `srcs`) and may depend on other packages (with `deps`). +Each [go_library] has an `importpath`, which is the name used to import it +in Go source files. + +[go_binary] also builds a single `main` package and links it into an +executable. It may embed the content of a [go_library] using the `embed` +attribute. Embedded sources are compiled together in the same package. +Binaries can be built for alternative platforms and configurations by setting +`goos`, `goarch`, and other attributes. + +[go_test] builds a test executable. Like tests produced by `go test`, this +consists of three packages: an internal test package compiled together with +the library being tested (specified with `embed`), an external test package +compiled separately, and a generated test main package. + +Here is an example of a Bazel build graph for a project using these core rules: + +![](./buildgraph.svg) + +By instrumenting the lower level go tooling, we can cache smaller, finer +artifacts with Bazel and thus, speed up incremental builds. + +Rules +----- + +""" + +load("//go/private/rules:binary.bzl", _go_binary = "go_binary") +load("//go/private/rules:cross.bzl", _go_cross_binary = "go_cross_binary") +load("//go/private/rules:library.bzl", _go_library = "go_library") +load("//go/private/rules:source.bzl", _go_source = "go_source") +load("//go/private/rules:test.bzl", _go_test = "go_test") +load("//go/private/rules:transition.bzl", _go_reset_target = "go_reset_target") +load("//go/private/tools:path.bzl", _go_path = "go_path") + +go_library = _go_library +go_binary = _go_binary +go_test = _go_test +go_source = _go_source +go_path = _go_path +go_cross_binary = _go_cross_binary +go_reset_target = _go_reset_target diff --git a/third_party/rgo/v0_62_0/base/docs/go/core/rules.md b/third_party/rgo/v0_62_0/base/docs/go/core/rules.md new file mode 100644 index 00000000..50d98025 --- /dev/null +++ b/third_party/rgo/v0_62_0/base/docs/go/core/rules.md @@ -0,0 +1,422 @@ + + + ["Make variable"]: https://docs.bazel.build/versions/master/be/make-variables.html + [Bourne shell tokenization]: https://docs.bazel.build/versions/master/be/common-definitions.html#sh-tokenization + [Gazelle]: https://github.com/bazelbuild/bazel-gazelle + [GoArchive]: /go/providers.rst#GoArchive + [GoPath]: /go/providers.rst#GoPath + [GoInfo]: /go/providers.rst#GoInfo + [build constraints]: https://golang.org/pkg/go/build/#hdr-Build_Constraints + [cc_library deps]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_library.deps + [cgo]: http://golang.org/cmd/cgo/ + [config_setting]: https://docs.bazel.build/versions/master/be/general.html#config_setting + [data dependencies]: https://bazel.build/concepts/dependencies#data-dependencies + [goarch]: /go/modes.rst#goarch + [goos]: /go/modes.rst#goos + [mode attributes]: /go/modes.rst#mode-attributes + [nogo]: /go/nogo.rst#nogo + [pure]: /go/modes.rst#pure + [race]: /go/modes.rst#race + [msan]: /go/modes.rst#msan + [select]: https://docs.bazel.build/versions/master/be/functions.html#select + [shard_count]: https://docs.bazel.build/versions/master/be/common-definitions.html#test.shard_count + [static]: /go/modes.rst#static + [test_arg]: https://docs.bazel.build/versions/master/user-manual.html#flag--test_arg + [test_filter]: https://docs.bazel.build/versions/master/user-manual.html#flag--test_filter + [test_env]: https://docs.bazel.build/versions/master/user-manual.html#flag--test_env + [test_runner_fail_fast]: https://docs.bazel.build/versions/master/command-line-reference.html#flag--test_runner_fail_fast + [define and register a C/C++ toolchain and platforms]: https://bazel.build/extending/toolchains#toolchain-definitions + [bazel]: https://pkg.go.dev/github.com/bazelbuild/rules_go/go/tools/bazel?tab=doc + [go_library]: #go_library + [go_binary]: #go_binary + [go_test]: #go_test + [go_path]: #go_path + [go_source]: #go_source + [go_test]: #go_test + [go_reset_target]: #go_reset_target + [Examples]: examples.md#examples + [Defines and stamping]: defines_and_stamping.md#defines-and-stamping + [Stamping with the workspace status script]: defines_and_stamping.md#stamping-with-the-workspace-status-script + [Embedding]: embedding.md#embedding + [Cross compilation]: cross_compilation.md#cross-compilation + [Platform-specific dependencies]: platform-specific_dependencies.md#platform-specific-dependencies + +# Core Go rules + +These are the core go rules, required for basic operation. The intent is that these rules are +sufficient to match the capabilities of the normal go tools. + +## Additional resources +- ["Make variable"] +- [Bourne shell tokenization] +- [Gazelle] +- [GoArchive] +- [GoPath] +- [GoInfo] +- [build constraints]: +- [cc_library deps] +- [cgo] +- [config_setting] +- [data dependencies] +- [goarch] +- [goos] +- [mode attributes] +- [nogo] +- [pure] +- [race] +- [msan] +- [select]: +- [shard_count] +- [static] +- [test_arg] +- [test_filter] +- [test_env] +- [test_runner_fail_fast] +- [define and register a C/C++ toolchain and platforms] +- [bazel] + + +------------------------------------------------------------------------ + +Introduction +------------ + +Three core rules may be used to build most projects: [go_library], [go_binary], +and [go_test]. These rules reimplement the low level plumping commands of a normal +'go build' invocation: compiling package's source files to archives, then linking +archives into go binary. + +[go_library] builds a single package. It has a list of source files +(specified with `srcs`) and may depend on other packages (with `deps`). +Each [go_library] has an `importpath`, which is the name used to import it +in Go source files. + +[go_binary] also builds a single `main` package and links it into an +executable. It may embed the content of a [go_library] using the `embed` +attribute. Embedded sources are compiled together in the same package. +Binaries can be built for alternative platforms and configurations by setting +`goos`, `goarch`, and other attributes. + +[go_test] builds a test executable. Like tests produced by `go test`, this +consists of three packages: an internal test package compiled together with +the library being tested (specified with `embed`), an external test package +compiled separately, and a generated test main package. + +Here is an example of a Bazel build graph for a project using these core rules: + +![](./buildgraph.svg) + +By instrumenting the lower level go tooling, we can cache smaller, finer +artifacts with Bazel and thus, speed up incremental builds. + +Rules +----- + + + +## go_binary + +
+load("@rules_go//docs/go/core:rules.bzl", "go_binary")
+
+go_binary(name, deps, srcs, data, out, basename, cdeps, cgo, clinkopts, copts, cppopts, cxxopts,
+          embed, embedsrcs, env, gc_goopts, gc_linkopts, goarch, goos, gotags, importpath, linkmode,
+          msan, pgoprofile, pure, race, static, x_defs)
+
+ +This builds an executable from a set of source files, +which must all be in the `main` package. You can run the binary with +`bazel run`, or you can build it with `bazel build` and run it directly. + +***Note:*** `name` should be the same as the desired name of the generated binary. + +**Providers:** +- [GoArchive] + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | List of Go libraries this package imports directly. These may be `go_library` rules or compatible rules with the [GoInfo] provider. | List of labels | optional | `[]` | +| srcs | The list of Go source files that are compiled to create the package. Only `.go`, `.s`, and `.syso` files are permitted, unless the `cgo` attribute is set, in which case, `.c .cc .cpp .cxx .h .hh .hpp .hxx .inc .m .mm` files are also permitted. Files may be filtered at build time using Go [build constraints]. | List of labels | optional | `[]` | +| data | List of files needed by this rule at run-time. This may include data files needed or other programs that may be executed. The [bazel] package may be used to locate run files; they may appear in different places depending on the operating system and environment. See [data dependencies] for more information on data files. | List of labels | optional | `[]` | +| out | Sets the output filename for the generated executable. When set, `go_binary` will write this file without mode-specific directory prefixes, without linkmode-specific prefixes like "lib", and without platform-specific suffixes like ".exe". Note that without a mode-specific directory prefix, the output file (but not its dependencies) will be invalidated in Bazel's cache when changing configurations. | String | optional | `""` | +| basename | The basename of this binary. The binary basename may also be platform-dependent: on Windows, we add an .exe extension. | String | optional | `""` | +| cdeps | The list of other libraries that the c code depends on. This can be anything that would be allowed in [cc_library deps] Only valid if `cgo` = `True`. | List of labels | optional | `[]` | +| cgo | If `True`, the package may contain [cgo] code, and `srcs` may contain C, C++, Objective-C, and Objective-C++ files and non-Go assembly files. When cgo is enabled, these files will be compiled with the C/C++ toolchain and included in the package. Note that this attribute does not force cgo to be enabled. Cgo is enabled for non-cross-compiling builds when a C/C++ toolchain is configured. | Boolean | optional | `False` | +| clinkopts | List of flags to add to the C link command. Subject to ["Make variable"] substitution and [Bourne shell tokenization]. Only valid if `cgo` = `True`. | List of strings | optional | `[]` | +| copts | List of flags to add to the C compilation command. Subject to ["Make variable"] substitution and [Bourne shell tokenization]. Only valid if `cgo` = `True`. | List of strings | optional | `[]` | +| cppopts | List of flags to add to the C/C++ preprocessor command. Subject to ["Make variable"] substitution and [Bourne shell tokenization]. Only valid if `cgo` = `True`. | List of strings | optional | `[]` | +| cxxopts | List of flags to add to the C++ compilation command. Subject to ["Make variable"] substitution and [Bourne shell tokenization]. Only valid if `cgo` = `True`. | List of strings | optional | `[]` | +| embed | List of Go libraries whose sources should be compiled together with this binary's sources. Labels listed here must name `go_library`, `go_proto_library`, or other compatible targets with the [GoInfo] provider. Embedded libraries must all have the same `importpath`, which must match the `importpath` for this `go_binary` if one is specified. At most one embedded library may have `cgo = True`, and the embedding binary may not also have `cgo = True`. See [Embedding] for more information. | List of labels | optional | `[]` | +| embedsrcs | The list of files that may be embedded into the compiled package using `//go:embed` directives. All files must be in the same logical directory or a subdirectory as source files. All source files containing `//go:embed` directives must be in the same logical directory. It's okay to mix static and generated source files and static and generated embeddable files. | List of labels | optional | `[]` | +| env | Environment variables to set when the binary is executed with bazel run. The values (but not keys) are subject to [location expansion](https://docs.bazel.build/versions/main/skylark/macros.html) but not full [make variable expansion](https://docs.bazel.build/versions/main/be/make-variables.html). | Dictionary: String -> String | optional | `{}` | +| gc_goopts | List of flags to add to the Go compilation command when using the gc compiler. Subject to ["Make variable"] substitution and [Bourne shell tokenization]. | List of strings | optional | `[]` | +| gc_linkopts | List of flags to add to the Go link command when using the gc compiler. Subject to ["Make variable"] substitution and [Bourne shell tokenization]. | List of strings | optional | `[]` | +| goarch | Forces a binary to be cross-compiled for a specific architecture. It's usually better to control this on the command line with `--platforms`.

This disables cgo by default, since a cross-compiling C/C++ toolchain is rarely available. To force cgo, set `pure` = `off`.

See [Cross compilation] for more information. | String | optional | `"auto"` | +| goos | Forces a binary to be cross-compiled for a specific operating system. It's usually better to control this on the command line with `--platforms`.

This disables cgo by default, since a cross-compiling C/C++ toolchain is rarely available. To force cgo, set `pure` = `off`.

See [Cross compilation] for more information. | String | optional | `"auto"` | +| gotags | Enables a list of build tags when evaluating [build constraints]. Useful for conditional compilation. | List of strings | optional | `[]` | +| importpath | The import path of this binary. Binaries can't actually be imported, but this may be used by [go_path] and other tools to report the location of source files. This may be inferred from embedded libraries. | String | optional | `""` | +| linkmode | Determines how the binary should be built and linked. This accepts some of the same values as `go build -buildmode` and works the same way.

  • `auto` (default): Controlled by `//go/config:linkmode`, which defaults to `pie` on supported platforms and `normal` elsewhere.
  • `normal`: Builds a normal executable with position-dependent code.
  • `pie`: Builds a position-independent executable.
  • `plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.
  • `c-shared`: Builds a shared library that can be linked into a C program.
  • `c-archive`: Builds an archive that can be linked into a C program.
| String | optional | `"auto"` | +| msan | Controls whether code is instrumented for memory sanitization. May be one of `on`, `off`, or `auto`. Not available when cgo is disabled. In most cases, it's better to control this on the command line with `--@io_bazel_rules_go//go/config:msan`. See [mode attributes], specifically [msan]. | String | optional | `"auto"` | +| pgoprofile | Provides a pprof file to be used for profile guided optimization when compiling go targets. A pprof file can also be provided via `--@io_bazel_rules_go//go/config:pgoprofile=