From aec08d16258d3ad3dc6dba49be532b7a7d901948 Mon Sep 17 00:00:00 2001 From: David Pine Date: Wed, 18 Mar 2026 10:00:55 -0500 Subject: [PATCH 1/9] Add polyglot exports for activemq Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitignore | 7 + .../ValidationAppHost/.aspire/settings.json | 7 + .../ValidationAppHost/apphost.run.json | 11 + .../ValidationAppHost/apphost.ts | 62 ++ .../ValidationAppHost/package-lock.json | 962 ++++++++++++++++++ .../ValidationAppHost/package.json | 19 + .../ValidationAppHost/tsconfig.json | 15 + .../ActiveMQBuilderExtensions.cs | 9 + .../ActiveMQServerResourceBase.cs | 5 + 9 files changed, 1097 insertions(+) create mode 100644 playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/.aspire/settings.json create mode 100644 playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.run.json create mode 100644 playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts create mode 100644 playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json create mode 100644 playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json create mode 100644 playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json diff --git a/.gitignore b/.gitignore index 959f23f3f..e99efb890 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,10 @@ nuget target node_modules + +# Playground +playground/**/dist/ +playground/**/.gitignore +playground/**/azure.yaml +playground/**/next-steps.md +!playground/polyglot/**/.aspire/ diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/.aspire/settings.json b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/.aspire/settings.json new file mode 100644 index 000000000..df765ed5c --- /dev/null +++ b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/.aspire/settings.json @@ -0,0 +1,7 @@ +{ + "appHostPath": "../apphost.ts", + "language": "typescript/nodejs", + "packages": { + "CommunityToolkit.Aspire.Hosting.ActiveMQ": "" + } +} diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.run.json b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.run.json new file mode 100644 index 000000000..7ab9dec4c --- /dev/null +++ b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.run.json @@ -0,0 +1,11 @@ +{ + "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" + } + } + } +} diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts new file mode 100644 index 000000000..d9bee9618 --- /dev/null +++ b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts @@ -0,0 +1,62 @@ +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// addActiveMQ — ActiveMQ Classic with all parameters +const mqPassword = await builder.addParameter("mq-password", { secret: true }); +const mqUser = await builder.addParameter("mq-user"); +const classic = await builder.addActiveMQ("classic", { + userName: mqUser, + password: mqPassword, + port: 61616, + scheme: "tcp", + webPort: 8161 +}); + +// addActiveMQ — minimal overload (defaults) +const classic2 = await builder.addActiveMQ("classic2"); + +// addActiveMQArtemis — Artemis with all parameters +const artemis = await builder.addActiveMQArtemis("artemis", { + userName: mqUser, + password: mqPassword, + port: 61617, + scheme: "tcp", + webPort: 8162 +}); + +// addActiveMQArtemis — minimal overload (defaults) +const artemis2 = await builder.addActiveMQArtemis("artemis2"); + +// 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("/tmp/artemis-data"); + +// withConfBindMount — bind mount on Artemis +await artemis.withConfBindMount("/tmp/artemis-conf"); + +// 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 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(); + +await builder.build().run(); diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json new file mode 100644 index 000000000..67af33374 --- /dev/null +++ b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json @@ -0,0 +1,962 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "validationapphost", + "version": "1.0.0", + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + } + } +} diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json new file mode 100644 index 000000000..54f1c98e3 --- /dev/null +++ b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json @@ -0,0 +1,19 @@ +{ + "name": "validationapphost", + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "aspire run", + "build": "tsc", + "dev": "tsc --watch" + }, + "dependencies": { + "vscode-jsonrpc": "^8.2.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "nodemon": "^3.1.11", + "tsx": "^4.19.0", + "typescript": "^5.3.0" + } +} diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json new file mode 100644 index 000000000..e8c2d93b8 --- /dev/null +++ b/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "." + }, + "include": ["apphost.ts", ".modules/**/*.ts", ".modules/**/*.d.ts"], + "exclude": ["node_modules"] +} diff --git a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs index 3483045bc..56db1cecf 100644 --- a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs @@ -5,8 +5,11 @@ using Aspire.Hosting.Utils; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using System.Diagnostics.CodeAnalysis; using System.Text; +#pragma warning disable ASPIREATS001 // AspireExport is experimental + namespace Aspire.Hosting; /// @@ -28,6 +31,7 @@ public static class ActiveMQBuilderExtensions /// The scheme of the endpoint, e.g. tcp or activemq (for masstransit). Defaults to tcp. /// The host port that the underlying webconsole is bound to when running locally. /// A reference to the . + [AspireExport("addActiveMQ", Description = "Adds an ActiveMQ Classic container resource")] public static IResourceBuilder AddActiveMQ(this IDistributedApplicationBuilder builder, [ResourceName] string name, IResourceBuilder? userName = null, @@ -62,6 +66,7 @@ public static IResourceBuilder AddActiveMQ(this IDistrib /// The scheme of the endpoint, e.g. tcp or activemq (for masstransit). Defaults to tcp. /// The host port that the underlying webconsole is bound to when running locally. /// A reference to the . + [AspireExport("addActiveMQArtemis", Description = "Adds an ActiveMQ Artemis container resource")] public static IResourceBuilder AddActiveMQArtemis(this IDistributedApplicationBuilder builder, [ResourceName] string name, IResourceBuilder? userName = null, @@ -104,6 +109,7 @@ private static IResourceBuilder Build(this IDistributedApplicationBuilder /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withDataVolume", Description = "Adds a named volume for the data folder to an ActiveMQ container resource")] public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) where T : ActiveMQServerResourceBase => builder @@ -118,6 +124,7 @@ public static IResourceBuilder WithDataVolume(this IResourceBuilder bui /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A flag that indicates if this is a read-only volume. /// The . + [AspireExport("withConfVolume", Description = "Adds a named volume for the config folder to an ActiveMQ container resource")] public static IResourceBuilder WithConfVolume(this IResourceBuilder builder, string? name = null, bool isReadOnly = false) where T : ActiveMQServerResourceBase => builder @@ -132,6 +139,7 @@ public static IResourceBuilder WithConfVolume(this IResourceBuilder bui /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withDataBindMount", Description = "Adds a bind mount for the data folder to an ActiveMQ container resource")] public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) where T : ActiveMQServerResourceBase => builder.WithBindMount(source, builder.Resource.ActiveMqSettings.DataPath, isReadOnly); @@ -143,6 +151,7 @@ public static IResourceBuilder WithDataBindMount(this IResourceBuilder /// The source directory on the host to mount into the container. /// A flag that indicates if this is a read-only mount. /// The . + [AspireExport("withConfBindMount", Description = "Adds a bind mount for the conf folder to an ActiveMQ container resource")] public static IResourceBuilder WithConfBindMount(this IResourceBuilder builder, string source, bool isReadOnly = false) where T : ActiveMQServerResourceBase => builder.WithBindMount(source, builder.Resource.ActiveMqSettings.ConfPath, isReadOnly); diff --git a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs index bd4872cf4..a3b20b6c4 100644 --- a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs +++ b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs @@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +#pragma warning disable ASPIREATS001 // AspireExport is experimental + namespace Aspire.Hosting.ApplicationModel; /// @@ -12,6 +14,7 @@ namespace Aspire.Hosting.ApplicationModel; /// A parameter that contains the ActiveMQ server password. /// Scheme used in the connectionString (e.g. tcp or activemq, see MassTransit) /// Settings being used for ActiveMQ Classic or Artemis +[AspireExport(ExposeProperties = true)] public abstract class ActiveMQServerResourceBase(string name, ParameterResource? userName, ParameterResource password, string scheme, IActiveMQSettings settings) : ContainerResource(name), IResourceWithConnectionString, IResourceWithEnvironment { internal const string PrimaryEndpointName = "tcp"; @@ -53,6 +56,8 @@ public abstract class ActiveMQServerResourceBase(string name, ParameterResource? /// /// Gets the ActiveMQ settings. /// + /// This property is not available in polyglot app hosts. + [AspireExportIgnore(Reason = "IActiveMQSettings is an internal configuration type not compatible with ATS.")] public IActiveMQSettings ActiveMqSettings { get; } = settings; internal ReferenceExpression UserNameReference => From 8f2b923fa68e70f2e2a47b1ab0abd8dc4998b549 Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Wed, 25 Mar 2026 00:16:25 -0500 Subject: [PATCH 2/9] Address ActiveMQ polyglot feedback - move the TypeScript apphost into examples - add reusable TypeScript apphost validation coverage - fix the ActiveMQ export review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitignore | 9 +- eng/testing/validate-typescript-apphost.ps1 | 145 ++++++++++++++++++ .../.aspire/settings.json | 0 .../apphost.run.json | 0 .../apphost.ts | 54 +++++-- .../package-lock.json | 4 +- .../package.json | 6 +- .../tsconfig.json | 5 +- .../ActiveMQBuilderExtensions.cs | 4 +- .../ActiveMQServerResourceBase.cs | 4 +- .../TypeScriptAppHostTests.cs | 27 ++++ .../ProcessTestUtilities.cs | 67 ++++++++ 12 files changed, 296 insertions(+), 29 deletions(-) create mode 100644 eng/testing/validate-typescript-apphost.ps1 rename {playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost => examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript}/.aspire/settings.json (100%) rename {playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost => examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript}/apphost.run.json (100%) rename {playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost => examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript}/apphost.ts (52%) rename {playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost => examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript}/package-lock.json (99%) rename {playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost => examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript}/package.json (57%) rename {playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost => examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript}/tsconfig.json (81%) create mode 100644 tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs create mode 100644 tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs diff --git a/.gitignore b/.gitignore index e99efb890..f442955ab 100644 --- a/.gitignore +++ b/.gitignore @@ -19,10 +19,5 @@ nuget target node_modules - -# Playground -playground/**/dist/ -playground/**/.gitignore -playground/**/azure.yaml -playground/**/next-steps.md -!playground/polyglot/**/.aspire/ +**/.modules/ +**/aspire.config.json diff --git a/eng/testing/validate-typescript-apphost.ps1 b/eng/testing/validate-typescript-apphost.ps1 new file mode 100644 index 000000000..815dfa3bb --- /dev/null +++ b/eng/testing/validate-typescript-apphost.ps1 @@ -0,0 +1,145 @@ +#!/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]$PackageVersion = "", + + [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" + } +} + +$resolvedAppHostPath = (Resolve-Path $AppHostPath).Path +$resolvedPackageProjectPath = (Resolve-Path $PackageProjectPath).Path +$appHostDirectory = Split-Path -Parent $resolvedAppHostPath +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\\..")).Path +$settingsPath = Join-Path $appHostDirectory ".aspire\\settings.json" +$nugetConfigPath = Join-Path $appHostDirectory "nuget.config" +$localSource = Join-Path ([System.IO.Path]::GetTempPath()) ("ct-polyglot-" + [Guid]::NewGuid().ToString("N")) +$originalSettings = $null +$appStarted = $false + +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) +} + +try { + $originalSettings = Get-Content -Path $settingsPath -Raw + New-Item -ItemType Directory -Path $localSource -Force | Out-Null + + Invoke-ExternalCommand "dotnet" @( + "pack", + $resolvedPackageProjectPath, + "-c", "Debug", + "-p:PackageVersion=$PackageVersion", + "-o", $localSource + ) + + $settings = $originalSettings | ConvertFrom-Json + $settings.packages.$PackageName = $PackageVersion + $settings | ConvertTo-Json -Depth 10 | Set-Content -Path $settingsPath -NoNewline + + @" + + + + + + +"@ | 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, + "--apphost", $resolvedAppHostPath, + "--timeout", $WaitTimeoutSeconds + ) + } + + Invoke-ExternalCommand "aspire" @( + "describe", + "--apphost", $resolvedAppHostPath, + "--format", "Json" + ) +} +finally { + if ($null -ne $originalSettings) { + Set-Content -Path $settingsPath -Value $originalSettings -NoNewline + } + + if (Test-Path $nugetConfigPath) { + Remove-Item $nugetConfigPath -Force + } + + if (Test-Path $localSource) { + Remove-Item $localSource -Recurse -Force + } + + if ($appStarted) { + Invoke-ExternalCommand "aspire" @( + "stop", + "--apphost", $resolvedAppHostPath + ) + } +} diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/.aspire/settings.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/.aspire/settings.json similarity index 100% rename from playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/.aspire/settings.json rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/.aspire/settings.json diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.run.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.run.json similarity index 100% rename from playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.run.json rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.run.json diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.ts similarity index 52% rename from playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.ts index d9bee9618..334110e13 100644 --- a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/apphost.ts +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.ts @@ -1,32 +1,52 @@ +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 mqPassword = await builder.addParameter("mq-password", { secret: true }); -const mqUser = await builder.addParameter("mq-user"); const classic = await builder.addActiveMQ("classic", { userName: mqUser, password: mqPassword, - port: 61616, - scheme: "tcp", - webPort: 8161 + port: 36161, + scheme: "activemq", + webPort: 38161 }); -// addActiveMQ — minimal overload (defaults) -const classic2 = await builder.addActiveMQ("classic2"); +// 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: 61617, + port: 36162, scheme: "tcp", - webPort: 8162 + webPort: 38162 }); -// addActiveMQArtemis — minimal overload (defaults) -const artemis2 = await builder.addActiveMQArtemis("artemis2"); +// 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" }); @@ -35,10 +55,10 @@ await classic.withDataVolume({ name: "classic-data" }); await classic.withConfVolume({ name: "classic-conf" }); // withDataBindMount — bind mount on Artemis -await artemis.withDataBindMount("/tmp/artemis-data"); +await artemis.withDataBindMount(artemisDataPath); // withConfBindMount — bind mount on Artemis -await artemis.withConfBindMount("/tmp/artemis-conf"); +await artemis.withConfBindMount(artemisConfPath); // withDataVolume + withConfVolume — chaining on Artemis await artemis2.withDataVolume(); @@ -52,6 +72,10 @@ 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(); @@ -59,4 +83,8 @@ 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(); diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/package-lock.json similarity index 99% rename from playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/package-lock.json index 67af33374..046aa2f76 100644 --- a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package-lock.json +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/package-lock.json @@ -1,11 +1,11 @@ { - "name": "validationapphost", + "name": "communitytoolkit-aspire-hosting-activemq-apphost-typescript", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "validationapphost", + "name": "communitytoolkit-aspire-hosting-activemq-apphost-typescript", "version": "1.0.0", "dependencies": { "vscode-jsonrpc": "^8.2.0" diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/package.json similarity index 57% rename from playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/package.json index 54f1c98e3..354efc32b 100644 --- a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/package.json +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/package.json @@ -1,10 +1,12 @@ { - "name": "validationapphost", + "name": "communitytoolkit-aspire-hosting-activemq-apphost-typescript", "version": "1.0.0", "type": "module", "scripts": { - "start": "aspire run", "build": "tsc", + "start": "aspire start --apphost apphost.ts", + "stop": "aspire stop --apphost apphost.ts", + "validate": "npm ci && npx tsc --noEmit", "dev": "tsc --watch" }, "dependencies": { diff --git a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/tsconfig.json similarity index 81% rename from playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/tsconfig.json index e8c2d93b8..9cf99bb13 100644 --- a/playground/polyglot/TypeScript/CommunityToolkit.Aspire.Hosting.ActiveMQ/ValidationAppHost/tsconfig.json +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/tsconfig.json @@ -5,10 +5,9 @@ "moduleResolution": "NodeNext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, + "noEmit": true, "strict": true, - "skipLibCheck": true, - "outDir": "./dist", - "rootDir": "." + "skipLibCheck": true }, "include": ["apphost.ts", ".modules/**/*.ts", ".modules/**/*.d.ts"], "exclude": ["node_modules"] diff --git a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs index 56db1cecf..8d0bf8308 100644 --- a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQBuilderExtensions.cs @@ -5,7 +5,6 @@ using Aspire.Hosting.Utils; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using System.Diagnostics.CodeAnalysis; using System.Text; #pragma warning disable ASPIREATS001 // AspireExport is experimental @@ -75,6 +74,7 @@ public static IResourceBuilder AddActiveMQArtemis string scheme = "tcp", int? webPort = null) { + ArgumentNullException.ThrowIfNull(builder, nameof(builder)); ArgumentNullException.ThrowIfNull(name, nameof(name)); ArgumentNullException.ThrowIfNull(scheme, nameof(scheme)); @@ -223,3 +223,5 @@ private static IResourceBuilder WithJolokiaHealthCheck( return builder; } } + +#pragma warning restore ASPIREATS001 diff --git a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs index a3b20b6c4..ec4c7d567 100644 --- a/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs +++ b/src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ActiveMQServerResourceBase.cs @@ -84,4 +84,6 @@ IEnumerable> IResourceWithConnectionSt private static T ThrowIfNull([NotNull] T? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) => argument ?? throw new ArgumentNullException(paramName); -} \ No newline at end of file +} + +#pragma warning restore ASPIREATS001 diff --git a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs new file mode 100644 index 000000000..6f3979e76 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs @@ -0,0 +1,27 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests; + +[RequiresDocker] +public class TypeScriptAppHostTests +{ + [Fact] + public async Task TypeScriptAppHostCompilesAndStarts() + { + string repoRoot = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..")); + string scriptPath = Path.Combine(repoRoot, "eng", "testing", "validate-typescript-apphost.ps1"); + string appHostPath = Path.Combine(repoRoot, "examples", "activemq", "CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript", "apphost.ts"); + string packageProjectPath = Path.Combine(repoRoot, "src", "CommunityToolkit.Aspire.Hosting.ActiveMQ", "CommunityToolkit.Aspire.Hosting.ActiveMQ.csproj"); + string shell = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh"; + + await ProcessTestUtilities.RunProcessAsync(shell, [ + "-NoLogo", + "-NoProfile", + "-File", scriptPath, + "-AppHostPath", appHostPath, + "-PackageProjectPath", packageProjectPath, + "-PackageName", "CommunityToolkit.Aspire.Hosting.ActiveMQ", + "-WaitForResources", "classic,classic2,artemis,artemis2" + ], repoRoot, TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs b/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs new file mode 100644 index 000000000..5704f26d5 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs @@ -0,0 +1,67 @@ +using System.Diagnostics; +using System.Text; +using Xunit.Sdk; + +namespace CommunityToolkit.Aspire.Testing; + +public static class ProcessTestUtilities +{ + public static async Task RunProcessAsync(string fileName, IEnumerable arguments, string workingDirectory, CancellationToken cancellationToken = default) + { + ProcessStartInfo startInfo = new(fileName) + { + RedirectStandardError = true, + RedirectStandardOutput = true, + UseShellExecute = false, + WorkingDirectory = workingDirectory + }; + + foreach (string argument in arguments) { + startInfo.ArgumentList.Add(argument); + } + + using Process process = new() + { + StartInfo = startInfo + }; + + StringBuilder standardOutput = new(); + StringBuilder standardError = new(); + process.OutputDataReceived += (_, args) => + { + if (args.Data is not null) + { + standardOutput.AppendLine(args.Data); + } + }; + process.ErrorDataReceived += (_, args) => + { + if (args.Data is not null) + { + standardError.AppendLine(args.Data); + } + }; + + if (!process.Start()) + { + throw new XunitException($"Failed to start process '{fileName}'."); + } + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + await process.WaitForExitAsync(cancellationToken); + + if (process.ExitCode != 0) + { + string joinedArguments = string.Join(" ", arguments.Select(QuoteArgument)); + throw new XunitException( + $"Command '{fileName} {joinedArguments}' failed with exit code {process.ExitCode}.{Environment.NewLine}" + + $"Standard output:{Environment.NewLine}{standardOutput}{Environment.NewLine}" + + $"Standard error:{Environment.NewLine}{standardError}"); + } + } + + private static string QuoteArgument(string argument) => + argument.Contains(' ', StringComparison.Ordinal) ? $"\"{argument}\"" : argument; +} From 3b3cf010ce7b1baceb8032f16915b528dc49ecee Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Wed, 25 Mar 2026 15:42:35 -0500 Subject: [PATCH 3/9] Address polyglot follow-up feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitignore | 1 + eng/testing/validate-typescript-apphost.ps1 | 70 ++++++++++++++++--- .../ProcessTestUtilities.cs | 1 + 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index f442955ab..3e9347d52 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ target node_modules **/.modules/ **/aspire.config.json +**/*.AppHost.TypeScript/nuget.config diff --git a/eng/testing/validate-typescript-apphost.ps1 b/eng/testing/validate-typescript-apphost.ps1 index 815dfa3bb..233a5f258 100644 --- a/eng/testing/validate-typescript-apphost.ps1 +++ b/eng/testing/validate-typescript-apphost.ps1 @@ -36,6 +36,31 @@ function Invoke-ExternalCommand { } } +function Invoke-CleanupStep { + param( + [Parameter(Mandatory = $true)] + [string]$Description, + + [Parameter(Mandatory = $true)] + [scriptblock]$Action, + + [System.Collections.Generic.List[string]]$Failures + ) + + 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 @@ -45,6 +70,8 @@ $nugetConfigPath = Join-Path $appHostDirectory "nuget.config" $localSource = Join-Path ([System.IO.Path]::GetTempPath()) ("ct-polyglot-" + [Guid]::NewGuid().ToString("N")) $originalSettings = $null $appStarted = $false +$cleanupFailures = [System.Collections.Generic.List[string]]::new() +$primaryError = $null if ([string]::IsNullOrWhiteSpace($PackageVersion)) { $versionPrefix = (& dotnet msbuild $resolvedPackageProjectPath -nologo -v:q -getProperty:VersionPrefix).Trim() @@ -123,23 +150,48 @@ try { "--format", "Json" ) } +catch { + $primaryError = $_ +} finally { if ($null -ne $originalSettings) { - Set-Content -Path $settingsPath -Value $originalSettings -NoNewline + Invoke-CleanupStep -Description "Restore .aspire\\settings.json" -Failures $cleanupFailures -Action { + Set-Content -Path $settingsPath -Value $originalSettings -NoNewline + } } - if (Test-Path $nugetConfigPath) { - Remove-Item $nugetConfigPath -Force + Invoke-CleanupStep -Description "Remove generated nuget.config" -Failures $cleanupFailures -Action { + if (Test-Path $nugetConfigPath) { + Remove-Item $nugetConfigPath -Force + } } - if (Test-Path $localSource) { - Remove-Item $localSource -Recurse -Force + Invoke-CleanupStep -Description "Remove local package source" -Failures $cleanupFailures -Action { + if (Test-Path $localSource) { + Remove-Item $localSource -Recurse -Force + } } if ($appStarted) { - Invoke-ExternalCommand "aspire" @( - "stop", - "--apphost", $resolvedAppHostPath - ) + Invoke-CleanupStep -Description "Stop Aspire app" -Failures $cleanupFailures -Action { + Invoke-ExternalCommand "aspire" @( + "stop", + "--apphost", $resolvedAppHostPath + ) + } + } +} + +if ($cleanupFailures.Count -gt 0) { + $cleanupFailureMessage = "Cleanup encountered the following issues:`n - " + ($cleanupFailures -join "`n - ") + if ($null -ne $primaryError) { + Write-Warning $cleanupFailureMessage + } + else { + throw $cleanupFailureMessage } } + +if ($null -ne $primaryError) { + throw $primaryError +} diff --git a/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs b/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs index 5704f26d5..473b545ec 100644 --- a/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs +++ b/tests/CommunityToolkit.Aspire.Testing/ProcessTestUtilities.cs @@ -51,6 +51,7 @@ public static async Task RunProcessAsync(string fileName, IEnumerable ar process.BeginErrorReadLine(); await process.WaitForExitAsync(cancellationToken); + process.WaitForExit(); if (process.ExitCode != 0) { From e010b19da08415bbe6efdaf83f253dc460d18ac8 Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Wed, 25 Mar 2026 18:30:39 -0500 Subject: [PATCH 4/9] Migrate TypeScript apphost config for Aspire 13.2 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitignore | 1 - eng/testing/validate-typescript-apphost.ps1 | 65 ++++++++++++------- .../.aspire/settings.json | 7 -- .../{apphost.run.json => aspire.config.json} | 9 ++- 4 files changed, 51 insertions(+), 31 deletions(-) delete mode 100644 examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/.aspire/settings.json rename examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/{apphost.run.json => aspire.config.json} (66%) diff --git a/.gitignore b/.gitignore index 3e9347d52..ccf1022b7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,4 @@ target node_modules **/.modules/ -**/aspire.config.json **/*.AppHost.TypeScript/nuget.config diff --git a/eng/testing/validate-typescript-apphost.ps1 b/eng/testing/validate-typescript-apphost.ps1 index 233a5f258..c38f57a2f 100644 --- a/eng/testing/validate-typescript-apphost.ps1 +++ b/eng/testing/validate-typescript-apphost.ps1 @@ -13,8 +13,13 @@ param( [Parameter(Mandatory = $true)] [string[]]$WaitForResources, + [string[]]$RequiredCommands = @(), + [string]$PackageVersion = "", + [ValidateSet("healthy", "up", "down")] + [string]$WaitStatus = "healthy", + [int]$WaitTimeoutSeconds = 180 ) @@ -44,7 +49,7 @@ function Invoke-CleanupStep { [Parameter(Mandatory = $true)] [scriptblock]$Action, - [System.Collections.Generic.List[string]]$Failures + [System.Collections.Generic.List[string]]$Failures = $null ) try { @@ -65,13 +70,13 @@ $resolvedAppHostPath = (Resolve-Path $AppHostPath).Path $resolvedPackageProjectPath = (Resolve-Path $PackageProjectPath).Path $appHostDirectory = Split-Path -Parent $resolvedAppHostPath $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\\..")).Path -$settingsPath = Join-Path $appHostDirectory ".aspire\\settings.json" +$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")) -$originalSettings = $null +$originalConfig = $null $appStarted = $false -$cleanupFailures = [System.Collections.Generic.List[string]]::new() $primaryError = $null +$cleanupFailures = [System.Collections.Generic.List[string]]::new() if ([string]::IsNullOrWhiteSpace($PackageVersion)) { $versionPrefix = (& dotnet msbuild $resolvedPackageProjectPath -nologo -v:q -getProperty:VersionPrefix).Trim() @@ -87,8 +92,19 @@ if ($WaitForResources.Count -eq 1) { $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 { - $originalSettings = Get-Content -Path $settingsPath -Raw + $originalConfig = Get-Content -Path $configPath -Raw New-Item -ItemType Directory -Path $localSource -Force | Out-Null Invoke-ExternalCommand "dotnet" @( @@ -99,9 +115,13 @@ try { "-o", $localSource ) - $settings = $originalSettings | ConvertFrom-Json - $settings.packages.$PackageName = $PackageVersion - $settings | ConvertTo-Json -Depth 10 | Set-Content -Path $settingsPath -NoNewline + $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 @" @@ -139,6 +159,7 @@ try { Invoke-ExternalCommand "aspire" @( "wait", $resource, + "--status", $WaitStatus, "--apphost", $resolvedAppHostPath, "--timeout", $WaitTimeoutSeconds ) @@ -154,38 +175,38 @@ catch { $primaryError = $_ } finally { - if ($null -ne $originalSettings) { - Invoke-CleanupStep -Description "Restore .aspire\\settings.json" -Failures $cleanupFailures -Action { - Set-Content -Path $settingsPath -Value $originalSettings -NoNewline + 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" -Failures $cleanupFailures -Action { + 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" -Failures $cleanupFailures -Action { + Invoke-CleanupStep -Description "remove local package source" -Action { if (Test-Path $localSource) { Remove-Item $localSource -Recurse -Force } - } + } -Failures $cleanupFailures - if ($appStarted) { - Invoke-CleanupStep -Description "Stop Aspire app" -Failures $cleanupFailures -Action { + Invoke-CleanupStep -Description "stop Aspire app" -Action { + if ($appStarted) { Invoke-ExternalCommand "aspire" @( "stop", "--apphost", $resolvedAppHostPath ) } - } + } -Failures $cleanupFailures } if ($cleanupFailures.Count -gt 0) { - $cleanupFailureMessage = "Cleanup encountered the following issues:`n - " + ($cleanupFailures -join "`n - ") + $cleanupFailureMessage = "Cleanup failures:${Environment.NewLine}$($cleanupFailures -join [Environment]::NewLine)" if ($null -ne $primaryError) { - Write-Warning $cleanupFailureMessage + Write-Error -Message $cleanupFailureMessage -ErrorAction Continue } else { throw $cleanupFailureMessage @@ -194,4 +215,4 @@ if ($cleanupFailures.Count -gt 0) { if ($null -ne $primaryError) { throw $primaryError -} +} \ No newline at end of file diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/.aspire/settings.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/.aspire/settings.json deleted file mode 100644 index df765ed5c..000000000 --- a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/.aspire/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "appHostPath": "../apphost.ts", - "language": "typescript/nodejs", - "packages": { - "CommunityToolkit.Aspire.Hosting.ActiveMQ": "" - } -} diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.run.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/aspire.config.json similarity index 66% rename from examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.run.json rename to examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/aspire.config.json index 7ab9dec4c..612bd8bf9 100644 --- a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/apphost.run.json +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript/aspire.config.json @@ -1,4 +1,8 @@ { + "appHost": { + "path": "apphost.ts", + "language": "typescript/nodejs" + }, "profiles": { "https": { "applicationUrl": "https://localhost:29750;http://localhost:28931", @@ -7,5 +11,8 @@ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13319" } } + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.ActiveMQ": "" } -} +} \ No newline at end of file From 17be3111c1b05100f93f17a468a34ebc62dcc8b1 Mon Sep 17 00:00:00 2001 From: David Pine Date: Thu, 26 Mar 2026 15:30:40 -0500 Subject: [PATCH 5/9] Refactor TypeScript apphost validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../actions/setup-runtimes-caching/action.yml | 13 +++- .../TypeScriptAppHostTests.cs | 21 ++---- .../TypeScriptAppHostTest.cs | 68 +++++++++++++++++++ 3 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index ac273c089..5c18c43f8 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -24,6 +24,18 @@ runs: 9.0.x 10.0.x + - name: Install Aspire CLI + shell: pwsh + run: | + $aspireVersion = '13.2.0' + Invoke-Expression "& { $(Invoke-RestMethod 'https://aspire.dev/install.ps1') } -Version '$aspireVersion'" + + $aspireToolPath = Join-Path (Join-Path $HOME '.aspire') 'bin' + Add-Content -Path $env:GITHUB_PATH -Value $aspireToolPath + $env:PATH = "$aspireToolPath$([IO.Path]::PathSeparator)$env:PATH" + + aspire --version + - name: Set up Python uses: actions/setup-python@v5 with: @@ -129,4 +141,3 @@ runs: if: ${{ inputs.name == 'Full' || contains(inputs.name, 'Hosting.Ollama') }} with: version: 0.11.8 - diff --git a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs index 6f3979e76..a1fc7ea45 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/TypeScriptAppHostTests.cs @@ -8,20 +8,11 @@ public class TypeScriptAppHostTests [Fact] public async Task TypeScriptAppHostCompilesAndStarts() { - string repoRoot = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..")); - string scriptPath = Path.Combine(repoRoot, "eng", "testing", "validate-typescript-apphost.ps1"); - string appHostPath = Path.Combine(repoRoot, "examples", "activemq", "CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript", "apphost.ts"); - string packageProjectPath = Path.Combine(repoRoot, "src", "CommunityToolkit.Aspire.Hosting.ActiveMQ", "CommunityToolkit.Aspire.Hosting.ActiveMQ.csproj"); - string shell = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh"; - - await ProcessTestUtilities.RunProcessAsync(shell, [ - "-NoLogo", - "-NoProfile", - "-File", scriptPath, - "-AppHostPath", appHostPath, - "-PackageProjectPath", packageProjectPath, - "-PackageName", "CommunityToolkit.Aspire.Hosting.ActiveMQ", - "-WaitForResources", "classic,classic2,artemis,artemis2" - ], repoRoot, TestContext.Current.CancellationToken); + await TypeScriptAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.TypeScript", + packageName: "CommunityToolkit.Aspire.Hosting.ActiveMQ", + exampleName: "activemq", + waitForResources: ["classic", "classic2", "artemis", "artemis2"], + cancellationToken: TestContext.Current.CancellationToken); } } diff --git a/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs b/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs new file mode 100644 index 000000000..a4d47b31b --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs @@ -0,0 +1,68 @@ +namespace CommunityToolkit.Aspire.Testing; + +/// +/// Runs the shared TypeScript AppHost validation flow for example app hosts. +/// +public static class TypeScriptAppHostTest +{ + /// + /// Runs the TypeScript AppHost validation script for an example app host. + /// + /// The app host project directory name under the example folder. + /// The integration package name and project directory name. + /// The example folder name. + /// The resources that must reach the expected Aspire state. + /// Optional commands that must exist on PATH before validation runs. + /// The cancellation token. + public static async Task Run( + string appHostProject, + string packageName, + string exampleName, + IEnumerable waitForResources, + IEnumerable? requiredCommands = null, + CancellationToken cancellationToken = default) + { + ArgumentException.ThrowIfNullOrWhiteSpace(appHostProject); + ArgumentException.ThrowIfNullOrWhiteSpace(packageName); + ArgumentException.ThrowIfNullOrWhiteSpace(exampleName); + ArgumentNullException.ThrowIfNull(waitForResources); + + List resources = waitForResources + .Where(static resource => !string.IsNullOrWhiteSpace(resource)) + .ToList(); + + if (resources.Count == 0) + { + throw new ArgumentException("At least one resource name is required.", nameof(waitForResources)); + } + + List commands = requiredCommands? + .Where(static command => !string.IsNullOrWhiteSpace(command)) + .ToList() ?? []; + + string repoRoot = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..")); + string scriptPath = Path.Combine(repoRoot, "eng", "testing", "validate-typescript-apphost.ps1"); + string appHostPath = Path.Combine(repoRoot, "examples", exampleName, appHostProject, "apphost.ts"); + string packageProjectPath = Path.Combine(repoRoot, "src", packageName, $"{packageName}.csproj"); + string shell = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh"; + + List arguments = + [ + "-NoLogo", + "-NoProfile", + "-File", scriptPath, + "-AppHostPath", appHostPath, + "-PackageProjectPath", packageProjectPath, + "-PackageName", packageName, + "-WaitForResources", string.Join(',', resources) + ]; + + if (commands.Count > 0) + { + arguments.Add("-RequiredCommands"); + arguments.Add(string.Join(',', commands)); + } + + await ProcessTestUtilities.RunProcessAsync(shell, arguments, repoRoot, cancellationToken); + } +} From 27b555d6b8f414fd626c56e1d09c43f7c9c75ad1 Mon Sep 17 00:00:00 2001 From: David Pine Date: Thu, 26 Mar 2026 16:09:54 -0500 Subject: [PATCH 6/9] Extend TypeScript apphost helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../TypeScriptAppHostTest.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs b/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs index a4d47b31b..927eec71b 100644 --- a/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs +++ b/tests/CommunityToolkit.Aspire.Testing/TypeScriptAppHostTest.cs @@ -13,6 +13,7 @@ public static class TypeScriptAppHostTest /// The example folder name. /// The resources that must reach the expected Aspire state. /// Optional commands that must exist on PATH before validation runs. + /// Optional Aspire resource status to wait for. /// The cancellation token. public static async Task Run( string appHostProject, @@ -20,6 +21,7 @@ public static async Task Run( string exampleName, IEnumerable waitForResources, IEnumerable? requiredCommands = null, + string? waitStatus = null, CancellationToken cancellationToken = default) { ArgumentException.ThrowIfNullOrWhiteSpace(appHostProject); @@ -57,6 +59,12 @@ public static async Task Run( "-WaitForResources", string.Join(',', resources) ]; + if (!string.IsNullOrWhiteSpace(waitStatus)) + { + arguments.Add("-WaitStatus"); + arguments.Add(waitStatus); + } + if (commands.Count > 0) { arguments.Add("-RequiredCommands"); From a30502bd0581fe0ba78679f56207a1162961364e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 27 Mar 2026 11:55:09 +1100 Subject: [PATCH 7/9] Update .github/actions/setup-runtimes-caching/action.yml --- .github/actions/setup-runtimes-caching/action.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index 5c18c43f8..5497ceb47 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -25,16 +25,9 @@ runs: 10.0.x - name: Install Aspire CLI - shell: pwsh - run: | - $aspireVersion = '13.2.0' - Invoke-Expression "& { $(Invoke-RestMethod 'https://aspire.dev/install.ps1') } -Version '$aspireVersion'" - - $aspireToolPath = Join-Path (Join-Path $HOME '.aspire') 'bin' - Add-Content -Path $env:GITHUB_PATH -Value $aspireToolPath - $env:PATH = "$aspireToolPath$([IO.Path]::PathSeparator)$env:PATH" - - aspire --version + use: timheuer/setup-aspire@v0.1.0 + with: + version: 13.2.0 - name: Set up Python uses: actions/setup-python@v5 From ab054bcb046e03316da1965593b4a42fb2849525 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 27 Mar 2026 11:56:13 +1100 Subject: [PATCH 8/9] Update .github/actions/setup-runtimes-caching/action.yml --- .github/actions/setup-runtimes-caching/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index 5497ceb47..a9ceb3bc9 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -25,7 +25,7 @@ runs: 10.0.x - name: Install Aspire CLI - use: timheuer/setup-aspire@v0.1.0 + uses: timheuer/setup-aspire@v0.1.0 with: version: 13.2.0 From 8573b1750e0bf0ef81a7a2c73bf57fcfa87f1a72 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 27 Mar 2026 12:08:55 +1100 Subject: [PATCH 9/9] Update .github/actions/setup-runtimes-caching/action.yml --- .github/actions/setup-runtimes-caching/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index a9ceb3bc9..107ce5311 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -27,7 +27,7 @@ runs: - name: Install Aspire CLI uses: timheuer/setup-aspire@v0.1.0 with: - version: 13.2.0 + quality: release # temp workaround until url is fixed - name: Set up Python uses: actions/setup-python@v5