Skip to content

Comments

Add conditional if expressions to runtime configuration#16638

Merged
pelikhan merged 3 commits intomainfrom
copilot/automatically-detect-runtimes
Feb 18, 2026
Merged

Add conditional if expressions to runtime configuration#16638
pelikhan merged 3 commits intomainfrom
copilot/automatically-detect-runtimes

Conversation

Copy link
Contributor

Copilot AI commented Feb 18, 2026

Centrally-defined workflows using workflow_call cannot provide runtime configuration at compile time. This adds support for GitHub Actions conditional expressions in the runtimes section to enable file-based runtime detection.

Changes

Runtime Configuration

  • Added optional if field to RuntimeConfig accepting GitHub Actions expressions
  • Propagated IfCondition through RuntimeRequirement to step generation
  • Updated runtimesConfigToMap to preserve if field in round-trip conversion

Compilation Pipeline

  • Modified generateSetupStep to emit if: condition in generated YAML
  • Updated applyRuntimeOverrides to extract and apply conditional expressions
  • Schema updated to validate if property in runtime objects

Testing

  • Unit tests for parsing, conversion, and step generation
  • Integration test for end-to-end workflow compilation with conditionals

Example

runtimes:
  go:
    version: "1.25"
    if: hashFiles('go.mod') != ''
  python:
    version: "3.11"
    if: hashFiles('requirements.txt') != '' || hashFiles('pyproject.toml') != ''

Generates:

- name: Setup Go
  uses: actions/setup-go@<sha>
  if: hashFiles('go.mod') != ''
  with:
    go-version: '1.25'

Supports full GitHub Actions expression syntax. Backward compatible - runtimes without if conditions unchanged.

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:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GOMOD GOMODCACHE go env ck &#39;scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GOMOD GOMODCACHE go m/_n�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GOMOD GOMODCACHE go env GOPATH); \ if coGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/11bd71901bbe5b1630ceea73d27597364c9af683
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/11bd71901bbe5b1630ceea73d27597364c9af683 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node /hom�� --check **/*.cjs 64/bin/go **/*.json --ignore-path ../../../.pretti/home/REDACTED/work/gh-aw/gh-aw/.github/workflows go (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha xFkv/UoPwMwqRq6HGOSUMDB GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE 0313489/b375/imprev-parse -c che/go-build/a2/a2615bb3240425a6GOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-f (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v7 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v7 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE erignore env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v7 --jq .object.sha che/go-build/f9/f9dd00c75c79c7baGOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-f -o /tmp/go-build394-f -trimpath 64/bin/go -p github.com/githu-1 -lang=go1.25 go (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/4dc6199c7b1a012772edbd06daecab0f50c9053c
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/4dc6199c7b1a012772edbd06daecab0f50c9053c --jq .object.sha k/gh-aw/gh-aw/pkg/stringutil/ideGOINSECURE k/gh-aw/gh-aw/pkg/stringutil/patGOMOD 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcrev-parse -o /tmp/go-build3940313489/b395/_pkGOINSECURE -trimpath 64/bin/go -p main -lang=go1.25 go (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v5 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ck &#39;scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha g/styles/theme.gGOINSECURE g/styles/theme_tGOMOD 64/bin/go GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE env 0313489/b326/_pkGOINSECURE GO111MODULE 64/bin/go GOINSECURE b/gh-aw/pkg/work--norc GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha 35126d5394e2a1caGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE env 0313489/b398/_pkGOINSECURE GO111MODULE 64/bin/go GOINSECURE b/gh-aw/pkg/test--norc GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env ck &#39;scripts/**/*GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq .object.sha g/stringutil/ideGOINSECURE g/stringutil/patGOMOD 64/bin/go GOINSECURE GOMOD GOMODCACHE ache/go/1.25.0/xGO111MODULE env 0313489/b395/_pkGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq .object.sha &#34;prettier&#34; --check &#39;scripts/**/*GOINSECURE GOPROXY 9bc83b2626bd1c50ffc60cd633225807-d GOSUMDB GOWORK 64/bin/go go env -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
  • https://api.github.com/repos/anchore/sbom-action/git/ref/tags/v0
    • Triggering command: /usr/bin/gh gh api /repos/anchore/sbom-action/git/ref/tags/v0 --jq .object.sha che/go-build/b7/remote.origin.url GOPROXY $name) { hasDiscussionsEnabled } } GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-f -o /tmp/go-build394-f -trimpath 64/bin/go -p github.com/githu-C -lang=go1.25 go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/anchore/sbom-action/git/ref/tags/v0 --jq .object.sha k/gh-aw/gh-aw/pkremote.origin.url k/gh-aw/gh-aw/pkg/repoutil/repouGOMOD 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcrev-parse -o /tmp/go-build3940313489/b391/_pkGOINSECURE -trimpath 64/bin/go -p main -lang=go1.25 go (http block)
  • https://api.github.com/repos/docker/build-push-action/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v6 --jq .object.sha che/go-build/12/12f9de6d07e84c14GOINSECURE GOPROXY $name) { hasDiscussionsEnabled } } GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcrev-parse -o /tmp/go-build3940313489/b382/_pkGOINSECURE -trimpath 64/bin/go -p github.com/githu-1 -lang=go1.25 go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v6 --jq .object.sha k/gh-aw/gh-aw/pkg/styles/theme.gGOINSECURE k/gh-aw/gh-aw/pkg/styles/theme_tGOMOD $name) { hasDiscussionsEnabled } } GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-f -o /tmp/go-build394-f -trimpath 64/bin/go -p github.com/githu-1 -lang=go1.25 go (http block)
  • https://api.github.com/repos/docker/login-action/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/docker/login-action/git/ref/tags/v3 --jq .object.sha che/go-build/28/2888c116b4dd41c7GOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcrev-parse -o /tmp/go-build3940313489/b383/_pkGOINSECURE -trimpath 64/bin/go -p github.com/githu-1 -lang=go1.25 go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/login-action/git/ref/tags/v3 --jq .object.sha che/go-build/35/35126d5394e2a1caGOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcrev-parse -o /tmp/go-build3940313489/b398/_pkGOINSECURE -trimpath 64/bin/go -p github.com/githu-C -lang=go1.25 go (http block)
  • https://api.github.com/repos/docker/metadata-action/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v5 --jq .object.sha 0313489/b387/embremote.origin.url GOPROXY 64/bin/go GOSUMDB GOWORK run-script/lib/ngraphql /opt/hostedtoolc-f -o /tmp/go-build394-f -trimpath 64/bin/go -p main -lang=go1.25 go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v5 --jq .object.sha k/gh-aw/gh-aw/pkg/sliceutil/slicGOINSECURE k/gh-aw/gh-aw/pkg/sliceutil/slicGOMOD 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-f -o /tmp/go-build394-f -trimpath 64/bin/go -p main -lang=go1.25 go (http block)
  • https://api.github.com/repos/docker/setup-buildx-action/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha 0313489/b374/embedcfg GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolc-f -o /tmp/go-build394-f -trimpath 64/bin/go -p github.com/githu-C -lang=go1.25 go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha che/go-build/b1/-f GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go /opt/hostedtoolcrev-parse @/tm�� x_amd64/vet git 64/bin/go -v origin 64/bin/go go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/c4e091835c7a94dc7d3acb8ed3ae145afb4995f3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/c4e091835c7a94dc7d3acb8ed3ae145afb4995f3 --jq .object.sha tformat GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE sh (http block)
  • https://api.github.com/repos/githubnext/agentics/git/ref/tags/-
    • Triggering command: /usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/- --jq .object.sha -json GO111MODULE $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE node (http block)
  • https://api.github.com/user
    • Triggering command: /usr/bin/gh gh api user --jq .login d -n 10 (http block)
    • Triggering command: /usr/bin/gh gh api user --jq .login rt/yaml/yaml_default.go (http block)
    • Triggering command: /usr/bin/gh gh api user --jq .login (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Automatically detect runtimes to install based on files in the repository</issue_title>
<issue_description>Current behavior: runtime (go, python, uv) setup is driven by runtimes: and/or detection; steps run whenever that runtime is selected. Detection is done by parsing the custom steps for commands to create runtimes from.

In my use-case im centrally defining workflows that are workflow_call-ed. In this case a user can't provide the runtime keys they need nor can they provide steps that can be detected at compile time.

It would be nice if runtimes could contain an if conditional that could default (or at least be used) to detecting the presence of certain well known files like install the go runtime if go.mod exists, install the uv runtime if uv.lock exists, etc.
</issue_description>

Comments on the Issue (you are @copilot in this section)

@pelikhan do you have some simple code samples? @pelikhan @copilot update `runtimes` to specify a custom `if` condition that gets merged in the generated steps.

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits February 18, 2026 20:40
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add automatic runtime detection based on repository files Add conditional if expressions to runtime configuration Feb 18, 2026
@pelikhan pelikhan marked this pull request as ready for review February 18, 2026 21:44
Copilot AI review requested due to automatic review settings February 18, 2026 21:44
@pelikhan pelikhan merged commit 41df3c3 into main Feb 18, 2026
128 checks passed
@pelikhan pelikhan deleted the copilot/automatically-detect-runtimes branch February 18, 2026 21:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds conditional execution support for runtime setup steps in GitHub Actions workflows by introducing an optional if field to runtime configurations. This enables file-based runtime detection, which is particularly useful for centrally-defined workflows using workflow_call that cannot provide runtime configuration at compile time.

Changes:

  • Added if field to RuntimeConfig and RuntimeRequirement structures to accept GitHub Actions conditional expressions
  • Modified step generation to emit if: conditions in the generated YAML when specified
  • Updated schema validation to accept the new if property in runtime objects

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/workflow/frontmatter_types.go Added If field to RuntimeConfig struct and updated parsing/conversion logic to handle optional if conditions
pkg/workflow/runtime_definitions.go Added IfCondition field to RuntimeRequirement struct
pkg/workflow/runtime_overrides.go Modified to extract and apply if conditions from runtime configuration
pkg/workflow/runtime_step_generator.go Updated step generation to emit if: condition in YAML when present
pkg/parser/schemas/main_workflow_schema.json Added schema validation for the new if property with description and examples
pkg/workflow/frontmatter_types_test.go Added comprehensive unit tests for parsing and round-trip conversion of runtime configs with if conditions
pkg/workflow/runtime_setup_test.go Added tests for step generation with various if conditions across different runtimes
pkg/workflow/runtime_integration_test.go Added end-to-end integration tests validating the full compilation pipeline with conditional expressions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 90 to +97
fmt.Sprintf(" uses: %s", actionRef),
}

// Add if condition if specified
if req.IfCondition != "" {
step = append(step, fmt.Sprintf(" if: %s", req.IfCondition))
}

Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if: condition is inserted after the uses: line but before the with: block. According to GitHub Actions YAML syntax, the if: condition should appear immediately after the step name and before uses:. The current placement may work but violates the conventional order of step properties (name, if, uses, with, run, etc.).

Suggested change
fmt.Sprintf(" uses: %s", actionRef),
}
// Add if condition if specified
if req.IfCondition != "" {
step = append(step, fmt.Sprintf(" if: %s", req.IfCondition))
}
}
// Add if condition if specified (must appear before 'uses:' in the step)
if req.IfCondition != "" {
step = append(step, fmt.Sprintf(" if: %s", req.IfCondition))
}
// Add the action reference after any 'if:' condition
step = append(step, fmt.Sprintf(" uses: %s", actionRef))

Copilot uses AI. Check for mistakes.
Comment on lines +265 to +267
// Extract version (optional)
var version string
if versionAny, hasVersion := configMap["version"]; hasVersion {
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "Extract version (optional)" is misleading. While the version field itself is optional in the YAML, the changed logic now allows runtime configs with only an if condition and no version. Consider updating the comment to clarify that a runtime config can have either a version, an if condition, or both.

Copilot uses AI. Check for mistakes.
Comment on lines +689 to +698
nodeMap := map[string]any{}
if config.Node.Version != "" {
nodeMap["version"] = config.Node.Version
}
if config.Node.If != "" {
nodeMap["if"] = config.Node.If
}
if len(nodeMap) > 0 {
result["node"] = nodeMap
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conversion logic for each runtime (node, python, go, uv, bun, deno) is duplicated six times with only the runtime name and config field changing. This repetitive code could be refactored into a helper function that takes the runtime name and config as parameters, reducing code duplication and making future modifications easier.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automatically detect runtimes to install based on files in the repository

2 participants