Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class GitHubActionsConfiguration : ConfigurationEntity
public (GitHubActionsPermissions Type, string Permission)[] Permissions { get; set; }
public string ConcurrencyGroup { get; set; }
public bool ConcurrencyCancelInProgress { get; set; }
public string DefaultShell { get; set; }
public GitHubActionsJob[] Jobs { get; set; }

public override void Write(CustomFileWriter writer)
Expand Down Expand Up @@ -75,6 +76,21 @@ public override void Write(CustomFileWriter writer)
}
}

if (!DefaultShell.IsNullOrWhiteSpace())
{
writer.WriteLine();
// defaults.run currently carries only shell; further run defaults (e.g. working-directory) slot in here
writer.WriteLine("defaults:");
using (writer.Indent())
{
writer.WriteLine("run:");
using (writer.Indent())
{
writer.WriteLine($"shell: {DefaultShell}");
}
}
}

writer.WriteLine();

writer.WriteLine("jobs:");
Expand Down
10 changes: 10 additions & 0 deletions src/Fallout.Common/CI/GitHubActions/GitHubActionsAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ public GitHubActionsAttribute(
public string JobConcurrencyGroup { get; set; }
public bool JobConcurrencyCancelInProgress { get; set; }

/// <summary>
/// Pins the shell for every <c>run:</c> step via a workflow-level <c>defaults.run.shell</c> block,
/// so cross-platform matrix jobs use one consistent shell instead of the per-OS default (<c>bash</c>
/// on Linux/macOS, <c>pwsh</c> on Windows). Accepts any value GitHub allows — a built-in (<c>bash</c>,
/// <c>pwsh</c>, <c>sh</c>, <c>cmd</c>, <c>powershell</c>, <c>python</c>) or a custom <c>command {0}</c>
/// template. Unset or whitespace-only emits no <c>defaults:</c> block.
/// </summary>
public string DefaultShell { get; set; }

public string[] InvokedTargets { get; set; } = new string[0];

public GitHubActionsSubmodules Submodules
Expand Down Expand Up @@ -169,6 +178,7 @@ public override ConfigurationEntity GetConfiguration(IReadOnlyCollection<Executa
.Concat(ReadPermissions.Select(x => (x, "read"))).ToArray(),
ConcurrencyGroup = ConcurrencyGroup,
ConcurrencyCancelInProgress = ConcurrencyCancelInProgress,
DefaultShell = DefaultShell,
Jobs = _images.Select(x => GetJobs(x, relevantTargets)).ToArray()
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# ------------------------------------------------------------------------------
# <auto-generated>
#
# This code was generated.
#
# - To turn off auto-generation set:
#
# [TestGitHubActions (AutoGenerate = false)]
#
# - To trigger manual generation invoke:
#
# fallout --generate-configuration GitHubActions_test --host GitHubActions
#
# </auto-generated>
# ------------------------------------------------------------------------------

name: test

on: [push]

permissions:
contents: write
actions: read

concurrency:
group: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.run_id }}
cancel-in-progress: true

defaults:
run:
shell: pwsh

jobs:
ubuntu-latest:
name: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
with:
path: |
.fallout/temp
~/.nuget/packages
key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: 'Restore: dotnet tools'
run: dotnet tool restore
- name: 'Run: Test'
run: dotnet fallout Test
- name: 'Publish: src'
uses: actions/upload-artifact@v5
with:
name: src
path: src
- name: 'Publish: test-results'
uses: actions/upload-artifact@v5
with:
name: test-results
path: output/test-results
- name: 'Publish: coverage-report.zip'
uses: actions/upload-artifact@v5
with:
name: coverage-report.zip
path: output/coverage-report.zip
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ------------------------------------------------------------------------------
# <auto-generated>
#
# This code was generated.
#
# - To turn off auto-generation set:
#
# [TestGitHubActions (AutoGenerate = false)]
#
# - To trigger manual generation invoke:
#
# fallout --generate-configuration GitHubActions_test --host GitHubActions
#
# </auto-generated>
# ------------------------------------------------------------------------------

name: test

on: [push]

defaults:
run:
shell: pwsh

jobs:
ubuntu-latest:
name: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: 'Cache: .fallout/temp, ~/.nuget/packages'
uses: actions/cache@v4
with:
path: |
.fallout/temp
~/.nuget/packages
key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
- name: 'Setup: .NET SDK'
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: 'Restore: dotnet tools'
run: dotnet tool restore
- name: 'Run: Test'
run: dotnet fallout Test
- name: 'Publish: src'
uses: actions/upload-artifact@v5
with:
name: src
path: src
- name: 'Publish: test-results'
uses: actions/upload-artifact@v5
with:
name: test-results
path: output/test-results
- name: 'Publish: coverage-report.zip'
uses: actions/upload-artifact@v5
with:
name: coverage-report.zip
path: output/coverage-report.zip
27 changes: 27 additions & 0 deletions tests/Fallout.Common.Tests/CI/ConfigurationGenerationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,33 @@ public class TestBuild : FalloutBuild
}
);

yield return
(
"default-shell",
new TestGitHubActionsAttribute(GitHubActionsImage.UbuntuLatest)
{
On = new[] { GitHubActionsTrigger.Push },
InvokedTargets = new[] { nameof(Test) },
DefaultShell = "pwsh"
}
);

// Ordering guard: with DefaultShell, permissions, and concurrency all set, the defaults:
// block must be emitted after concurrency: and before jobs:, with correct blank lines.
yield return
(
"default-shell-with-permissions",
new TestGitHubActionsAttribute(GitHubActionsImage.UbuntuLatest)
{
On = new[] { GitHubActionsTrigger.Push },
InvokedTargets = new[] { nameof(Test) },
DefaultShell = "pwsh",
WritePermissions = new[] { GitHubActionsPermissions.Contents },
ReadPermissions = new[] { GitHubActionsPermissions.Actions },
ConcurrencyCancelInProgress = true
}
);

yield return
(
null,
Expand Down
Loading