Skip to content

Commit ad92a83

Browse files
gfraiteurclaude
andcommitted
Add -Timestamp parameter for TeamCity Docker cache invalidation
On TeamCity, use the -Timestamp parameter value or default to the first day of the current week for automatic weekly cache invalidation of unpinned components like Claude CLI. Also includes: Use AppContext.BaseDirectory as fallback for repo lookup. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 205851c commit ad92a83

3 files changed

Lines changed: 97 additions & 9 deletions

File tree

DockerBuild.ps1

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ param(
1212
[switch]$Claude, # Run Claude CLI instead of Build.ps1. Use -Claude for interactive, -Claude "prompt" for non-interactive.
1313
[switch]$NoMcp, # Do not start the MCP approval server (for -Claude mode).
1414
[switch]$Update, # Update timestamp to invalidate Docker cache and force Claude/plugin updates (Claude mode only).
15+
# Timestamp value for Docker cache invalidation. Increase this to force updates of unpinned components like Claude CLI.
16+
# If not specified, defaults to the first day of the current week (so cache auto-invalidates weekly).
17+
[string]$Timestamp,
1518
[string]$ImageName, # Image name (defaults to a name based on the directory).
1619
[string]$BuildAgentPath, # Path to build agent directory (defaults based on platform).
1720
[switch]$LoadEnvFromKeyVault, # Forces loading environment variables form the key vault.
@@ -319,6 +322,39 @@ function Get-TimestampFile
319322
return $timestampFile
320323
}
321324

325+
# Creates a timestamp file for TeamCity builds to control Docker cache invalidation.
326+
# Uses the -Timestamp parameter if provided, otherwise defaults to first day of current week
327+
# for automatic weekly invalidation of unpinned components like Claude CLI.
328+
function New-TeamCityTimestampFile
329+
{
330+
param(
331+
[string]$TimestampValue,
332+
[string]$DockerContextDir
333+
)
334+
335+
if ([string]::IsNullOrEmpty($TimestampValue))
336+
{
337+
# Default to first day of current week (Monday) for weekly cache invalidation
338+
$today = [DateTime]::UtcNow.Date
339+
$daysFromMonday = [int]$today.DayOfWeek - 1
340+
if ($daysFromMonday -lt 0) { $daysFromMonday = 6 } # Sunday = 6 days from Monday
341+
$firstDayOfWeek = $today.AddDays(-$daysFromMonday)
342+
$TimestampValue = $firstDayOfWeek.ToString("yyyy-MM-dd")
343+
}
344+
345+
$gDirectory = Join-Path $DockerContextDir ".g"
346+
if (-not (Test-Path $gDirectory))
347+
{
348+
New-Item -ItemType Directory -Path $gDirectory -Force | Out-Null
349+
}
350+
351+
$timestampFile = Join-Path $gDirectory "update.timestamp"
352+
Set-Content -Path $timestampFile -Value $TimestampValue -NoNewline -Force
353+
Write-Host "TeamCity timestamp: $TimestampValue" -ForegroundColor Cyan
354+
355+
return $timestampFile
356+
}
357+
322358
# Dictionary to track volume mounts with "writable wins" logic
323359
$script:VolumeMountDict = @{}
324360

@@ -430,7 +466,14 @@ if (-not $KeepEnv)
430466
# Get/update timestamp file for cache invalidation (only if building image)
431467
if (-not $NoBuildImage)
432468
{
433-
$timestampFile = Get-TimestampFile -Update:$Update
469+
if ($env:IS_TEAMCITY_AGENT)
470+
{
471+
$timestampFile = New-TeamCityTimestampFile -TimestampValue $Timestamp -DockerContextDir $dockerContextDirectory
472+
}
473+
else
474+
{
475+
$timestampFile = Get-TimestampFile -Update:$Update
476+
}
434477
}
435478
}
436479
else
@@ -997,7 +1040,8 @@ foreach (`$dir in `$gitDirectories) {
9971040
}
9981041

9991042
# Copy timestamp file to docker context (for Claude mode cache invalidation)
1000-
if ($Claude -and $timestampFile)
1043+
# Skip if running on TeamCity - we already created the file directly in docker-context
1044+
if ($Claude -and $timestampFile -and -not $env:IS_TEAMCITY_AGENT)
10011045
{
10021046
$gDirectory = Join-Path $dockerContextDirectory ".g"
10031047
if (-not (Test-Path $gDirectory))

src/PostSharp.Engineering.BuildTools/Build/BuildContext.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ public static bool TryCreate(
9696
{
9797
buildContext = null;
9898

99-
// Use the repo directory from environment variable if provided, otherwise search from current directory
100-
var repoDirectory = FindRepoDirectory( Environment.GetEnvironmentVariable( EnvironmentVariableNames.RepoDirectory ) )
101-
?? FindRepoDirectory( Environment.CurrentDirectory )
102-
?? FindRepoDirectory( AppContext.BaseDirectory );
99+
// Use the repo directory from an environment variable if provided, otherwise search from the current directory.
100+
var repoDirectory =
101+
FindRepoDirectory( Environment.GetEnvironmentVariable( EnvironmentVariableNames.RepoDirectory ) ) ??
102+
FindRepoDirectory( AppContext.BaseDirectory );
103103

104104
var console = new ConsoleHelper();
105105

@@ -147,7 +147,7 @@ public static bool TryCreate(
147147

148148
// Resolve links and junctions.
149149
var realPath = FileSystemHelper.GetFinalPath( gitIgnorePath );
150-
150+
151151
return Path.GetDirectoryName( realPath );
152152
}
153153
else

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

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ param(
1212
[switch]$Claude, # Run Claude CLI instead of Build.ps1. Use -Claude for interactive, -Claude "prompt" for non-interactive.
1313
[switch]$NoMcp, # Do not start the MCP approval server (for -Claude mode).
1414
[switch]$Update, # Update timestamp to invalidate Docker cache and force Claude/plugin updates (Claude mode only).
15+
# Timestamp value for Docker cache invalidation. Increase this to force updates of unpinned components like Claude CLI.
16+
# If not specified, defaults to the first day of the current week (so cache auto-invalidates weekly).
17+
[string]$Timestamp,
1518
[string]$ImageName, # Image name (defaults to a name based on the directory).
1619
[string]$BuildAgentPath, # Path to build agent directory (defaults based on platform).
1720
[switch]$LoadEnvFromKeyVault, # Forces loading environment variables form the key vault.
@@ -319,6 +322,39 @@ function Get-TimestampFile
319322
return $timestampFile
320323
}
321324

325+
# Creates a timestamp file for TeamCity builds to control Docker cache invalidation.
326+
# Uses the -Timestamp parameter if provided, otherwise defaults to first day of current week
327+
# for automatic weekly invalidation of unpinned components like Claude CLI.
328+
function New-TeamCityTimestampFile
329+
{
330+
param(
331+
[string]$TimestampValue,
332+
[string]$DockerContextDir
333+
)
334+
335+
if ([string]::IsNullOrEmpty($TimestampValue))
336+
{
337+
# Default to first day of current week (Monday) for weekly cache invalidation
338+
$today = [DateTime]::UtcNow.Date
339+
$daysFromMonday = [int]$today.DayOfWeek - 1
340+
if ($daysFromMonday -lt 0) { $daysFromMonday = 6 } # Sunday = 6 days from Monday
341+
$firstDayOfWeek = $today.AddDays(-$daysFromMonday)
342+
$TimestampValue = $firstDayOfWeek.ToString("yyyy-MM-dd")
343+
}
344+
345+
$gDirectory = Join-Path $DockerContextDir ".g"
346+
if (-not (Test-Path $gDirectory))
347+
{
348+
New-Item -ItemType Directory -Path $gDirectory -Force | Out-Null
349+
}
350+
351+
$timestampFile = Join-Path $gDirectory "update.timestamp"
352+
Set-Content -Path $timestampFile -Value $TimestampValue -NoNewline -Force
353+
Write-Host "TeamCity timestamp: $TimestampValue" -ForegroundColor Cyan
354+
355+
return $timestampFile
356+
}
357+
322358
# Dictionary to track volume mounts with "writable wins" logic
323359
$script:VolumeMountDict = @{}
324360

@@ -430,7 +466,14 @@ if (-not $KeepEnv)
430466
# Get/update timestamp file for cache invalidation (only if building image)
431467
if (-not $NoBuildImage)
432468
{
433-
$timestampFile = Get-TimestampFile -Update:$Update
469+
if ($env:IS_TEAMCITY_AGENT)
470+
{
471+
$timestampFile = New-TeamCityTimestampFile -TimestampValue $Timestamp -DockerContextDir $dockerContextDirectory
472+
}
473+
else
474+
{
475+
$timestampFile = Get-TimestampFile -Update:$Update
476+
}
434477
}
435478
}
436479
else
@@ -997,7 +1040,8 @@ foreach (`$dir in `$gitDirectories) {
9971040
}
9981041

9991042
# Copy timestamp file to docker context (for Claude mode cache invalidation)
1000-
if ($Claude -and $timestampFile)
1043+
# Skip if running on TeamCity - we already created the file directly in docker-context
1044+
if ($Claude -and $timestampFile -and -not $env:IS_TEAMCITY_AGENT)
10011045
{
10021046
$gDirectory = Join-Path $dockerContextDirectory ".g"
10031047
if (-not (Test-Path $gDirectory))

0 commit comments

Comments
 (0)