Skip to content

Commit 24ac8f4

Browse files
Improve tooling and code (#25)
* Package Powershell module during build * Verify that all Cmdlets are exposed in the manifest as part of the build process * Use common MSBuild properties and complete package metadata
1 parent e44057c commit 24ac8f4

File tree

10 files changed

+232
-75
lines changed

10 files changed

+232
-75
lines changed

build/Clean-PsModule.ps1

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#Requires -Version 7.4
2+
<#
3+
.SYNOPSIS
4+
Remove the Powershell module from the build output.
5+
.DESCRIPTION
6+
This script removes the Powershell module from the build output.
7+
It is intended to be called by MSBuild during the normal clean process.
8+
The script might be called once for each target framework.
9+
#>
10+
[CmdletBinding()]
11+
param(
12+
[Parameter()]
13+
[string]
14+
[ValidateNotNullOrEmpty()]
15+
$OutputDirectory
16+
)
17+
18+
$PSNativeCommandUseErrorActionPreference = $true
19+
$ErrorActionPreference = 'Stop'
20+
21+
$modulePath = Join-Path $OutputDirectory "PsModule"
22+
23+
if (Test-Path $modulePath) {
24+
# This script might be called in parallel for each target framework.
25+
# Hence, we ignore errors as files might have been removed by another instance.
26+
Remove-Item -Path $modulePath -Force -Recurse -ErrorAction SilentlyContinue
27+
}

build/Eryph.IdentityClient.psd1

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ ClrVersion = '4.0'
5151
# ProcessorArchitecture = ''
5252

5353
# Modules that must be imported into the global environment prior to importing this module
54-
RequiredModules = @(@{ModuleName="Eryph.ClientRuntime.Configuration"; ModuleVersion="0.1.0"; GUID="31a5834e-973e-478f-a48d-cea5f1e92962"})
54+
RequiredModules = @(
55+
@{ ModuleName="Eryph.ClientRuntime.Configuration"; ModuleVersion="0.8.1"; GUID="31a5834e-973e-478f-a48d-cea5f1e92962" }
56+
)
5557

5658
# Assemblies that must be loaded prior to importing this module
5759
# RequiredAssemblies = @()
@@ -72,7 +74,13 @@ RequiredModules = @(@{ModuleName="Eryph.ClientRuntime.Configuration"; ModuleVers
7274
FunctionsToExport = @()
7375

7476
# 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.
75-
CmdletsToExport = @("Get-EryphClient", "New-EryphClient", "New-EryphClientKey", "Remove-EryphClient", "Set-EryphClient")
77+
CmdletsToExport = @(
78+
"Get-EryphClient",
79+
"New-EryphClient",
80+
"New-EryphClientKey",
81+
"Remove-EryphClient",
82+
"Set-EryphClient"
83+
)
7684

7785
# Variables to export from this module
7886
VariablesToExport = '*'

build/Package-PsModule.ps1

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#Requires -Version 7.4
2+
<#
3+
.SYNOPSIS
4+
Package the Powershell module.
5+
.DESCRIPTION
6+
This script packages the Powershell module for distribution.
7+
It is intended to be called by MSBuild during the normal build
8+
process. The script will be called once for each target framework.
9+
#>
10+
[CmdletBinding()]
11+
param(
12+
[Parameter()]
13+
[string]
14+
[ValidateScript({ $_ -match '[a-zA-Z\.]+' }, ErrorMessage = "The module name '{0}' is invalid.")]
15+
$ModuleName,
16+
[Parameter()]
17+
[string]
18+
[ValidateScript({ Test-Path $_ }, ErrorMessage = "The path '{0}' is invalid.")]
19+
$TargetPath,
20+
[Parameter()]
21+
[string]
22+
[ValidateScript({ $_ -match 'net\d+\.?\d+' }, ErrorMessage = "The target framework '{0}' is invalid.")]
23+
$TargetFramework,
24+
[Parameter()]
25+
[string]
26+
[ValidateScript({ Test-Path $_ }, ErrorMessage = "The path '{0}' is invalid.")]
27+
$OutputDirectory,
28+
[Parameter()]
29+
[string]
30+
[ValidateScript({ $_ -match '\d+\.\d+\.\d+' }, ErrorMessage = "The version '{0}' is invalid.")]
31+
$MajorMinorPatch,
32+
[Parameter()]
33+
[string]
34+
$NuGetPreReleaseTag
35+
)
36+
37+
$PSNativeCommandUseErrorActionPreference = $true
38+
$ErrorActionPreference = 'Stop'
39+
40+
$excludedFiles = @("System.Management.Automation.dll", "JetBrains.Annotations.dll")
41+
42+
$modulePath = Join-Path $OutputDirectory "PsModule" $ModuleName
43+
$isWindowsPowershell = $TargetFramework -like 'net4*'
44+
$moduleAssemblyPath = Join-Path $modulePath ($isWindowsPowershell ? 'desktop' : 'coreclr')
45+
46+
# Prepare the output directory
47+
if (-not (Test-Path $modulePath)) {
48+
$null = New-Item -ItemType Directory -Path $modulePath -ErrorAction SilentlyContinue
49+
}
50+
51+
# Copy the build output
52+
if (Test-Path $moduleAssemblyPath) {
53+
Remove-Item -Path $moduleAssemblyPath -Force -Recurse
54+
}
55+
$null = New-Item -ItemType Directory -Path $moduleAssemblyPath
56+
$targetDirectory = (Get-Item $TargetPath).Directory.FullName
57+
Copy-Item -Path (Join-Path $targetDirectory "*") -Destination $moduleAssemblyPath -Exclude $excludedFiles -Recurse
58+
59+
# Prepare the module manifest
60+
$config = Get-Content (Join-Path $PSScriptRoot "$ModuleName.psd1") -Raw
61+
$config = $config.Replace("ModuleVersion = '0.1'", "ModuleVersion = '$MajorMinorPatch'");
62+
if (-not [string]::IsNullOrWhiteSpace($NuGetPreReleaseTag)) {
63+
$config = $config.Replace("# Prerelease = ''", "Prerelease = '$NuGetPreReleaseTag'");
64+
}
65+
Set-Content -Path (Join-Path $modulePath "$ModuleName.psd1") -Value $config
66+
Copy-Item -Path (Join-Path $PSScriptRoot "$ModuleName.psm1") -Destination $modulePath
67+
68+
# This Powershell module requires the module Eryph.ClientRuntime.Configuration.
69+
# We download that module first to ensure that it is available. Otherwise,
70+
# the import during the test below would fail.
71+
$configData = Import-PowerShellDataFile (Join-Path $modulePath "$ModuleName.psd1")
72+
$clientRuntimeVersion = $configData.RequiredModules[0].ModuleVersion
73+
$clientRuntimeModulePath = Join-Path $OutputDirectory "PsModuleDependencies" "Eryph.ClientRuntime.Configuration"
74+
if (-not (Test-Path (Join-Path $clientRuntimeModulePath $clientRuntimeVersion))) {
75+
Save-Module -Path (Join-Path $OutputDirectory "PsModuleDependencies") -Name 'Eryph.ClientRuntime.Configuration' -AllowPrerelease -Force
76+
}
77+
78+
# Verify that all Cmdlets are exposed in the manifest. We must load the modules
79+
# in separate Powershell processes to avoid conflicts.
80+
$powershell = $isWindowsPowershell ? 'powershell.exe' : 'pwsh.exe'
81+
$moduleCmdlets = (& $powershell -Command "Import-Module $clientRuntimeModulePath -RequiredVersion $clientRuntimeVersion; [array](Import-Module -Scope Local $modulePath -PassThru).ExportedCmdlets.Keys -join ','") -split ','
82+
$assemblyCmdlets = (& $powershell -Command "[array](Import-Module -Scope Local $TargetPath -PassThru).ExportedCmdlets.Keys -join ','") -split ','
83+
$missingCmdlets = [Linq.Enumerable]::Except($assemblyCmdlets, $moduleCmdlets)
84+
if ($missingCmdlets.Count -gt 0) {
85+
throw "The following Cmdlets are not exposed in the module manifest: $($missingCmdlets -join ', ')"
86+
}

build/build-cmdlet.ps1

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,35 @@
1-
param ($Configuration = "Debug", $OutputDir = ".")
2-
3-
$cmdletName = "Eryph.IdentityClient"
4-
$excludedFiles = @("System.Management.Automation.dll", "JetBrains.Annotations.dll")
5-
6-
# If this script is not running on a build server, remind user to
7-
# set environment variables so that this script can be debugged
8-
if(-not ($Env:GITVERSION_MajorMinorPatch))
9-
{
10-
Write-Error "You must set the following environment variables"
11-
Write-Error "to test this script interactively (values are examples)"
12-
Write-Host '$Env:GITVERSION_MajorMinorPatch = "1.0.0"'
13-
Write-Host '$Env:GITVERSION_NuGetPreReleaseTag = "ci0030"'
14-
exit 1
15-
}
16-
17-
18-
Push-Location $PSScriptRoot
19-
cd ..
20-
$rootDir = Get-Location
21-
22-
Push-Location $OutputDir
23-
24-
if(Test-Path cmdlet ) {
25-
rm cmdlet -Force -Recurse -ErrorAction Stop
1+
#Requires -Version 7.4
2+
<#
3+
.SYNOPSIS
4+
Prepare the Powershell module for publication.
5+
.DESCRIPTION
6+
This script moves the already built Powershell module to a location
7+
where the release pipeline will pick it up for publication.
8+
The name and output location of this script cannot be changed as
9+
it would break the release pipeline.
10+
#>
11+
[CmdletBinding()]
12+
param (
13+
[Parameter()]
14+
[string]
15+
[ValidateNotNullOrEmpty()]
16+
$Configuration,
17+
[Parameter()]
18+
[string]
19+
[ValidateScript({ Test-Path $_ }, ErrorMessage = "The path '{0}' is invalid.")]
20+
$OutputDir
21+
)
22+
23+
$ErrorActionPreference = 'Stop'
24+
$moduleName = "Eryph.IdentityClient"
25+
26+
$repositoryPath = Resolve-Path (Join-Path $PSScriptRoot "..")
27+
$targetPath = Join-Path $OutputDir "cmdlet"
28+
29+
if (Test-Path $targetPath ) {
30+
Remove-Item $targetPath -Force -Recurse
2631
}
32+
$null = New-Item -ItemType Directory $targetPath
2733

28-
mkdir cmdlet | Out-Null
29-
cd cmdlet
30-
mkdir ${cmdletName} | Out-Null
31-
cd ${cmdletName}
32-
33-
mkdir coreclr | Out-Null
34-
mkdir desktop | Out-Null
35-
36-
cp $rootDir\build\${cmdletName}* .
37-
cp $rootDir\src\${cmdletName}.Commands\bin\${Configuration}\net6.0\* coreclr -Exclude $excludedFiles -Recurse
38-
cp $rootDir\src\${cmdletName}.Commands\bin\${Configuration}\net462\* desktop -Exclude $excludedFiles -Recurse
39-
40-
$config = gc "${cmdletName}.psd1" -Raw
41-
$config = $config.Replace("ModuleVersion = '0.1'", "ModuleVersion = '${Env:GITVERSION_MajorMinorPatch}'");
42-
43-
if(-not [string]::IsNullOrWhiteSpace($Env:GITVERSION_NuGetPreReleaseTag)) {
44-
$config = $config.Replace("# Prerelease = ''", "Prerelease = '${Env:GITVERSION_NuGetPreReleaseTag}'");
45-
}
46-
47-
$config | sc "${cmdletName}.psd1"
48-
49-
Pop-Location
34+
$modulePath = Join-Path $repositoryPath "src" "$moduleName.Commands" "bin" $Configuration "PsModule"
35+
Copy-Item $modulePath\* $targetPath -Recurse

gen/generate_local.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ $PSNativeCommandUseErrorActionPreference = $true
1212
$ErrorActionPreference = 'Stop'
1313

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

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

2121
npm exec --package="[email protected]" -- `
2222
autorest `
23-
--version="3.10.2" `
23+
--version="3.10.3" `
2424
--use="@autorest/csharp@$autoRestCSharpVersion" `
2525
--use="@autorest/[email protected]" `
2626
"$PSScriptRoot/../../eryph-api-spec/specification/$spec" `

src/Directory.Build.props

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Project>
2+
<PropertyGroup>
3+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
4+
<PackageProjectUrl>https://www.eryph.io</PackageProjectUrl>
5+
<PackageReleaseNotes>https://github.com/eryph-org/dotnet-identityclient/releases</PackageReleaseNotes>
6+
<Authors>dbosoft GmbH and Eryph contributors</Authors>
7+
<Company>dbosoft GmbH</Company>
8+
<Product>Eryph</Product>
9+
<Copyright>dbosoft GmbH. All rights reserved.</Copyright>
10+
<RepositoryUrl>https://github.com/eryph-org/dotnet-identityclient</RepositoryUrl>
11+
<!-- Declare that the Repository URL can be published to NuSpec -->
12+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
13+
<!-- Embed source files that are not tracked by the source control manager to the PDB -->
14+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
15+
<!-- Include PDB in the built .nupkg -->
16+
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
17+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
18+
</PropertyGroup>
19+
20+
<PropertyGroup>
21+
<LangVersion>12</LangVersion>
22+
<NoWarn>CS1591</NoWarn>
23+
</PropertyGroup>
24+
25+
<PropertyGroup>
26+
<ContinuousIntegrationBuild Condition="'$(TF_BUILD)' == 'true'">True</ContinuousIntegrationBuild>
27+
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">True</ContinuousIntegrationBuild>
28+
</PropertyGroup>
29+
30+
<ItemGroup>
31+
<PackageReference Include="GitVersion.MsBuild" Version="5.11.1">
32+
<PrivateAssets>all</PrivateAssets>
33+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
34+
</PackageReference>
35+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
36+
</ItemGroup>
37+
</Project>
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net462;net6.0</TargetFrameworks>
4+
<TargetFrameworks>net462;net8.0</TargetFrameworks>
55
<IsPackable>false</IsPackable>
66
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
7-
<LangVersion>12</LangVersion>
87
</PropertyGroup>
98

109
<ItemGroup>
11-
<PackageReference Include="Eryph.ClientRuntime.Powershell" Version="0.7.0" />
12-
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
13-
<PrivateAssets>all</PrivateAssets>
14-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
15-
</PackageReference>
10+
<PackageReference Include="Eryph.ClientRuntime.Powershell" Version="0.8.1-beta.1" />
1611
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1">
1712
<PrivateAssets>All</PrivateAssets>
1813
</PackageReference>
@@ -22,4 +17,20 @@
2217
<ProjectReference Include="..\Eryph.IdentityClient\Eryph.IdentityClient.csproj" />
2318
</ItemGroup>
2419

20+
<!-- Custom properties and targets for packaging the Powershell module -->
21+
<PropertyGroup>
22+
<PsModuleName>Eryph.IdentityClient</PsModuleName>
23+
<PowershellExecutable>pwsh.exe</PowershellExecutable>
24+
</PropertyGroup>
25+
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
26+
<PowershellExecutable>powershell.exe</PowershellExecutable>
27+
</PropertyGroup>
28+
29+
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
30+
<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;" />
31+
</Target>
32+
<Target Name="PostClean" AfterTargets="Clean">
33+
<Exec Command="pwsh.exe -NoProfile -File &quot;$(ProjectDir)../../build/Clean-PsModule.ps1&quot; -OutputDirectory &quot;$([System.IO.Path]::Combine($(ProjectDir), 'bin', $(Configuration)))&quot;" />
34+
</Target>
35+
2536
</Project>
Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
{
22
"profiles": {
3-
"Eryph.IdentityClient.Commands": {
4-
"commandName": "Project"
5-
},
63
"Run in Powershell": {
74
"commandName": "Executable",
8-
"executablePath": "powershell.exe",
9-
"commandLineArgs": "-NoProfile -NoExit -Command \"Import-Module $(TargetPath)\""
10-
},
11-
"Run in Powershell Core": {
12-
"commandName": "Executable",
13-
"executablePath": "pwsh.exe",
14-
"commandLineArgs": "-NoProfile -NoExit -Command \"Import-Module $(TargetPath)\""
5+
"executablePath": "$(PowershellExecutable)",
6+
"commandLineArgs": "-NoProfile -NoExit -Command \"Import-Module '$(ProjectDir)bin/$(Configuration)/PsModule/$(PsModuleName)'\""
157
}
168
}
179
}

src/Eryph.IdentityClient/Eryph.IdentityClient.csproj

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,16 @@
44
<TargetFramework>netstandard2.0</TargetFramework>
55
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
66
<Nullable>annotations</Nullable>
7+
<description>Client library for the eryph identity API.</description>
78
</PropertyGroup>
89

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

1515
<ItemGroup>
16-
<PackageReference Include="Eryph.ClientRuntime.Authentication" Version="0.7.0" />
17-
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
18-
<PrivateAssets>all</PrivateAssets>
19-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
20-
</PackageReference>
21-
<PackageReference Include="Microsoft.Azure.AutoRest.CSharp" Version="3.0.0-beta.20240527.2" PrivateAssets="All" />
16+
<PackageReference Include="Eryph.ClientRuntime.Authentication" Version="0.8.1-beta.1" />
17+
<PackageReference Include="Microsoft.Azure.AutoRest.CSharp" Version="3.0.0-beta.20241108.1" PrivateAssets="All" />
2218
</ItemGroup>
2319
</Project>

src/Eryph.IdentityClient/Generated/Internal/RequestContentHelper.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ public static RequestContent FromEnumerable(IEnumerable<BinaryData> enumerable)
5555
return content;
5656
}
5757

58+
public static RequestContent FromEnumerable<T>(ReadOnlySpan<T> span)
59+
where T : notnull
60+
{
61+
Utf8JsonRequestContent content = new Utf8JsonRequestContent();
62+
content.JsonWriter.WriteStartArray();
63+
for (int i = 0; i < span.Length; i++)
64+
{
65+
content.JsonWriter.WriteObjectValue(span[i]);
66+
}
67+
content.JsonWriter.WriteEndArray();
68+
69+
return content;
70+
}
71+
5872
public static RequestContent FromDictionary<TValue>(IDictionary<string, TValue> dictionary)
5973
where TValue : notnull
6074
{

0 commit comments

Comments
 (0)