diff --git a/.github/workflows/ubuntu-latest.yml b/.github/workflows/ubuntu-latest.yml index 7aaa4355a..dfd3e733f 100644 --- a/.github/workflows/ubuntu-latest.yml +++ b/.github/workflows/ubuntu-latest.yml @@ -34,10 +34,6 @@ jobs: with: submodules: recursive fetch-depth: 0 - # Check out the source branch (not the merge SHA) so HEAD stays - # attached. GitHubTasksTest.GitHubRepositoryFromLocalDirectoryTest - # requires repository.Branch to be non-null. NOTE: this file is - # auto-generated by Fallout; next regen will overwrite. Track in #110. ref: ${{ github.head_ref }} - name: 'Cache: .fallout/temp, ~/.nuget/packages' uses: actions/cache@v4 diff --git a/build/Build.CI.GitHubActions.cs b/build/Build.CI.GitHubActions.cs index a27ebb397..67ee7df96 100644 --- a/build/Build.CI.GitHubActions.cs +++ b/build/Build.CI.GitHubActions.cs @@ -27,11 +27,16 @@ PublishArtifacts = false)] // pull_request only — same-repo branches would otherwise fire both push and // pull_request events on every push, double-running the validation. +// +// CheckoutRef = github.head_ref pins checkout to the PR source branch instead of the merge SHA, +// keeping HEAD attached so GitHubTasksTest.GitHubRepositoryFromLocalDirectoryTest (which reads +// .git/HEAD via GitRepository.FromLocalDirectory) resolves a non-null branch. [GitHubActions( "ubuntu-latest", GitHubActionsImage.UbuntuLatest, FetchDepth = 0, Submodules = GitHubActionsSubmodules.Recursive, + CheckoutRef = "${{ github.head_ref }}", OnPullRequestBranches = new[] { MainBranch }, OnPullRequestExcludePaths = new[] { "docs/**", ".assets/**", "**/*.md" }, InvokedTargets = new[] { nameof(ITest.Test), nameof(IPack.Pack) }, diff --git a/src/Fallout.Common/CI/GitHubActions/Configuration/GitHubActionsCheckoutStep.cs b/src/Fallout.Common/CI/GitHubActions/Configuration/GitHubActionsCheckoutStep.cs index 67d95dfb1..78cea71ff 100644 --- a/src/Fallout.Common/CI/GitHubActions/Configuration/GitHubActionsCheckoutStep.cs +++ b/src/Fallout.Common/CI/GitHubActions/Configuration/GitHubActionsCheckoutStep.cs @@ -17,11 +17,21 @@ public class GitHubActionsCheckoutStep : GitHubActionsStep public bool? Progress { get; set; } public string Filter { get; set; } + /// + /// The git ref to check out. When unset, actions/checkout picks the default for the event + /// (the merge SHA on pull_request triggers, which leaves HEAD detached). Set to + /// ${{ github.head_ref }} on PR workflows that read .git/HEAD directly + /// (e.g. ) so the branch + /// resolves correctly. + /// + public string Ref { get; set; } + public override void Write(CustomFileWriter writer) { writer.WriteLine("- uses: actions/checkout@v6"); - if (Submodules.HasValue || Lfs.HasValue || FetchDepth.HasValue || Progress.HasValue || !Filter.IsNullOrWhiteSpace()) + if (Submodules.HasValue || Lfs.HasValue || FetchDepth.HasValue || Progress.HasValue || + !Filter.IsNullOrWhiteSpace() || !Ref.IsNullOrWhiteSpace()) { using (writer.Indent()) { @@ -38,6 +48,8 @@ public override void Write(CustomFileWriter writer) writer.WriteLine($"progress: {Progress.ToString().ToLowerInvariant()}"); if (!Filter.IsNullOrWhiteSpace()) writer.WriteLine($"filter: {Filter}"); + if (!Ref.IsNullOrWhiteSpace()) + writer.WriteLine($"ref: {Ref}"); } } } diff --git a/src/Fallout.Common/CI/GitHubActions/GitHubActionsAttribute.cs b/src/Fallout.Common/CI/GitHubActions/GitHubActionsAttribute.cs index aac79378f..195ed005a 100644 --- a/src/Fallout.Common/CI/GitHubActions/GitHubActionsAttribute.cs +++ b/src/Fallout.Common/CI/GitHubActions/GitHubActionsAttribute.cs @@ -29,6 +29,7 @@ public class GitHubActionsAttribute : ConfigurationAttributeBase private uint? _fetchDepth; private bool? _progress; private string _filter; + private string _ref; public GitHubActionsAttribute( string name, @@ -117,6 +118,17 @@ public string Filter get => throw new NotSupportedException(); } + /// + /// Forwarded to actions/checkout's ref input. Set to + /// ${{ github.head_ref }} on PR-triggered workflows that need .git/HEAD + /// to stay attached (e.g. ones that read the current branch via GitRepository). + /// + public string CheckoutRef + { + set => _ref = value; + get => throw new NotSupportedException(); + } + public override CustomFileWriter CreateWriter(StreamWriter streamWriter) { return new CustomFileWriter(streamWriter, indentationFactor: 2, commentPrefix: "#"); @@ -167,7 +179,8 @@ private IEnumerable GetSteps(GitHubActionsImage image, IReadO Lfs = _lfs, FetchDepth = _fetchDepth, Progress = _progress, - Filter = _filter + Filter = _filter, + Ref = _ref }; if (CacheKeyFiles.Any())