feat(execstream): carry annotations, summaries and step outcomes
- commit
- d727ef4bcd2380fd52da59468e7ab1700869da13
- author
- brice · · 2026-10-13 14:41 UTC
- parent
- de0182d
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +478 -65
M internal/execstream/exec.proto +47 -0
| @@ -25,6 +25,8 @@ message Frame { | |||
| 25 | 25 | StepCompleted step_completed = 7; // executor -> host | |
| 26 | 26 | Log log = 8; // executor -> host | |
| 27 | 27 | JobResult job_result = 9; // executor -> host, before Exit | |
| 28 | + | StepAnnotations step_annotations = 10; // executor -> host, before the StepCompleted of the step | |
| 29 | + | StepSummary step_summary = 11; // executor -> host, before the StepCompleted of the step | |
| 28 | 30 | } | |
| 29 | 31 | } | |
| 30 | 32 | ||
| @@ -66,6 +68,11 @@ message JobSpec { | |||
| 66 | 68 | // executor, and booting the sandbox takes time. 0 means "use | |
| 67 | 69 | // timeout_minutes from now". | |
| 68 | 70 | int64 deadline_ms = 12; | |
| 71 | + | // send_annotations and send_summaries say that the server keeps annotations | |
| 72 | + | // (feature ci.annotations) and step summaries (ci.summaries). The executor | |
| 73 | + | // sends StepAnnotations and StepSummary frames only when they are set. | |
| 74 | + | bool send_annotations = 13; | |
| 75 | + | bool send_summaries = 14; | |
| 69 | 76 | } | |
| 70 | 77 | ||
| 71 | 78 | enum StreamKind { | |
| @@ -117,6 +124,46 @@ message StepCompleted { | |||
| 117 | 124 | string name = 2; | |
| 118 | 125 | StepConclusion conclusion = 3; | |
| 119 | 126 | int64 unix_nano = 4; | |
| 127 | + | // outcome is steps.<id>.outcome: the result before continue-on-error. It | |
| 128 | + | // differs from conclusion only for a failed step with continue-on-error. | |
| 129 | + | // UNSPECIFIED means the same as conclusion. | |
| 130 | + | StepConclusion outcome = 5; | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | enum AnnotationLevel { | |
| 134 | + | ANNOTATION_LEVEL_UNSPECIFIED = 0; | |
| 135 | + | ANNOTATION_LEVEL_NOTICE = 1; | |
| 136 | + | ANNOTATION_LEVEL_WARNING = 2; | |
| 137 | + | ANNOTATION_LEVEL_FAILURE = 3; | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // Annotation is one ::notice, ::warning or ::error (or a problem matcher | |
| 141 | + | // match), masked. The host validates every field again before it sends them. | |
| 142 | + | message Annotation { | |
| 143 | + | AnnotationLevel level = 1; | |
| 144 | + | string title = 2; | |
| 145 | + | string message = 3; | |
| 146 | + | string file = 4; // relative to the repository when the file is in it | |
| 147 | + | int32 start_line = 5; | |
| 148 | + | int32 end_line = 6; | |
| 149 | + | int32 start_column = 7; | |
| 150 | + | int32 end_column = 8; | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // StepAnnotations is the complete list of the annotations of a step (the ones | |
| 154 | + | // the runner keeps: at most 10 per level), replacing any earlier list of that | |
| 155 | + | // step. Annotations of the steps inside a composite action are those of the | |
| 156 | + | // step of the workflow that uses it. | |
| 157 | + | message StepAnnotations { | |
| 158 | + | int32 step = 1; | |
| 159 | + | repeated Annotation annotations = 2; | |
| 160 | + | } | |
| 161 | + | ||
| 162 | + | // StepSummary is the masked content of GITHUB_STEP_SUMMARY after a step, at | |
| 163 | + | // most 1 MiB. | |
| 164 | + | message StepSummary { | |
| 165 | + | int32 step = 1; | |
| 166 | + | string markdown = 2; | |
| 120 | 167 | } | |
| 121 | 168 | ||
| 122 | 169 | enum StepConclusion { | |
| @@ -25,6 +25,8 @@ message Frame { | |||||
| 25 | StepCompleted step_completed = 7; // executor -> host | 25 | StepCompleted step_completed = 7; // executor -> host | ||
| 26 | Log log = 8; // executor -> host | 26 | Log log = 8; // executor -> host | ||
| 27 | JobResult job_result = 9; // executor -> host, before Exit | 27 | JobResult job_result = 9; // executor -> host, before Exit | ||
| 28 | + | StepAnnotations step_annotations = 10; // executor -> host, before the StepCompleted of the step | |||
| 29 | + | StepSummary step_summary = 11; // executor -> host, before the StepCompleted of the step | |||
| 28 | } | 30 | } | ||
| 29 | } | 31 | } | ||
| 30 | 32 | ||||
| @@ -66,6 +68,11 @@ message JobSpec { | |||||
| 66 | // executor, and booting the sandbox takes time. 0 means "use | 68 | // executor, and booting the sandbox takes time. 0 means "use | ||
| 67 | // timeout_minutes from now". | 69 | // timeout_minutes from now". | ||
| 68 | int64 deadline_ms = 12; | 70 | int64 deadline_ms = 12; | ||
| 71 | + | // send_annotations and send_summaries say that the server keeps annotations | |||
| 72 | + | // (feature ci.annotations) and step summaries (ci.summaries). The executor | |||
| 73 | + | // sends StepAnnotations and StepSummary frames only when they are set. | |||
| 74 | + | bool send_annotations = 13; | |||
| 75 | + | bool send_summaries = 14; | |||
| 69 | } | 76 | } | ||
| 70 | 77 | ||||
| 71 | enum StreamKind { | 78 | enum StreamKind { | ||
| @@ -117,6 +124,46 @@ message StepCompleted { | |||||
| 117 | string name = 2; | 124 | string name = 2; | ||
| 118 | StepConclusion conclusion = 3; | 125 | StepConclusion conclusion = 3; | ||
| 119 | int64 unix_nano = 4; | 126 | int64 unix_nano = 4; | ||
| 127 | + | // outcome is steps.<id>.outcome: the result before continue-on-error. It | |||
| 128 | + | // differs from conclusion only for a failed step with continue-on-error. | |||
| 129 | + | // UNSPECIFIED means the same as conclusion. | |||
| 130 | + | StepConclusion outcome = 5; | |||
| 131 | + | } | |||
| 132 | + | ||||
| 133 | + | enum AnnotationLevel { | |||
| 134 | + | ANNOTATION_LEVEL_UNSPECIFIED = 0; | |||
| 135 | + | ANNOTATION_LEVEL_NOTICE = 1; | |||
| 136 | + | ANNOTATION_LEVEL_WARNING = 2; | |||
| 137 | + | ANNOTATION_LEVEL_FAILURE = 3; | |||
| 138 | + | } | |||
| 139 | + | ||||
| 140 | + | // Annotation is one ::notice, ::warning or ::error (or a problem matcher | |||
| 141 | + | // match), masked. The host validates every field again before it sends them. | |||
| 142 | + | message Annotation { | |||
| 143 | + | AnnotationLevel level = 1; | |||
| 144 | + | string title = 2; | |||
| 145 | + | string message = 3; | |||
| 146 | + | string file = 4; // relative to the repository when the file is in it | |||
| 147 | + | int32 start_line = 5; | |||
| 148 | + | int32 end_line = 6; | |||
| 149 | + | int32 start_column = 7; | |||
| 150 | + | int32 end_column = 8; | |||
| 151 | + | } | |||
| 152 | + | ||||
| 153 | + | // StepAnnotations is the complete list of the annotations of a step (the ones | |||
| 154 | + | // the runner keeps: at most 10 per level), replacing any earlier list of that | |||
| 155 | + | // step. Annotations of the steps inside a composite action are those of the | |||
| 156 | + | // step of the workflow that uses it. | |||
| 157 | + | message StepAnnotations { | |||
| 158 | + | int32 step = 1; | |||
| 159 | + | repeated Annotation annotations = 2; | |||
| 160 | + | } | |||
| 161 | + | ||||
| 162 | + | // StepSummary is the masked content of GITHUB_STEP_SUMMARY after a step, at | |||
| 163 | + | // most 1 MiB. | |||
| 164 | + | message StepSummary { | |||
| 165 | + | int32 step = 1; | |||
| 166 | + | string markdown = 2; | |||
| 120 | } | 167 | } | ||
| 121 | 168 | ||||
| 122 | enum StepConclusion { | 169 | enum StepConclusion { | ||