Skip to content

[GitHubActions] generator: control the shell for run steps (defaults.run.shell + per-step shell:) #388

Description

@avidenic

Description

GitHub-hosted runners default run: steps to different shells per OS (bash on Linux/macOS, pwsh on Windows), which silently changes script semantics (quoting, error handling, set -e vs $ErrorActionPreference) in cross-platform jobs. The only robust fix is an explicit shell, which Fallout cannot currently emit. GitHubActionsRunStep.Write (src/Fallout.Common/CI/GitHubActions/Configuration/GitHubActionsRunStep.cs:14-44) writes the run: line and an optional env: block but never a shell: key, and GitHubActionsStep (Configuration/GitHubActionsStep.cs:6-8) is an empty abstract base with no Shell member.

Proposed change: offer two levels (prefer the first as the primary mechanism):

  1. defaults.run.shell at workflow (and optionally job) level: set the shell once for every run: step in scope (tool restore, dotnet fallout, and any injected steps) via a single emitted defaults: block. This is the idiomatic GitHub mechanism and is cleaner than threading shell: through every step type. Surface as e.g. DefaultShell on GitHubActionsAttribute.
  2. Per-step shell: as an escape hatch: a nullable Shell on the generated run step, emitted only when set.

Usage Example

[GitHubActions(
    "build",
    GitHubActionsImage.WindowsLatest,
    GitHubActionsImage.UbuntuLatest,
    InvokedTargets = [nameof(Compile)],
    DefaultShell = "pwsh")] // pin shell for ALL run steps in the workflow
class Build : NukeBuild { /* ... */ }

Resulting YAML:

name: build

on: [push]

defaults:
  run:
    shell: pwsh

jobs:
  windows-latest:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v6
      - name: 'Setup: .NET SDK'
        uses: actions/setup-dotnet@v4
      - name: 'Restore: dotnet tools'
        run: dotnet tool restore
      - name: 'Run: Compile'
        run: dotnet fallout Compile

Alternative

No step type exposes a shell field and GitHubActionsRunStep.Write hardcodes a shell:-free run: line, so the only workarounds are hand-editing the YAML (lost on regen) or forking.

Could you help with a pull-request?

Yes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions