Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,16 @@ jobs:
contents: read
id-token: write

# Terraform documentation freshness check
terraform-docs-check:
name: Terraform Docs Check
uses: ./.github/workflows/terraform-docs-check.yml
with:
soft-fail: true
permissions:
contents: read


# CodeQL security analysis
codeql-analysis:
name: CodeQL Analysis
Expand Down Expand Up @@ -213,6 +223,7 @@ jobs:
- terraform-tests
- go-lint
- go-tests
- terraform-docs-check
- codeql-analysis
name: Release Please
runs-on: ubuntu-latest
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/pester-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ jobs:
$testPaths += $testFile
}
}

# Map scripts/ root source to test: scripts/Foo.ps1 -> shared/ci/tests/scripts/Foo.Tests.ps1
if ($file -match '^scripts/([^/]+)\.psm?1$') {
$relativePath = $Matches[1]
$testFile = "shared/ci/tests/scripts/$relativePath.Tests.ps1"
if (Test-Path $testFile) {
$testPaths += $testFile
}
}
}

$uniquePaths = $testPaths | Sort-Object -Unique
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ jobs:
permissions:
contents: read

# Terraform documentation freshness check
terraform-docs-check:
name: Terraform Docs Check
uses: ./.github/workflows/terraform-docs-check.yml
with:
soft-fail: true
changed-files-only: true
permissions:
contents: read

# Go tests
go-tests:
name: Go Tests
Expand All @@ -206,6 +216,7 @@ jobs:
contents: read
id-token: write


# CodeQL security analysis
codeql-analysis:
name: CodeQL Analysis
Expand Down
87 changes: 87 additions & 0 deletions .github/workflows/terraform-docs-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Terraform Docs Check

on:
workflow_call:
inputs:
soft-fail:
description: 'Whether to continue on terraform-docs drift detection'
required: false
type: boolean
default: false
changed-files-only:
description: 'Only check directories with changed Terraform files'
required: false
type: boolean
default: false
terraform-docs-version:
description: 'terraform-docs version to install'
required: false
type: string
default: 'v0.21.0'
terraform-docs-sha256:
description: 'SHA256 checksum of terraform-docs linux-amd64 tarball'
required: false
type: string
default: '2fdd81b8d21ff1498cd559af0dcc5d155835f84600db06d3923e217124fc735a'

permissions:
contents: read

defaults:
run:
shell: pwsh

jobs:
terraform-docs-check:
name: Terraform Docs Check
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
fetch-depth: ${{ inputs.changed-files-only && '0' || '1' }}

- name: Create logs directory
run: New-Item -ItemType Directory -Force -Path logs | Out-Null

- name: Setup Node.js and install dependencies
uses: ./.github/actions/setup-node-deps

- name: Install terraform-docs
run: |
$version = '${{ inputs.terraform-docs-version }}'
$expectedSha = '${{ inputs.terraform-docs-sha256 }}'
$tarball = 'terraform-docs.tar.gz'
$url = "https://github.com/terraform-docs/terraform-docs/releases/download/${version}/terraform-docs-${version}-linux-amd64.tar.gz"

Invoke-WebRequest -Uri $url -OutFile $tarball

$actualSha = (Get-FileHash -Path $tarball -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actualSha -ne $expectedSha) {
throw "SHA256 mismatch for terraform-docs ${version}: expected '${expectedSha}', got '${actualSha}'"
}
Write-Output "SHA256 verified: ${actualSha}"

tar -xzf $tarball
sudo mv terraform-docs /usr/local/bin/
terraform-docs --version

- name: Run terraform-docs check
continue-on-error: ${{ inputs.soft-fail }}
run: |
$params = @{}
if ('${{ inputs.changed-files-only }}' -eq 'true') {
$params['ChangedFilesOnly'] = $true
}
shared/ci/linting/Invoke-TerraformDocsCheck.ps1 @params

- name: Upload terraform-docs check results
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: terraform-docs-check-results
path: logs/terraform-docs-check-results.json
retention-days: 30
52 changes: 38 additions & 14 deletions scripts/Update-TerraformDocs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,21 @@
Check mode: generate docs and verify no uncommitted changes (for CI).
.PARAMETER ConfigPreview
Print configuration and exit without making changes.
.PARAMETER TerraformDir
Root directory containing Terraform files. Defaults to infrastructure/terraform.
.PARAMETER ConfigPath
Path to the .terraform-docs.yml configuration file. Defaults to repo root.
.PARAMETER PassthroughArgs
Additional arguments. When --check is included, activates check mode.
#>

[CmdletBinding()]
param(
[switch]$Check,
[switch]$ConfigPreview
[switch]$ConfigPreview,
[string]$TerraformDir,
[string]$ConfigPath,
[string[]]$PassthroughArgs
)

Set-StrictMode -Version Latest
Expand All @@ -32,16 +41,24 @@ function Update-TerraformDocsCore {
[CmdletBinding()]
param(
[switch]$Check,
[switch]$ConfigPreview
[switch]$ConfigPreview,
[string]$TerraformDir,
[string]$ConfigPath,
[string[]]$PassthroughArgs
)

$repoRoot = & git rev-parse --show-toplevel 2>$null
if (-not $repoRoot) {
$repoRoot = (Get-Item $PSScriptRoot).Parent.FullName
}

$tfBaseDir = Join-Path $repoRoot 'infrastructure/terraform'
$configFile = Join-Path $repoRoot '.terraform-docs.yml'
if (-not $TerraformDir) { $TerraformDir = Join-Path $repoRoot 'infrastructure/terraform' }
if (-not $ConfigPath) { $ConfigPath = Join-Path $repoRoot '.terraform-docs.yml' }

$isCheckMode = $Check.IsPresent
if ($PassthroughArgs -contains '--check') {
$isCheckMode = $true
}

# Validate required tools
foreach ($tool in @('terraform-docs', 'npx', 'git')) {
Expand All @@ -51,17 +68,22 @@ function Update-TerraformDocsCore {
}
}

if (-not (Test-Path $ConfigPath)) {
Write-CIAnnotation -Level Error -Message "Config file not found: $ConfigPath"
return 1
Comment thread
WilliamBerryiii marked this conversation as resolved.
}

# Discover Terraform directories (exclude tests/ and setup/)
$tfDirs = Get-ChildItem -Path $tfBaseDir -Filter '*.tf' -Recurse -File |
$tfDirs = Get-ChildItem -Path $TerraformDir -Filter '*.tf' -Recurse -File |
Where-Object { $_.FullName -notmatch '[/\\]tests[/\\]' -and $_.FullName -notmatch '[/\\]setup[/\\]' } |
ForEach-Object { $_.DirectoryName } |
Sort-Object -Unique

if ($ConfigPreview) {
Write-Host '=== Configuration Preview ==='
Write-Host "Base Directory : $tfBaseDir"
Write-Host "Config File : $configFile"
Write-Host "Check Mode : $Check"
Write-Host "Base Directory : $TerraformDir"
Write-Host "Config File : $ConfigPath"
Write-Host "Check Mode : $isCheckMode"
Write-Host "Directories : $($tfDirs.Count)"
foreach ($dir in $tfDirs) {
$relDir = $dir.Substring($repoRoot.Length + 1)
Expand All @@ -77,7 +99,7 @@ function Update-TerraformDocsCore {
foreach ($dir in $tfDirs) {
$relDir = $dir.Substring($repoRoot.Length + 1)
Write-Host "Processing: $relDir"
& terraform-docs markdown table --config $configFile --output-file TERRAFORM.md $dir
& terraform-docs markdown table --config $ConfigPath --output-file TERRAFORM.md $dir
if ($LASTEXITCODE -ne 0) {
Write-CIAnnotation -Level Error -Message "terraform-docs failed for $relDir"
return 1
Expand All @@ -100,13 +122,15 @@ function Update-TerraformDocsCore {
}

# Check mode: verify no uncommitted changes to generated files
if ($Check) {
if ($isCheckMode) {
Write-Host '=== Checking for Changes ==='
$tfDocFiles = Get-ChildItem -Path $tfBaseDir -Filter 'TERRAFORM.md' -Recurse -File |
$tfDocFiles = Get-ChildItem -Path $TerraformDir -Filter 'TERRAFORM.md' -Recurse -File |
ForEach-Object { $_.FullName }
& git diff --exit-code -- @tfDocFiles
if ($LASTEXITCODE -ne 0) {
Write-CIAnnotation -Level Error -Message "terraform-docs output is out of date. Run 'npm run docs:generate:tf' to update."
$diffOutput = & git diff -- @tfDocFiles
if ($diffOutput) {
Comment thread
WilliamBerryiii marked this conversation as resolved.
$diffOutput
Write-Host 'Restoring modified files to original state...'
& git checkout -- @tfDocFiles
return 1
}
}
Expand Down
44 changes: 43 additions & 1 deletion setup-dev.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env pwsh
#!/usr/bin/env pwsh
Comment thread
WilliamBerryiii marked this conversation as resolved.
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -89,6 +89,48 @@ Write-Host ''
Write-Host 'If this script fails, the devcontainer is your fallback.'
Write-Host ''

Write-Section 'Git Symlink Resolution'

# Git symlinks are stored as text files on Windows when core.symlinks=false.
# Replace broken symlinks with junctions (directories) or hard links (files).
$symlinkEntries = git ls-files -s 2>$null | Select-String '120000' | ForEach-Object {
($_ -split '\s+', 4)[3]
}
$repairedCount = 0
foreach ($entry in $symlinkEntries) {
$fullPath = Join-Path $ScriptDir $entry
if (-not (Test-Path $fullPath)) { continue }

$item = Get-Item $fullPath -Force
# Already a junction/symlink — nothing to fix
if ($item.LinkType) { continue }
# Only fix plain text files (broken symlink placeholders)
if ($item.PSIsContainer) { continue }

$target = (Get-Content $fullPath -Raw).Trim()
$resolvedTarget = Resolve-Path (Join-Path (Split-Path $fullPath) $target) -ErrorAction SilentlyContinue
if (-not $resolvedTarget) {
Write-Warn "Symlink target not found: $entry -> $target"
continue
}

Remove-Item $fullPath -Force
$targetItem = Get-Item $resolvedTarget.Path
if ($targetItem.PSIsContainer) {
New-Item -ItemType Junction -Path $fullPath -Target $resolvedTarget.Path | Out-Null
}
else {
New-Item -ItemType HardLink -Path $fullPath -Target $resolvedTarget.Path | Out-Null
}
$repairedCount++
}
if ($repairedCount -gt 0) {
Write-Info "Repaired $repairedCount broken git symlink(s) (junctions/hard links)"
}
else {
Write-Info 'All git symlinks are intact'
}

Write-Section 'Tool Verification'

Assert-Tools az, terraform, kubectl, helm, jq
Expand Down
Loading
Loading