The Tuist GitHub App posts a “🛠️ Tuist Run Report” (tests, builds, …) as a pull request comment, gated on git_ref starting with refs/pull/. GitHub merge queue runs use refs like gh-readonly-queue/main/pr-123-<sha>, which never match, so those runs get no report and teams have to maintain their own JUnit reporting. This PR surfaces the report in the GitHub Actions job summary ($GITHUB_STEP_SUMMARY) so it shows up inline on the run, regardless of how the workflow was triggered.
What it looks like

What changed
The CLI renders the summary locally from data it already has and appends it to $GITHUB_STEP_SUMMARY when running in GitHub Actions:
- The test command derives per-scheme counts and failed-test names from
parseTestStatuses (the lightweight xcresult status read already used for quarantine/retry); the build command captures scheme / outcome / duration around the xcodebuild invocation. Both are stashed on RunMetadataStorage as RunReportTestRun / RunReportBuildRun.
GitHubActionsJobSummaryService renders Tests, Failed Tests, and Builds tables plus a link to the dashboard run, and appends them to the job summary. It’s best-effort and never fails the command it reports on.
Why CLI-rendered, not server-rendered
The first iteration fetched a server-rendered report from a new endpoint. That can’t work in the hosted setup: tuist test/build upload the raw result bundle / activity log with status processing, and the server materializes the results asynchronously (the xcresult / activity-log processors). At command end the data isn’t queryable yet, and — unlike the pull request comment, which those processors re-render when they finish — the job summary is written once by the CLI and can’t converge afterward. Rendering from a lightweight local parse (already on the hot path) is immediate and reliable. Server-only insights such as flaky tests and bundle-size deltas stay in the PR comment / dashboard, which the summary links to.
Scope is GitHub Actions, tests + builds. It’s automatic when a report exists, mirroring the always-on PR comment, so no new flag or config knob was added.
Validation
- CLI: the
tuist scheme and the Tuist-Workspace test target both compile with the compilation cache disabled; SwiftFormat and SwiftLint are clean on the touched files. The renderer is unit-tested (logic is pure); test execution runs in CI.
- Server: no net change — the first iteration’s endpoint, OpenAPI operation,
RunReportURLs refactor, and GetRunJobSummaryService were reverted, so the server side is identical to main.
🤖 Generated with Claude Code