Skip to content

Commit

Permalink
Improve tooling and code (#92)
Browse files Browse the repository at this point in the history
* Package Powershell module during build
* Verify that all Cmdlets are exposed in the manifest as part of the build
* Use common MSBuild properties and complete package metadata
  • Loading branch information
ChristopherMann authored Nov 21, 2024
1 parent 35217b1 commit 5f7e2a0
Show file tree
Hide file tree
Showing 18 changed files with 235 additions and 95 deletions.
27 changes: 27 additions & 0 deletions build/Clean-PsModule.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#Requires -Version 7.4
<#
.SYNOPSIS
Remove the Powershell module from the build output.
.DESCRIPTION
This script removes the Powershell module from the build output.
It is intended to be called by MSBuild during the normal clean process.
The script might be called once for each target framework.
#>
[CmdletBinding()]
param(
[Parameter()]
[string]
[ValidateNotNullOrEmpty()]
$OutputDirectory
)

$PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Stop'

$modulePath = Join-Path $OutputDirectory "PsModule"

if (Test-Path $modulePath) {
# This script might be called in parallel for each target framework.
# Hence, we ignore errors as files might have been removed by another instance.
Remove-Item -Path $modulePath -Force -Recurse -ErrorAction SilentlyContinue
}
12 changes: 6 additions & 6 deletions build/Eryph.ComputeClient.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ FunctionsToExport = @()

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @(
"Get-Catlet",
"New-Catlet",
"Remove-Catlet",
"Update-Catlet",
"Start-Catlet",
"Stop-Catlet",
"Get-Catlet",
"New-Catlet",
"Remove-Catlet",
"Update-Catlet",
"Start-Catlet",
"Stop-Catlet",
"Get-CatletIp",
"Get-CatletDisk",
"New-CatletDisk",
Expand Down
76 changes: 76 additions & 0 deletions build/Package-PsModule.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#Requires -Version 7.4
<#
.SYNOPSIS
Package the Powershell module.
.DESCRIPTION
This script packages the Powershell module for distribution.
It is intended to be called by MSBuild during the normal build
process. The script will be called once for each target framework.
#>
[CmdletBinding()]
param(
[Parameter()]
[string]
[ValidateScript({ $_ -match '[a-zA-Z\.]+' }, ErrorMessage = "The module name '{0}' is invalid.")]
$ModuleName,
[Parameter()]
[string]
[ValidateScript({ Test-Path $_ }, ErrorMessage = "The path '{0}' is invalid.")]
$TargetPath,
[Parameter()]
[string]
[ValidateScript({ $_ -match 'net\d+\.?\d+' }, ErrorMessage = "The target framework '{0}' is invalid.")]
$TargetFramework,
[Parameter()]
[string]
[ValidateScript({ Test-Path $_ }, ErrorMessage = "The path '{0}' is invalid.")]
$OutputDirectory,
[Parameter()]
[string]
[ValidateScript({ $_ -match '\d+\.\d+\.\d+' }, ErrorMessage = "The version '{0}' is invalid.")]
$MajorMinorPatch,
[Parameter()]
[string]
$NuGetPreReleaseTag
)

$PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Stop'

$excludedFiles = @("System.Management.Automation.dll", "JetBrains.Annotations.dll")

$modulePath = Join-Path $OutputDirectory "PsModule" $ModuleName
$isWindowsPowershell = $TargetFramework -like 'net4*'
$moduleAssemblyPath = Join-Path $modulePath ($isWindowsPowershell ? 'desktop' : 'coreclr')

# Prepare the output directory
if (-not (Test-Path $modulePath)) {
$null = New-Item -ItemType Directory -Path $modulePath
}

# Copy the build output
if (Test-Path $moduleAssemblyPath) {
Remove-Item -Path $moduleAssemblyPath -Force -Recurse
}
$null = New-Item -ItemType Directory -Path $moduleAssemblyPath
$targetDirectory = (Get-Item $TargetPath).Directory.FullName
Copy-Item -Path (Join-Path $targetDirectory "*") -Destination $moduleAssemblyPath -Exclude $excludedFiles -Recurse

# Prepare the module manifest
$config = Get-Content (Join-Path $PSScriptRoot "$ModuleName.psd1") -Raw
$config = $config.Replace("ModuleVersion = '0.1'", "ModuleVersion = '$MajorMinorPatch'");
if (-not [string]::IsNullOrWhiteSpace($NuGetPreReleaseTag)) {
$config = $config.Replace("# Prerelease = ''", "Prerelease = '$NuGetPreReleaseTag'");
}
Set-Content -Path (Join-Path $modulePath "$ModuleName.psd1") -Value $config
Copy-Item -Path (Join-Path $PSScriptRoot "$ModuleName.psm1") -Destination $modulePath

# Verify that all Cmdlets are exposed in the manifest. We must load the modules
# in separate Powershell processes to avoid conflicts.
$powershell = $isWindowsPowershell ? 'powershell.exe' : 'pwsh.exe'
$moduleCmdlets = (& $powershell -Command "[array](Import-Module -Scope Local $modulePath -PassThru).ExportedCmdlets.Keys -join ','") -split ','
$assemblyCmdlets = (& $powershell -Command "[array](Import-Module -Scope Local $TargetPath -PassThru).ExportedCmdlets.Keys -join ','") -split ','
$missingCmdlets = [Linq.Enumerable]::Except($assemblyCmdlets, $moduleCmdlets)
if ($missingCmdlets.Count -gt 0) {
throw "The following Cmdlets are not exposed in the module manifest: $($missingCmdlets -join ', ')"
}
80 changes: 33 additions & 47 deletions build/build-cmdlet.ps1
Original file line number Diff line number Diff line change
@@ -1,49 +1,35 @@
param ($Configuration = "Debug", $OutputDir = ".")

$cmdletName = "Eryph.ComputeClient"
$excludedFiles = @("System.Management.Automation.dll", "JetBrains.Annotations.dll")

# If this script is not running on a build server, remind user to
# set environment variables so that this script can be debugged
if(-not ($Env:GITVERSION_MajorMinorPatch))
{
Write-Error "You must set the following environment variables"
Write-Error "to test this script interactively (values are examples)"
Write-Host '$Env:GITVERSION_MajorMinorPatch = "1.0.0"'
Write-Host '$Env:GITVERSION_NuGetPreReleaseTag = "ci0030"'
exit 1
}


Push-Location $PSScriptRoot
cd ..
$rootDir = Get-Location

Push-Location $OutputDir

if(Test-Path cmdlet ) {
rm cmdlet -Force -Recurse -ErrorAction Stop
#Requires -Version 7.4
<#
.SYNOPSIS
Prepare the Powershell module for publication.
.DESCRIPTION
This script moves the already built Powershell module to a location
where the release pipeline will pick it up for publication.
The name and output location of this script cannot be changed as
it would break the release pipeline.
#>
[CmdletBinding()]
param (
[Parameter()]
[string]
[ValidateNotNullOrEmpty()]
$Configuration,
[Parameter()]
[string]
[ValidateScript({ Test-Path $_ }, ErrorMessage = "The path '{0}' is invalid.")]
$OutputDir
)

$ErrorActionPreference = 'Stop'
$moduleName = "Eryph.ComputeClient"

$repositoryPath = Resolve-Path (Join-Path $PSScriptRoot "..")
$targetPath = Join-Path $OutputDir "cmdlet"

if (Test-Path $targetPath ) {
Remove-Item $targetPath -Force -Recurse
}
$null = New-Item -ItemType Directory $targetPath

mkdir cmdlet | Out-Null
cd cmdlet
mkdir ${cmdletName} | Out-Null
cd ${cmdletName}

mkdir coreclr | Out-Null
mkdir desktop | Out-Null

cp $rootDir\build\${cmdletName}* .
cp $rootDir\src\${cmdletName}.Commands\bin\${Configuration}\net6.0\* coreclr -Exclude $excludedFiles -Recurse
cp $rootDir\src\${cmdletName}.Commands\bin\${Configuration}\net462\* desktop -Exclude $excludedFiles -Recurse

$config = gc "${cmdletName}.psd1" -Raw
$config = $config.Replace("ModuleVersion = '0.1'", "ModuleVersion = '${Env:GITVERSION_MajorMinorPatch}'");

if(-not [string]::IsNullOrWhiteSpace($Env:GITVERSION_NuGetPreReleaseTag)) {
$config = $config.Replace("# Prerelease = ''", "Prerelease = '${Env:GITVERSION_NuGetPreReleaseTag}'");
}

$config | sc "${cmdletName}.psd1"

Pop-Location
$modulePath = Join-Path $repositoryPath "src" "$moduleName.Commands" "bin" $Configuration "PsModule"
Copy-Item $modulePath\* $targetPath -Recurse
4 changes: 2 additions & 2 deletions gen/generate_local.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ $PSNativeCommandUseErrorActionPreference = $true
$ErrorActionPreference = 'Stop'

# Update the version in the csproj when changing this
$autoRestCSharpVersion = "3.0.0-beta.20240527.2"
$autoRestCSharpVersion = "3.0.0-beta.20241108.1"

$settings = Get-Content -Raw -Path "$PSScriptRoot/config.json" | ConvertFrom-Json
$tag = $settings.tag
$spec = $settings.spec

npm exec --package="autorest@3.7.1" -- `
autorest `
--version="3.10.2" `
--version="3.10.3" `
--use="@autorest/csharp@$autoRestCSharpVersion" `
--use="@autorest/modelerfour@4.27.0" `
"$PSScriptRoot/../../eryph-api-spec/specification/$spec" `
Expand Down
37 changes: 37 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Project>
<PropertyGroup>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://www.eryph.io</PackageProjectUrl>
<PackageReleaseNotes>https://github.com/eryph-org/dotnet-computeclient/releases</PackageReleaseNotes>
<Authors>dbosoft GmbH and Eryph contributors</Authors>
<Company>dbosoft GmbH</Company>
<Product>Eryph</Product>
<Copyright>dbosoft GmbH. All rights reserved.</Copyright>
<RepositoryUrl>https://github.com/eryph-org/dotnet-computeclient</RepositoryUrl>
<!-- Declare that the Repository URL can be published to NuSpec -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!-- Embed source files that are not tracked by the source control manager to the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Include PDB in the built .nupkg -->
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<PropertyGroup>
<LangVersion>12</LangVersion>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>

<PropertyGroup>
<ContinuousIntegrationBuild Condition="'$(TF_BUILD)' == 'true'">True</ContinuousIntegrationBuild>
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">True</ContinuousIntegrationBuild>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GitVersion.MsBuild" Version="5.11.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net462;net6.0</TargetFrameworks>
<TargetFrameworks>net462;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<LangVersion>12</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Eryph.ClientRuntime.Powershell" Version="0.7.0" />
<PackageReference Include="Eryph.ClientRuntime.Powershell" Version="0.8.1-beta.1" />
<PackageReference Include="Eryph.ConfigModel.Catlets.Json" Version="0.7.0" />
<PackageReference Include="Eryph.ConfigModel.Catlets.Yaml" Version="0.7.0" />
<PackageReference Include="Eryph.ConfigModel.Networks.Json" Version="0.7.0" />
<PackageReference Include="Eryph.ConfigModel.Networks.Yaml" Version="0.7.0" />
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
Expand All @@ -25,4 +20,21 @@
<ItemGroup>
<ProjectReference Include="..\Eryph.ComputeClient\Eryph.ComputeClient.csproj" />
</ItemGroup>

<!-- Custom properties and targets for packaging the Powershell module -->
<PropertyGroup>
<PsModuleName>Eryph.ComputeClient</PsModuleName>
<PowershellExecutable>pwsh.exe</PowershellExecutable>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
<PowershellExecutable>powershell.exe</PowershellExecutable>
</PropertyGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="pwsh.exe -NoProfile -File &quot;$(ProjectDir)../../build/Package-PsModule.ps1&quot; -ModuleName &quot;$(PsModuleName)&quot; -OutputDirectory &quot;$([System.IO.Path]::Combine($(ProjectDir), 'bin', $(Configuration)))&quot; -TargetPath &quot;$(TargetPath)&quot; -TargetFramework &quot;$(TargetFramework)&quot; -MajorMinorPatch &quot;$(GitVersion_MajorMinorPatch)&quot; -NuGetPreReleaseTag &quot;$(GitVersion_NuGetPreReleaseTag)&quot;" />
</Target>
<Target Name="PostClean" AfterTargets="Clean">
<Exec Command="pwsh.exe -NoProfile -File &quot;$(ProjectDir)../../build/Clean-PsModule.ps1&quot; -OutputDirectory &quot;$([System.IO.Path]::Combine($(ProjectDir), 'bin', $(Configuration)))&quot;" />
</Target>

</Project>
12 changes: 2 additions & 10 deletions src/Eryph.ComputeClient.Commands/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
{
"profiles": {
"Eryph.ComputeClient.Commands": {
"commandName": "Project"
},
"Run in Powershell": {
"commandName": "Executable",
"executablePath": "powershell.exe",
"commandLineArgs": "-NoProfile -NoExit -Command \"Import-Module $(TargetPath)\""
},
"Run in Powershell Core": {
"commandName": "Executable",
"executablePath": "pwsh.exe",
"commandLineArgs": "-NoProfile -NoExit -Command \"Import-Module $(TargetPath)\""
"executablePath": "$(PowershellExecutable)",
"commandLineArgs": "-NoProfile -NoExit -Command \"Import-Module '$(ProjectDir)bin/$(Configuration)/PsModule/$(PsModuleName)'\""
}
}
}
10 changes: 3 additions & 7 deletions src/Eryph.ComputeClient/Eryph.ComputeClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
<TargetFramework>netstandard2.0</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>annotations</Nullable>
<description>Client library for the eryph compute API.</description>
</PropertyGroup>

<PropertyGroup>
<LangVersion>12</LangVersion>
<IncludeGeneratorSharedCode>true</IncludeGeneratorSharedCode>
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json</RestoreAdditionalProjectSources>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Eryph.ClientRuntime.Authentication" Version="0.7.0" />
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Azure.AutoRest.CSharp" Version="3.0.0-beta.20240527.2" PrivateAssets="All" />
<PackageReference Include="Eryph.ClientRuntime.Authentication" Version="0.8.1-beta.1" />
<PackageReference Include="Microsoft.Azure.AutoRest.CSharp" Version="3.0.0-beta.20241108.1" PrivateAssets="All" />
</ItemGroup>

</Project>
14 changes: 14 additions & 0 deletions src/Eryph.ComputeClient/Generated/Internal/RequestContentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ public static RequestContent FromEnumerable(IEnumerable<BinaryData> enumerable)
return content;
}

public static RequestContent FromEnumerable<T>(ReadOnlySpan<T> span)
where T : notnull
{
Utf8JsonRequestContent content = new Utf8JsonRequestContent();
content.JsonWriter.WriteStartArray();
for (int i = 0; i < span.Length; i++)
{
content.JsonWriter.WriteObjectValue(span[i]);
}
content.JsonWriter.WriteEndArray();

return content;
}

public static RequestContent FromDictionary<TValue>(IDictionary<string, TValue> dictionary)
where TValue : notnull
{
Expand Down
4 changes: 2 additions & 2 deletions src/Eryph.ComputeClient/Generated/Models/CatletDriveType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public CatletDriveType(string value)
public static bool operator ==(CatletDriveType left, CatletDriveType right) => left.Equals(right);
/// <summary> Determines if two <see cref="CatletDriveType"/> values are not the same. </summary>
public static bool operator !=(CatletDriveType left, CatletDriveType right) => !left.Equals(right);
/// <summary> Converts a string to a <see cref="CatletDriveType"/>. </summary>
/// <summary> Converts a <see cref="string"/> to a <see cref="CatletDriveType"/>. </summary>
public static implicit operator CatletDriveType(string value) => new CatletDriveType(value);

/// <inheritdoc />
Expand All @@ -53,7 +53,7 @@ public CatletDriveType(string value)

/// <inheritdoc />
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => _value?.GetHashCode() ?? 0;
public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0;
/// <inheritdoc />
public override string ToString() => _value;
}
Expand Down
Loading

0 comments on commit 5f7e2a0

Please sign in to comment.