Skip to content

GitHub Actions run step hardcodes ./build.cmd — breaks non-Windows runners (fix: pwsh build.ps1) #516

Open

Description

@ChrisonSimtian

Summary

GitHubActionsRunStep.Write() emits run: ./{BuildCmdPath} <targets> for every job regardless of the runner image, and ConfigurationAttributeBase.BuildCmdPath only globs build.cmd (never build.sh/build.ps1). So any workflow generated for an Ubuntu*/MacOs* image gets ./build.cmd, which can't execute — only windows-* runners work.

Repro

[GitHubActions("ci", GitHubActionsImage.UbuntuLatest, InvokedTargets = [nameof(Foo)])]

generates:

runs-on: ubuntu-latest
...
  run: ./build.cmd Foo      # .cmd on ubuntu → fails

Cause (10.3.49)

  • Fallout.Common.CI.GitHubActions.Configuration.GitHubActionsRunStep.Write → " run: ./" + BuildCmdPath + " " + JoinSpace(InvokedTargets)
  • Fallout.Common.CI.ConfigurationAttributeBase.BuildCmdPath → globs build.cmd, */build.cmd only

No branch on GitHubActionsImage. Confirmed across both assemblies: zero references to build.sh or build.ps1; build.cmd is the only build-script string (2 glob literals in Fallout.Build). The build.sh/build.ps1 bootstrap files ship, but the generator only ever knows build.cmd.

Fix — pwsh route (decided)

pwsh is on every GitHub-hosted runner (win/linux/mac) and build.ps1 already takes targets positionally (ValueFromRemainingArguments), so invoke pwsh and drop per-OS script selection entirely:

  1. ConfigurationAttributeBase — add a pwsh path mirroring BuildCmdPath:
    protected virtual string BuildScriptPath =>
        Build.RootDirectory.GlobFiles("build.ps1", "*/build.ps1")
            .Select(x => Build.RootDirectory.GetUnixRelativePathTo(x))
            .FirstOrDefault().NotNull();
  2. GitHubActionsRunStep.Write — invoke pwsh:
    writer.WriteLine("  run: pwsh -File ./" + BuildScriptPath + " " + JoinSpace(InvokedTargets));
    (thread BuildScriptPath through the attribute's GetSteps where it currently passes BuildCmdPath.)

pwsh -File ./build.ps1 <targets> runs regardless of the runner's default shell — no shell: key, no image branch. Same swap applies to the other CI run-step writers if we want them pwsh too.

Workaround

Pin GitHubActionsImage.WindowsLatest (only image where the generated ./build.cmd runs).


Filed by AI (Claude Opus 4.8 (1M context)) on Chris's behalf.

Activity

  1. ChrisonSimtian commented on Jul 20, 2026

    @ChrisonSimtian
    CollaboratorAuthor

    Update after investigating on main (2026 line).

    The GitHub Actions repro in this issue no longer applies to main: GitHubActionsRunStep stopped emitting ./build.cmd back in #203/#204 — it now generates setup-dotnet → dotnet tool restore → dotnet fallout <targets>, which is cross-platform. So the original ./build.cmd-on-Ubuntu bug for GHA only exists on the legacy v10 line (where this was filed, 10.3.49).

    But the same class of bug is live on main in two other providers, which this issue's analysis didn't cover:

    • AppVeyor — emitted - sh: ./build.cmd … (a Unix shell running a .cmd).
    • Azure Pipelines — CmdLine@2 ran ./build.cmd … regardless of agent OS.

    (TeamCity and SpaceAutomation already swap to .sh on non-Windows, so they're fine.)

    Decision: rather than the pwsh route originally proposed here, fix these the same way GitHub Actions was fixed — invoke the cross-platform fallout local tool (dotnet tool restore + dotnet fallout <targets>), dropping OS-specific build-script selection entirely. Keeps all providers consistent.

    Fixed in #517 (targets main). The v10 GHA fix is a separate backport if we decide it's worth it — flag if so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions