Skip to content

Commit caa0c84

Browse files
committed
Changes needed by PostSharp.
1 parent e0c42cf commit caa0c84

4 files changed

Lines changed: 148 additions & 38 deletions

File tree

src/PostSharp.Engineering.BuildTools/Build/Model/Product.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,18 @@ public DockerSpec? DockerSpec
255255
/// </summary>
256256
public bool GenerateTeamCitySettings { get; init; } = true;
257257

258+
/// <summary>
259+
/// Gets or sets additional environment variable names to pass to the Docker container.
260+
/// These are appended to the standard list defined in <see cref="EnvironmentVariableNames.All"/>.
261+
/// </summary>
262+
public string[] AdditionalDockerEnvironmentVariables { get; init; } = [];
263+
264+
/// <summary>
265+
/// Gets or sets a value indicating whether the <c>generate-scripts</c> command should generate Dockerfiles.
266+
/// When <c>false</c>, DockerBuild.ps1 is still generated but Dockerfiles must be maintained manually.
267+
/// </summary>
268+
public bool GenerateDockerfiles { get; init; } = true;
269+
258270
/// <summary>
259271
/// Gets or sets a value indicating whether the <c>prepare</c> command should generate the <c>nuget.config</c> file.
260272
/// </summary>

src/PostSharp.Engineering.BuildTools/ContinuousIntegration/GenerateScriptsCommand.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,26 @@ public static bool Execute( BuildContext context, CommonCommandSettings settings
3838
{
3939
EmbeddedResourceHelper.ExtractScript( context, "DockerBuild.ps1", "" );
4040
EmbeddedResourceHelper.ExtractScript( context, "RunClaude.ps1", "eng" );
41-
var image = (ContainerRequirements) product.OverriddenBuildAgentRequirements!;
4241

43-
if ( !image.WriteDockerfile( context, ContainerOperatingSystem.Windows2025, "Dockerfile" ) )
42+
if ( product.GenerateDockerfiles )
4443
{
45-
return false;
46-
}
47-
48-
if ( !image.WriteDockerfile( context, ContainerOperatingSystem.Windows2022, "Dockerfile.win2022" ) )
49-
{
50-
return false;
51-
}
44+
var image = (ContainerRequirements) product.OverriddenBuildAgentRequirements!;
5245

53-
// Generate Claude Dockerfile (will auto-add NodeJs if not present)
54-
if ( !image.WriteClaudeDockerfile( context, ContainerOperatingSystem.Windows2025, "Dockerfile.claude" ) )
55-
{
56-
return false;
46+
if ( !image.WriteDockerfile( context, ContainerOperatingSystem.Windows2025, "Dockerfile" ) )
47+
{
48+
return false;
49+
}
50+
51+
if ( !image.WriteDockerfile( context, ContainerOperatingSystem.Windows2022, "Dockerfile.win2022" ) )
52+
{
53+
return false;
54+
}
55+
56+
// Generate Claude Dockerfile (will auto-add NodeJs if not present)
57+
if ( !image.WriteClaudeDockerfile( context, ContainerOperatingSystem.Windows2025, "Dockerfile.claude" ) )
58+
{
59+
return false;
60+
}
5761
}
5862

5963
// Generate DockerMounts.g.ps1 to define additional mount points for dependencies

src/PostSharp.Engineering.BuildTools/Resources/DockerBuild.ps1

Lines changed: 112 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ param(
2020
[string]$Dockerfile, # Path to custom Dockerfile (defaults to Dockerfile or Dockerfile.claude based on -Claude).
2121
[switch]$NoInit, # Do not generate or call Init.g.ps1 (skips git config, safe.directory, etc).
2222
[string]$Isolation = 'process', # Docker isolation mode (process or hyperv). Memory/CPU limits only apply to hyperv.
23-
[string]$Memory, # Docker memory limit (e.g., "8g"). Only used with hyperv isolation.
23+
[string]$Memory = '16g', # Minimum required memory for the container. On build agents, actual memory is calculated from BuildAgentMemorySize.
2424
[int]$Cpus = [Environment]::ProcessorCount, # Docker CPU limit. Only used with hyperv isolation.
2525
[string[]]$Mount, # Additional directories to mount from host (readonly by default, append :w for writable). Supports * and ** glob patterns.
2626
[string[]]$Env, # Additional environment variables to pass from host to container.
@@ -45,11 +45,7 @@ $EnvironmentVariables = '<ENVIRONMENT_VARIABLES>'
4545
$ErrorActionPreference = "Stop"
4646
$dockerContextDirectory = "$EngPath/docker-context"
4747

48-
# Detect platform (use built-in variables if available, fallback for older PowerShell)
49-
if ($null -eq $IsWindows)
50-
{
51-
$IsWindows = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT
52-
}
48+
# $IsWindows is a built-in automatic variable in PowerShell 6+.
5349
$IsUnix = -not $IsWindows # Covers both Linux and macOS
5450

5551
# Docker isolation is Windows-only
@@ -562,6 +558,10 @@ if ($Claude -and -not $NoMcp)
562558
if ($Clean)
563559
{
564560
Write-Host "Cleaning up." -ForegroundColor Green
561+
if (Test-Path "artifacts")
562+
{
563+
Remove-Item artifacts -Force -Recurse -ErrorAction SilentlyContinue
564+
}
565565
Get-ChildItem "bin" -Recurse | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue
566566
Get-ChildItem "obj" -Recurse | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue
567567
}
@@ -591,20 +591,20 @@ if (-not $KeepEnv)
591591
}
592592

593593
# Add git identity to environment
594+
$env:GIT_USER_EMAIL = git config --global user.email
595+
$env:GIT_USER_NAME = git config --global user.name
596+
594597
if ($env:IS_TEAMCITY_AGENT)
595598
{
596-
# On TeamCity agents, check if the environment variables are set.
597-
if (-not $env:GIT_USER_EMAIL -or -not $env:GIT_USER_NAME)
599+
# On TeamCity agents, use defaults if not set.
600+
if (-not $env:GIT_USER_EMAIL)
598601
{
599-
Write-Error "On TeamCity agents, the GIT_USER_EMAIL and GIT_USER_NAME environment variables must be set."
600-
exit 1
602+
$env:GIT_USER_EMAIL = 'teamcity@postsharp.net'
603+
}
604+
if (-not $env:GIT_USER_NAME)
605+
{
606+
$env:GIT_USER_NAME = 'teamcity'
601607
}
602-
}
603-
else
604-
{
605-
# On developer machines, use the current git user.
606-
$env:GIT_USER_EMAIL = git config --global user.email
607-
$env:GIT_USER_NAME = git config --global user.name
608608
}
609609

610610
New-EnvJson -EnvironmentVariableList $EnvironmentVariables
@@ -1195,6 +1195,72 @@ if (-not $existingContainerId)
11951195
}
11961196
}
11971197

1198+
# Memory validation and calculation
1199+
$hostReservedMemoryGB = 8
1200+
1201+
# Parse Memory to get numeric value in GB
1202+
function ConvertTo-MemoryGB
1203+
{
1204+
param([string]$MemoryString)
1205+
1206+
if ($MemoryString -match '^(\d+(?:\.\d+)?)\s*[gG][bB]?$')
1207+
{
1208+
return [double]$Matches[1]
1209+
}
1210+
elseif ($MemoryString -match '^(\d+(?:\.\d+)?)\s*[mM][bB]?$')
1211+
{
1212+
return [double]$Matches[1] / 1024
1213+
}
1214+
elseif ($MemoryString -match '^(\d+)$')
1215+
{
1216+
# Assume bytes
1217+
return [double]$Matches[1] / 1024 / 1024 / 1024
1218+
}
1219+
else
1220+
{
1221+
Write-Error "Invalid memory format: $MemoryString. Use formats like '12g', '12GB', '12288m', or '12288MB'."
1222+
exit 1
1223+
}
1224+
}
1225+
1226+
# Determine actual Docker memory limit
1227+
if ($env:BuildAgentMemorySize)
1228+
{
1229+
# On build agents, use BuildAgentMemorySize to determine actual container memory
1230+
$availableMemoryGB = ConvertTo-MemoryGB -MemoryString $env:BuildAgentMemorySize
1231+
Write-Host "Available memory: $availableMemoryGB GB" -ForegroundColor Cyan
1232+
1233+
$calculatedMemoryGB = [math]::Floor($availableMemoryGB - $hostReservedMemoryGB)
1234+
Write-Host "Memory available for container: $calculatedMemoryGB GB (after reserving ${hostReservedMemoryGB}GB for host)" -ForegroundColor Cyan
1235+
1236+
if ($env:BuildAgentMaxMemory) {
1237+
$dockerMemoryLimitGB = [math]::Min($env:BuildAgentMaxMemory, $calculatedMemoryGB)
1238+
Write-Host "Max memory limit set to $env:BuildAgentMaxMemory GB from BuildAgentMaxMemory environment variable." -ForegroundColor Cyan
1239+
} else {
1240+
$dockerMemoryLimitGB = $calculatedMemoryGB
1241+
}
1242+
$dockerMemoryLimit = "${dockerMemoryLimitGB}g"
1243+
Write-Host "Container memory set to $dockerMemoryLimit" -ForegroundColor Cyan
1244+
}
1245+
else
1246+
{
1247+
# On developer machines, use Memory parameter as actual limit
1248+
$dockerMemoryLimit = $Memory
1249+
Write-Host "Container memory set to $dockerMemoryLimit (from Memory parameter)" -ForegroundColor Cyan
1250+
}
1251+
1252+
Write-Host "Number of requested CPUs is set to $Cpus" -ForegroundColor Cyan
1253+
1254+
if ($env:BuildAgentMaxCpus)
1255+
{
1256+
$dockerCpus = [math]::Min($env:BuildAgentMaxCpus, $Cpus)
1257+
Write-Host "BuildAgentMaxCpus is set to $env:BuildAgentMaxCpus, actual number of CPUs will be $dockerCpus" -ForegroundColor Cyan
1258+
}
1259+
else
1260+
{
1261+
$dockerCpus = $Cpus
1262+
}
1263+
11981264
# GHCR authentication and pull logic
11991265
$builtNewImage = $false
12001266
$dockerConfigArg = @()
@@ -1298,8 +1364,8 @@ RUN if [ -n "`$MOUNTPOINTS" ]; then \
12981364

12991365
# Build docker build command with optional --memory (not supported in process isolation)
13001366
$dockerBuildCmd = @('build', '-t', $ImageTag)
1301-
if ($Memory -and $Isolation -ne 'process') {
1302-
$dockerBuildCmd += "--memory=$Memory"
1367+
if ($Isolation -ne 'process') {
1368+
$dockerBuildCmd += "--memory=$dockerMemoryLimit"
13031369
}
13041370
$dockerBuildCmd += @('--build-arg', "MOUNTPOINTS=$mountPointsAsString", '-f', '-', $dockerContextDirectory)
13051371

@@ -1344,7 +1410,8 @@ if (-not $BuildImage)
13441410
{
13451411
# Common setup for both Claude and normal build modes
13461412
$pwshPath = if ($IsUnix) { '/usr/bin/pwsh' } else { 'C:\Program Files\PowerShell\7\pwsh.exe' }
1347-
$initCall = if (-not $NoInit) { "& c:\docker-context\Init.g.ps1; " } else { "" }
1413+
$initScriptPath = if ($IsUnix) { '/docker-context/Init.g.ps1' } else { 'c:\docker-context\Init.g.ps1' }
1414+
$initCall = if (-not $NoInit) { "& '$initScriptPath'; " } else { "" }
13481415

13491416
# Convert volume mappings to docker args format (interleave "-v" flags)
13501417
$volumeArgs = @()
@@ -1455,6 +1522,29 @@ if (-not $BuildImage)
14551522
$BuildArgs = @("-StartVsmon") + $BuildArgs
14561523
}
14571524

1525+
# Pass through PowerShell verbosity preferences
1526+
$verbosityCommands = @()
1527+
if ($VerbosePreference -ne 'SilentlyContinue')
1528+
{
1529+
$verbosityCommands += "`$VerbosePreference = '$VerbosePreference'"
1530+
$BuildArgs = @("-Verbose") + $BuildArgs
1531+
}
1532+
if ($DebugPreference -ne 'SilentlyContinue')
1533+
{
1534+
$verbosityCommands += "`$DebugPreference = '$DebugPreference'"
1535+
$BuildArgs = @("-Debug") + $BuildArgs
1536+
}
1537+
if ($InformationPreference -ne 'SilentlyContinue')
1538+
{
1539+
$verbosityCommands += "`$InformationPreference = '$InformationPreference'"
1540+
}
1541+
if ($WarningPreference -ne 'Continue')
1542+
{
1543+
$verbosityCommands += "`$WarningPreference = '$WarningPreference'"
1544+
}
1545+
1546+
$verbositySetup = if ($verbosityCommands.Count -gt 0) { ($verbosityCommands -join '; ') + '; ' } else { '' }
1547+
14581548
if ($Interactive)
14591549
{
14601550
$pwshArgs = "-NoExit"
@@ -1482,7 +1572,7 @@ if (-not $BuildImage)
14821572
$scriptFullPath = Join-Path $ContainerSourceDir $Script
14831573
}
14841574
$scriptInvocation = "& '$scriptFullPath'"
1485-
$inlineScript = "${substCommandsInline}${initCall}cd '$SourceDirName'; $scriptInvocation $buildArgsString; $pwshExitCommand"
1575+
$inlineScript = "${substCommandsInline}${initCall}cd '$SourceDirName'; $verbositySetup$scriptInvocation $buildArgsString; $pwshExitCommand"
14861576

14871577
# No environment args for normal build
14881578
$envArgs = @()
@@ -1507,10 +1597,8 @@ if (-not $BuildImage)
15071597

15081598
# Only add --memory and --cpus when NOT using process isolation
15091599
if ($Isolation -ne 'process') {
1510-
if ($Memory) {
1511-
$dockerCmd += "--memory=$Memory"
1512-
}
1513-
$dockerCmd += "--cpus=$Cpus"
1600+
$dockerCmd += "--memory=$dockerMemoryLimit"
1601+
$dockerCmd += "--cpus=$dockerCpus"
15141602
}
15151603

15161604
if ($isolationArg) { $dockerCmd += $isolationArg }

src/PostSharp.Engineering.BuildTools/Utilities/EmbeddedResourceHelper.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ public static void ExtractScript( BuildContext context, string fileName, string
1515
var product = context.Product;
1616
var replacements = new Dictionary<string, string>();
1717
replacements.Add( "<ENG_PATH>", product.EngineeringDirectory );
18-
replacements.Add( "<ENVIRONMENT_VARIABLES>", string.Join( ",", EnvironmentVariableNames.All.OrderBy( x => x ) ) );
18+
19+
// Combine standard environment variables with product-specific additional ones
20+
var allEnvironmentVariables = EnvironmentVariableNames.All
21+
.Concat( product.AdditionalDockerEnvironmentVariables )
22+
.OrderBy( x => x );
23+
24+
replacements.Add( "<ENVIRONMENT_VARIABLES>", string.Join( ",", allEnvironmentVariables ) );
1925
replacements.Add( "<PRODUCT_NAME>", product.ProductNameWithoutDot );
2026

2127
ExtractResource( context, fileName, targetDirectory, replacements );

0 commit comments

Comments
 (0)