Conversation
ChristopherHX
left a comment
There was a problem hiding this comment.
I know this is a draft and I am not part of GitHub, tested this interesting thing anyway
8abb2f4 to
cef1d03
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds support for emitting collapsible step markers in composite action logs. The UI can parse ##[start-action] and ##[end-action] markers to render individual nested steps that were previously hidden in a single opaque log blob.
Changes:
- Added feature flag
actions_runner_emit_composite_markerswith environment variable fallback for internal testing - Implemented marker injection prevention by escaping user-emitted markers in OutputManager
- Added marker emission in CompositeActionHandler around each nested step with timing and outcome tracking
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/Runner.Common/Constants.cs | Added feature flag constant and environment variable name for composite markers |
| src/Runner.Common/ActionCommand.cs | Added public EscapeValue method to escape special characters in marker properties |
| src/Runner.Worker/Handlers/OutputManager.cs | Added injection prevention by replacing user-emitted ##[start-action and ##[end-action with escaped versions |
| src/Runner.Worker/Handlers/CompositeActionHandler.cs | Implemented marker emission with step ID generation, timing tracking, and outcome/conclusion reporting |
| src/Test/L0/Worker/OutputManagerL0.cs | Added tests for marker injection prevention in user output |
| src/Test/L0/Worker/Handlers/CompositeActionHandlerL0.cs | Added comprehensive tests for escaping, sanitization, marker format, and result mapping |
86faaeb to
648fa57
Compare
648fa57 to
2ccceb8
Compare
|
You need to take a look at actions with post steps within composite actions, like actions/cache@v4.
| ##[start-action display=Run actions/cache@v4;id=__self.__actions_cache]
| ##[group]Run actions/cache@v4
| with:
| enableCrossOsArchive: false
| fail-on-cache-miss: false
| lookup-only: false
| save-always: false
| ##[endgroup]
| ##[error]Input required and not supplied: key
| ##[end-action id=__self.__actions_cache;outcome=failure;conclusion=failure;duration_ms=148]
[.github/workflows/test.yml / _] Failed: Run ./
[.github/workflows/test.yml / _] Running: Post Run ./
| Post job cleanup.
| ##[start-action display=run;id=__ca4435ec-3068-4fdf-9051-7de2dd4c7686.__actions_cache]
| ##[end-action id=__ca4435ec-3068-4fdf-9051-7de2dd4c7686.__actions_cache;outcome=skipped;conclusion=skipped;duration_ms=0]Pre and Main step markers look good now. |
|
Thanks @ChristopherHX, good catch!
I just tested E2E with the UI changes and as you said, the marker IDs match so rendering is fine.
Since it's scoped to post-steps only, I will likely address in a follow-up PR. That will keep this diff easier for reviewers. I'm not sure yet how messy the fix will be. |
Summary
Emit
##[start-action]/##[end-action]markers in the log stream around each nested step inside a composite action. The UI parses these markers to render collapsible regions, giving users visibility into individual steps that were previously hidden in a single opaque log blob.Design
The runner writes
##[markers directly to the log stream viaExecutionContext.Output(), bypassing the logging command pipeline. No new::logging command is registered. Users cannot emit these markers from scripts.Marker format
ContextName(from YAMLid:or auto-generated with__prefix)continue-on-erroris appliedcontinue-on-errorNested composites use dot-separated IDs (e.g.
outer.inner-step) to keep each step globally unique.Feature flag
Gated behind
actions_runner_emit_composite_markers(job message variable) withACTIONS_RUNNER_EMIT_COMPOSITE_MARKERSenv var fallback (for internal testing only).Injection prevention
OutputManager.OnDataReceivedreplaces##[start-actionand##[end-actionfrom user process stdout/stderr with##[\start-actionand##[\end-action. This preventing users from injecting fake markers. The runner's own markers bypassOutputManagerentirely since they're written viaExecutionContext.Output()directly.