microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feat/1873-devcontainer

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

scripts/devcontainer/Write-DevcontainerChangeLog.ps1

198lines · modecode

1#!/usr/bin/env pwsh
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4#Requires -Version 7.0
5
6<#
7.SYNOPSIS
8 Classifies devcontainer file changes and generates a markdown summary.
9
10.DESCRIPTION
11 Analyzes git diff output to identify changed devcontainer infrastructure files,
12 classifies each by category and pre-build impact, and produces a markdown summary
13 table. In CI, writes to GITHUB_STEP_SUMMARY; locally, writes to stdout.
14
15.PARAMETER CommitSha
16 The commit SHA to diff against. Defaults to HEAD when not specified.
17
18.PARAMETER BranchName
19 The branch name for display in the summary header.
20
21.PARAMETER EventName
22 The GitHub event name that triggered the workflow. Defaults to 'local'.
23
24.PARAMETER BeforeSha
25 The before-push SHA for computing the diff range.
26
27.PARAMETER RepoRoot
28 Root directory of the repository. Defaults to git toplevel or script directory.
29
30.EXAMPLE
31 ./Write-DevcontainerChangeLog.ps1
32 Generate a local devcontainer change summary for the current HEAD.
33
34.EXAMPLE
35 ./Write-DevcontainerChangeLog.ps1 -CommitSha "abc123" -BeforeSha "def456" -BranchName "main" -EventName "push"
36 Generate a change summary for a specific commit range in CI.
37
38.NOTES
39 Runs via: npm run devcontainer:changelog (when configured)
40 Replaces inline bash in .github/workflows/devcontainer-change-log.yml
41#>
42
43[CmdletBinding()]
44param(
45 [Parameter(Mandatory = $false)]
46 [string]$CommitSha,
47
48 [Parameter(Mandatory = $false)]
49 [string]$BranchName,
50
51 [Parameter(Mandatory = $false)]
52 [string]$EventName = 'local',
53
54 [Parameter(Mandatory = $false)]
55 [string]$BeforeSha,
56
57 [Parameter(Mandatory = $false)]
58 [string]$RepoRoot = (git rev-parse --show-toplevel 2>$null)
59)
60
61if ([string]::IsNullOrWhiteSpace($RepoRoot)) { $RepoRoot = $PSScriptRoot }
62
63$ErrorActionPreference = 'Stop'
64
65Import-Module (Join-Path $PSScriptRoot '../lib/Modules/CIHelpers.psm1') -Force
66
67#region Functions
68
69function Get-DevcontainerFileClassification {
70 <#
71 .SYNOPSIS
72 Classifies a devcontainer file path by category and impact.
73 #>
74 [CmdletBinding()]
75 [OutputType([hashtable])]
76 param(
77 [Parameter(Mandatory)]
78 [string]$FilePath
79 )
80
81 switch -Wildcard ($FilePath) {
82 '.devcontainer/scripts/on-create.sh' { return @{ Category = 'Lifecycle Scripts'; Impact = 'High' } }
83 '.devcontainer/scripts/post-create.sh' { return @{ Category = 'Lifecycle Scripts'; Impact = 'Low' } }
84 { $_ -like '.devcontainer/Dockerfile*' -or $_ -like '.devcontainer/*.dockerfile' } { return @{ Category = 'Base Image'; Impact = 'High' } }
85 '.devcontainer/features/*' { return @{ Category = 'Features'; Impact = 'Medium' } }
86 '.devcontainer/devcontainer.json' { return @{ Category = 'Config'; Impact = 'High' } }
87 '.devcontainer/devcontainer-lock.json' { return @{ Category = 'Lockfile'; Impact = 'Medium' } }
88 '.github/workflows/copilot-setup-steps.yml' { return @{ Category = 'Setup Steps'; Impact = 'Medium' } }
89 '.devcontainer/*' { return @{ Category = 'Config'; Impact = 'Medium' } }
90 default { return @{ Category = 'Other'; Impact = 'Unknown' } }
91 }
92}
93
94function New-DevcontainerChangeSummary {
95 <#
96 .SYNOPSIS
97 Builds a markdown change summary for devcontainer infrastructure files.
98 #>
99 [CmdletBinding()]
100 [OutputType([string])]
101 param(
102 [Parameter(Mandatory = $false)]
103 [string]$CommitSha,
104
105 [Parameter(Mandatory = $false)]
106 [string]$BranchName,
107
108 [Parameter(Mandatory = $false)]
109 [string]$EventName = 'local',
110
111 [Parameter(Mandatory = $false)]
112 [string]$BeforeSha,
113
114 [Parameter(Mandatory = $false)]
115 [string]$RepoRoot
116 )
117
118 if ([string]::IsNullOrWhiteSpace($CommitSha)) {
119 $CommitSha = git -C $RepoRoot rev-parse HEAD 2>$null
120 }
121 if ([string]::IsNullOrWhiteSpace($BranchName)) {
122 $BranchName = git -C $RepoRoot rev-parse --abbrev-ref HEAD 2>$null
123 }
124
125 $sb = [System.Text.StringBuilder]::new()
126 [void]$sb.AppendLine('## Devcontainer Infrastructure Changes')
127 [void]$sb.AppendLine('')
128 [void]$sb.AppendLine('| Property | Value |')
129 [void]$sb.AppendLine('|----------|-------|')
130 [void]$sb.AppendLine("| Commit | ``$CommitSha`` |")
131 [void]$sb.AppendLine("| Branch | ``$BranchName`` |")
132 [void]$sb.AppendLine("| Trigger | ``$EventName`` |")
133 [void]$sb.AppendLine('')
134
135 if ($EventName -eq 'workflow_dispatch') {
136 [void]$sb.AppendLine('_Triggered via workflow_dispatch. No push range available for automatic diff._')
137 return $sb.ToString()
138 }
139
140 if ($BeforeSha -eq '0000000000000000000000000000000000000000') {
141 [void]$sb.AppendLine('_Initial push to branch -- no prior commit range available._')
142 return $sb.ToString()
143 }
144
145 if ([string]::IsNullOrWhiteSpace($BeforeSha)) {
146 # Local run without a before SHA -- diff HEAD~1 as a reasonable default
147 $BeforeSha = git -C $RepoRoot rev-parse 'HEAD~1' 2>$null
148 if ($LASTEXITCODE -ne 0) {
149 [void]$sb.AppendLine('_No prior commit available for diff (initial commit?)._')
150 return $sb.ToString()
151 }
152 }
153
154 $changed = git -C $RepoRoot diff --name-only $BeforeSha $CommitSha -- '.devcontainer/' '.github/workflows/copilot-setup-steps.yml' 2>&1
155 if ($LASTEXITCODE -ne 0) {
156 [void]$sb.AppendLine("_Could not compute diff: ``$BeforeSha`` may not be reachable (force push?)._")
157 return $sb.ToString()
158 }
159
160 $files = ($changed -split "`n") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
161 if (-not $files -or $files.Count -eq 0) {
162 [void]$sb.AppendLine('_No devcontainer infrastructure files changed in this push._')
163 return $sb.ToString()
164 }
165
166 [void]$sb.AppendLine('| File | Category | Pre-build Impact |')
167 [void]$sb.AppendLine('|------|----------|-----------------|')
168 foreach ($file in $files) {
169 $classification = Get-DevcontainerFileClassification -FilePath $file
170 [void]$sb.AppendLine("| ``$file`` | $($classification.Category) | $($classification.Impact) |")
171 }
172
173 return $sb.ToString()
174}
175
176#endregion Functions
177
178#region Main Execution
179
180if ($MyInvocation.InvocationName -ne '.') {
181 try {
182 $markdown = New-DevcontainerChangeSummary -CommitSha $CommitSha -BranchName $BranchName -EventName $EventName -BeforeSha $BeforeSha -RepoRoot $RepoRoot
183
184 if ($env:GITHUB_STEP_SUMMARY) {
185 $markdown | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding UTF8
186 }
187 else {
188 Write-Output $markdown
189 }
190 exit 0
191 }
192 catch {
193 Write-Error -ErrorAction Continue "Write-DevcontainerChangeLog failed: $($_.Exception.Message)"
194 exit 1
195 }
196}
197
198#endregion Main Execution
199