Skip to content

fix --binary-path for tracer source repo checkouts#6560

Draft
p-datadog wants to merge 2 commits intomainfrom
fix/binary-path-source-repos
Draft

fix --binary-path for tracer source repo checkouts#6560
p-datadog wants to merge 2 commits intomainfrom
fix/binary-path-source-repos

Conversation

@p-datadog
Copy link
Member

Summary

Right now, --binary-path works great for artifact-based tracers (Java jars, .NET tarballs, PHP packages) where the contents are flat files. But for libraries that support installing from a source repo checkout, it silently does the wrong thing — and that feels like it could be a real pain point for local development.

Here's what happens today if you try the natural invocation:

./build.sh ruby --binary-path ~/code/dd-trace-rb

build.sh runs cp -r ~/code/dd-trace-rb/* binaries/, spreading repo contents flat across binaries/. The Ruby install script checks for /binaries/dd-trace-rb (a named subdirectory), doesn't find it, and silently falls back to installing from rubygems.org instead of your local code. No warning, no error — just not testing what you think you're testing.

This affects 7 libraries that expect a named subdirectory inside binaries/:

Library Expected dir Silent fallback target
Ruby dd-trace-rb rubygems.org
Node.js dd-trace-js npm registry
Go dd-trace-go Go module proxy
Python dd-trace-py PyPI
Rust dd-trace-rs crates.io / GitHub
C++ dd-trace-cpp GitHub clone
C++ Kong dd-trace-cpp GitHub clone

What this PR does

  • Adds a get_expected_repo_dir() function that maps each library to its expected source repo directory name (e.g., rubydd-trace-rb)
  • When --binary-path is used and the basename of the path matches the expected repo dir, copies into binaries/<repo-dir>/ using rsync with symlink dereferencing (--copy-links) and .git exclusion — with a check that rsync is available
  • When the basename doesn't match but the library expects a repo dir, prints a warning to stderr so the silent fallback is no longer silent
  • When the basename doesn't match, preserves the existing flat cp -r behavior unchanged — so artifact-based workflows and staging directories keep working exactly as before

Why rsync for the source repo path?

Two reasons: symlink dereferencing and .git exclusion. Local repos often contain symlinks (git worktrees, bundler binstubs, monorepo package links) that would be broken inside the Docker container. And .git directories are large and unnecessary for the build.

This is the same approach that utils/scripts/watch.sh already uses for syncing local repos into binaries/.

How it works in practice

# These now all work as you'd expect:
./build.sh ruby   --binary-path ~/code/dd-trace-rb
./build.sh nodejs --binary-path ~/code/dd-trace-js
./build.sh golang --binary-path ~/code/dd-trace-go
./build.sh python --binary-path ~/code/dd-trace-py
./build.sh rust   --binary-path ~/code/dd-trace-rs

# Non-standard names get a warning instead of silent fallback:
./build.sh ruby --binary-path ~/code/dtr
# Warning: --binary-path basename 'dtr' does not match expected 'dd-trace-rb'.
#   Doing flat copy. If this is a source checkout, rename the directory to 'dd-trace-rb'.

# Existing artifact workflows are unchanged (no warning, plain cp -r):
./build.sh java   --binary-path ~/builds/java-artifacts   # flat jars
./build.sh dotnet --binary-path ~/builds/dotnet-output     # flat .so/.tar.gz

The documented workflow of cloning directly into binaries/ also continues to work — this just makes --binary-path do the right thing too.

Test plan

  • Verify --binary-path ~/code/dd-trace-rb correctly creates binaries/dd-trace-rb/ and installs from local source (Ruby)
  • Verify --binary-path ~/builds/java-artifacts still does flat copy for artifact-based tracers (Java)
  • Verify staging directory workflow still works: --binary-path /tmp/staging where staging contains dd-trace-rb/
  • Verify non-standard directory names produce a warning
  • Verify symlinks in source repos are dereferenced correctly
  • Verify .git directory is excluded from the copy

Generated with Claude Code

Unicorn Enterprises and others added 2 commits March 20, 2026 15:44
When --binary-path points directly at a tracer source repo (e.g.
~/code/dd-trace-rb), the flat copy `cp -r $BINARY_PATH/* ./` spreads
the repo contents across binaries/ instead of creating the named
subdirectory that install_ddtrace.sh expects (e.g. binaries/dd-trace-rb/).

This causes a silent fallback to installing from the public registry
(rubygems, npm, PyPI, Go proxy, crates.io, GitHub) instead of the
local source, with no warning.

The fix detects when the basename of BINARY_PATH matches the expected
repo directory name for the current library, and copies into the
correct subdirectory using rsync (with symlink dereferencing and .git
exclusion). When the basename does not match, the existing flat copy
behavior is preserved for artifact-based workflows and staging
directories.

Affected libraries: Ruby, Node.js, Go, Python, Rust, C++, C++ Kong.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add warning when --binary-path basename doesn't match expected repo
  dir for source-based tracers (e.g. ~/code/dtr instead of
  ~/code/dd-trace-rb). Surfaces the silent fallback issue.
- Add rsync availability check before using it.
- Revert cp -rL back to cp -r in the flat-copy path to avoid an
  undocumented behavior change for artifact-based workflows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Contributor

CODEOWNERS have been resolved as:

utils/build/build.sh                                                    @DataDog/system-tests-core

p-datadog pushed a commit to p-datadog/system-tests that referenced this pull request Mar 20, 2026
Reverts:
- 1f95bf3 selected test detection fixed
- 69e93c4 terminate self more efficiently
- 100a53d exit faster when nothing is collected
- 848db3c use rsync instead of cp
- 42f9453 use dtr

These are replaced by:
- DataDog#6558 (fail fast when no tests are selected)
- DataDog#6560 (fix --binary-path for source repos)
- DataDog#6561 (skip full wipe for --binary-path)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
p-datadog pushed a commit to p-datadog/system-tests that referenced this pull request Mar 20, 2026
* commit 'FETCH_HEAD':
  fix lint: collapse multi-line if to single line
  fail fast when no tests are selected after collection

* datadog/fix/binary-path-source-repos:
  address review feedback: warning, rsync check, preserve cp -r
  fix --binary-path for tracer source repo checkouts
@datadog-official
Copy link

datadog-official bot commented Mar 20, 2026

⚠️ Tests

Fix all issues with BitsAI or with Cursor

⚠️ Warnings

🧪 4 Tests failed

tests.integrations.test_dsm.Test_Dsm_Manual_Checkpoint_Inter_Process.test_dsm_manual_checkpoint_inter_process[spring-boot] from system_tests_suite (Datadog) (Fix with Cursor)
ValueError: Checkpoint has not been found, please have a look in logs

self = <tests.integrations.test_dsm.Test_Dsm_Manual_Checkpoint_Inter_Process object at 0x7f2bf534d640>

    def test_dsm_manual_checkpoint_inter_process(self):
        assert self.produce_threaded.status_code == 200
        assert self.produce_threaded.text == "ok"
        assert "dd-pathway-ctx-base64" in self.produce_threaded.headers
    
        assert self.consume_threaded.status_code == 200
...
tests.integrations.test_dsm.Test_Dsm_Manual_Checkpoint_Inter_Process.test_dsm_manual_checkpoint_inter_process[spring-boot] from system_tests_suite (Datadog) (Fix with Cursor)
ValueError: Checkpoint has not been found, please have a look in logs

self = <tests.integrations.test_dsm.Test_Dsm_Manual_Checkpoint_Inter_Process object at 0x7fbb348ec770>

    def test_dsm_manual_checkpoint_inter_process(self):
        assert self.produce_threaded.status_code == 200
        assert self.produce_threaded.text == "ok"
        assert "dd-pathway-ctx-base64" in self.produce_threaded.headers
    
        assert self.consume_threaded.status_code == 200
...
tests.parametric.test_dynamic_configuration.TestDynamicConfigV1.test_trace_sampling_rate_override_env[library_env0, parametric-golang] from system_tests_suite (Datadog) (Fix with Cursor)
AssertionError: No RemoteConfig apply status found, got requests []

self = <tests.parametric.test_dynamic_configuration.TestDynamicConfigV1 object at 0x7fd8034e3890>
library_env = {'DD_ENV': 'test_env', 'DD_INTERNAL_TELEMETRY_V2_ENABLED': '1', 'DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS': '0.2', 'DD_SERVICE': 'test_service', ...}
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7fd7ceb30230>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7fd7ce8e0290>

    @parametrize(
        "library_env",
        [{"DD_TRACE_SAMPLE_RATE": r, **DEFAULT_ENVVARS} for r in ["0.1", "1.0"]],
...
tests.parametric.test_library_tracestats.Test_Library_Tracestats.test_distinct_aggregationkeys_TS003[agent_env0-library_env0, parametric-golang] from system_tests_suite (Datadog) (Fix with Cursor)
AssertionError: There should be one bucket containing the stats
assert 2 == 1
 +  where 2 = len([{'Duration': 10000000000, 'Start': 1774038100000000000, 'Stats': [{'Duration': 2935247, 'ErrorSummary': store: {}}, m...key:0, offset:0, zero_count: 0.0, count: 0.0, sum: 0.0, min: inf, max: -inf, 'Errors': 0, 'GRPCStatusCode': '', ...}]}])

self = <tests.parametric.test_library_tracestats.Test_Library_Tracestats object at 0x7f31cab9e6f0>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7f3195f42030>
test_library = <utils.docker_fixtures._test_clients._test_client_parametric.ParametricTestClientApi object at 0x7f3195c3b320>

    @enable_tracestats()
    @enable_agent_version()
...
View all

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: e27c0fb | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback!

p-datadog pushed a commit to p-datadog/system-tests-runner that referenced this pull request Mar 20, 2026
…ource

Removes the manual rsync of ~/apps/dtr into binaries/dd-trace-rb and
delegates to build.sh --binary-path, which handles source repo syncing
via rsync with --delete and --copy-links (DataDog/system-tests#6560,
#6561).

--ruby-dev is kept as a shorthand for --binary-path ~/dd-trace-rb.
--binary-path is now exposed directly for other languages and non-standard
paths.

NOTE: build.sh detects source repos by directory basename, so the path
passed to --binary-path must be named 'dd-trace-rb' for Ruby (similarly
for other languages). A differently-named checkout will trigger a warning
and fall back to flat copy, silently installing from rubygems.org instead.
Rename or symlink your checkout accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant