Skip to content
Merged
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
14 changes: 11 additions & 3 deletions src/Shims/Nuke.Common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,27 @@ This package is a **partial transition shim** for projects mid-migration from NU
| `[Solution]` | `Fallout.Common.ProjectModel.SolutionAttribute` | Subclass |
| `[GitRepository]` | `Fallout.Common.Git.GitRepositoryAttribute` | Subclass |
| `CI host singletons` (`GitHubActions`, `AzurePipelines`, `TeamCity`, `AppVeyor`, `GitLab`, `Jenkins`, `Bamboo`, `Bitbucket`, `Bitrise`, `TravisCI`) | `Fallout.Common.CI.<Vendor>.<Vendor>` | Hand-written static class re-exposing `.Instance` (returns canonical type) |
| `DelegateDisposable` | `Fallout.Common.Utilities.DelegateDisposable` | Hand-written static class re-exposing `CreateBracket` / `SetAndRestore` |

The MVP unblocks a `class Build : NukeBuild` declaration with parameter/secret/solution/git injection — the entry-point surface of most consumer Build.cs files. CI host shims cover the `GitHubActions.Instance.Workflow`-style access path.

### CI host shim limitation
### Hand-bridge limitation (CI hosts, `DelegateDisposable`)

Because CI hosts are framework-injected, `[CI] readonly GitHubActions GitHubActions;` field declarations and `Host is GitHubActions` type checks need consumers to use the canonical (`Fallout.Common.CI.GitHubActions.GitHubActions`) type directly — the shim's `Instance` accessor returns a canonical instance, but the shim type itself is `static class` so it can't be used as a field type. Use `fallout-migrate` to rewrite those references.
These types are framework-injected or use private/internal constructors. The shim is `static class`, so consumers receiving canonical-typed instances (e.g. `[CI] readonly GitHubActions GitHubActions;`, `Host is GitHubActions`, methods returning `DelegateDisposable`) need to switch the type reference to canonical. Use `fallout-migrate` for those rewrites; the shim covers static factory / `.Instance` access paths only.

## What's NOT covered (and won't be)

These types have private/internal ctors and no public static factories, **and** are mainly used as value types — meaning the hand-bridge would be empty (no public statics to re-expose) and a subclass shim can't carry implicit operators or be assignment-compatible with framework-returned canonical instances:

- **`Fallout.Common.IO.AbsolutePath`** — used via `AbsolutePath path = "/foo"` (implicit `string`/`AbsolutePath` conversion), `parent / "child"` (`operator/`), and field-injection. None of those work through a static-class shim. Use `fallout-migrate` to rewrite `Nuke.Common.IO.AbsolutePath` → `Fallout.Common.IO.AbsolutePath`.
- **`Fallout.Common.Tools.AzureKeyVault.AzureKeyVault`** — zero public statics, framework-constructed only. `fallout-migrate` rename.
- **`Fallout.Common.Tools.MSBuild.MSBuildProject`** — zero public statics, framework-returned only. `fallout-migrate` rename.

## What's NOT covered (yet)

- **CI attributes** (`[GitHubActions]`, `[AzurePipelines]`, `[TeamCity]`, `[AppVeyor]`, ...) — these take enum parameters (`GitHubActionsImage`, etc.) that the shim doesn't re-export. C# can't subclass enums; bridging them needs a source generator. Tracked in the follow-up issue.
- **The `Target` delegate** — delegates can't be implicitly converted across types in C#, so the shim can't bridge `Nuke.Common.Target Compile => _ => _` cleanly. Use `fallout-migrate` for the source-level rename.
- **Static helper classes** — `DotNetTasks`, `MSBuildTasks`, etc. require method-by-method delegation. Tracked for the source-generator follow-up.
- **IO types** — `AbsolutePath`, file globbing helpers — also need wrapper classes with mirrored members.

## Packaging

Expand Down
27 changes: 27 additions & 0 deletions src/Shims/Nuke.Common/Utilities/DelegateDisposable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2026 Maintainers of Fallout.
// Originally based on NUKE by Matthias Koch and contributors.
// Distributed under the MIT License.
// https://github.com/ChrisonSimtian/Fallout/blob/main/LICENSE

// Hand-written transition shim. The canonical DelegateDisposable has a private
// ctor and exposes itself only via static factories; the generator skips it as
// no-accessible-ctor, and a subclass wouldn't compile anyway. This static-class
// shim re-exposes the three factories so consumers keep compiling on
// `using Nuke.Common.Utilities;`.

using System;
using System.Linq.Expressions;

namespace Nuke.Common.Utilities;

public static class DelegateDisposable
{
public static IDisposable CreateBracket(Action setup = null, Action cleanup = null)
=> global::Fallout.Common.Utilities.DelegateDisposable.CreateBracket(setup, cleanup);

public static IDisposable CreateBracket<T>(Func<T> setup, Action<T> cleanup)
=> global::Fallout.Common.Utilities.DelegateDisposable.CreateBracket(setup, cleanup);

public static IDisposable SetAndRestore<T>(Expression<Func<T>> memberProvider, T value)
=> global::Fallout.Common.Utilities.DelegateDisposable.SetAndRestore(memberProvider, value);
}
14 changes: 14 additions & 0 deletions tests/Nuke.Common.Shim.Tests/SampleConsumerBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Nuke.Common.CI.TeamCity;
using Nuke.Common.Git;
using Nuke.Common.ProjectModel;
using Nuke.Common.Utilities;

namespace Nuke.Common.Shim.Tests;

Expand Down Expand Up @@ -45,4 +46,17 @@ void TouchCiHostShims()
_ = AppVeyor.Instance?.AccountName;
_ = AppVeyor.MessageLimit;
}

// DelegateDisposable shim re-exposes the static factories. Consumer
// usage stays canonical-typed at runtime (the factories return
// canonical IDisposable instances).
void TouchDelegateDisposableShim()
{
using var bracket = DelegateDisposable.CreateBracket(
setup: () => { },
cleanup: () => { });
using var typed = DelegateDisposable.CreateBracket(
setup: () => 42,
cleanup: _ => { });
}
}
Loading