Skip to content

fix: recognize every terminal xcodebuild phase marker - #86

Merged
alexey1312 merged 2 commits into
masterfrom
fix/terminal-phase-markers
Aug 19, 2026
Merged

fix: recognize every terminal xcodebuild phase marker#86
alexey1312 merged 2 commits into
masterfrom
fix/terminal-phase-markers

Conversation

@alexey1312

Copy link
Copy Markdown
Collaborator

Fixes #85.

Problem

xcodebuild ends every operation with ** <PHASE> SUCCEEDED ** or ** <PHASE> FAILED **, but the parser matched a fixed list of literals: BUILD, TEST, TEST EXECUTE. Archive and export runs therefore ended without positive terminal evidence and reported status: "incomplete" with a truncation hint after a successful run.

The issue names two markers; the same shape gap broke three code paths:

Input before after
** ARCHIVE SUCCEEDED ** incomplete success
** EXPORT SUCCEEDED ** incomplete success
** CLEAN SUCCEEDED ** / ** ANALYZE SUCCEEDED ** incomplete success
** ARCHIVE FAILED ** / ** EXPORT FAILED ** incomplete failed
Archive Succeeded (xcbeautify) incomplete success
Test Execute Succeeded (xcbeautify) incomplete success
  1. parseBuildAndTestTime matched per-phase literals.
  2. The fast-path buckets held BUILD FAILED and TEST FAILED only, so ** ARCHIVE FAILED ** never reached the status parser at all.
  3. xcbeautify renders the whole family through one capture group — PhaseSuccessCaptureGroup rewrites ** <PHASE> SUCCEEDED ** to <Phase> Succeeded — but the xcbeautify path knew Build Succeeded and Test Succeeded only.

Change

Match the marker shape ( SUCCEEDED ** / FAILED **, and Succeeded for xcbeautify) instead of each phase name. The TEST FAILED branch moves first to keep its .testRunFailed event. New phases from future Xcode releases now work without a code change.

** BUILD INTERRUPTED ** stays incomplete — it is not a terminal outcome.

Verification

  • swift test — 440 tests, 0 failures.
  • New regression tests: five success markers and three failure markers in ParsingTests, archive/export/test-execute plus an ANSI-colored marker in XcbeautifyTests.
  • Manual check against real xcbeautify 3.2.1: printf '** ARCHIVE SUCCEEDED **\n' | xcbeautify | xcsift --xcbeautify reports success.
  • 2.7 MB build.txt fixture parses unchanged (0.37 s).

The colored-marker test guards a real trap: the terminal renderer emits \033[32;1mArchive Succeeded\033[0m, so the check must stay contains, not hasSuffix.

xcodebuild ends each operation with `** <PHASE> SUCCEEDED/FAILED **`, but
the parser matched only the BUILD and TEST literals. Archive and export
runs ended without positive evidence and reported `status: "incomplete"`
plus a truncation hint. Match the marker shape instead of each phase.

The same gap existed on two more paths:
- `** ARCHIVE FAILED **` never reached the status parser, because the
  fast-path buckets held `BUILD FAILED` and `TEST FAILED` only.
- xcbeautify rewrites the whole family to `<Phase> Succeeded`, but the
  xcbeautify path knew `Build Succeeded` and `Test Succeeded` only, so
  even `Test Execute Succeeded` was lost.

Fixes #85
The xcbeautify path set `sawSuccessMarker` for any line that contains
" Succeeded". xcbeautify rewrites `** <PHASE> SUCCEEDED **` to
"<Phase> Succeeded" and drops the `**` brackets, so a run-script line such
as "[Upload] Upload Succeeded" matched too. A killed build then reported
`success` instead of `incomplete`, which breaks the documented rule that
xcsift never reports a truncated run as `success`.

Match the known phase names instead. The list is verified against
xcbeautify 3.2.1 for the whole xcodebuild action set. The bare suffix stays
as a cheap gate in front of the phase test, so the cost per line does not
change.

Two more fixes in the same area:

- `** TEST EXECUTE FAILED **` now ends a test that is still in flight, as
  `** TEST FAILED **` already does.
- A terminal phase marker is authoritative again. Only `** TEST FAILED **`
  keeps the issue #52 escape hatch, because xcodebuild prints that one
  marker for a run that passes under `-skipMacroValidation`. An
  `** ARCHIVE FAILED **` no longer reports `success` after a passed test.
@alexey1312

Copy link
Copy Markdown
Collaborator Author

Self-review — one regression found and fixed in 82c086a

swift test: 444 tests, 0 failures. swift format lint: clean. The 2.8 MB fixture parses in 0.42 s against 0.48 s on master.

Fixed: the xcbeautify path accepted run-script output as a marker

sawSuccessMarker gated on a bare " Succeeded" substring. xcbeautify rewrites ** <PHASE> SUCCEEDED ** to <Phase> Succeeded and drops the ** brackets, so the phase name is the only thing that separates a marker from ordinary text:

$ printf 'Compiling MyApp\n[Upload] Upload Succeeded\nKilled: 9\n' | xcsift --xcbeautify
before: status: success      # a killed build reports green
after:  status: incomplete

This broke the rule in OutputFormats.md that xcsift never reports a truncated run as success, and it turns --exit-on-failure green on a dead CI job.

The fix matches the known phase names. I checked every xcodebuild action against xcbeautify 3.2.1 and listed all 15 rewrites, so Build For Testing Succeeded and Docbuild Succeeded work too. The bare suffix stays as a cheap gate in front of the phase test, so the cost per line does not change. The raw path keeps the generic SUCCEEDED ** suffix, because the ** brackets make it unambiguous.

Also fixed

  • ** TEST EXECUTE FAILED ** now ends a test that is still in flight, as ** TEST FAILED ** already does. The TEST FAILED branch matches a literal that TEST EXECUTE FAILED does not contain.
  • A terminal phase marker is authoritative again. ** ARCHIVE FAILED ** reported success after one passed test, because the issue Using xcodebuild's -skipMacroValidation gives unclear results #52 escape hatch applied to every marker. That hatch exists for ** TEST FAILED ** alone, which xcodebuild prints for a run that passes under -skipMacroValidation. sawFailureMarker now excludes ** TEST FAILED **, which arrives as .testRunFailed instead. The issue Using xcodebuild's -skipMacroValidation gives unclear results #52 test stays green.
  • The two status keywords in XcodebuildSymbols carry a comment: they route lines to the parser and are wider than the markers on purpose.

Withdrawn

I first read the missing xcbeautify failure marker as a gap. It is not. xcbeautify prints ** <PHASE> FAILED ** only when it collects errors, and then it passes the line through verbatim, so the raw path already reads it. A failure that xcbeautify cannot parse produces no marker at all, and incomplete is the honest answer.

Verification against issue #85

$ printf '** ARCHIVE SUCCEEDED **\n' | xcsift   ->  status: success
$ printf '** EXPORT SUCCEEDED **\n'  | xcsift   ->  status: success

No truncation hint on stderr. Both markers also pass end to end through real xcbeautify 3.2.1.

New tests

  • testScriptOutputContainingSucceededIsNotATerminalMarker — the regression above.
  • testEveryXcbeautifyPhaseSuccessMarker — all 15 rewrites, guards the list.
  • testFlushEmitsCrashForInFlightTestOnTestExecuteFailed
  • testArchiveFailedMarkerOutranksPassedTests

@alexey1312
alexey1312 merged commit 821f5b8 into master Aug 19, 2026
2 checks passed
@alexey1312
alexey1312 deleted the fix/terminal-phase-markers branch August 19, 2026 05:59
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.

ARCHIVE SUCCEEDED and EXPORT SUCCEEDED markers are reported as incomplete

1 participant