Skip to content

Commit 3587e6a

Browse files
refactor(scripts): align linting and tests with CIHelpers (#401)
## Description Refactored CI helper usage in linting and security scripts, expanded CI helper APIs, and aligned tests and documentation with the new behavior. - Extended CI helpers with environment flag and annotation helpers, plus coverage for new APIs. - Reworked linting scripts to rely on CI helper outputs and annotations, including the link language check core flow. - Hardened security and utility scripts with CI helper usage, response parsing improvements, and updated error handling. - Updated linting and security tests and mocks to use CI helper APIs and removed GitHub helper-specific coverage. - Updated GitHub documentation and removed the copilot setup workflow. ## Related Issue(s) Related to #351 ## Type of Change Select all that apply: **Code & Documentation:** - [ ] Bug fix (non-breaking change fixing an issue) - [ ] New feature (non-breaking change adding functionality) - [ ] Breaking change (fix or feature causing existing functionality to change) - [x] Documentation update **Infrastructure & Configuration:** - [x] GitHub Actions workflow - [ ] Linting configuration (markdown, PowerShell, etc.) - [x] Security configuration - [ ] DevContainer configuration - [ ] Dependency update **AI Artifacts:** - [ ] Reviewed contribution with `prompt-builder` agent and addressed all feedback - [ ] Copilot instructions (`.github/instructions/*.instructions.md`) - [ ] Copilot prompt (`.github/prompts/*.prompt.md`) - [ ] Copilot agent (`.github/agents/*.agent.md`) > **Note for AI Artifact Contributors**: > > - **Agents**: Research, indexing/referencing other project (using standard VS Code GitHub Copilot/MCP tools), planning, and general implementation agents likely already exist. Review `.github/agents/` before creating new ones. > - **Model Versions**: Only contributions targeting the **latest Anthropic and OpenAI models** will be accepted. Older model versions (e.g., GPT-3.5, Claude 3) will be rejected. > - See [Agents Not Accepted](../docs/contributing/custom-agents.md#agents-not-accepted) and [Model Version Requirements](../docs/contributing/ai-artifacts-common.md#model-version-requirements). **Other:** - [x] Script/automation (`.ps1`, `.sh`, `.py`) - [ ] Other (please describe): ## Testing <!-- Describe how you tested these changes --> ## Checklist ### Required Checks - [ ] Documentation is updated (if applicable) - [ ] Files follow existing naming conventions - [ ] Changes are backwards compatible (if applicable) - [ ] Tests added for new functionality (if applicable) ### Required Automated Checks The following validation commands must pass before merging: - [ ] Markdown linting: `npm run lint:md` - [ ] Spell checking: `npm run spell-check` - [ ] Frontmatter validation: `npm run lint:frontmatter` - [ ] Link validation: `npm run lint:md-links` - [ ] PowerShell analysis: `npm run lint:ps` ## Security Considerations - [x] This PR does not contain any sensitive or NDA information - [ ] Any new dependencies have been reviewed for security issues - [ ] Security-related scripts follow the principle of least privilege --------- Co-authored-by: littleKitchen <[email protected]>
1 parent 492a7b1 commit 3587e6a

25 files changed

Lines changed: 1109 additions & 968 deletions

scripts/lib/Modules/CIHelpers.psm1

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Copyright (c) Microsoft Corporation.
2-
# Licensed under the MIT license.
2+
# SPDX-License-Identifier: MIT
33

44
# CIHelpers.psm1
55
#
@@ -198,6 +198,60 @@ function Set-CIOutput {
198198
}
199199
}
200200

201+
function Set-CIEnv {
202+
<#
203+
.SYNOPSIS
204+
Sets a CI environment variable.
205+
206+
.DESCRIPTION
207+
Writes environment variables for GitHub Actions or Azure DevOps.
208+
209+
.PARAMETER Name
210+
The environment variable name.
211+
212+
.PARAMETER Value
213+
The environment variable value.
214+
#>
215+
[CmdletBinding()]
216+
param(
217+
[Parameter(Mandatory = $true)]
218+
[string]$Name,
219+
220+
[Parameter(Mandatory = $true)]
221+
[string]$Value
222+
)
223+
224+
$platform = Get-CIPlatform
225+
226+
switch ($platform) {
227+
'github' {
228+
if ($env:GITHUB_ENV) {
229+
if ($Name -notmatch '^[A-Za-z_][A-Za-z0-9_]*$') {
230+
throw "Invalid GitHub Actions environment variable name: '$Name'. Names must match '^[A-Za-z_][A-Za-z0-9_]*\$'."
231+
}
232+
233+
$delimiter = "EOF_$([guid]::NewGuid().ToString('N'))"
234+
@(
235+
"$Name<<$delimiter"
236+
$Value
237+
$delimiter
238+
) | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
239+
}
240+
else {
241+
Write-Verbose "GITHUB_ENV not set, would set: $Name=$Value"
242+
}
243+
}
244+
'azdo' {
245+
$escapedName = ConvertTo-AzureDevOpsEscaped -Value $Name -ForProperty
246+
$escapedValue = ConvertTo-AzureDevOpsEscaped -Value $Value
247+
Write-Output "##vso[task.setvariable variable=$escapedName]$escapedValue"
248+
}
249+
'local' {
250+
Write-Verbose "CI Env: $Name=$Value"
251+
}
252+
}
253+
}
254+
201255
function Write-CIStepSummary {
202256
<#
203257
.SYNOPSIS
@@ -277,6 +331,7 @@ function Write-CIAnnotation {
277331
[CmdletBinding()]
278332
param(
279333
[Parameter(Mandatory = $true)]
334+
[AllowEmptyString()]
280335
[string]$Message,
281336

282337
[Parameter(Mandatory = $false)]
@@ -342,6 +397,66 @@ function Write-CIAnnotation {
342397
}
343398
}
344399

400+
function Write-CIAnnotations {
401+
<#
402+
.SYNOPSIS
403+
Writes CI annotations for summary results.
404+
405+
.DESCRIPTION
406+
Emits annotations for each issue in a summary object, mapping errors and warnings
407+
to the platform-specific annotation formats.
408+
409+
.PARAMETER Summary
410+
Summary object containing Results with Issues and file metadata.
411+
#>
412+
[CmdletBinding()]
413+
param(
414+
[Parameter(Mandatory = $true)]
415+
$Summary
416+
)
417+
418+
if (-not $Summary -or -not $Summary.Results) {
419+
return
420+
}
421+
422+
foreach ($result in $Summary.Results) {
423+
if (-not $result -or -not $result.Issues) {
424+
continue
425+
}
426+
427+
foreach ($issue in $result.Issues) {
428+
if (-not $issue) {
429+
continue
430+
}
431+
432+
# Skip issues with null or empty messages
433+
if ([string]::IsNullOrWhiteSpace($issue.Message)) {
434+
continue
435+
}
436+
437+
$level = if ($issue.Type -eq 'Error') { 'Error' } else { 'Warning' }
438+
$line = if ($issue.Line -gt 0) { $issue.Line } else { 1 }
439+
$filePath = if ($result.RelativePath) { $result.RelativePath } elseif ($issue.FilePath) { $issue.FilePath } else { $null }
440+
441+
$annotationParams = @{
442+
Message = [string]$issue.Message
443+
Level = $level
444+
}
445+
446+
if ($filePath) {
447+
$annotationParams['File'] = [string]$filePath
448+
$annotationParams['Line'] = $line
449+
}
450+
451+
if ($issue.Column -gt 0) {
452+
$annotationParams['Column'] = $issue.Column
453+
}
454+
455+
Write-CIAnnotation @annotationParams
456+
}
457+
}
458+
}
459+
345460
function Set-CITaskResult {
346461
<#
347462
.SYNOPSIS
@@ -441,8 +556,10 @@ Export-ModuleMember -Function @(
441556
'Get-CIPlatform',
442557
'Test-CIEnvironment',
443558
'Set-CIOutput',
559+
'Set-CIEnv',
444560
'Write-CIStepSummary',
445561
'Write-CIAnnotation',
562+
'Write-CIAnnotations',
446563
'Set-CITaskResult',
447564
'Publish-CIArtifact'
448565
)

scripts/linting/Invoke-LinkLanguageCheck.ps1

Lines changed: 79 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#
77
# Purpose: Wrapper for Link-Lang-Check.ps1 with GitHub Actions integration
88
# Author: HVE Core Team
9-
# Created: 2025-11-05
109

1110
#Requires -Version 7.0
1211

@@ -21,64 +20,64 @@ $ErrorActionPreference = 'Stop'
2120
Import-Module (Join-Path $PSScriptRoot "Modules/LintingHelpers.psm1") -Force
2221
Import-Module (Join-Path $PSScriptRoot "../lib/Modules/CIHelpers.psm1") -Force
2322

24-
# Get repository root
25-
$repoRoot = git rev-parse --show-toplevel 2>$null
26-
if ($LASTEXITCODE -ne 0) {
27-
Write-Error "Not in a git repository"
28-
exit 1
29-
}
30-
31-
# Create logs directory if it doesn't exist
32-
$logsDir = Join-Path $repoRoot "logs"
33-
if (-not (Test-Path $logsDir)) {
34-
New-Item -ItemType Directory -Path $logsDir -Force | Out-Null
35-
}
23+
$script:SkipMain = $env:HVE_SKIP_MAIN -eq '1'
3624

37-
Write-Host "🔍 Checking for URLs with language paths..." -ForegroundColor Cyan
25+
function Invoke-LinkLanguageCheckCore {
26+
[CmdletBinding()]
27+
param(
28+
[string[]]$ExcludePaths = @()
29+
)
3830

39-
#region Main Execution
31+
$repoRoot = git rev-parse --show-toplevel 2>$null
32+
if ($LASTEXITCODE -ne 0) {
33+
Write-Error "Not in a git repository"
34+
return 1
35+
}
4036

41-
try {
42-
# Run the language check script
43-
$scriptArgs = @{}
44-
if ($ExcludePaths.Count -gt 0) {
45-
$scriptArgs['ExcludePaths'] = $ExcludePaths
37+
$logsDir = Join-Path $repoRoot "logs"
38+
if (-not (Test-Path $logsDir)) {
39+
New-Item -ItemType Directory -Path $logsDir -Force | Out-Null
4640
}
47-
$jsonOutput = & (Join-Path $PSScriptRoot "Link-Lang-Check.ps1") @scriptArgs 2>&1
48-
49-
$results = $jsonOutput | ConvertFrom-Json
50-
51-
if ($results -and $results.Count -gt 0) {
52-
Write-Host "Found $($results.Count) URLs with 'en-us' language paths`n" -ForegroundColor Yellow
53-
54-
# Create annotations
55-
foreach ($item in $results) {
56-
Write-GitHubAnnotation `
57-
-Type 'warning' `
58-
-Message "URL contains language path: $($item.original_url)" `
59-
-File $item.file `
60-
-Line $item.line_number
41+
42+
Write-Host "🔍 Checking for URLs with language paths..." -ForegroundColor Cyan
43+
44+
try {
45+
$scriptArgs = @{}
46+
if ($ExcludePaths.Count -gt 0) {
47+
$scriptArgs['ExcludePaths'] = $ExcludePaths
6148
}
62-
63-
# Save results
64-
$outputData = @{
65-
timestamp = (Get-Date).ToUniversalTime().ToString("o")
66-
script = "link-lang-check"
67-
summary = @{
68-
total_issues = $results.Count
69-
files_affected = ($results | Select-Object -ExpandProperty file -Unique).Count
49+
$jsonOutput = & (Join-Path $PSScriptRoot "Link-Lang-Check.ps1") @scriptArgs 2>&1
50+
51+
$results = $jsonOutput | ConvertFrom-Json
52+
53+
if ($results -and $results.Count -gt 0) {
54+
Write-Host "Found $($results.Count) URLs with 'en-us' language paths`n" -ForegroundColor Yellow
55+
56+
foreach ($item in $results) {
57+
Write-CIAnnotation `
58+
-Message "URL contains language path: $($item.original_url)" `
59+
-Level Warning `
60+
-File $item.file `
61+
-Line $item.line_number
7062
}
71-
issues = $results
72-
}
73-
$outputData | ConvertTo-Json -Depth 3 | Out-File (Join-Path $logsDir "link-lang-check-results.json") -Encoding utf8
74-
75-
Set-GitHubOutput -Name "issues" -Value $results.Count
76-
Set-GitHubEnv -Name "LINK_LANG_FAILED" -Value "true"
77-
78-
# Write summary
79-
$uniqueFiles = $results | Select-Object -ExpandProperty file -Unique
80-
81-
Write-GitHubStepSummary -Content @"
63+
64+
$outputData = @{
65+
timestamp = (Get-Date).ToUniversalTime().ToString("o")
66+
script = "link-lang-check"
67+
summary = @{
68+
total_issues = $results.Count
69+
files_affected = ($results | Select-Object -ExpandProperty file -Unique).Count
70+
}
71+
issues = $results
72+
}
73+
$outputData | ConvertTo-Json -Depth 3 | Out-File (Join-Path $logsDir "link-lang-check-results.json") -Encoding utf8
74+
75+
Set-CIOutput -Name "issues" -Value $results.Count
76+
Set-CIEnv -Name "LINK_LANG_FAILED" -Value "true"
77+
78+
$uniqueFiles = $results | Select-Object -ExpandProperty file -Unique
79+
80+
Write-CIStepSummary -Content @"
8281
## Link Language Path Check Results
8382
8483
⚠️ **Status**: Issues Found
@@ -94,15 +93,20 @@ scripts/linting/Link-Lang-Check.ps1 -Fix
9493
``````
9594
9695
**Files affected:**
97-
$(($uniqueFiles | ForEach-Object { $count = ($results | Where-Object file -eq $_).Count; "- $_ ($count occurrence(s))" }) -join "`n")
96+
$(($uniqueFiles | ForEach-Object {
97+
$count = ($results | Where-Object file -eq $_).Count
98+
$safePath = if ((Get-CIPlatform) -eq 'azdo') {
99+
ConvertTo-AzureDevOpsEscaped -Value $_
100+
} else { $_ }
101+
"- $safePath ($count occurrence(s))"
102+
}) -join "`n")
98103
"@
99-
100-
exit 1
101-
}
102-
else {
104+
105+
return 1
106+
}
107+
103108
Write-Host "✅ No URLs with language paths found" -ForegroundColor Green
104-
105-
# Save empty results
109+
106110
$emptyResults = @{
107111
timestamp = (Get-Date).ToUniversalTime().ToString("o")
108112
script = "link-lang-check"
@@ -113,27 +117,29 @@ $(($uniqueFiles | ForEach-Object { $count = ($results | Where-Object file -eq $_
113117
issues = @()
114118
}
115119
$emptyResults | ConvertTo-Json -Depth 3 | Out-File (Join-Path $logsDir "link-lang-check-results.json") -Encoding utf8
116-
117-
Set-GitHubOutput -Name "issues" -Value "0"
118-
119-
Write-GitHubStepSummary -Content @"
120+
121+
Set-CIOutput -Name "issues" -Value "0"
122+
123+
Write-CIStepSummary -Content @"
120124
## Link Language Path Check Results
121125
122126
✅ **Status**: Passed
123127
124128
No URLs with language-specific paths detected.
125129
"@
126-
127-
exit 0
130+
131+
return 0
128132
}
129-
}
130-
catch {
131-
Write-Error "Link-language check failed: $($_.Exception.Message)"
132-
if ($env:GITHUB_ACTIONS -eq 'true') {
133-
$escapedMsg = ConvertTo-GitHubActionsEscaped -Value $_.Exception.Message
134-
Write-Output "::error::$escapedMsg"
133+
catch {
134+
Write-Error -ErrorAction Continue "Link-language check failed: $($_.Exception.Message)"
135+
Write-CIAnnotation -Message "Link-language check failed: $($_.Exception.Message)" -Level Error
136+
return 1
135137
}
136-
exit 1
137138
}
138139

140+
#region Main Execution
141+
if (-not $script:SkipMain) {
142+
$exitCode = Invoke-LinkLanguageCheckCore -ExcludePaths $ExcludePaths
143+
exit $exitCode
144+
}
139145
#endregion

0 commit comments

Comments
 (0)