microsoft/hve-core

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
docs/621-ai-artifacts

Branches

Tags

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

Clone

HTTPS

Download ZIP

scripts/linting/Modules/LintingHelpers.psm1

193lines · modecode

1# Copyright (c) Microsoft Corporation.
2# SPDX-License-Identifier: MIT
3
4# LintingHelpers.psm1
5#
6# Purpose: Shared helper functions for linting scripts and workflows
7# Author: HVE Core Team
8
9Import-Module (Join-Path $PSScriptRoot "../../lib/Modules/CIHelpers.psm1") -Force
10
11function Get-ChangedFilesFromGit {
12 <#
13 .SYNOPSIS
14 Gets changed files from git with intelligent fallback strategies.
15
16 .DESCRIPTION
17 Attempts to detect changed files using merge-base, with fallbacks for different scenarios.
18
19 .PARAMETER BaseBranch
20 The base branch to compare against (default: origin/main).
21
22 .PARAMETER FileExtensions
23 Array of file extensions to filter (e.g., @('*.ps1', '*.md')).
24
25 .OUTPUTS
26 Array of changed file paths.
27 #>
28 [CmdletBinding()]
29 param(
30 [Parameter(Mandatory = $false)]
31 [string]$BaseBranch = "origin/main",
32
33 [Parameter(Mandatory = $false)]
34 [string[]]$FileExtensions = @('*')
35 )
36
37 $changedFiles = @()
38
39 try {
40 # Try merge-base first (best for PRs)
41 $mergeBase = git merge-base HEAD $BaseBranch 2>$null
42
43 if ($LASTEXITCODE -eq 0 -and $mergeBase) {
44 Write-Verbose "Using merge-base: $mergeBase"
45 $changedFiles = git diff --name-only --diff-filter=ACMR $mergeBase HEAD 2>$null
46 }
47 elseif ((git rev-parse HEAD~1 2>$null)) {
48 Write-Verbose "Merge base failed, using HEAD~1"
49 $changedFiles = git diff --name-only --diff-filter=ACMR HEAD~1 HEAD 2>$null
50 }
51 else {
52 Write-Verbose "HEAD~1 failed, using staged/unstaged files"
53 $changedFiles = git diff --name-only HEAD 2>$null
54 }
55
56 if ($LASTEXITCODE -ne 0) {
57 Write-Warning "Unable to determine changed files from git"
58 return @()
59 }
60
61 # Filter by extensions and verify files exist
62 $filteredFiles = $changedFiles | Where-Object {
63 if ([string]::IsNullOrEmpty($_)) { return $false }
64
65 # Check if file matches any of the allowed extensions
66 $currentFile = $_
67 $matchesExtension = $false
68 foreach ($pattern in $FileExtensions) {
69 if ($currentFile -like $pattern) {
70 $matchesExtension = $true
71 break
72 }
73 }
74
75 $matchesExtension -and (Test-Path $currentFile -PathType Leaf)
76 }
77
78 Write-Verbose "Found $($filteredFiles.Count) changed files matching extensions: $($FileExtensions -join ', ')"
79 return $filteredFiles
80 }
81 catch {
82 Write-Warning "Error getting changed files: $($_.Exception.Message)"
83 return @()
84 }
85}
86
87function Get-FilesRecursive {
88 <#
89 .SYNOPSIS
90 Gets files recursively with gitignore filtering.
91
92 .DESCRIPTION
93 Recursively finds files by extension, respecting .gitignore patterns.
94
95 .PARAMETER Path
96 Root path to search from.
97
98 .PARAMETER Include
99 File patterns to include (e.g., @('*.ps1', '*.psm1')).
100
101 .PARAMETER GitIgnorePath
102 Path to .gitignore file for exclusion patterns.
103
104 .OUTPUTS
105 Array of FileInfo objects.
106 #>
107 [CmdletBinding()]
108 param(
109 [Parameter(Mandatory = $true)]
110 [string]$Path,
111
112 [Parameter(Mandatory = $true)]
113 [string[]]$Include,
114
115 [Parameter(Mandatory = $false)]
116 [string]$GitIgnorePath
117 )
118
119 $files = Get-ChildItem -Path $Path -Recurse -Include $Include -File -ErrorAction SilentlyContinue
120
121 # Apply gitignore filtering if provided
122 if ($GitIgnorePath -and (Test-Path $GitIgnorePath)) {
123 $gitignorePatterns = Get-GitIgnorePatterns -GitIgnorePath $GitIgnorePath
124
125 $files = $files | Where-Object {
126 $file = $_
127 $excluded = $false
128
129 foreach ($pattern in $gitignorePatterns) {
130 if ($file.FullName -like $pattern) {
131 $excluded = $true
132 break
133 }
134 }
135
136 -not $excluded
137 }
138 }
139
140 return $files
141}
142
143function Get-GitIgnorePatterns {
144 <#
145 .SYNOPSIS
146 Parses .gitignore into PowerShell wildcard patterns.
147
148 .PARAMETER GitIgnorePath
149 Path to .gitignore file.
150
151 .OUTPUTS
152 Array of wildcard patterns using platform-appropriate separators.
153 #>
154 [CmdletBinding()]
155 param(
156 [Parameter(Mandatory = $true)]
157 [string]$GitIgnorePath
158 )
159
160 if (-not (Test-Path $GitIgnorePath)) {
161 return @()
162 }
163
164 $sep = [System.IO.Path]::DirectorySeparatorChar
165
166 $patterns = Get-Content $GitIgnorePath | Where-Object {
167 $_ -and -not $_.StartsWith('#') -and $_.Trim() -ne ''
168 } | ForEach-Object {
169 $pattern = $_.Trim()
170
171 # Normalize to platform separator
172 $normalizedPattern = $pattern.Replace('/', $sep).Replace('\', $sep)
173
174 if ($pattern.EndsWith('/')) {
175 "*$sep$($normalizedPattern.TrimEnd($sep))$sep*"
176 }
177 elseif ($pattern.Contains('/') -or $pattern.Contains('\')) {
178 "*$sep$normalizedPattern*"
179 }
180 else {
181 "*$sep$normalizedPattern$sep*"
182 }
183 }
184
185 return $patterns
186}
187
188# Export local functions only - CIHelpers functions are used via direct import
189Export-ModuleMember -Function @(
190 'Get-ChangedFilesFromGit',
191 'Get-FilesRecursive',
192 'Get-GitIgnorePatterns'
193)