-
Notifications
You must be signed in to change notification settings - Fork 163
Add polyglot exports for ActiveMQ #1176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
aec08d1
Add polyglot exports for activemq
IEvangelist 8f2b923
Address ActiveMQ polyglot feedback
IEvangelist 3b3cf01
Address polyglot follow-up feedback
IEvangelist e010b19
Migrate TypeScript apphost config for Aspire 13.2
IEvangelist 17be311
Refactor TypeScript apphost validation
IEvangelist 27b555d
Extend TypeScript apphost helper
IEvangelist a30502b
Update .github/actions/setup-runtimes-caching/action.yml
aaronpowell ab054bc
Update .github/actions/setup-runtimes-caching/action.yml
aaronpowell 8573b17
Update .github/actions/setup-runtimes-caching/action.yml
aaronpowell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,3 +19,5 @@ nuget | |
| target | ||
|
|
||
| node_modules | ||
| **/.modules/ | ||
| **/*.AppHost.TypeScript/nuget.config | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| #!/usr/bin/env pwsh | ||
|
|
||
| param( | ||
| [Parameter(Mandatory = $true)] | ||
| [string]$AppHostPath, | ||
|
|
||
| [Parameter(Mandatory = $true)] | ||
| [string]$PackageProjectPath, | ||
|
|
||
| [Parameter(Mandatory = $true)] | ||
| [string]$PackageName, | ||
|
|
||
| [Parameter(Mandatory = $true)] | ||
| [string[]]$WaitForResources, | ||
|
|
||
| [string[]]$RequiredCommands = @(), | ||
|
|
||
| [string]$PackageVersion = "", | ||
|
|
||
| [ValidateSet("healthy", "up", "down")] | ||
| [string]$WaitStatus = "healthy", | ||
|
|
||
| [int]$WaitTimeoutSeconds = 180 | ||
| ) | ||
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| function Invoke-ExternalCommand { | ||
| param( | ||
| [Parameter(Mandatory = $true)] | ||
| [string]$FilePath, | ||
|
|
||
| [Parameter(Mandatory = $true)] | ||
| [string[]]$Arguments | ||
| ) | ||
|
|
||
| & $FilePath @Arguments | ||
| if ($LASTEXITCODE -ne 0) { | ||
| $joinedArguments = [string]::Join(" ", $Arguments) | ||
| throw "Command failed with exit code ${LASTEXITCODE}: $FilePath $joinedArguments" | ||
| } | ||
| } | ||
|
|
||
| function Invoke-CleanupStep { | ||
| param( | ||
| [Parameter(Mandatory = $true)] | ||
| [string]$Description, | ||
|
|
||
| [Parameter(Mandatory = $true)] | ||
| [scriptblock]$Action, | ||
|
|
||
| [System.Collections.Generic.List[string]]$Failures = $null | ||
| ) | ||
|
|
||
| try { | ||
| & $Action | ||
| } | ||
| catch { | ||
| $message = "Cleanup step '$Description' failed: $($_.Exception.Message)" | ||
| if ($null -ne $Failures) { | ||
| $Failures.Add($message) | ||
| return | ||
| } | ||
|
|
||
| throw $message | ||
| } | ||
| } | ||
|
|
||
| $resolvedAppHostPath = (Resolve-Path $AppHostPath).Path | ||
| $resolvedPackageProjectPath = (Resolve-Path $PackageProjectPath).Path | ||
| $appHostDirectory = Split-Path -Parent $resolvedAppHostPath | ||
| $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\\..")).Path | ||
| $configPath = Join-Path $appHostDirectory "aspire.config.json" | ||
| $nugetConfigPath = Join-Path $appHostDirectory "nuget.config" | ||
| $localSource = Join-Path ([System.IO.Path]::GetTempPath()) ("ct-polyglot-" + [Guid]::NewGuid().ToString("N")) | ||
| $originalConfig = $null | ||
| $appStarted = $false | ||
| $primaryError = $null | ||
| $cleanupFailures = [System.Collections.Generic.List[string]]::new() | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($PackageVersion)) { | ||
| $versionPrefix = (& dotnet msbuild $resolvedPackageProjectPath -nologo -v:q -getProperty:VersionPrefix).Trim() | ||
| if ([string]::IsNullOrWhiteSpace($versionPrefix)) { | ||
| throw "Could not determine the evaluated VersionPrefix for $resolvedPackageProjectPath." | ||
| } | ||
|
|
||
| $PackageVersion = "$versionPrefix-polyglot.local" | ||
| } | ||
|
|
||
| if ($WaitForResources.Count -eq 1) { | ||
| $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries -bor [System.StringSplitOptions]::TrimEntries | ||
| $WaitForResources = $WaitForResources[0].Split(",", $splitOptions) | ||
| } | ||
|
|
||
| if ($RequiredCommands.Count -eq 1) { | ||
| $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries -bor [System.StringSplitOptions]::TrimEntries | ||
| $RequiredCommands = $RequiredCommands[0].Split(",", $splitOptions) | ||
| } | ||
|
|
||
| foreach ($commandName in $RequiredCommands) { | ||
| if ($null -eq (Get-Command $commandName -ErrorAction SilentlyContinue)) { | ||
| throw "Required command '$commandName' was not found on PATH." | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| $originalConfig = Get-Content -Path $configPath -Raw | ||
| New-Item -ItemType Directory -Path $localSource -Force | Out-Null | ||
|
|
||
| Invoke-ExternalCommand "dotnet" @( | ||
| "pack", | ||
| $resolvedPackageProjectPath, | ||
| "-c", "Debug", | ||
| "-p:PackageVersion=$PackageVersion", | ||
| "-o", $localSource | ||
| ) | ||
|
|
||
| $config = $originalConfig | ConvertFrom-Json -AsHashtable | ||
| if ($null -eq $config["packages"]) { | ||
| $config["packages"] = [ordered]@{} | ||
| } | ||
|
|
||
| $config["packages"][$PackageName] = $PackageVersion | ||
| $config | ConvertTo-Json -Depth 10 | Set-Content -Path $configPath -NoNewline | ||
|
|
||
| @" | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <configuration> | ||
| <packageSources> | ||
| <add key="local-polyglot" value="$localSource" /> | ||
| </packageSources> | ||
| </configuration> | ||
| "@ | Set-Content -Path $nugetConfigPath -NoNewline | ||
|
|
||
| Push-Location $appHostDirectory | ||
| try { | ||
| Invoke-ExternalCommand "npm" @("ci") | ||
| Invoke-ExternalCommand "aspire" @( | ||
| "restore", | ||
| "--apphost", $resolvedAppHostPath, | ||
| "--non-interactive" | ||
| ) | ||
| Invoke-ExternalCommand "npx" @("tsc", "--noEmit") | ||
| } | ||
| finally { | ||
| Pop-Location | ||
| } | ||
|
|
||
| Invoke-ExternalCommand "aspire" @( | ||
| "start", | ||
| "--apphost", $resolvedAppHostPath, | ||
| "--isolated", | ||
| "--format", "Json", | ||
| "--non-interactive" | ||
| ) | ||
| $appStarted = $true | ||
|
|
||
| foreach ($resource in $WaitForResources) { | ||
| Invoke-ExternalCommand "aspire" @( | ||
| "wait", | ||
| $resource, | ||
| "--status", $WaitStatus, | ||
| "--apphost", $resolvedAppHostPath, | ||
| "--timeout", $WaitTimeoutSeconds | ||
| ) | ||
| } | ||
|
|
||
| Invoke-ExternalCommand "aspire" @( | ||
| "describe", | ||
| "--apphost", $resolvedAppHostPath, | ||
| "--format", "Json" | ||
| ) | ||
| } | ||
| catch { | ||
| $primaryError = $_ | ||
| } | ||
| finally { | ||
| Invoke-CleanupStep -Description "restore Aspire config" -Action { | ||
| if ($null -ne $originalConfig) { | ||
| Set-Content -Path $configPath -Value $originalConfig -NoNewline | ||
| } | ||
| } -Failures $cleanupFailures | ||
|
|
||
| Invoke-CleanupStep -Description "remove generated nuget.config" -Action { | ||
| if (Test-Path $nugetConfigPath) { | ||
| Remove-Item $nugetConfigPath -Force | ||
| } | ||
| } -Failures $cleanupFailures | ||
|
|
||
| Invoke-CleanupStep -Description "remove local package source" -Action { | ||
| if (Test-Path $localSource) { | ||
| Remove-Item $localSource -Recurse -Force | ||
| } | ||
| } -Failures $cleanupFailures | ||
|
|
||
| Invoke-CleanupStep -Description "stop Aspire app" -Action { | ||
| if ($appStarted) { | ||
| Invoke-ExternalCommand "aspire" @( | ||
| "stop", | ||
| "--apphost", $resolvedAppHostPath | ||
| ) | ||
| } | ||
| } -Failures $cleanupFailures | ||
| } | ||
|
|
||
| if ($cleanupFailures.Count -gt 0) { | ||
| $cleanupFailureMessage = "Cleanup failures:${Environment.NewLine}$($cleanupFailures -join [Environment]::NewLine)" | ||
| if ($null -ne $primaryError) { | ||
| Write-Error -Message $cleanupFailureMessage -ErrorAction Continue | ||
| } | ||
| else { | ||
| throw $cleanupFailureMessage | ||
| } | ||
| } | ||
|
|
||
| if ($null -ne $primaryError) { | ||
| throw $primaryError | ||
| } |
90 changes: 90 additions & 0 deletions
90
examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| import { mkdirSync, mkdtempSync } from 'node:fs'; | ||
| import { tmpdir } from 'node:os'; | ||
| import { join } from 'node:path'; | ||
| import { createBuilder } from './.modules/aspire.js'; | ||
|
|
||
| const builder = await createBuilder(); | ||
| const bindMountRoot = mkdtempSync(join(tmpdir(), 'activemq-polyglot-')); | ||
| const artemisDataPath = join(bindMountRoot, 'artemis-data'); | ||
| const artemisConfPath = join(bindMountRoot, 'artemis-conf'); | ||
|
|
||
| mkdirSync(artemisDataPath, { recursive: true }); | ||
| mkdirSync(artemisConfPath, { recursive: true }); | ||
|
|
||
| const mqPassword = await builder.addParameterWithValue("mq-password", "admin", { | ||
| secret: true | ||
| }); | ||
| const mqUser = await builder.addParameterWithValue("mq-user", "admin", { | ||
| publishValueAsDefault: true | ||
| }); | ||
|
|
||
| // addActiveMQ — ActiveMQ Classic with all parameters | ||
| const classic = await builder.addActiveMQ("classic", { | ||
| userName: mqUser, | ||
| password: mqPassword, | ||
| port: 36161, | ||
| scheme: "activemq", | ||
| webPort: 38161 | ||
| }); | ||
|
|
||
| // addActiveMQ — minimal overloads with explicit credentials for repeatable startup | ||
| const classic2 = await builder.addActiveMQ("classic2", { | ||
| userName: mqUser, | ||
| password: mqPassword | ||
| }); | ||
|
|
||
| // addActiveMQArtemis — Artemis with all parameters | ||
| const artemis = await builder.addActiveMQArtemis("artemis", { | ||
| userName: mqUser, | ||
| password: mqPassword, | ||
| port: 36162, | ||
| scheme: "tcp", | ||
| webPort: 38162 | ||
| }); | ||
|
|
||
| // addActiveMQArtemis — minimal overloads with explicit credentials for repeatable startup | ||
| const artemis2 = await builder.addActiveMQArtemis("artemis2", { | ||
| userName: mqUser, | ||
| password: mqPassword | ||
| }); | ||
|
|
||
| // withDataVolume — fluent chaining on Classic | ||
| await classic.withDataVolume({ name: "classic-data" }); | ||
|
|
||
| // withConfVolume — fluent chaining on Classic | ||
| await classic.withConfVolume({ name: "classic-conf" }); | ||
|
|
||
| // withDataBindMount — bind mount on Artemis | ||
| await artemis.withDataBindMount(artemisDataPath); | ||
|
|
||
| // withConfBindMount — bind mount on Artemis | ||
| await artemis.withConfBindMount(artemisConfPath); | ||
|
|
||
| // withDataVolume + withConfVolume — chaining on Artemis | ||
| await artemis2.withDataVolume(); | ||
| await artemis2.withConfVolume(); | ||
|
|
||
| // ---- Property access on ActiveMQServerResourceBase (ExposeProperties = true) ---- | ||
| const classicResource = await classic; | ||
| const _classicEndpoint = await classicResource.primaryEndpoint.get(); | ||
| const _classicHost = await classicResource.host.get(); | ||
| const _classicPort = await classicResource.port.get(); | ||
| const _classicUri = await classicResource.uriExpression.get(); | ||
| const _classicCstr = await classicResource.connectionStringExpression.get(); | ||
|
|
||
| const classic2Resource = await classic2; | ||
| const _classic2Host = await classic2Resource.host.get(); | ||
| const _classic2Port = await classic2Resource.port.get(); | ||
|
|
||
| const artemisResource = await artemis; | ||
| const _artemisEndpoint = await artemisResource.primaryEndpoint.get(); | ||
| const _artemisHost = await artemisResource.host.get(); | ||
| const _artemisPort = await artemisResource.port.get(); | ||
| const _artemisUri = await artemisResource.uriExpression.get(); | ||
| const _artemisCstr = await artemisResource.connectionStringExpression.get(); | ||
|
|
||
| const artemis2Resource = await artemis2; | ||
| const _artemis2Host = await artemis2Resource.host.get(); | ||
| const _artemis2Port = await artemis2Resource.port.get(); | ||
|
|
||
| await builder.build().run(); |
18 changes: 18 additions & 0 deletions
18
...s/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/aspire.config.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "appHost": { | ||
| "path": "apphost.ts", | ||
| "language": "typescript/nodejs" | ||
| }, | ||
| "profiles": { | ||
| "https": { | ||
| "applicationUrl": "https://localhost:29750;http://localhost:28931", | ||
| "environmentVariables": { | ||
| "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10975", | ||
| "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13319" | ||
| } | ||
| } | ||
| }, | ||
| "packages": { | ||
| "CommunityToolkit.Aspire.Hosting.ActiveMQ": "" | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.