Skip to content

Contain xcodebuild's derived data in the test's temp dir - #3050

Merged
keith merged 1 commit into
bazelbuild:mainfrom
erneestoc:derived-data-tmpdir
Aug 21, 2026
Merged

Contain xcodebuild's derived data in the test's temp dir#3050
keith merged 1 commit into
bazelbuild:mainfrom
erneestoc:derived-data-tmpdir

Conversation

@erneestoc

@erneestoc erneestoc commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Every xcodebuild test-without-building invocation creates a ~/Library/Developer/Xcode/DerivedData/temporary-<hash>/ directory that nothing ever deletes. When the runner does not pass -resultBundlePath — i.e. any xcodebuild-path run without create_xcresult_bundle — that directory receives a full .xcresult of the run; and passing -resultBundlePath alone does not fix it, a bookkeeping directory still leaks per run.

One development machine had accumulated 267 of these directories totaling 26GB. Every CI agent running simulator tests through the xcodebuild path leaks one per test run, silently.

Fix: pass -derivedDataPath pointed into the runner's test_tmp_dir, which the existing EXIT trap already deletes. An explicit -resultBundlePath (from create_xcresult_bundle or xcodebuild_args) still wins for the result bundle itself.

Measurements

New DerivedData temporary-* directories created per invocation (Xcode 26.2, iOS 26.2 simulator, hosted unit test):

xcodebuild flags new dirs per run contents
(none — today's runner without create_xcresult_bundle) 1 152K, including a complete orphan .xcresult
-resultBundlePath only 1 24K bookkeeping
-derivedDataPath (this PR) 0
both 0

End-to-end through the runner after this change: default mode, dir count unchanged across runs (was +1 per run); with create_xcresult_bundle = True, the bundle still lands in TEST_UNDECLARED_OUTPUTS_DIR (verified present in outputs.zip) and DerivedData stays untouched.

Steps to reproduce the leak

ls -d ~/Library/Developer/Xcode/DerivedData/temporary-* | wc -l
# run any hosted test through ios_xctestrun_runner without create_xcresult_bundle,
# e.g. a unit test with a test_host (forces the xcodebuild path):
bazel test //your:HostedTest --runner=@rules_apple//apple/testing/default_runner:ios_xctestrun_ordered_runner --nocache_test_results
ls -d ~/Library/Developer/Xcode/DerivedData/temporary-* | wc -l   # +1, forever

Test plan

  • Manual xcodebuild test-without-building flag matrix above (each variant run against the same xctestrun).
  • Runner end-to-end: default mode creates no DerivedData directories; CREATE_XCRESULT_BUNDLE=1 still produces tests.xcresult in undeclared outputs with DerivedData untouched.
  • Rendered template passes bash -n.

Every `xcodebuild test-without-building` invocation creates a
~/Library/Developer/Xcode/DerivedData/temporary-<hash>/ directory that
nothing ever deletes. When the runner does not pass -resultBundlePath
(any xcodebuild-path run without create_xcresult_bundle), that directory
receives a full .xcresult of the run; passing -resultBundlePath alone
does not fix it - a bookkeeping directory still leaks per run. One
development machine had accumulated 267 of these totaling 26GB; CI
agents leak one per simulator test run, silently.

Pass -derivedDataPath pointed into the runner's test_tmp_dir, which the
existing EXIT trap already deletes. Measured per invocation, new
DerivedData directories: no flags -> 1 (152K incl. the orphan xcresult);
-resultBundlePath alone -> 1 (24K bookkeeping); -derivedDataPath -> 0.

An explicit -resultBundlePath (create_xcresult_bundle or xcodebuild_args)
still wins for the result bundle itself: verified that with
create_xcresult_bundle the bundle still lands in
TEST_UNDECLARED_OUTPUTS_DIR while DerivedData stays untouched.
@keith
keith enabled auto-merge (squash) August 21, 2026 00:36
@erneestoc

Copy link
Copy Markdown
Contributor Author

The CI failures here are the pre-existing wedged-simulator flake, not this change:

  • The failing set (HelloWorldSwiftUITests, ButtonsUITests, ios_coverage_ui_test_coverage_new_runner) is the same session-sensitive group that has been failing on other PRs whose runner-test caches get invalidated (Give each concurrent test action its own simulator via a per-(device, OS) pool #3026 has the full diagnosis: a previously-terminated test leaves the reused, still-booted simulator with a dead device-side session, and every later xcodebuild test-without-building against it hangs or fails to initialize).
  • The attempt log shows the signature exactly: reused booted BAZEL_TEST_iPhone 16_26.0, a well-formed invocation with -derivedDataPath, then silence until the timeout SIGTERM.
  • 1163 tests passed on the same run — including the hosted unit tests, which exercise -derivedDataPath on every invocation.
  • All three failing targets pass locally on this branch (9.8s / 11.6s / 5.3s).

#3026 adds the recovery machinery for this (its own CI is now fully green, including the previously-failing 9.x job, because its first run self-heals a wedged agent). Suggest retrying this build after #3026 lands — no change needed here.

@adincebic adincebic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good.

@keith
keith merged commit a881caf into bazelbuild:main Aug 21, 2026
9 checks passed
@erneestoc
erneestoc deleted the derived-data-tmpdir branch August 21, 2026 06:43
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.

3 participants