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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class PublishModule : Module<CommandResult>
protected override async Task<CommandResult?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
// This is real C#. Set a breakpoint. Inspect variables. Debug locally.
return await context.DotNet().PublishAsync(new DotNetPublishOptions
return await context.Tools.DotNet.PublishAsync(new DotNetPublishOptions
{
ProjectSolution = "src/MyApp/MyApp.csproj",
Configuration = "Release",
Expand Down Expand Up @@ -77,7 +77,7 @@ public class BuildModule : Module<BuildInfo>
{
protected override async Task<BuildInfo?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().BuildAsync(
await context.Tools.DotNet.BuildAsync(
new DotNetBuildOptions { ProjectSolution = "MyApp.csproj" },
cancellationToken: cancellationToken);
return new BuildInfo { Version = "1.0.0", OutputPath = "bin/Release" };
Expand Down
4 changes: 2 additions & 2 deletions README_Template.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class PublishModule : Module<CommandResult>
protected override async Task<CommandResult?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
// This is real C#. Set a breakpoint. Inspect variables. Debug locally.
return await context.DotNet().PublishAsync(new DotNetPublishOptions
return await context.Tools.DotNet.PublishAsync(new DotNetPublishOptions
{
ProjectSolution = "src/MyApp/MyApp.csproj",
Configuration = "Release",
Expand Down Expand Up @@ -77,7 +77,7 @@ public class BuildModule : Module<BuildInfo>
{
protected override async Task<BuildInfo?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().BuildAsync(
await context.Tools.DotNet.BuildAsync(
new DotNetBuildOptions { ProjectSolution = "MyApp.csproj" },
cancellationToken: cancellationToken);
return new BuildInfo { Version = "1.0.0", OutputPath = "bin/Release" };
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/distributed/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class DockerBuildModule : Module<string>
IModuleContext context, CancellationToken cancellationToken)
{
// Only executes on workers that advertise "docker"
await context.Docker().BuildAsync(new());
await context.Tools.Docker.BuildAsync(new());
return "built";
}
}
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/distributed/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public class RestoreModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().RestoreAsync(new());
await context.Tools.DotNet.RestoreAsync(new());
return "restored";
}
}
Expand All @@ -158,7 +158,7 @@ public class BuildModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().BuildAsync(new());
await context.Tools.DotNet.BuildAsync(new());
return "built";
}
}
Expand All @@ -169,7 +169,7 @@ public class TestModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().TestAsync(new());
await context.Tools.DotNet.TestAsync(new());
return "tested";
}
}
Expand Down
14 changes: 7 additions & 7 deletions docs/docs/distributed/github-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public class RestoreModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().RestoreAsync(new());
await context.Tools.DotNet.RestoreAsync(new());
return "restored";
}
}
Expand All @@ -125,8 +125,8 @@ public class LinuxBuildModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().BuildAsync(new());
await context.DotNet().TestAsync(new());
await context.Tools.DotNet.BuildAsync(new());
await context.Tools.DotNet.TestAsync(new());
return "linux-ok";
}
}
Expand All @@ -138,8 +138,8 @@ public class WindowsBuildModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().BuildAsync(new());
await context.DotNet().TestAsync(new());
await context.Tools.DotNet.BuildAsync(new());
await context.Tools.DotNet.TestAsync(new());
return "windows-ok";
}
}
Expand All @@ -151,8 +151,8 @@ public class MacBuildModule : Module<string>
protected override async Task<string?> ExecuteAsync(
IModuleContext context, CancellationToken cancellationToken)
{
await context.DotNet().BuildAsync(new());
await context.DotNet().TestAsync(new());
await context.Tools.DotNet.BuildAsync(new());
await context.Tools.DotNet.TestAsync(new());
return "macos-ok";
}
}
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/examples/azure-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ProvisionUserAssignedIdentityModule : Module<UserAssignedIdentityRe
{
protected override async Task<UserAssignedIdentityResource?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
var userAssignedIdentityProvisionResponse = await context.Azure().Provisioner.Security.UserAssignedIdentity(
var userAssignedIdentityProvisionResponse = await context.Tools.Azure.Provisioner.Security.UserAssignedIdentity(
new AzureResourceIdentifier("MySubscription", "MyResourceGroup", "MyUserIdentity"),
new UserAssignedIdentityData(AzureLocation.UKSouth)
);
Expand All @@ -37,7 +37,7 @@ public class ProvisionBlobStorageAccountModule : Module<StorageAccountResource>
{
protected override async Task<StorageAccountResource?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
var blobStorageAccountProvisionResponse = await context.Azure().Provisioner.Storage.StorageAccount(
var blobStorageAccountProvisionResponse = await context.Tools.Azure.Provisioner.Storage.StorageAccount(
new AzureResourceIdentifier("MySubscription", "MyResourceGroup", "MyStorage"),
new StorageAccountCreateOrUpdateContent(new StorageSku(StorageSkuName.StandardGrs), StorageKind.BlobStorage, AzureLocation.UKSouth)
);
Expand All @@ -57,7 +57,7 @@ public class ProvisionBlobStorageContainerModule : Module<BlobContainerResource>
{
var blobStorageAccount = await context.GetModule<ProvisionBlobStorageAccountModule>();

var blobContainerProvisionResponse = await context.Azure().Provisioner.Storage.BlobContainer(
var blobContainerProvisionResponse = await context.Tools.Azure.Provisioner.Storage.BlobContainer(
blobStorageAccount.ValueOrDefault!.Id,
"MyContainer",
new BlobContainerData()
Expand All @@ -81,7 +81,7 @@ public class AssignAccessToBlobStorageModule : Module<RoleAssignmentResource>

var storageAccount = await context.GetModule<ProvisionBlobStorageAccountModule>();

var roleAssignmentResource = await context.Azure().Provisioner.Security.RoleAssignment(
var roleAssignmentResource = await context.Tools.Azure.Provisioner.Security.RoleAssignment(
storageAccount.ValueOrDefault!.Id,
new RoleAssignmentCreateOrUpdateContent(WellKnownRoleDefinitions.BlobStorageOwnerDefinitionId, userAssignedIdentity.ValueOrDefault!.Data.PrincipalId!.Value)
);
Expand All @@ -106,7 +106,7 @@ public class ProvisionAzureFunction : Module<WebSiteResource>
var storageAccount = await context.GetModule<ProvisionBlobStorageAccountModule>();
var blobContainer = await context.GetModule<ProvisionBlobStorageContainerModule>();

var functionProvisionResponse = await context.Azure().Provisioner.Compute.WebSite(
var functionProvisionResponse = await context.Tools.Azure.Provisioner.Compute.WebSite(
new AzureResourceIdentifier("MySubscription", "MyResourceGroup", "MyFunction"),
new WebSiteData(AzureLocation.UKSouth)
{
Expand Down
12 changes: 6 additions & 6 deletions docs/docs/examples/dotnet-test-build-publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class NugetVersionGeneratorModule : Module<string>
{
protected override async Task<string?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
var gitVersionInformation = await context.Git().Versioning.GetGitVersioningInformation();
var gitVersionInformation = await context.Tools.Git.Versioning.GetGitVersioningInformation();
return gitVersionInformation.FullSemVer;
}
}
Expand All @@ -28,7 +28,7 @@ public class PackProjectsModule : Module<CommandResult[]>
{
var packageVersion = await context.GetModule<NugetVersionGeneratorModule>();

var repositoryInfo = await context.Git().Information.GetInfoAsync()
var repositoryInfo = await context.Tools.Git.Information.GetInfoAsync()
?? throw new InvalidOperationException("Git repository information is unavailable.");
var projects = repositoryInfo.Root
.GetFiles(x =>
Expand All @@ -37,7 +37,7 @@ public class PackProjectsModule : Module<CommandResult[]>

return await projects
.ToAsyncProcessorBuilder()
.SelectAsync(async projectFile => await context.DotNet().PackAsync(new DotNetPackOptions
.SelectAsync(async projectFile => await context.Tools.DotNet.PackAsync(new DotNetPackOptions
{
TargetPath = projectFile.Path,
IncludeSource = true,
Expand All @@ -61,13 +61,13 @@ public class RunUnitTestsModule : Module<DotNetTestResult[]>
{
protected override async Task<DotNetTestResult[]?> ExecuteAsync(IModuleContext context, CancellationToken cancellationToken)
{
var repositoryInfo = await context.Git().Information.GetInfoAsync()
var repositoryInfo = await context.Tools.Git.Information.GetInfoAsync()
?? throw new InvalidOperationException("Git repository information is unavailable.");
return await repositoryInfo.Root
.GetFiles(file => file.Path.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)
&& file.Path.Contains("UnitTests", StringComparison.OrdinalIgnoreCase))
.ToAsyncProcessorBuilder()
.SelectAsync(async unitTestProjectFile => await context.DotNet().TestAsync(new DotNetTestOptions
.SelectAsync(async unitTestProjectFile => await context.Tools.DotNet.TestAsync(new DotNetTestOptions
{
TargetPath = unitTestProjectFile.Path,
Collect = "XPlat Code Coverage",
Expand Down Expand Up @@ -96,7 +96,7 @@ public class UploadPackagesToNugetModule : Module<CommandResult[]>
{
ArgumentNullException.ThrowIfNull(_nugetSettings.Value.ApiKey);

var repositoryInfo = await context.Git().Information.GetInfoAsync()
var repositoryInfo = await context.Tools.Git.Information.GetInfoAsync()
?? throw new InvalidOperationException("Git repository information is unavailable.");
var packages = repositoryInfo.Root
.GetFiles(x =>
Expand Down
17 changes: 17 additions & 0 deletions docs/docs/fundamentals.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ The building blocks of your pipelines are called Modules. Modules can be as big

Modules can retrieve other modules and access information from them.

## Tool Integrations

Installed tool integrations are available from the discoverable `context.Tools` surface:

```csharp
await context.Tools.DotNet.BuildAsync(new DotNetBuildOptions
{
ProjectSolution = "MyApp.sln"
}, cancellationToken: cancellationToken);
```

`context.Tools.DotNet` is the canonical C# 14 API and does not require an integration
extension namespace import. The older `context.DotNet()` extension method remains available
as a compatibility fallback for projects using an earlier C# language version. When a project
declares an integration accessor in its own compilation, source-generator warning `MPG0008`
identifies that fallback on earlier language versions.

## Strong Typing

Modules are strongly typed, so we can return clear, concrete objects, and other modules have direct access to those strong objects, without any need for casting or guessing the type, or guessing keys from a dictionary.
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/how-to/generate-private-cli-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ or `GetType`, because instance-member lookup would hide the generated property.
`context.Tools.*` is the preferred discoverable API; the original extension method remains
available for compatibility. Generated tool properties use C# 14 extension members. On
older language versions, registration metadata still generates and `MPG0008` explains why
the optional `Tools` property was skipped.
the optional `Tools` property was skipped and names the `context.X()` compatibility accessor.

Referencing the `ModularPipelines` package includes the source generator as an analyzer.
The generator emits immutable assembly registration metadata, which each pipeline consumes
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/how-to/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ When you execute CLI commands (e.g., `dotnet build`, `docker run`), ModularPipel
### Per-Command Configuration

```csharp
await context.DotNet().BuildAsync(
await context.Tools.DotNet.BuildAsync(
new DotNetBuildOptions { Configuration = "Release" },
new CommandExecutionOptions
{
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/how-to/source-generator-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ accessible and non-generic. Until fixed, Modular Pipelines uses runtime reflecti

A tool accessor cannot generate a discoverable `context.Tools` property because
the consuming project uses a language version older than C# 14. Registration
metadata still generates. Use C# 14 or preview to enable the property.
metadata still generates. Use C# 14 or preview to enable the property, or use
the diagnostic's `context.X()` compatibility accessor.

**Severity:** Warning

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/how-to/sub-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class PackProjectsModule : Module<CommandResult[]>
{
var packageVersion = await context.GetModule<NugetVersionGeneratorModule>();

var repositoryInfo = await context.Git().Information.GetInfoAsync()
var repositoryInfo = await context.Tools.Git.Information.GetInfoAsync()
?? throw new InvalidOperationException("Git repository information is unavailable.");
var projects = repositoryInfo.Root
.GetFiles(x =>
Expand All @@ -40,7 +40,7 @@ public class PackProjectsModule : Module<CommandResult[]>
{
foreach (var project in projects)
{
yield return await context.SubModule(project.Name, () => context.DotNet().PackAsync(new DotNetPackOptions
yield return await context.SubModule(project.Name, () => context.Tools.DotNet.PackAsync(new DotNetPackOptions
{
TargetPath = project,
Configuration = Configuration.Release,
Expand Down
3 changes: 1 addition & 2 deletions docs/docs/mp-packages/ansible.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ The `ansible` executable must be installed and available on `PATH` when the pipe
## Run an ad-hoc command

```csharp
using ModularPipelines.Ansible.Extensions;
using ModularPipelines.Ansible.Options;

var result = await context.Ansible().ExecuteAsync(
var result = await context.Tools.Ansible.ExecuteAsync(
new AnsibleExecuteOptions("webservers")
{
Inventory = ["hosts.ini"],
Expand Down
5 changes: 2 additions & 3 deletions docs/docs/mp-packages/argocd.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ The `argocd` executable must be installed and available on `PATH` when the pipel

```csharp
using ModularPipelines.ArgoCd.Enums;
using ModularPipelines.ArgoCd.Extensions;
using ModularPipelines.ArgoCd.Options;

var result = await context.ArgoCd().App.GetAsync(
var result = await context.Tools.ArgoCd.App.GetAsync(
new ArgoCdAppGetOptions("guestbook")
{
AppNamespace = "argocd",
Expand All @@ -42,7 +41,7 @@ argocd app get guestbook --app-namespace=argocd --output=json --refresh
## Create ApplicationSets

```csharp
var result = await context.ArgoCd().ApplicationSet.CreateAsync(
var result = await context.Tools.ArgoCd.ApplicationSet.CreateAsync(
new ArgoCdApplicationSetCreateOptions(["apps.yaml", "more-apps.yaml"])
{
DryRun = true,
Expand Down
7 changes: 3 additions & 4 deletions docs/docs/mp-packages/azure-pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,21 @@ dotnet add package ModularPipelines.Azure.Pipelines

## Context entry points

Import `ModularPipelines.Azure.Pipelines.Extensions`, then use this service from a module:
Use the discoverable `context.Tools` surface from a module:

- `context.AzurePipeline()`
- `context.Tools.AzurePipeline`

## Module example

```csharp
using ModularPipelines.Azure.Pipelines.Extensions;

public class UseAzurePipelineModule : SyncModule<None>
{
protected override None Execute(
IModuleContext context,
CancellationToken cancellationToken)
{
var azurePipeline = context.AzurePipeline();
var azurePipeline = context.Tools.AzurePipeline;

// Call the integration's strongly typed operations here.
context.Logger.LogInformation("AzurePipeline integration is ready");
Expand Down
9 changes: 4 additions & 5 deletions docs/docs/mp-packages/azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@ Required command-line tool: `az`. It must be installed and available on `PATH` w

## Context entry points

Import `ModularPipelines.Azure.Extensions`, then use these services from a module:
Use the discoverable `context.Tools` surface from a module:

- `context.Azure()`
- `context.Az()`
- `context.Tools.Azure`
- `context.Tools.Az`

## Module example

```csharp
using ModularPipelines.Context;
using ModularPipelines.Models;
using ModularPipelines.Modules;
using ModularPipelines.Azure.Extensions;
using ModularPipelines.Azure.Options;

public class UseAzureModule : Module<CommandResult>
Expand All @@ -36,7 +35,7 @@ public class UseAzureModule : Module<CommandResult>
IModuleContext context,
CancellationToken cancellationToken)
{
return await context.Az().Account.ListAsync(
return await context.Tools.Az.Account.ListAsync(
new AzAccountListOptions(),
cancellationToken: cancellationToken);
}
Expand Down
7 changes: 3 additions & 4 deletions docs/docs/mp-packages/buildah.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,21 @@ Required command-line tool: `buildah`. It must be installed and available on `PA

## Context entry points

Import `ModularPipelines.Buildah.Extensions`, then use this service from a module:
Use the discoverable `context.Tools` surface from a module:

- `context.Buildah()`
- `context.Tools.Buildah`

## Module example

```csharp
using ModularPipelines.Buildah.Extensions;

public class UseBuildahModule : SyncModule<None>
{
protected override None Execute(
IModuleContext context,
CancellationToken cancellationToken)
{
var buildah = context.Buildah();
var buildah = context.Tools.Buildah;

// Call the integration's strongly typed operations here.
context.Logger.LogInformation("Buildah integration is ready");
Expand Down
Loading
Loading