fix(ci): correct reusable-dispatch stage skip expression#1730
Conversation
5594d71 to
7d24618
Compare
The per-repo silent-skip output used a GHA expression where empty string is falsy, so skipped roles still dispatched. Fixes fullsend-ai#1199. Signed-off-by: Barak Korren <bkorren@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Site previewPreview: https://4a204e0c-site.fullsend-ai.workers.dev Commit: |
7d24618 to
1efe7cb
Compare
ReviewFindingsMedium
Low
Info
|
| pull-requests: read | ||
| outputs: | ||
| stage: ${{ steps.role-check.outputs.skipped == 'true' && '' || steps.route.outputs.stage }} | ||
| stage: ${{ steps.role-check.outputs.skipped != 'true' && steps.route.outputs.stage || '' }} |
There was a problem hiding this comment.
It does look like this does not produce a string output, it seems like it would produce a boolean. If it is bash then I guess this makes sense but I'm not sure. If you are confident this does what it is supposed to do, then go ahead.
There was a problem hiding this comment.
The \!= does produce a boolean, but GHA short-circuit semantics keep it from leaking into the output. When skipped is 'true': false && stage short-circuits to false, then false || '' yields ''. When skipped isn't 'true': true && stage yields the stage string (e.g. 'review'), then 'review' || '' yields 'review'. So the final value is always either the stage string or empty — the intermediate boolean never reaches the output.
There was a problem hiding this comment.
For reference, the GHA expression evaluator source confirms && and || return operand values, not booleans — same semantics as JavaScript:
visitLogical(logical: Logical): data.ExpressionData {
let result: data.ExpressionData;
for (const arg of logical.args) {
result = this.eval(arg);
if (
(logical.operator.type === TokenType.AND && falsy(result)) ||
(logical.operator.type === TokenType.OR && truthy(result))
) {
break;
}
}
return result!;
}|
@ralphbean @rh-hemartin @ascerra can we merge this or should we wait until after Wednesday? |
Summary
routejobstageoutput in.github/workflows/reusable-dispatch.ymlso per-repo silent-skip works when a routed stage's role is not indefaults.roles.skipped == 'true' && '' || stage(always evaluates tostagebecause''is falsy in GHA) withskipped != 'true' && stage || ''.Fixes #1199
Test plan
.fullsend/config.yamlroles—routeshould output emptystageand all stage jobs should be skipped.Made with Cursor