microsoft/hve-core

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feat-ds-agent

Branches

Tags

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

Clone

HTTPS

Download ZIP

scripts/linting/README.md

584lines · modecode

1---
2title: Linting Scripts
3description: PowerShell scripts for code quality validation and documentation checks
4author: HVE Core Team
5ms.date: 2025-11-05
6ms.topic: reference
7keywords:
8 - powershell
9 - linting
10 - validation
11 - code quality
12 - markdown
13estimated_reading_time: 10
14---
15
16This directory contains PowerShell scripts for validating code quality and documentation standards in the `hve-core` repository.
17
18## Architecture
19
20The linting scripts follow a **modular architecture** with shared helper functions:
21
22* **Wrapper Scripts** (`Invoke-*.ps1`) - Entry points that orchestrate validation logic
23* **Core Scripts** - Existing validation logic (e.g., `Link-Lang-Check.ps1`, `Validate-MarkdownFrontmatter.ps1`)
24* **Shared Module** (`Modules/LintingHelpers.psm1`) - Common functions for file discovery and git operations
25* **CI Helpers** (`scripts/lib/Modules/CIHelpers.psm1`) - CI annotations, outputs, env flags, and step summaries
26* **Configuration Files** - Tool-specific settings (e.g., `PSScriptAnalyzer.psd1`, `markdown-link-check.config.json`)
27
28## Scripts
29
30### PowerShell Linting
31
32#### `Invoke-PSScriptAnalyzer.ps1`
33
34Static analysis for PowerShell scripts using PSScriptAnalyzer.
35
36**Purpose**: Enforce PowerShell best practices and detect common issues.
37
38**Features**:
39
40* Detects changed PowerShell files via Git
41* Supports analyzing all files or changed files only
42* Creates CI annotations for violations
43* Exports JSON results and markdown summary
44* Configurable via `PSScriptAnalyzer.psd1`
45
46**Parameters**:
47
48* `-ChangedFilesOnly` (switch) - Analyze only files changed in current branch
49
50**Usage**:
51
52```powershell
53# Analyze all PowerShell files
54./scripts/linting/Invoke-PSScriptAnalyzer.ps1 -Verbose
55
56# Analyze only changed files
57./scripts/linting/Invoke-PSScriptAnalyzer.ps1 -ChangedFilesOnly
58
59# View detailed output
60./scripts/linting/Invoke-PSScriptAnalyzer.ps1 -Verbose -Debug
61```
62
63**GitHub Actions Integration**:
64
65* Workflow: `.github/workflows/psscriptanalyzer.yml`
66* Artifacts: `psscriptanalyzer-results` (JSON + markdown)
67* Exit Code: Non-zero if violations found
68
69#### `PSScriptAnalyzer.psd1`
70
71Configuration file for PSScriptAnalyzer rules.
72
73**Enforced Rules**:
74
75* **Severity**: Error and Warning levels
76* **Best Practices**: Avoid aliases, use approved verbs, singular nouns
77* **Help**: Require comment-based help
78* **Security**: Check for credentials in code
79* **Performance**: Identify inefficient patterns
80
81**Excluded Rules**:
82
83* `PSAvoidUsingWriteHost` - Allowed for script output
84
85### YAML Linting
86
87#### `Invoke-YamlLint.ps1`
88
89Static analysis for GitHub Actions workflow files using actionlint.
90
91**Purpose**: Validate GitHub Actions workflow YAML syntax and best practices.
92
93**Features**:
94
95* Validates `.github/workflows/*.yml` and `.yaml` files
96* Detects changed workflow files via Git
97* Supports analyzing all files or changed files only
98* Creates CI annotations for violations
99* Exports JSON results and markdown summary
100* Configurable via `.github/actionlint.yaml`
101
102**Parameters**:
103
104* `-ChangedFilesOnly` (switch) - Analyze only files changed in current branch
105* `-BaseBranch` (string) - Base branch for comparison (default: `origin/main`)
106* `-OutputPath` (string) - Output path for JSON results (default: `logs/yaml-lint-results.json`)
107
108**Usage**:
109
110```powershell
111# Analyze all workflow files
112./scripts/linting/Invoke-YamlLint.ps1 -Verbose
113
114# Analyze only changed files
115./scripts/linting/Invoke-YamlLint.ps1 -ChangedFilesOnly
116
117# View detailed output
118./scripts/linting/Invoke-YamlLint.ps1 -Verbose -Debug
119```
120
121**GitHub Actions Integration**:
122
123* Workflow: `.github/workflows/yaml-lint.yml`
124* Configuration: `.github/actionlint.yaml`
125* Artifacts: `yaml-lint-results` (JSON)
126* Exit Code: Non-zero if violations found
127
128### Markdown Validation
129
130#### `Validate-MarkdownFrontmatter.ps1`
131
132Validates YAML frontmatter and footer format in markdown files.
133
134**Purpose**: Ensure consistent metadata across documentation.
135
136**Features**:
137
138* Validates required frontmatter fields
139* Checks footer format and copyright notice
140* Supports changed files only mode
141* Configurable warnings-as-errors
142* Creates CI annotations for all issues
143* Exports JSON results with detailed statistics
144* Generates comprehensive step summary
145
146**Parameters**:
147
148* `-ChangedFilesOnly` (switch) - Validate only changed markdown files
149* `-SkipFooterValidation` (switch) - Skip footer checks
150* `-WarningsAsErrors` (switch) - Treat warnings as errors
151
152**Artifacts Generated**:
153
154* `logs/frontmatter-validation-results.json` - Complete validation results including:
155 * Timestamp and script name
156 * Summary statistics (total files, error/warning counts)
157 * Lists of all errors and warnings
158
159**Usage**:
160
161```powershell
162# Validate all markdown files
163./scripts/linting/Validate-MarkdownFrontmatter.ps1
164
165# Validate only changed files
166./scripts/linting/Validate-MarkdownFrontmatter.ps1 -ChangedFilesOnly
167
168# Skip footer validation
169./scripts/linting/Validate-MarkdownFrontmatter.ps1 -SkipFooterValidation
170```
171
172**GitHub Actions Integration**:
173
174* Workflow: `.github/workflows/frontmatter-validation.yml`
175* Artifacts: `frontmatter-validation-results` (JSON)
176* Annotations: Errors and warnings with file paths
177* Exit Code: Non-zero if validation fails
178
179#### `Invoke-LinkLanguageCheck.ps1`
180
181Detects URLs with language paths (e.g., `/en-us/`) that should be removed.
182
183**Purpose**: Ensure language-agnostic URLs for better internationalization.
184
185**Features**:
186
187* Scans all markdown files recursively
188* Calls `Link-Lang-Check.ps1` for detection logic
189* Creates CI warning annotations
190* Provides fix instructions in summary
191
192**Usage**:
193
194```powershell
195# Check all markdown files
196./scripts/linting/Invoke-LinkLanguageCheck.ps1 -Verbose
197
198# View detection details
199./scripts/linting/Invoke-LinkLanguageCheck.ps1 -Debug
200```
201
202**GitHub Actions Integration**:
203
204* Workflow: `.github/workflows/link-lang-check.yml`
205* Annotations: Warnings on files with language paths
206* Artifacts: `link-lang-check-results` (JSON + markdown)
207
208#### `Link-Lang-Check.ps1`
209
210Core logic for detecting language paths in URLs.
211
212**Detection Pattern**: Matches `/[a-z]{2}-[a-z]{2}/` patterns in Microsoft domain URLs.
213
214#### `Markdown-Link-Check.ps1`
215
216Validates all links in markdown files using markdown-link-check npm package.
217
218**Purpose**: Detect broken links before deployment.
219
220**Features**:
221
222* Checks internal and external links
223* Configurable via `markdown-link-check.config.json`
224* Retries failed links
225* Respects robots.txt
226* Creates CI annotations for broken links
227* Exports JSON results with link statistics
228* Generates detailed step summary
229
230**Artifacts Generated**:
231
232* `logs/markdown-link-check-results.json` - Complete validation results including:
233 * Timestamp and script name
234 * Summary statistics (total files, broken links count)
235 * List of all broken links with file paths
236
237**GitHub Actions Integration**:
238
239* Workflow: `.github/workflows/markdown-link-check.yml`
240* Configuration: `markdown-link-check.config.json`
241* Artifacts: `markdown-link-check-results` (JSON)
242* Annotations: Error for each broken link
243* Exit Code: Non-zero if broken links found
244
245### Copyright Header Validation
246
247#### `Test-CopyrightHeaders.ps1`
248
249Validates copyright and SPDX license headers in source files.
250
251**Purpose**: Ensure all PowerShell and shell scripts include the required Microsoft copyright notice and MIT SPDX license identifier in their first 15 lines.
252
253**Features**:
254
255* Scans `.ps1`, `.psm1`, `.psd1`, and `.sh` files recursively
256* Checks for `Copyright (c) Microsoft Corporation` header
257* Checks for `SPDX-License-Identifier: MIT` identifier
258* Configurable file extensions and exclude paths
259* Exports JSON results with per-file compliance details
260* Calculates compliance percentage across all scanned files
261
262**Parameters**:
263
264* `-Path` (string) - Root path to scan (default: repository root via `git rev-parse --show-toplevel`)
265* `-FileExtensions` (string[]) - File extensions to check (default: `@('*.ps1', '*.psm1', '*.psd1', '*.sh')`)
266* `-OutputPath` (string) - Path for JSON results (default: `logs/copyright-header-results.json`)
267* `-FailOnMissing` (switch) - Exit with code 1 if any files lack required headers
268* `-ExcludePaths` (string[]) - Directories to exclude (default: `@('node_modules', '.git', 'vendor', 'logs')`)
269
270**Usage**:
271
272```powershell
273# Check all source files (report only)
274./scripts/linting/Test-CopyrightHeaders.ps1
275
276# Check and fail on missing headers
277./scripts/linting/Test-CopyrightHeaders.ps1 -FailOnMissing
278
279# Check specific path with verbose output
280./scripts/linting/Test-CopyrightHeaders.ps1 -Path ./scripts -FailOnMissing -Verbose
281```
282
283**GitHub Actions Integration**:
284
285* Workflow: `.github/workflows/copyright-headers.yml`
286* Artifacts: `copyright-header-results` (JSON)
287* Exit Code: Non-zero if validation fails (with `-FailOnMissing`)
288
289## Shared Module
290
291### `Modules/LintingHelpers.psm1`
292
293Common helper functions for file discovery and git operations.
294
295**Exported Functions**:
296
297#### `Get-ChangedFilesFromGit`
298
299Detects files changed in current branch compared to main.
300
301**Parameters**:
302
303* `-BaseBranch` (string) - Base branch to compare against (default: `origin/main`)
304* `-FileExtensions` (string[]) - Array of file patterns to filter (e.g., `@('*.ps1', '*.md')`)
305
306**Returns**: Array of changed file paths
307
308**Fallbacks**:
309
3101. `git merge-base` with specified base branch
3112. `git diff HEAD~1` when merge-base fails
3123. `git diff HEAD` for staged/unstaged files
313
314#### `Get-FilesRecursive`
315
316Recursively finds files matching patterns with gitignore support.
317
318**Parameters**:
319
320* `-Path` (string, required) - Root directory to search from
321* `-Include` (string[], required) - File patterns to include (e.g., `@('*.ps1', '*.psm1')`)
322* `-GitIgnorePath` (string) - Path to `.gitignore` file for exclusion patterns
323
324**Returns**: Array of FileInfo objects
325
326**Respects**: `.gitignore` patterns when `-GitIgnorePath` is provided
327
328#### `Get-GitIgnorePatterns`
329
330Parses `.gitignore` into PowerShell wildcard patterns.
331
332**Parameters**:
333
334* `-GitIgnorePath` (string, required) - Path to `.gitignore` file
335
336**Returns**: Array of wildcard patterns using platform-appropriate separators
337
338### `scripts/lib/Modules/CIHelpers.psm1`
339
340CI helper functions for annotations, outputs, environment flags, and summaries.
341
342**Exported Functions**:
343
344#### `Write-CIAnnotation`
345
346Creates a CI annotation.
347
348**Parameters**:
349
350* `-Level` ('Error'|'Warning'|'Notice') - Annotation severity
351* `-Message` (string) - Annotation text
352* `-File` (string, optional) - File path
353* `-Line` (int, optional) - Line number
354* `-Column` (int, optional) - Column number
355
356**Output**: CI annotation command
357
358#### `Write-CIAnnotations`
359
360Writes CI annotations from a validation summary.
361
362**Parameters**:
363
364* `-Summary` (ValidationSummary) - Validation results to annotate
365
366#### `Set-CIOutput`
367
368Sets a CI output variable.
369
370**Parameters**:
371
372* `-Name` (string) - Variable name
373* `-Value` (string) - Variable value
374
375#### `Set-CIEnv`
376
377Sets a CI environment variable.
378
379**Parameters**:
380
381* `-Name` (string) - Variable name
382* `-Value` (string) - Variable value
383
384#### `Write-CIStepSummary`
385
386Appends content to the CI step summary.
387
388**Parameters**:
389
390* `-Content` (string) - Markdown content
391
392**Usage Example**:
393
394```powershell
395Import-Module ./Modules/LintingHelpers.psm1
396
397# Get changed PowerShell files
398$files = Get-ChangedFilesFromGit -FileExtension '.ps1'
399
400# Create error annotation
401Write-CIAnnotation -Level 'Error' -Message 'Syntax error' -File 'script.ps1' -Line 42
402
403# Set output variable
404Set-CIOutput -Name 'files-analyzed' -Value $files.Count
405
406# Add to step summary
407Write-CIStepSummary -Content "## Results`n`nAnalyzed $($files.Count) files"
408```
409
410## Configuration Files
411
412### Configuration: `PSScriptAnalyzer.psd1`
413
414PSScriptAnalyzer rule configuration.
415
416**Key Settings**:
417
418* Severity: Error, Warning
419* IncludeRules: Best practices, security, performance
420* ExcludeRules: `PSAvoidUsingWriteHost`
421
422### `markdown-link-check.config.json`
423
424Markdown link checker configuration.
425
426**Key Settings**:
427
428* Retry attempts: 3
429* Timeout: 10 seconds
430* Ignore patterns: Localhost, example.com
431
432## Testing
433
434All scripts support local testing before running in GitHub Actions:
435
436```powershell
437# Test PSScriptAnalyzer
438./scripts/linting/Invoke-PSScriptAnalyzer.ps1 -Verbose
439
440# Test frontmatter validation
441./scripts/linting/Validate-MarkdownFrontmatter.ps1 -ChangedFilesOnly
442
443# Test link language check
444./scripts/linting/Invoke-LinkLanguageCheck.ps1
445
446# Test markdown links
447./scripts/linting/Markdown-Link-Check.ps1
448
449# Test shared module
450Import-Module ./scripts/linting/Modules/LintingHelpers.psm1
451Get-Command -Module LintingHelpers
452```
453
454## GitHub Actions Workflows
455
456All linting scripts are integrated into GitHub Actions workflows:
457
458* **PSScriptAnalyzer**: `.github/workflows/psscriptanalyzer.yml`
459* **YAML Lint**: `.github/workflows/yaml-lint.yml`
460* **Frontmatter Validation**: `.github/workflows/frontmatter-validation.yml`
461* **Link Language Check**: `.github/workflows/link-lang-check.yml`
462* **Markdown Link Check**: `.github/workflows/markdown-link-check.yml`
463
464See [GitHub Workflows Documentation](../../.github/workflows/README.md) for details.
465
466## Adding New Linting Scripts
467
468To add a new linting script:
469
4701. **Create wrapper script** following `Invoke-*.ps1` naming convention
4712. **Import LintingHelpers and CIHelpers modules** for file discovery and CI integration
4723. **Implement core validation logic** with clear error reporting
4734. **Support common parameters**: `-Verbose`, `-Debug`, `-ChangedFilesOnly` (if applicable)
4745. **Create GitHub Actions workflow** in `.github/workflows/`
4756. **Add to PR validation** in `.github/workflows/pr-validation.yml`
4767. **Document** in this README and workflows README
4778. **Test locally** before creating PR
478
479**Template**:
480
481```powershell
482#!/usr/bin/env pwsh
483<#
484.SYNOPSIS
485 Brief description of validation.
486
487.DESCRIPTION
488 Detailed description.
489
490.PARAMETER ChangedFilesOnly
491 Validate only changed files.
492
493.EXAMPLE
494 ./scripts/linting/Invoke-MyValidator.ps1 -Verbose
495#>
496
497[CmdletBinding()]
498param(
499 [switch]$ChangedFilesOnly
500)
501
502$ErrorActionPreference = 'Stop'
503Import-Module (Join-Path $PSScriptRoot 'Modules/LintingHelpers.psm1') -Force
504Import-Module (Join-Path $PSScriptRoot '../lib/Modules/CIHelpers.psm1') -Force
505
506#region Functions
507
508function Invoke-MyValidatorCore {
509 [CmdletBinding()]
510 [OutputType([void])]
511 param(
512 [switch]$ChangedFilesOnly
513 )
514
515 Write-Host "🔍 Running MyValidator..."
516
517 if ($ChangedFilesOnly) {
518 $files = Get-ChangedFilesFromGit -FileExtension '.ext'
519 }
520 else {
521 $files = Get-FilesRecursive -Path (Get-Location) -Pattern '*.ext'
522 }
523
524 if ($files.Count -eq 0) {
525 Write-Host "✅ No files to validate"
526 return
527 }
528
529 # Perform validation
530 $issues = @()
531 foreach ($file in $files) {
532 # Validation logic here
533 if ($issue) {
534 $issues += $issue
535 Write-CIAnnotation -Level 'Error' -Message 'Issue found' -File $file
536 }
537 }
538
539 Write-CIStepSummary -Content "## Validation Results`n`nFound $($issues.Count) issues"
540
541 if ($issues.Count -gt 0) {
542 throw "Found $($issues.Count) issues"
543 }
544
545 Write-Host "✅ All files validated successfully"
546}
547
548#endregion Functions
549
550#region Main Execution
551if ($MyInvocation.InvocationName -ne '.') {
552 try {
553 Invoke-MyValidatorCore @PSBoundParameters
554 exit 0
555 }
556 catch {
557 Write-Error -ErrorAction Continue "Invoke-MyValidator failed: $($_.Exception.Message)"
558 Write-CIAnnotation -Message $_.Exception.Message -Level Error
559 exit 1
560 }
561}
562#endregion Main Execution
563```
564
565## Contributing
566
567When modifying linting scripts:
568
5691. Follow PowerShell best practices (PSScriptAnalyzer compliant)
5702. Maintain CI integration patterns
5713. Keep scripts testable locally without GitHub Actions
5724. Update documentation in README files
5735. Test thoroughly before creating PR
5746. Get CODEOWNERS approval
575
576## Related Documentation
577
578* [Scripts Documentation](../README.md)
579* [GitHub Workflows Documentation](../../.github/workflows/README.md)
580* [Contributing Guidelines](../../CONTRIBUTING.md)
581
582---
583
584🤖 Crafted with precision by ✨Copilot following brilliant human instruction, then carefully refined by our team of discerning human reviewers.
585