-
Notifications
You must be signed in to change notification settings - Fork 36
fix: stop xcodebuild collecting a sysdiagnose the user did not ask for #281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
lpusok
merged 18 commits into
bitrise-steplib:master
from
pgyula:fix/xcode26-collect-test-diagnostics
Sep 22, 2026
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
f860582
fix: stop xcodebuild collecting a sysdiagnose the user did not ask for
pgyula 6b3b738
Merge branch 'master' into fix/xcode26-collect-test-diagnostics
pgyula dd24e56
comments cleanup
lpusok dec8d33
Do not treat -collect-test-diagnostics=value as a user override
lpusok c64a7bd
Skip the Step's own Simulator diagnostics collection on Xcode 26 and …
lpusok a666d27
Document that always equals on_failure on Xcode 26 and later
lpusok 0355622
Add project_setting to collect_simulator_diagnostics
lpusok 2442790
Inline the -collect-test-diagnostics option name
lpusok 4b4f765
Migrate to the shared steps-check workflow
lpusok c2a4eaa
Keep the top-level error messages capitalised
lpusok f3085ed
Pass formatted errors to the logger as arguments
lpusok 79d17bd
Compact the collectTestDiagnosticsValue doc comment
lpusok 43a6536
Name the diagnostics helpers after who collects
lpusok b6e7dfb
Replace the xcodebuildDiagnosticsOverride doc comment with inline notes
lpusok 7895290
Replace the shouldStepCollectDiagnostics doc comment with an inline note
lpusok 1bd9be2
Only mention xcodebuild's diagnostics collection where it exists
lpusok 82be39b
Name the xcodebuild-collects decision in teardown
lpusok 3f68c64
Merge branch 'master' into fix/xcode26-collect-test-diagnostics
lpusok File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| package step | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func Test_xcodebuildDiagnosticsOverride(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| condition exportCondition | ||
| xcodeMajorVersion int64 | ||
| additionalOptions []string | ||
| want string | ||
| }{ | ||
| { | ||
| name: "Xcode 26, never - suppresses xcodebuild's own collection", | ||
| condition: never, | ||
| xcodeMajorVersion: 26, | ||
| want: "never", | ||
| }, | ||
| { | ||
| name: "Xcode 27, never - suppresses xcodebuild's own collection", | ||
| condition: never, | ||
| xcodeMajorVersion: 27, | ||
| want: "never", | ||
| }, | ||
| { | ||
| name: "Xcode 27, on_failure - keeps xcodebuild's collection", | ||
| condition: onFailure, | ||
| xcodeMajorVersion: 27, | ||
| want: "on-failure", | ||
| }, | ||
| { | ||
| // xcodebuild has no "always"; its collection is failure-triggered regardless. | ||
| name: "Xcode 27, always - maps onto on-failure", | ||
| condition: always, | ||
| xcodeMajorVersion: 27, | ||
| want: "on-failure", | ||
| }, | ||
| { | ||
| // project_setting leaves the decision to the test plan, so nothing is passed. | ||
| name: "Xcode 27, project_setting - option not passed", | ||
| condition: projectSetting, | ||
| xcodeMajorVersion: 27, | ||
| want: "", | ||
| }, | ||
| { | ||
| // The option does not exist before Xcode 26; passing it would be a usage error. | ||
| name: "Xcode 25, never - option not passed", | ||
| condition: never, | ||
| xcodeMajorVersion: 25, | ||
| want: "", | ||
| }, | ||
| { | ||
| name: "Xcode 15, always - option not passed", | ||
| condition: always, | ||
| xcodeMajorVersion: 15, | ||
| want: "", | ||
| }, | ||
| { | ||
| // main.go treats an unreadable Xcode version as non-fatal and leaves Major at 0. | ||
| name: "unknown Xcode version - option not passed", | ||
| condition: never, | ||
| xcodeMajorVersion: 0, | ||
| want: "", | ||
| }, | ||
| { | ||
| name: "user set the option explicitly - theirs wins", | ||
| condition: never, | ||
| xcodeMajorVersion: 27, | ||
| additionalOptions: []string{"-collect-test-diagnostics", "on-failure"}, | ||
| want: "", | ||
| }, | ||
| { | ||
| // xcodebuild silently drops the -option=value form, so it must not count as an override. | ||
| name: "user wrote the option with = syntax - Step still passes its own", | ||
| condition: never, | ||
| xcodeMajorVersion: 27, | ||
| additionalOptions: []string{"-collect-test-diagnostics=on-failure"}, | ||
| want: "never", | ||
| }, | ||
| { | ||
| name: "unrelated additional options are ignored", | ||
| condition: never, | ||
| xcodeMajorVersion: 27, | ||
| additionalOptions: []string{"-quiet", "-parallel-testing-enabled", "NO"}, | ||
| want: "never", | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got := xcodebuildDiagnosticsOverride(tt.condition, tt.xcodeMajorVersion, tt.additionalOptions) | ||
| require.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func Test_shouldStepCollectDiagnostics(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| condition exportCondition | ||
| testFailed bool | ||
| xcodeMajorVersion int64 | ||
| want bool | ||
| }{ | ||
| {name: "Xcode 16, always, passed", condition: always, testFailed: false, xcodeMajorVersion: 16, want: true}, | ||
| {name: "Xcode 16, always, failed", condition: always, testFailed: true, xcodeMajorVersion: 16, want: true}, | ||
| {name: "Xcode 16, on_failure, passed", condition: onFailure, testFailed: false, xcodeMajorVersion: 16, want: false}, | ||
| {name: "Xcode 16, on_failure, failed", condition: onFailure, testFailed: true, xcodeMajorVersion: 16, want: true}, | ||
| {name: "Xcode 16, never, failed", condition: never, testFailed: true, xcodeMajorVersion: 16, want: false}, | ||
| // project_setting has nothing to follow before Xcode 26, the Step does not collect on its own. | ||
| {name: "Xcode 16, project_setting, failed", condition: projectSetting, testFailed: true, xcodeMajorVersion: 16, want: false}, | ||
| {name: "Xcode 27, project_setting, failed", condition: projectSetting, testFailed: true, xcodeMajorVersion: 27, want: false}, | ||
| // main.go leaves the major at 0 when the Xcode version cannot be read; keep collecting there. | ||
| {name: "unknown Xcode, on_failure, failed", condition: onFailure, testFailed: true, xcodeMajorVersion: 0, want: true}, | ||
| // Since Xcode 26 xcodebuild collects into the xcresult itself; the Step must not collect a second copy. | ||
| {name: "Xcode 26, on_failure, failed", condition: onFailure, testFailed: true, xcodeMajorVersion: 26, want: false}, | ||
| {name: "Xcode 27, always, failed", condition: always, testFailed: true, xcodeMajorVersion: 27, want: false}, | ||
| {name: "Xcode 27, always, passed", condition: always, testFailed: false, xcodeMajorVersion: 27, want: false}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got := shouldStepCollectDiagnostics(tt.condition, tt.testFailed, tt.xcodeMajorVersion) | ||
| require.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func Test_xcodebuildCollectsDiagnostics(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| condition exportCondition | ||
| testFailed bool | ||
| xcodeMajorVersion int64 | ||
| want bool | ||
| }{ | ||
| {name: "Xcode 27, on_failure, failed", condition: onFailure, testFailed: true, xcodeMajorVersion: 27, want: true}, | ||
| {name: "Xcode 27, always, failed", condition: always, testFailed: true, xcodeMajorVersion: 27, want: true}, | ||
| {name: "Xcode 27, project_setting, failed", condition: projectSetting, testFailed: true, xcodeMajorVersion: 27, want: true}, | ||
| {name: "Xcode 27, never, failed", condition: never, testFailed: true, xcodeMajorVersion: 27, want: false}, | ||
| {name: "Xcode 27, on_failure, passed", condition: onFailure, testFailed: false, xcodeMajorVersion: 27, want: false}, | ||
| // xcodebuild has no collection of its own before Xcode 26. | ||
| {name: "Xcode 16, on_failure, failed", condition: onFailure, testFailed: true, xcodeMajorVersion: 16, want: false}, | ||
| {name: "Xcode 16, project_setting, failed", condition: projectSetting, testFailed: true, xcodeMajorVersion: 16, want: false}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got := xcodebuildCollectsDiagnostics(tt.condition, tt.testFailed, tt.xcodeMajorVersion) | ||
| require.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rewrite this description so that the default and simple description explains the new (Xcode 26+) behavior, and the older behavior is explained as an exception. We'll phase out those older Xcodes in a few years and will be left with only the new behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rephrased once more