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
4 changes: 3 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"esbenp.prettier-vscode",
"redhat.vscode-yaml",
"rust-lang.rust-analyzer",
"oven.bun-vscode"
"oven.bun-vscode",
"nihilus118.perl-debugger",
"bscan.perlnavigator"
]
}
},
Expand Down
5 changes: 5 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
sudo apt-get update && \
sudo apt upgrade -y && \
sudo apt-get install -y cpanminus protobuf-compiler libprotobuf-dev libprotoc-dev cmake g++ && \
sudo apt-get install -y dos2unix libsecret-1-0 xdg-utils libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libatspi2.0-0 libx11-6 libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 libgbm1 libxcb1 libxkbcommon0 libpango-1.0-0 libcairo2 libasound2 && \
sudo apt clean -y && \
sudo rm -rf /var/lib/apt/lists/*
Expand All @@ -22,4 +23,8 @@ curl -fsSL https://bun.sh/install | bash
echo Setting up dapr
dapr init

echo "Setting up perl dependencies for packages"
# Note: CPAN module names are Pascal case (e.g. Carton), but installed binaries are lowercase (e.g. carton).
sudo cpanm Carton --notest --force

echo Done!
5 changes: 5 additions & 0 deletions .github/actions/setup-runtimes-caching/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ runs:
with:
bun-version: latest

- name: Install cpanminus
if: runner.os == 'Linux'
shell: bash
run: sudo apt-get install -y cpanminus
Comment on lines +81 to +84
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will we be doing with Windows runners? Or are those tests not going to be run on Windows?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so, strawberry perl on windows comes with cpanm, which is a better package manager for CLI than the cpan.

So on Linux distros often you need to use cpan to install cpanm. That's what this is trying to do.

I was assuming the tests would run on both, and that on the Linux side we'd just sneak in cpanm before the tests run.

This is my first time using actions though so it may not be right.


- uses: actions/cache@v4
name: Cache NuGet packages
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
Hosting.Ngrok.Tests,
Hosting.Ollama.Tests,
Hosting.OpenTelemetryCollector.Tests,
Hosting.Perl.Tests,
Hosting.PapercutSmtp.Tests,
Hosting.PostgreSQL.Extensions.Tests,
Hosting.PowerShell.Tests,
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ nuget
target

node_modules
examples/perl/**/local/*
**cpanfile.snapshot
**/.modules/
**/*.AppHost.TypeScript/nuget.config
6 changes: 6 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,9 @@
/src/CommunityToolkit.Aspire.Hosting.PowerShell/ @oising
/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/ @oising
/examples/powershell/ @oising

# CommunityToolkit.Aspire.Hosting.Perl

/src/CommunityToolkit.Aspire.Hosting.Perl/ @Omnideth
/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/ @Omnideth
/examples/perl/ @Omnideth
5 changes: 5 additions & 0 deletions CommunityToolkit.Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@
<Project Path="examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.SendMailApi/CommunityToolkit.Aspire.Hosting.PapercutSmtp.SendMailApi.csproj" />
<Project Path="examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.ServiceDefaults/CommunityToolkit.Aspire.Hosting.PapercutSmtp.ServiceDefaults.csproj" />
</Folder>
<Folder Name="/examples/perl/">
<Project Path="examples/perl/cpanm-api-integration/CpanmApiIntegration.AppHost/CpanmApiIntegration.AppHost.csproj" />
</Folder>
<Folder Name="/examples/postgres-ext/">
<Project Path="examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.csproj" />
</Folder>
Expand Down Expand Up @@ -224,6 +227,7 @@
<Project Path="src/CommunityToolkit.Aspire.Hosting.Ollama/CommunityToolkit.Aspire.Hosting.Ollama.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PapercutSmtp/CommunityToolkit.Aspire.Hosting.PapercutSmtp.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Perl/CommunityToolkit.Aspire.Hosting.Perl.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PowerShell/CommunityToolkit.Aspire.Hosting.PowerShell.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Python.Extensions/CommunityToolkit.Aspire.Hosting.Python.Extensions.csproj" />
Expand Down Expand Up @@ -288,6 +292,7 @@
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/CommunityToolkit.Aspire.Hosting.Perl.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/CommunityToolkit.Aspire.Hosting.Rust.Tests.csproj" />
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This repository contains the source code for the Aspire Community Toolkit, a col
| - **Learn More**: [`Hosting.SqlDatabaseProjects`][sql-database-projects-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects][sql-database-projects-shields]][sql-database-projects-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects][sql-database-projects-shields-preview]][sql-database-projects-nuget-preview] | A hosting integration for the SQL Databases Projects. |
| - **Learn More**: [`Hosting.Rust`][rust-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Rust][rust-shields]][rust-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Rust][rust-shields-preview]][rust-nuget-preview] | A hosting integration for the Rust apps. |
| - **Learn More**: [`Hosting.Bun`][bun-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Bun][bun-shields]][bun-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Bun][bun-shields-preview]][bun-nuget-preview] | A hosting integration for the Bun apps. |
| - **Learn More**: [`Hosting.Perl`][perl-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Perl][perl-shields]][perl-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Perl][perl-shields-preview]][perl-nuget-preview] | A hosting integration for Perl scripts and APIs. |
| - **Learn More**: [`Hosting.Python.Extensions`][python-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Python.Extensions][python-ext-shields]][python-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Python.Extensions][python-ext-shields-preview]][python-ext-nuget-preview] | An integration that contains some additional extensions for running python applications |
| - **Learn More**: [`Hosting.KurrentDB`][kurrentdb-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.KurrentDB][kurrentdb-shields]][kurrentdb-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.KurrentDB][kurrentdb-shields-preview]][kurrentdb-nuget-preview] | An Aspire hosting integration leveraging the [KurrentDB](https://www.kurrent.io) container. |
| - **Learn More**: [`KurrentDB`][kurrentdb-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.KurrentDB][kurrentdb-client-shields]][kurrentdb-client-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.KurrentDB][kurrentdb-client-shields-preview]][kurrentdb-client-nuget-preview] | An Aspire client integration for the [KurrentDB](https://github.com/kurrent-io/KurrentDB-Client-Dotnet) package. |
Expand Down Expand Up @@ -153,6 +154,11 @@ This project is supported by the [.NET Foundation](https://dotnetfoundation.org)
[bun-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Bun/
[bun-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Bun?label=nuget%20(preview)
[bun-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Bun/absoluteLatest
[perl-integration-docs]: https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-perl
[perl-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Perl
[perl-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Perl/
[perl-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Perl?label=nuget%20(preview)
[perl-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Perl/absoluteLatest
[python-ext-integration-docs]: https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-python-extensions
[python-ext-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Python.Extensions
[python-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Python.Extensions/
Expand Down
28 changes: 26 additions & 2 deletions docs/diagnostics.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Aspire Community Toolkit Diagnostics

Some of the API's in the Aspire Community Toolkit are decorated with the [`ExperimentalAttrible`](https://learn.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute). This attribute is used to indicate that an API is not ready for production use and is subject to change in the future.
Some of the API's in the Aspire Community Toolkit are decorated with the [`ExperimentalAttribute`](https://learn.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute). This attribute is used to indicate that an API is not ready for production use and is subject to change in the future.

## CTASPIRE001

There are cases where there is an API provided by the Aspire Community Toolkit that is an intermidiary solution until a feature is added to Aspire itself. This could be a private API that is not yet ready for public consumption, or a workaround waiting for the completion of a feature in Aspire.
There are cases where there is an API provided by the Aspire Community Toolkit that is an intermediary solution until a feature is added to Aspire itself. This could be a private API that is not yet ready for public consumption, or a workaround waiting for the completion of a feature in Aspire.

In these cases, refer to the `<remarks>` docs section of the API for more information on the feature in Aspire and the issue(s) to track.

Expand All @@ -17,3 +17,27 @@ This API is marked as experimental as it does not have a stable implementation,
## CTASPIRE003

The API is marked for deprecation and will be removed in a future release.

## CTASPIREPERL001

This API is marked as experimental for the Perl hosting integration and may change or be removed in future updates.

Current usage:

- `WithPerlCertificateTrust(...)`

Suppress this diagnostic only when you intentionally opt into the experimental API surface.

## CTASPIREPERL002

Dockerfile generation for Perl resources is marked as experimental. The publish-mode Dockerfile
builder (`BuildCpanmDockerfile`, `BuildCartonDockerfile`, `BuildContainerEntrypointArguments`)
has not been fully validated across all deployment targets and may change in future releases.

Current usage:

- `BuildCpanmDockerfile(...)` - single-stage cpanm Dockerfile generation
- `BuildCartonDockerfile(...)` - multi-stage Carton Dockerfile generation
- `BuildContainerEntrypointArguments(...)` - container entrypoint argument construction

Suppress this diagnostic only when you intentionally opt into the experimental Dockerfile generation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
var builder = DistributedApplication.CreateBuilder(args);

var perlApi = builder.AddPerlApi("perl-api", ".", "../scripts/API.pl")
.WithCpanMinus()
.WithPackage("Mojolicious::Lite", force: true, skipTest: true)
.WithLocalLib("local") //to avoid 'sudo' applying to system perl.
.WithHttpEndpoint(name: "http", env: "PORT");

builder.AddPerlScript("perl-driver", "../scripts", "driver.pl")
.WithEnvironment("API_URL", perlApi.GetEndpoint("http"))
.WithReference(perlApi)
.WaitFor(perlApi);

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Aspire.AppHost.Sdk/13.2.0">

<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\CommunityToolkit.Aspire.Hosting.Perl\CommunityToolkit.Aspire.Hosting.Perl.csproj" IsAspireProjectResource="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17453;http://localhost:15453",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21453",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22453"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15453",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19453",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20453"
}
}
}
}
21 changes: 21 additions & 0 deletions examples/perl/cpanm-api-integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# cpanm-api-integration

Minimal Perl API example for integration tests using `cpanm` and `Mojolicious::Lite`.

## Project
- `CpanmApiIntegration.AppHost` (Aspire AppHost)

## Perl focus
- Uses `AddPerlApi(...)`
- Uses `WithCpanMinus()`
- Uses `WithPackage("Mojolicious::Lite")`
- Uses HTTP endpoint wiring with `PORT`
- No HTTPS and no OpenTelemetry setup

## Endpoint
- `/`

## Run
```powershell
aspire run
```
15 changes: 15 additions & 0 deletions examples/perl/cpanm-api-integration/scripts/API.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use Mojolicious::Lite -signatures;

my $port = $ENV{PORT} // 3000;

my @listeners = ("http://*:$port");

get '/' => sub ($c) {
$c->render(text => 'HEY!');
};

get '/fleeting' => sub ($c) {
$c->render(text => 'fragile');
};

app->start('daemon', map { ('-l', $_) } @listeners);
28 changes: 28 additions & 0 deletions examples/perl/cpanm-api-integration/scripts/driver.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use strict;
use warnings;
use HTTP::Tiny;

$| = 1; # autoflush stdout so prints appear in Aspire dashboard immediately

my $api_url = $ENV{API_URL};
die "API_URL environment variable is not set\n" unless defined $api_url && $api_url ne '';

# Strip trailing slash if present
$api_url =~ s{/\z}{};

my $target = "$api_url/fleeting";
my $http = HTTP::Tiny->new(timeout => 5);

print "Driver started — polling $target every 3 seconds...\n";

while (1) {
my $response = $http->get($target);

if ($response->{success}) {
print "[OK] $target => $response->{content}\n";
} else {
print "[ERR] $target => $response->{status} $response->{reason}\n";
}

sleep 3;
}
3 changes: 3 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"sdk": {
"allowPrerelease": true
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

/// <summary>
/// Records whether <c>carton install --deployment</c> should be used during publish-mode Dockerfile generation.
/// When <see langword="true"/>, Carton uses <c>--deployment</c> to install from a locked <c>cpanfile.snapshot</c>.
/// </summary>
/// <param name="useDeployment">Whether to pass <c>--deployment</c> to <c>carton install</c>.</param>
internal sealed class PerlCartonDeploymentAnnotation(bool useDeployment) : IResourceAnnotation
{
/// <summary>
/// Gets a value indicating whether <c>--deployment</c> should be used with <c>carton install</c>.
/// </summary>
public bool UseDeployment { get; } = useDeployment;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

/// <summary>
/// Marker annotation that prevents duplicate <c>WithPerlCertificateTrust</c> registrations.
/// </summary>
internal sealed class PerlCertificateTrustAnnotation : IResourceAnnotation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Aspire.Hosting.ApplicationModel;
using CommunityToolkit.Aspire.Hosting.Perl;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

/// <summary>
/// An annotation that stores the entrypoint type and path for a Perl application resource,
/// used to determine how the application is launched (e.g., as a script or via a framework runner).
/// </summary>
/// <see cref="EntrypointType"/>
internal class PerlEntrypointAnnotation : IResourceAnnotation
{
public required EntrypointType Type { get; set; }
public required string Entrypoint { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

internal sealed class PerlLocalLibAnnotation(string path) : IResourceAnnotation
{
public string Path { get; } = path;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

internal sealed class PerlLocalLibInstallerEnvironmentAnnotation : IResourceAnnotation
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

internal sealed class PerlLocalLibResourceEnvironmentAnnotation : IResourceAnnotation
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

/// <summary>
/// Links a <see cref="PerlAppResource"/> to its installer child resource.
/// This annotation tracks the <see cref="ExecutableResource"/> that performs the installation.
/// </summary>
/// <param name="installerResource">The child executable resource that runs the install command.</param>
internal sealed class PerlModuleInstallerAnnotation(ExecutableResource installerResource) : IResourceAnnotation
{
public ExecutableResource Resource { get; } = installerResource;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Perl.Annotations;

/// <summary>
/// Represents the annotation for the Perl package manager used in a resource.
/// </summary>
/// <param name="packageManager">The package manager to use for module installation.</param>
internal sealed class PerlPackageManagerAnnotation(PerlPackageManager packageManager) : IResourceAnnotation
{
/// <summary>
/// Gets the package manager variant.
/// </summary>
public PerlPackageManager PackageManager { get; } = packageManager;

/// <summary>
/// Gets the executable name used to invoke this package manager on the command line.
/// </summary>
public string ExecutableName => PackageManager.ToExecutableName();
}
Loading
Loading