Conversation
…ndler config
When `safe-outputs.create-pull-request.draft` was set via a GitHub Actions
expression (e.g. `${{ inputs.draft-prs }}`), the value was silently dropped
from `GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG`.
Root cause: `Draft *bool` could not unmarshal expression strings, leaving the
field nil, which caused `AddBoolPtr` to skip it.
Fix:
- Change `Draft *bool` to `Draft *string` to support both literal booleans
(pre-processed before unmarshal) and expression strings
- Update schema to accept string in addition to boolean for `draft`
- Use `AddStringPtr` in handler config builder
- Update JS handler to correctly parse string "false" (previously truthy in JS)
- Add test for expression-based draft compilation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
draft values in create-pull-request handler config
|
Extract the ad-hoc bool→string preprocessing for `draft` into a shared
helper `preprocessBoolFieldAsString`, and add a new `AddTemplatableBool`
builder method that properly maps "true"/"false" to JSON booleans and
passes expression strings through for runtime evaluation.
Apply the templatable-boolean pattern to:
- `FallbackAsIssue *bool` → `*string` (CreatePullRequestsConfig)
- `FallbackToIssue *bool` → `*string` (CreateDiscussionsConfig)
Both fields now accept `${{ inputs.x }}` expressions in addition to
literal booleans. `getFallbackAsIssue()` returns true for expressions
(safe default for compile-time permission decisions).
JS handlers updated: use `String(x) !== "false"` for both fields so
that string "false" from a resolved expression is correctly treated as
falsy (previously `x !== false` would treat "false" string as truthy).
Schema updated to accept boolean|string for both fallback fields.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 8c52f20. Here's what was added/changed: New shared infrastructure:
Applied to:
JS handlers — fixed Schema — Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
draft values in create-pull-request handler config|
At @copilot: refactor the helpers and code to handle boolean strings and templatables in files, |
Create pkg/workflow/templatables.go as the canonical Go home for all "templatable field" helpers (fields that don't change the .lock.yml but can accept expressions). Move preprocessBoolFieldAsString (from config_helpers.go) and AddTemplatableBool method (from compiler_safe_outputs_config.go) there with a top-level doc comment. Create actions/setup/js/templatable.cjs with parseBoolTemplatable() — the JS counterpart used by safe-output handlers at runtime. Add a full test suite in templatable.test.cjs. Update create_pull_request.cjs and create_discussion.cjs to use parseBoolTemplatable() instead of the inline String(x) !== "false" expressions. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in b99d944.
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where boolean configuration fields in safe-outputs (draft, fallback-as-issue, and fallback-to-issue) couldn't accept GitHub Actions expressions like ${{ inputs.draft-prs }}. When expressions were provided, the fields were unmarshaled as nil due to type mismatch (*bool couldn't accept string expressions), causing the handlers to silently fall back to default behavior.
Changes:
- Introduced templatable field infrastructure to support both literal boolean values and GitHub Actions expressions for runtime-evaluated config fields
- Changed affected boolean fields from
*boolto*stringtype with preprocessing to accept both literals and expressions - Updated environment variable generation to properly embed expressions unquoted for GitHub Actions evaluation
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
pkg/workflow/templatables.go |
New canonical home for templatable field helpers with preprocessBoolFieldAsString and AddTemplatableBool functions |
actions/setup/js/templatable.cjs |
JavaScript counterpart with parseBoolTemplatable function for runtime evaluation |
actions/setup/js/templatable.test.cjs |
Comprehensive test suite for the JS templatable parser |
pkg/workflow/create_pull_request.go |
Updated Draft and FallbackAsIssue fields to *string, added preprocessing, updated env var generation |
pkg/workflow/create_discussion.go |
Updated FallbackToIssue field to *string, added preprocessing, updated env var generation |
pkg/workflow/compiler_safe_outputs_config.go |
Updated handler registry to use AddTemplatableBool instead of AddBoolPtr for affected fields |
pkg/workflow/tool_description_enhancer.go |
Updated draft check to compare string value == "true" |
pkg/workflow/test_helpers_shared_test.go |
Added strPtr helper function for tests |
pkg/workflow/safe_outputs_permissions_test.go |
Updated test to use strPtr("false") instead of ptrBool(false) |
pkg/workflow/safe_outputs_max_test.go |
Updated test assertions to expect string "true" instead of boolean |
pkg/workflow/create_discussion_validation_test.go |
Updated tests to use strPtr and added test case for expression values |
pkg/workflow/compiler_safe_outputs_config_test.go |
Updated tests to use testStringPtr and added expected value assertions |
pkg/workflow/compile_outputs_pr_test.go |
Added new test for draft expression and updated fallback-as-issue assertion |
pkg/parser/schemas/main_workflow_schema.json |
Updated schema to accept `boolean |
actions/setup/js/create_pull_request.cjs |
Updated to use parseBoolTemplatable for draft and fallback_as_issue |
actions/setup/js/create_discussion.cjs |
Updated to use parseBoolTemplatable for fallback_to_issue |
Comments suppressed due to low confidence (3)
pkg/workflow/create_pull_request.go:117
- The expression detection uses
strings.HasPrefix(draftVal, "${{")but doesn't validate that the expression is properly closed with}}. While GitHub Actions will likely reject malformed expressions at runtime, consider adding validation to ensure the expression is well-formed (e.g.,strings.HasPrefix(val, "${{") && strings.HasSuffix(val, "}}")) for earlier error detection and better user experience.
This issue also appears on line 141 of the same file.
if strings.HasPrefix(draftVal, "${{") {
// Expression value - embed unquoted so GitHub Actions evaluates it
customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_PR_DRAFT: %s\n", draftVal))
pkg/workflow/create_pull_request.go:142
- Same as the draft field above: consider validating that expressions are properly closed with
}}for consistency and better error detection.
if strings.HasPrefix(faiVal, "${{") {
customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_PR_FALLBACK_AS_ISSUE: %s\n", faiVal))
pkg/workflow/create_discussion.go:150
- Consider validating that expressions are properly closed with
}}for consistency with other expression handling and better error detection.
if strings.HasPrefix(*ftiVal, "${{") {
customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_DISCUSSION_FALLBACK_TO_ISSUE: %s\n", *ftiVal))
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
You could introduce a templatable boolean type in the main json schema so you can easily assign this templatable boolean to fields. @copilot |
Introduce a reusable `templatable_boolean` definition in the `$defs`
section of the main workflow schema. The type captures the "either a
literal boolean or a GitHub Actions expression string" pattern that is
common to templatable safe-output config fields.
Replace the three duplicate inline oneOf patterns for `draft`,
`fallback-as-issue`, and `fallback-to-issue` with
`allOf: [{"$ref": "#/$defs/templatable_boolean"}]` so that adding
the same behaviour to future fields requires only a one-liner $ref.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in ff432b1. Added "templatable_boolean": {
"description": "A boolean value that may also be specified as a GitHub Actions expression string...",
"oneOf": [
{ "type": "boolean" },
{ "type": "string", "description": "GitHub Actions expression that resolves to a boolean at runtime" }
]
}The three existing fields now reference it via Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot the parser helper should enforce that the template Boolean value is a Boolean or a string starting with ${{ . Don't allow free form string literals. Update the JSON type with pattern constraints. |
- JSON schema: add pattern `^\$\{\{.*\}\}$` to the string branch of the
new `templatable_boolean` $defs type so that only valid GitHub Actions
expressions are accepted; free-form strings are rejected by validation.
- Go helper: `preprocessBoolFieldAsString` now returns an error when the
field value is a string that does not match the `${{ ... }}` form
(must both start with `${{` and end with `}}`). Callers in
`create_discussion.go` and `create_pull_request.go` log the error and
return nil, triggering the safe fallback behaviour.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 1936c82. Schema — added Go helper — Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
…able)
fallback-as-issue controls whether issues:write permission is included in
the generated .lock.yml at compile time, so it cannot be a runtime
expression. Reverted from *string back to *bool.
- FallbackAsIssue *string → *bool in CreatePullRequestsConfig
- getFallbackAsIssue simplified back to plain bool dereference
- Removed preprocessBoolFieldAsString call for fallback-as-issue
- GH_AW_PR_FALLBACK_AS_ISSUE env var uses simple %t formatting
- AddTemplatableBool → AddBoolPtr for fallback_as_issue in config builder
- Schema: fallback-as-issue reverted to {type: boolean}
- Tests updated to use boolPtr(false) instead of strPtr("false")
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 5e06842. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
| const maxCount = config.max || 10; | ||
| const expiresHours = config.expires ? parseInt(String(config.expires), 10) : 0; | ||
| const fallbackToIssue = config.fallback_to_issue !== false; // Default to true | ||
| const fallbackToIssue = parseBoolTemplatable(config.fallback_to_issue, true); // Default to true |
There was a problem hiding this comment.
@copilot make sure fallabackToIssue is back to a Boolean
There was a problem hiding this comment.
Done in 804ee83. fallbackToIssue in create_discussion.cjs now uses config.fallback_to_issue !== false (plain boolean), and FallbackToIssue in Go is back to *bool.
| const { defaultTargetRepo, allowedRepos } = resolveTargetRepoConfig(config); | ||
| const includeFooter = config.footer !== false; // Default to true (include footer) | ||
| const fallbackAsIssue = config.fallback_as_issue !== false; // Default to true (fallback enabled) | ||
| const fallbackAsIssue = parseBoolTemplatable(config.fallback_as_issue, true); // Default to true (fallback enabled) |
There was a problem hiding this comment.
Done in 804ee83. fallbackAsIssue in create_pull_request.cjs now uses config.fallback_as_issue !== false (plain boolean, matching the static *bool on the Go side).
Both fallback fields are compile-time / non-templatable config, not
runtime expressions. Revert JS handlers to simple !== false evaluation
and Go struct back to *bool.
- create_discussion.cjs: use config.fallback_to_issue !== false, remove parseBoolTemplatable import
- create_pull_request.cjs: use config.fallback_as_issue !== false
- CreateDiscussionsConfig.FallbackToIssue *string → *bool
- Removed preprocessBoolFieldAsString for fallback-to-issue
- GH_AW_DISCUSSION_FALLBACK_TO_ISSUE env var uses %t formatting
- AddTemplatableBool → AddBoolPtr for fallback_to_issue in compiler
- Schema: fallback-to-issue reverted to {type: boolean}
- Tests updated to use boolPtr()
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
The
draftboolean field insafe-outputs.create-pull-requestwas typed as*bool, which couldn't unmarshal GitHub Actions expression strings like${{ inputs.draft-prs }}. This left the fieldnil, causingAddBoolPtrto silently omit it fromGH_AW_SAFE_OUTPUTS_HANDLER_CONFIG. The handler then fell back to its default draft behavior regardless of the runtime value.The
fallback-as-issueandfallback-to-issuefields affect compile-time behavior (permissions in the generated.lock.yml) and remain plain*boolfields.Changes
Templatable field infrastructure (dedicated files)
pkg/workflow/templatables.go— canonical home for all templatable-field helpers, with a doc comment explaining the concept (fields that don't affect.lock.ymlbut can accept GitHub Actions expressions):preprocessBoolFieldAsString(configData, fieldName, log)— converts YAML booleans to strings before unmarshaling so*stringfields accept both literal booleans and expression strings; rejects free-form strings that are not GitHub Actions expressions (must match${{ … }})AddTemplatableBool(key, *string)onhandlerConfigBuilder— stores"true"/"false"as proper JSON booleans (backward-compatible) and expression strings as-is for runtime evaluationactions/setup/js/templatable.cjs— JS counterpart withparseBoolTemplatable(value, defaultValue)for use by safe-output handlers that need expression support at runtimeactions/setup/js/templatable.test.cjs— full test suite forparseBoolTemplatableJSON Schema
$defs.templatable_boolean— new reusable type in the main workflow schema that captures the "literal boolean or GitHub Actions expression string" pattern; the string branch is constrained bypattern: ^\$\{\{.*\}\}$to reject free-form strings; future templatable boolean fields need only a single$refdraft— references#/$defs/templatable_booleanviaallOf: [{"$ref": ...}]fallback-as-issueandfallback-to-issue— remain{type: boolean}since they affect compile-time behavior in the generated.lock.ymlApplied to templatable boolean fields
CreatePullRequestsConfig.Draft:*bool→*string; usespreprocessBoolFieldAsString+AddTemplatableBoolCreatePullRequestsConfig.FallbackAsIssue: remains*bool— controls whetherissues:writeis included in the compiled.lock.ymlCreateDiscussionsConfig.FallbackToIssue: remains*bool— plain boolean, not a runtime expressionGH_AW_PR_DRAFTenv var: usesstrings.HasPrefix(val, "${{")to embed expressions unquoted in the compiled YAMLJS handlers updated
create_pull_request.cjs:draftDefaultusesparseBoolTemplatable()fromtemplatable.cjs;fallbackAsIssueuses plain!== falseevaluationcreate_discussion.cjs:fallbackToIssueuses plain!== falseevaluationtool_description_enhancer.go: checks== "true"explicitly for draft to avoid treating unresolved expressions as draft modeExample — now compiles and propagates correctly:
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.