Skip to content

Commit d5a10f5

Browse files
committed
fix: Add date placeholder replacement functions and verification scripts for Bash and PowerShell
1 parent 24ff227 commit d5a10f5

File tree

4 files changed

+359
-0
lines changed

4 files changed

+359
-0
lines changed

scripts/bash/create-new-feature.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,23 @@ fi
280280
FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"
281281
mkdir -p "$FEATURE_DIR"
282282

283+
# Function to replace [DATE] placeholders with current date in ISO format (YYYY-MM-DD)
284+
replace_date_placeholders() {
285+
local file="$1"
286+
local current_date=$(date +%Y-%m-%d)
287+
288+
if [ -f "$file" ]; then
289+
# Use sed to replace [DATE] with current date
290+
if [[ "$OSTYPE" == "darwin"* ]]; then
291+
# macOS requires empty string for -i
292+
sed -i '' "s/\[DATE\]/${current_date}/g" "$file"
293+
else
294+
# Linux/other systems
295+
sed -i "s/\[DATE\]/${current_date}/g" "$file"
296+
fi
297+
fi
298+
}
299+
283300
# Mode-aware template selection
284301
MODE_FILE="$REPO_ROOT/.specify/config/config.json"
285302
CURRENT_MODE="spec"
@@ -302,6 +319,9 @@ fi
302319
SPEC_FILE="$FEATURE_DIR/spec.md"
303320
if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE"; fi
304321

322+
# Replace [DATE] placeholders with current date
323+
replace_date_placeholders "$SPEC_FILE"
324+
305325
CONTEXT_TEMPLATE="$REPO_ROOT/templates/context-template.md"
306326
CONTEXT_FILE="$FEATURE_DIR/context.md"
307327

scripts/bash/verify-dates.sh

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#!/usr/bin/env bash
2+
3+
# Verify that generated files contain current dates (not stale [DATE] placeholders)
4+
# Usage: verify-dates.sh [feature-dir]
5+
# verify-dates.sh # Checks current feature based on branch
6+
# verify-dates.sh specs/001-feature # Checks specific feature directory
7+
8+
set -e
9+
10+
# Resolve repository root
11+
find_repo_root() {
12+
local dir="$1"
13+
while [ "$dir" != "/" ]; do
14+
if [ -d "$dir/.git" ] || [ -d "$dir/.specify" ]; then
15+
echo "$dir"
16+
return 0
17+
fi
18+
dir="$(dirname "$dir")"
19+
done
20+
return 1
21+
}
22+
23+
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24+
25+
if git rev-parse --show-toplevel >/dev/null 2>&1; then
26+
REPO_ROOT=$(git rev-parse --show-toplevel)
27+
else
28+
REPO_ROOT="$(find_repo_root "$SCRIPT_DIR")"
29+
if [ -z "$REPO_ROOT" ]; then
30+
echo "Error: Could not determine repository root." >&2
31+
exit 1
32+
fi
33+
fi
34+
35+
# Determine feature directory
36+
if [ -n "$1" ]; then
37+
# Use provided path
38+
if [[ "$1" = /* ]]; then
39+
FEATURE_DIR="$1"
40+
else
41+
FEATURE_DIR="$REPO_ROOT/$1"
42+
fi
43+
else
44+
# Auto-detect from current branch or SPECIFY_FEATURE env var
45+
if [ -n "$SPECIFY_FEATURE" ]; then
46+
FEATURE_DIR="$REPO_ROOT/specs/$SPECIFY_FEATURE"
47+
elif git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
48+
BRANCH=$(git rev-parse --abbrev-ref HEAD)
49+
FEATURE_DIR="$REPO_ROOT/specs/$BRANCH"
50+
else
51+
echo "Error: Could not determine feature directory. Please provide a path." >&2
52+
exit 1
53+
fi
54+
fi
55+
56+
if [ ! -d "$FEATURE_DIR" ]; then
57+
echo "Error: Feature directory not found: $FEATURE_DIR" >&2
58+
exit 1
59+
fi
60+
61+
# Get current date in ISO format
62+
CURRENT_DATE=$(date +%Y-%m-%d)
63+
64+
# Track issues found
65+
ISSUES_FOUND=0
66+
FILES_CHECKED=0
67+
68+
echo "=============================================="
69+
echo "Date Verification Report"
70+
echo "=============================================="
71+
echo "Feature Directory: $FEATURE_DIR"
72+
echo "Current Date: $CURRENT_DATE"
73+
echo "=============================================="
74+
echo ""
75+
76+
# Function to check a file for date issues
77+
check_file() {
78+
local file="$1"
79+
local file_name=$(basename "$file")
80+
81+
if [ ! -f "$file" ]; then
82+
return 0
83+
fi
84+
85+
FILES_CHECKED=$((FILES_CHECKED + 1))
86+
87+
# Check for remaining [DATE] placeholders
88+
if grep -q '\[DATE\]' "$file"; then
89+
echo "❌ FAIL: $file_name contains unresolved [DATE] placeholder"
90+
ISSUES_FOUND=$((ISSUES_FOUND + 1))
91+
return 1
92+
fi
93+
94+
# Check if file contains any date in ISO format
95+
if grep -qE '[0-9]{4}-[0-9]{2}-[0-9]{2}' "$file"; then
96+
# Extract the date found
97+
FOUND_DATE=$(grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' "$file" | head -1)
98+
99+
# Check if date is in the future (more than 1 day ahead) - likely incorrect
100+
FOUND_YEAR=$(echo "$FOUND_DATE" | cut -d'-' -f1)
101+
CURRENT_YEAR=$(date +%Y)
102+
103+
if [ "$FOUND_YEAR" -gt "$CURRENT_YEAR" ]; then
104+
echo "⚠️ WARN: $file_name contains future date: $FOUND_DATE"
105+
ISSUES_FOUND=$((ISSUES_FOUND + 1))
106+
return 1
107+
fi
108+
109+
# Check if date matches current date (ideal case)
110+
if [ "$FOUND_DATE" = "$CURRENT_DATE" ]; then
111+
echo "✅ PASS: $file_name has current date ($FOUND_DATE)"
112+
else
113+
echo "ℹ️ INFO: $file_name has date: $FOUND_DATE (not today, but valid)"
114+
fi
115+
else
116+
echo "ℹ️ INFO: $file_name has no ISO date (may be okay depending on template)"
117+
fi
118+
119+
return 0
120+
}
121+
122+
# Check all relevant files
123+
echo "Checking files..."
124+
echo ""
125+
126+
# Check spec.md
127+
check_file "$FEATURE_DIR/spec.md"
128+
129+
# Check plan.md
130+
check_file "$FEATURE_DIR/plan.md"
131+
132+
# Check context.md
133+
check_file "$FEATURE_DIR/context.md"
134+
135+
# Check tasks.md
136+
check_file "$FEATURE_DIR/tasks.md"
137+
138+
# Check checklist.md (if exists)
139+
check_file "$FEATURE_DIR/checklist.md"
140+
141+
echo ""
142+
echo "=============================================="
143+
echo "Summary"
144+
echo "=============================================="
145+
echo "Files Checked: $FILES_CHECKED"
146+
echo "Issues Found: $ISSUES_FOUND"
147+
148+
if [ $ISSUES_FOUND -eq 0 ]; then
149+
echo ""
150+
echo "✅ All dates verified successfully!"
151+
exit 0
152+
else
153+
echo ""
154+
echo "❌ Found $ISSUES_FOUND issue(s) that need attention."
155+
exit 1
156+
fi

scripts/powershell/create-new-feature.ps1

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,18 @@ if (Test-Path $modeFile) {
269269
}
270270
}
271271

272+
# Function to replace [DATE] placeholders with current date in ISO format (YYYY-MM-DD)
273+
function Replace-DatePlaceholders {
274+
param([string]$FilePath)
275+
276+
if (Test-Path $FilePath) {
277+
$currentDate = Get-Date -Format "yyyy-MM-dd"
278+
$content = Get-Content -Path $FilePath -Raw
279+
$content = $content -replace '\[DATE\]', $currentDate
280+
Set-Content -Path $FilePath -Value $content -NoNewline
281+
}
282+
}
283+
272284
# Select template based on mode
273285
if ($currentMode -eq "build") {
274286
$template = Join-Path $repoRoot 'templates/spec-template-build.md'
@@ -282,6 +294,9 @@ if (Test-Path $template) {
282294
New-Item -ItemType File -Path $specFile | Out-Null
283295
}
284296

297+
# Replace [DATE] placeholders with current date
298+
Replace-DatePlaceholders -FilePath $specFile
299+
285300
# Function to populate context.md with intelligent defaults (mode-aware)
286301
function Populate-ContextFile {
287302
param(
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#!/usr/bin/env pwsh
2+
# Verify that generated files contain current dates (not stale [DATE] placeholders)
3+
# Usage: verify-dates.ps1 [-FeaturePath <path>]
4+
# verify-dates.ps1 # Checks current feature based on branch
5+
# verify-dates.ps1 -FeaturePath specs/001-feature # Checks specific feature directory
6+
7+
[CmdletBinding()]
8+
param(
9+
[Parameter(Position = 0)]
10+
[string]$FeaturePath
11+
)
12+
13+
$ErrorActionPreference = 'Stop'
14+
15+
# Resolve repository root
16+
function Find-RepositoryRoot {
17+
param(
18+
[string]$StartDir,
19+
[string[]]$Markers = @('.git', '.specify')
20+
)
21+
$current = Resolve-Path $StartDir
22+
while ($true) {
23+
foreach ($marker in $Markers) {
24+
if (Test-Path (Join-Path $current $marker)) {
25+
return $current
26+
}
27+
}
28+
$parent = Split-Path $current -Parent
29+
if ($parent -eq $current) {
30+
return $null
31+
}
32+
$current = $parent
33+
}
34+
}
35+
36+
# Determine repo root
37+
try {
38+
$repoRoot = git rev-parse --show-toplevel 2>$null
39+
if ($LASTEXITCODE -ne 0) {
40+
throw "Git not available"
41+
}
42+
} catch {
43+
$repoRoot = Find-RepositoryRoot -StartDir $PSScriptRoot
44+
if (-not $repoRoot) {
45+
Write-Error "Error: Could not determine repository root."
46+
exit 1
47+
}
48+
}
49+
50+
# Determine feature directory
51+
if ($FeaturePath) {
52+
if ([System.IO.Path]::IsPathRooted($FeaturePath)) {
53+
$featureDir = $FeaturePath
54+
} else {
55+
$featureDir = Join-Path $repoRoot $FeaturePath
56+
}
57+
} else {
58+
# Auto-detect from current branch or SPECIFY_FEATURE env var
59+
if ($env:SPECIFY_FEATURE) {
60+
$featureDir = Join-Path $repoRoot "specs/$($env:SPECIFY_FEATURE)"
61+
} else {
62+
try {
63+
$branch = git rev-parse --abbrev-ref HEAD 2>$null
64+
if ($LASTEXITCODE -eq 0 -and $branch) {
65+
$featureDir = Join-Path $repoRoot "specs/$branch"
66+
} else {
67+
throw "Could not determine branch"
68+
}
69+
} catch {
70+
Write-Error "Error: Could not determine feature directory. Please provide a path."
71+
exit 1
72+
}
73+
}
74+
}
75+
76+
if (-not (Test-Path $featureDir -PathType Container)) {
77+
Write-Error "Error: Feature directory not found: $featureDir"
78+
exit 1
79+
}
80+
81+
# Get current date in ISO format
82+
$currentDate = Get-Date -Format "yyyy-MM-dd"
83+
$currentYear = (Get-Date).Year
84+
85+
# Track issues found
86+
$issuesFound = 0
87+
$filesChecked = 0
88+
89+
Write-Host "=============================================="
90+
Write-Host "Date Verification Report"
91+
Write-Host "=============================================="
92+
Write-Host "Feature Directory: $featureDir"
93+
Write-Host "Current Date: $currentDate"
94+
Write-Host "=============================================="
95+
Write-Host ""
96+
97+
# Function to check a file for date issues
98+
function Test-FileDate {
99+
param([string]$FilePath)
100+
101+
$fileName = Split-Path $FilePath -Leaf
102+
103+
if (-not (Test-Path $FilePath)) {
104+
return 0
105+
}
106+
107+
$script:filesChecked++
108+
109+
$content = Get-Content -Path $FilePath -Raw
110+
111+
# Check for remaining [DATE] placeholders
112+
if ($content -match '\[DATE\]') {
113+
Write-Host "X FAIL: $fileName contains unresolved [DATE] placeholder" -ForegroundColor Red
114+
$script:issuesFound++
115+
return 1
116+
}
117+
118+
# Check if file contains any date in ISO format
119+
if ($content -match '(\d{4})-(\d{2})-(\d{2})') {
120+
$foundDate = $Matches[0]
121+
$foundYear = [int]$Matches[1]
122+
123+
# Check if date is in the future (more than current year) - likely incorrect
124+
if ($foundYear -gt $currentYear) {
125+
Write-Host "! WARN: $fileName contains future date: $foundDate" -ForegroundColor Yellow
126+
$script:issuesFound++
127+
return 1
128+
}
129+
130+
# Check if date matches current date (ideal case)
131+
if ($foundDate -eq $currentDate) {
132+
Write-Host "V PASS: $fileName has current date ($foundDate)" -ForegroundColor Green
133+
} else {
134+
Write-Host "i INFO: $fileName has date: $foundDate (not today, but valid)" -ForegroundColor Cyan
135+
}
136+
} else {
137+
Write-Host "i INFO: $fileName has no ISO date (may be okay depending on template)" -ForegroundColor Cyan
138+
}
139+
140+
return 0
141+
}
142+
143+
Write-Host "Checking files..."
144+
Write-Host ""
145+
146+
# Check all relevant files
147+
Test-FileDate -FilePath (Join-Path $featureDir "spec.md") | Out-Null
148+
Test-FileDate -FilePath (Join-Path $featureDir "plan.md") | Out-Null
149+
Test-FileDate -FilePath (Join-Path $featureDir "context.md") | Out-Null
150+
Test-FileDate -FilePath (Join-Path $featureDir "tasks.md") | Out-Null
151+
Test-FileDate -FilePath (Join-Path $featureDir "checklist.md") | Out-Null
152+
153+
Write-Host ""
154+
Write-Host "=============================================="
155+
Write-Host "Summary"
156+
Write-Host "=============================================="
157+
Write-Host "Files Checked: $filesChecked"
158+
Write-Host "Issues Found: $issuesFound"
159+
160+
if ($issuesFound -eq 0) {
161+
Write-Host ""
162+
Write-Host "V All dates verified successfully!" -ForegroundColor Green
163+
exit 0
164+
} else {
165+
Write-Host ""
166+
Write-Host "X Found $issuesFound issue(s) that need attention." -ForegroundColor Red
167+
exit 1
168+
}

0 commit comments

Comments
 (0)