Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/build-cli-native-archives.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ jobs:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

# Node.js is required because PackDotnetTool now depends on PackNpmPackage,
# which shells out to `npm pack` to produce the @microsoft/aspire-cli npm
# tarballs alongside the existing dotnet tool packages. GitHub-hosted
# runners ship Node by default, but installing it explicitly pins the
# version and avoids relying on the runner image.
- name: Install node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22.x

# Build RID-specific NuGet packages (DCP + Dashboard) locally instead of
# downloading them from the build_packages job. This allows the CLI archive
# build to run in parallel with build_packages.
Expand Down Expand Up @@ -121,15 +131,33 @@ jobs:
-Rid $rid `
-ArchivePath $archive[0].FullName

# Upload DCP, Dashboard, and CLI tool NuGets so test/polyglot jobs can download them
- name: Upload RID-specific NuGets
- name: Verify CLI npm package
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'

$rid = '${{ matrix.targets.rids }}'
$archiveExtension = if ($rid.StartsWith('win-')) { 'zip' } else { 'tar.gz' }
$archive = @(Get-ChildItem -Path 'artifacts/packages/${{ inputs.configuration }}' -Filter "aspire-cli-$rid-*.$archiveExtension" -Recurse -File -ErrorAction SilentlyContinue)
if ($archive.Count -ne 1) {
throw "Expected exactly one CLI archive for $rid, but found $($archive.Count): $($archive.FullName -join ', ')"
}

eng/scripts/verify-cli-npm-package.ps1 `
-PackagesDir artifacts/packages/${{ inputs.configuration }} `
-Rid $rid `
-ArchivePath $archive[0].FullName

# Upload DCP, Dashboard, and CLI tool packages so test/polyglot jobs can download them
- name: Upload RID-specific packages
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: built-nugets-for-${{ matrix.targets.rids }}
path: |
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.Hosting.Orchestration.${{ matrix.targets.rids }}.*.nupkg
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.Dashboard.Sdk.${{ matrix.targets.rids }}.*.nupkg
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.Cli.*.nupkg
artifacts/packages/${{ inputs.configuration }}/Shipping/microsoft-aspire-cli*.tgz
if-no-files-found: error
retention-days: 15

Expand Down
212 changes: 212 additions & 0 deletions docs/specs/npm-cli-package.md

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions eng/Publishing.props
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
<_ExtensionSignatureFiles Include="$(ArtifactsPackagesDir)**\aspire-vscode-*.signature.p7s" />
<_CliToolPackagesToPublish Include="$(ArtifactsShippingPackagesDir)**\Aspire.Cli*.nupkg"
Exclude="$(ArtifactsShippingPackagesDir)**\*.symbols.nupkg" />
<_CliNpmPackagesToPublish Include="$(ArtifactsShippingPackagesDir)**\microsoft-aspire-cli*.tgz" />
<_CliNpmPackageSignaturesToPublish Include="$(ArtifactsShippingPackagesDir)**\microsoft-aspire-cli*.tgz.sig" />
</ItemGroup>

<!-- Validate VS Code extension artifacts: we expect exactly 1 VSIX and 1 manifest file.
Expand Down Expand Up @@ -87,11 +89,28 @@
<_CliPointerToolPackages Include="@(_CliToolPackagesToPublish)" Exclude="@(_CliRidSpecificToolPackageFilesWithRid)" />
</ItemGroup>

<ItemGroup Label="Validation of CLI npm packages">
<_CliRidSpecificNpmPackageFiles Include="@(_CliNpmPackagesToPublish)"
Condition="!$([System.Text.RegularExpressions.Regex]::IsMatch('%(_CliNpmPackagesToPublish.FileName)', '^microsoft-aspire-cli-\d'))" />

<!-- Extract the rid from filenames like microsoft-aspire-cli-linux-x64-9.0-dev and microsoft-aspire-cli-linux-arm64-9.4.0-preview.1.25358.11 -->
<_CliRidSpecificNpmPackageFilesWithRid Include="@(_CliRidSpecificNpmPackageFiles)">
<ExtractedRid>$([System.Text.RegularExpressions.Regex]::Match('%(_CliRidSpecificNpmPackageFiles.FileName)', '^microsoft-aspire-cli-(.*?)-\d+.*').Groups[1].Value)</ExtractedRid>
</_CliRidSpecificNpmPackageFilesWithRid>

<_MissingCliNpmPackageRids Include="@(_ExpectedCliRids)" Exclude="@(_CliRidSpecificNpmPackageFilesWithRid -> '%(ExtractedRid)')" />
<_UnexpectedCliNpmPackageRids Include="@(_CliRidSpecificNpmPackageFilesWithRid -> '%(ExtractedRid)')" Exclude="@(_ExpectedCliRids)" />
<_CliPointerNpmPackages Include="@(_CliNpmPackagesToPublish)" Exclude="@(_CliRidSpecificNpmPackageFilesWithRid)" />
</ItemGroup>

<Warning Condition="@(_UnexpectedArchiveRids->Count()) > 0" Text="Found unexpected CLI archives for @(_UnexpectedArchiveRids, ',') . These are all the cli archives found - @(_ArchiveFiles, ', ')" />
<Warning Condition="@(_UnexpectedCliPackageRids->Count()) > 0" Text="Found unexpected Aspire.Cli RID-specific packages for @(_UnexpectedCliPackageRids, ',') . These are all the CLI tool packages found - @(_CliToolPackagesToPublish, ', ')" />
<Warning Condition="@(_UnexpectedCliNpmPackageRids->Count()) > 0" Text="Found unexpected Aspire CLI npm RID-specific packages for @(_UnexpectedCliNpmPackageRids, ',') . These are all the CLI npm packages found - @(_CliNpmPackagesToPublish, ', ')" />
<Error Condition="@(_MissingArchiveRids->Count()) > 0" Text="Missing CLI archive(s) for runtime identifiers: @(_MissingArchiveRids, ', '). These are all the cli archives found - @(_ArchiveFiles, ', ')" />
<Error Condition="@(_MissingCliPackageRids->Count()) > 0" Text="Missing Aspire.Cli RID-specific package(s) for runtime identifiers: @(_MissingCliPackageRids, ', '). These are all the CLI tool packages found - @(_CliToolPackagesToPublish, ', ')" />
<Error Condition="@(_MissingCliNpmPackageRids->Count()) > 0" Text="Missing Aspire CLI npm RID-specific package(s) for runtime identifiers: @(_MissingCliNpmPackageRids, ', '). These are all the CLI npm packages found - @(_CliNpmPackagesToPublish, ', ')" />
<Error Condition="@(_CliPointerToolPackages->Count()) != 1" Text="Expected exactly one Aspire.Cli pointer package but found @(_CliPointerToolPackages->Count()). Files: @(_CliPointerToolPackages, ', ')" />
<Error Condition="@(_CliPointerNpmPackages->Count()) != 1" Text="Expected exactly one Aspire CLI npm pointer package but found @(_CliPointerNpmPackages->Count()). Files: @(_CliPointerNpmPackages, ', ')" />

<!-- Validate aspire-cli archive file extensions match expected format for each RID -->
<ItemGroup>
Expand Down Expand Up @@ -177,6 +196,16 @@
<IsShipping>true</IsShipping>
<Kind>Package</Kind>
</ItemsToPushToBlobFeed>
<ItemsToPushToBlobFeed Include="@(_CliNpmPackagesToPublish)">
<IsShipping>true</IsShipping>
<PublishFlatContainer>true</PublishFlatContainer>
<RelativeBlobPath>$(_UploadPathRoot)/$(_PackageVersion)/%(Filename)%(Extension)</RelativeBlobPath>
</ItemsToPushToBlobFeed>
<ItemsToPushToBlobFeed Include="@(_CliNpmPackageSignaturesToPublish)">
<IsShipping>true</IsShipping>
<PublishFlatContainer>true</PublishFlatContainer>
<RelativeBlobPath>$(_UploadPathRoot)/$(_PackageVersion)/%(Filename)%(Extension)</RelativeBlobPath>
</ItemsToPushToBlobFeed>
<ItemsToPushToBlobFeed Include="@(_ExtensionFilesToPublish)">
<IsShipping>false</IsShipping>
<PublishFlatContainer>true</PublishFlatContainer>
Expand Down Expand Up @@ -211,6 +240,8 @@
<Message Importance="High" Text="Aspire publish items to push: @(ItemsToPushToBlobFeed->Count()) total; @(_PackageItemsToPush->Count()) NuGet package(s); @(_FlatBlobItemsToPush->Count()) flat blob artifact(s)." />
<Message Importance="High" Text="Aspire NuGet packages: @(_PackageItemsToPush->Count()) total; @(_ShippingPackageItemsToPush->Count()) shipping." Condition="@(_PackageItemsToPush->Count()) > 0" />
<Message Importance="High" Text="Aspire CLI packages: @(_CliPointerToolPackages->Count()) pointer; @(_CliRidSpecificToolPackageFilesWithRid->Count())/@(_ExpectedCliRids->Count()) RID-specific; RIDs=@(_CliRidSpecificToolPackageFilesWithRid -> '%(ExtractedRid)', ', ')." Condition="@(_CliToolPackagesToPublish->Count()) > 0" />
<Message Importance="High" Text="Aspire CLI npm packages: @(_CliPointerNpmPackages->Count()) pointer; @(_CliRidSpecificNpmPackageFilesWithRid->Count())/@(_ExpectedCliRids->Count()) RID-specific; RIDs=@(_CliRidSpecificNpmPackageFilesWithRid -> '%(ExtractedRid)', ', ')." Condition="@(_CliNpmPackagesToPublish->Count()) > 0" />
<Message Importance="High" Text="Aspire CLI npm detached signatures: @(_CliNpmPackageSignaturesToPublish->Count()) sidecar(s)." Condition="@(_CliNpmPackageSignaturesToPublish->Count()) > 0" />
<Message Importance="High" Text="Aspire flat blob artifacts: @(_FlatBlobItemsToPush->Count()) total; @(_ShippingFlatBlobItemsToPush->Count()) shipping; @(_NonShippingFlatBlobItemsToPush->Count()) non-shipping." Condition="@(_FlatBlobItemsToPush->Count()) > 0" />
<Message Importance="High"
Text="Aspire flat blob item: %(_FlatBlobItemsToPush.Filename)%(_FlatBlobItemsToPush.Extension) | IsShipping=%(_FlatBlobItemsToPush.IsShipping) | RelativeBlobPath=%(_FlatBlobItemsToPush.RelativeBlobPath)" />
Expand Down
10 changes: 10 additions & 0 deletions eng/Signing.props
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@

<!-- Sign the manifest catalog on Windows -->
<FileSignInfo Condition="$([System.OperatingSystem]::IsWindows())" Include="manifest.cat" CertificateName="MicrosoftDotNet500" />

<!--
npm packages are tarballs, but only the Aspire CLI npm tarballs should get
detached signatures. Scope both the .tgz rule and the nested JavaScript
launcher override to the npm package ItemsToSign collision id so the global
.tgz/.js defaults remain unchanged for unrelated artifacts.
-->
<FileExtensionSignInfo Include=".tgz" CertificateName="LinuxSign500180PGP" CollisionPriorityId="AspireCliNpmPackage" />
<FileSignInfo Include="aspire.js" CertificateName="MicrosoftDotNet500" CollisionPriorityId="AspireCliNpmPackage" />
</ItemGroup>

<ItemGroup>
Expand All @@ -75,6 +84,7 @@
<ItemsToSign Include="$(VisualStudioSetupInsertionPath)\**\*.zip" Condition="'$(PostBuildSign)' != 'true'" />
<ItemsToSign Include="$(ArtifactsPackagesDir)**\aspire-cli-*.zip" />
<ItemsToSign Include="$(ArtifactsPackagesDir)**\aspire-cli-*.tar.gz" />
<ItemsToSign Include="$(ArtifactsShippingPackagesDir)**\microsoft-aspire-cli*.tgz" CollisionPriorityId="AspireCliNpmPackage" />
<ItemsToSign Include="$(RepoRoot)eng\scripts\get-aspire-cli.ps1" Condition="$([System.OperatingSystem]::IsWindows())" />

<!-- Sign only the final NativeAOT CLI publish output; CLI archives are signed separately. -->
Expand Down
21 changes: 20 additions & 1 deletion eng/clipack/Common.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
-->

<Target Name="PackDotnetTool"
DependsOnTargets="_InitializeDotnetToolPackProperties;_ExtractNativeBinaryFromArchive;_PackRidSpecificDotnetTool;_PackPointerDotnetTool" />
DependsOnTargets="_InitializeDotnetToolPackProperties;_ExtractNativeBinaryFromArchive;_PackRidSpecificDotnetTool;_PackPointerDotnetTool;PackNpmPackage" />

<Target Name="_InitializeDotnetToolPackProperties">
<Error Condition="'$(CliRuntime)' == ''"
Expand All @@ -183,6 +183,10 @@
<_CliToolPublishBaseDir>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tool-publish'))</_CliToolPublishBaseDir>
<_CliToolPublishDir>$([MSBuild]::NormalizeDirectory($(_CliToolPublishBaseDir), '$(CliRuntime)'))</_CliToolPublishDir>
<_CliToolPointerPublishDir>$([MSBuild]::NormalizeDirectory($(_CliToolPublishBaseDir), 'pointer'))</_CliToolPointerPublishDir>
<_CliNpmPackageStagingDir>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'npm-packages', '$(CliRuntime)'))</_CliNpmPackageStagingDir>
<_CliNpmPackageStagingDirArg>$(_CliNpmPackageStagingDir.TrimEnd('\').TrimEnd('/'))</_CliNpmPackageStagingDirArg>
<_PackageOutputPathArg>$(PackageOutputPath.TrimEnd('\').TrimEnd('/'))</_PackageOutputPathArg>
<NpmCliPackageName Condition="'$(NpmCliPackageName)' == ''">@microsoft/aspire-cli</NpmCliPackageName>
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -258,4 +262,19 @@
RemoveProperties="OutputPath;TargetFramework" />
</Target>

<Target Name="PackNpmPackage"
DependsOnTargets="_InitializeDotnetToolPackProperties;_ExtractNativeBinaryFromArchive">
<Message Importance="High"
Text="Packing CLI npm packages for $(CliRuntime) from '$(_ExtractedNativeBinaryPath)' extracted from '$(_CliArchivePath)'." />

<PropertyGroup>
<!-- Build the script path with MSBuild path helpers so it uses the correct separator
on every platform. The native CLI archives are built on Windows, Linux, and macOS,
and pwsh on non-Windows does not silently normalize mixed-separator paths. -->
<_PackCliNpmPackageScript>$([MSBuild]::NormalizePath($(RepoRoot), 'eng', 'scripts', 'pack-cli-npm-package.ps1'))</_PackCliNpmPackageScript>
</PropertyGroup>

<Exec Command="pwsh -NoProfile -NonInteractive -File &quot;$(_PackCliNpmPackageScript)&quot; -Rid &quot;$(CliRuntime)&quot; -Version &quot;$(Version)&quot; -NativeBinaryPath &quot;$(_ExtractedNativeBinaryPath)&quot; -OutputPath &quot;$(_PackageOutputPathArg)&quot; -StagingRoot &quot;$(_CliNpmPackageStagingDirArg)&quot; -PackageName &quot;$(NpmCliPackageName)&quot;" />
</Target>

</Project>
Loading
Loading