microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
hve-core-v3.0.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

scripts/linting/README.md

632lines · 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### Skill Structure Validation
246
247#### `Validate-SkillStructure.ps1`
248
249Validates the structural integrity of skill directories under `.github/skills/`.
250
251**Purpose**: Ensure all skill packages comply with the agentskills.io specification and hve-core conventions.
252
253**Features**:
254
255* Validates SKILL.md presence in each skill directory
256* Checks frontmatter for required `name` and `description` fields
257* Verifies `name` matches directory name
258* When `scripts/` subdirectory exists, requires both `.ps1` and `.sh` files for cross-platform support
259* Warns on unrecognized directories
260* Supports changed-files-only mode via Git
261* Creates CI annotations for violations
262* Exports JSON results to `logs/skill-validation-results.json`
263
264**Parameters**:
265
266* `-SkillsPath` (string) - Root path containing skill directories (default: `.github/skills`)
267* `-WarningsAsErrors` (switch) - Treat warnings as errors
268* `-ChangedFilesOnly` (switch) - Validate only skills with changed files
269* `-BaseBranch` (string) - Git reference for changed file detection (default: `origin/main`)
270
271**Usage**:
272
273```powershell
274# Validate all skills
275./scripts/linting/Validate-SkillStructure.ps1
276
277# Validate with warnings as errors
278./scripts/linting/Validate-SkillStructure.ps1 -WarningsAsErrors
279
280# Validate only changed skills
281./scripts/linting/Validate-SkillStructure.ps1 -ChangedFilesOnly
282```
283
284**GitHub Actions Integration**:
285
286* Workflow: `.github/workflows/skill-validation.yml`
287* Artifacts: `skill-validation-results` (JSON)
288* Exit Code: Non-zero if validation fails
289
290### Copyright Header Validation
291
292#### `Test-CopyrightHeaders.ps1`
293
294Validates copyright and SPDX license headers in source files.
295
296**Purpose**: Ensure all PowerShell and shell scripts include the required Microsoft copyright notice and MIT SPDX license identifier in their first 15 lines.
297
298**Features**:
299
300* Scans `.ps1`, `.psm1`, `.psd1`, and `.sh` files recursively
301* Checks for `Copyright (c) Microsoft Corporation` header
302* Checks for `SPDX-License-Identifier: MIT` identifier
303* Configurable file extensions and exclude paths
304* Exports JSON results with per-file compliance details
305* Calculates compliance percentage across all scanned files
306
307**Parameters**:
308
309* `-Path` (string) - Root path to scan (default: repository root via `git rev-parse --show-toplevel`)
310* `-FileExtensions` (string[]) - File extensions to check (default: `@('*.ps1', '*.psm1', '*.psd1', '*.sh')`)
311* `-OutputPath` (string) - Path for JSON results (default: `logs/copyright-header-results.json`)
312* `-FailOnMissing` (switch) - Exit with code 1 if any files lack required headers
313* `-ExcludePaths` (string[]) - Directories to exclude (default: `@('node_modules', '.git', 'vendor', 'logs')`)
314
315**Usage**:
316
317```powershell
318# Check all source files (report only)
319./scripts/linting/Test-CopyrightHeaders.ps1
320
321# Check and fail on missing headers
322./scripts/linting/Test-CopyrightHeaders.ps1 -FailOnMissing
323
324# Check specific path with verbose output
325./scripts/linting/Test-CopyrightHeaders.ps1 -Path ./scripts -FailOnMissing -Verbose
326```
327
328**GitHub Actions Integration**:
329
330* Workflow: `.github/workflows/copyright-headers.yml`
331* Artifacts: `copyright-header-results` (JSON)
332* Exit Code: Non-zero if validation fails (with `-FailOnMissing`)
333
334## Shared Module
335
336### `Modules/LintingHelpers.psm1`
337
338Common helper functions for file discovery and git operations.
339
340**Exported Functions**:
341
342#### `Get-ChangedFilesFromGit`
343
344Detects files changed in current branch compared to main.
345
346**Parameters**:
347
348* `-BaseBranch` (string) - Base branch to compare against (default: `origin/main`)
349* `-FileExtensions` (string[]) - Array of file patterns to filter (e.g., `@('*.ps1', '*.md')`)
350
351**Returns**: Array of changed file paths
352
353**Fallbacks**:
354
3551. `git merge-base` with specified base branch
3562. `git diff HEAD~1` when merge-base fails
3573. `git diff HEAD` for staged/unstaged files
358
359#### `Get-FilesRecursive`
360
361Finds files matching patterns using `git ls-files` with a `Get-ChildItem` fallback.
362
363**Parameters**:
364
365* `-Path` (string, required) - Root directory to search from
366* `-Include` (string[], required) - File patterns to include (e.g., `@('*.ps1', '*.psm1')`)
367* `-GitIgnorePath` (string) - Path to `.gitignore` file for exclusion patterns (fallback path only)
368
369**Returns**: Array of FileInfo objects
370
371**Behavior**:
372
373* Inside a git repository, uses `git ls-files --cached --others --exclude-standard` scoped to the given path. Git natively handles `.gitignore` exclusions.
374* Outside a git repository (or when `git` is unavailable), falls back to `Get-ChildItem -Recurse` with optional `-GitIgnorePath` filtering.
375
376#### `Get-GitIgnorePatterns`
377
378Parses `.gitignore` into PowerShell wildcard patterns.
379
380**Parameters**:
381
382* `-GitIgnorePath` (string, required) - Path to `.gitignore` file
383
384**Returns**: Array of wildcard patterns using platform-appropriate separators
385
386### `scripts/lib/Modules/CIHelpers.psm1`
387
388CI helper functions for annotations, outputs, environment flags, and summaries.
389
390**Exported Functions**:
391
392#### `Write-CIAnnotation`
393
394Creates a CI annotation.
395
396**Parameters**:
397
398* `-Level` ('Error'|'Warning'|'Notice') - Annotation severity
399* `-Message` (string) - Annotation text
400* `-File` (string, optional) - File path
401* `-Line` (int, optional) - Line number
402* `-Column` (int, optional) - Column number
403
404**Output**: CI annotation command
405
406#### `Write-CIAnnotations`
407
408Writes CI annotations from a validation summary.
409
410**Parameters**:
411
412* `-Summary` (ValidationSummary) - Validation results to annotate
413
414#### `Set-CIOutput`
415
416Sets a CI output variable.
417
418**Parameters**:
419
420* `-Name` (string) - Variable name
421* `-Value` (string) - Variable value
422
423#### `Set-CIEnv`
424
425Sets a CI environment variable.
426
427**Parameters**:
428
429* `-Name` (string) - Variable name
430* `-Value` (string) - Variable value
431
432#### `Write-CIStepSummary`
433
434Appends content to the CI step summary.
435
436**Parameters**:
437
438* `-Content` (string) - Markdown content
439
440**Usage Example**:
441
442```powershell
443Import-Module ./Modules/LintingHelpers.psm1
444
445# Get changed PowerShell files
446$files = Get-ChangedFilesFromGit -FileExtension '.ps1'
447
448# Create error annotation
449Write-CIAnnotation -Level 'Error' -Message 'Syntax error' -File 'script.ps1' -Line 42
450
451# Set output variable
452Set-CIOutput -Name 'files-analyzed' -Value $files.Count
453
454# Add to step summary
455Write-CIStepSummary -Content "## Results`n`nAnalyzed $($files.Count) files"
456```
457
458## Configuration Files
459
460### Configuration: `PSScriptAnalyzer.psd1`
461
462PSScriptAnalyzer rule configuration.
463
464**Key Settings**:
465
466* Severity: Error, Warning
467* IncludeRules: Best practices, security, performance
468* ExcludeRules: `PSAvoidUsingWriteHost`
469
470### `markdown-link-check.config.json`
471
472Markdown link checker configuration.
473
474**Key Settings**:
475
476* Retry attempts: 3
477* Timeout: 10 seconds
478* Ignore patterns: Localhost, example.com
479
480## Testing
481
482All scripts support local testing before running in GitHub Actions:
483
484```powershell
485# Test PSScriptAnalyzer
486./scripts/linting/Invoke-PSScriptAnalyzer.ps1 -Verbose
487
488# Test frontmatter validation
489./scripts/linting/Validate-MarkdownFrontmatter.ps1 -ChangedFilesOnly
490
491# Test link language check
492./scripts/linting/Invoke-LinkLanguageCheck.ps1
493
494# Test markdown links
495./scripts/linting/Markdown-Link-Check.ps1
496
497# Test shared module
498Import-Module ./scripts/linting/Modules/LintingHelpers.psm1
499Get-Command -Module LintingHelpers
500```
501
502## GitHub Actions Workflows
503
504All linting scripts are integrated into GitHub Actions workflows:
505
506* **PSScriptAnalyzer**: `.github/workflows/psscriptanalyzer.yml`
507* **YAML Lint**: `.github/workflows/yaml-lint.yml`
508* **Frontmatter Validation**: `.github/workflows/frontmatter-validation.yml`
509* **Link Language Check**: `.github/workflows/link-lang-check.yml`
510* **Markdown Link Check**: `.github/workflows/markdown-link-check.yml`
511
512See [GitHub Workflows Documentation](../../.github/workflows/README.md) for details.
513
514## Adding New Linting Scripts
515
516To add a new linting script:
517
5181. **Create wrapper script** following `Invoke-*.ps1` naming convention
5192. **Import LintingHelpers and CIHelpers modules** for file discovery and CI integration
5203. **Implement core validation logic** with clear error reporting
5214. **Support common parameters**: `-Verbose`, `-Debug`, `-ChangedFilesOnly` (if applicable)
5225. **Create GitHub Actions workflow** in `.github/workflows/`
5236. **Add to PR validation** in `.github/workflows/pr-validation.yml`
5247. **Document** in this README and workflows README
5258. **Test locally** before creating PR
526
527**Template**:
528
529```powershell
530#!/usr/bin/env pwsh
531<#
532.SYNOPSIS
533 Brief description of validation.
534
535.DESCRIPTION
536 Detailed description.
537
538.PARAMETER ChangedFilesOnly
539 Validate only changed files.
540
541.EXAMPLE
542 ./scripts/linting/Invoke-MyValidator.ps1 -Verbose
543#>
544
545[CmdletBinding()]
546param(
547 [switch]$ChangedFilesOnly
548)
549
550$ErrorActionPreference = 'Stop'
551Import-Module (Join-Path $PSScriptRoot 'Modules/LintingHelpers.psm1') -Force
552Import-Module (Join-Path $PSScriptRoot '../lib/Modules/CIHelpers.psm1') -Force
553
554#region Functions
555
556function Invoke-MyValidatorCore {
557 [CmdletBinding()]
558 [OutputType([void])]
559 param(
560 [switch]$ChangedFilesOnly
561 )
562
563 Write-Host "🔍 Running MyValidator..."
564
565 if ($ChangedFilesOnly) {
566 $files = Get-ChangedFilesFromGit -FileExtension '.ext'
567 }
568 else {
569 $files = Get-FilesRecursive -Path (Get-Location) -Pattern '*.ext'
570 }
571
572 if ($files.Count -eq 0) {
573 Write-Host "✅ No files to validate"
574 return
575 }
576
577 # Perform validation
578 $issues = @()
579 foreach ($file in $files) {
580 # Validation logic here
581 if ($issue) {
582 $issues += $issue
583 Write-CIAnnotation -Level 'Error' -Message 'Issue found' -File $file
584 }
585 }
586
587 Write-CIStepSummary -Content "## Validation Results`n`nFound $($issues.Count) issues"
588
589 if ($issues.Count -gt 0) {
590 throw "Found $($issues.Count) issues"
591 }
592
593 Write-Host "✅ All files validated successfully"
594}
595
596#endregion Functions
597
598#region Main Execution
599if ($MyInvocation.InvocationName -ne '.') {
600 try {
601 Invoke-MyValidatorCore @PSBoundParameters
602 exit 0
603 }
604 catch {
605 Write-Error -ErrorAction Continue "Invoke-MyValidator failed: $($_.Exception.Message)"
606 Write-CIAnnotation -Message $_.Exception.Message -Level Error
607 exit 1
608 }
609}
610#endregion Main Execution
611```
612
613## Contributing
614
615When modifying linting scripts:
616
6171. Follow PowerShell best practices (PSScriptAnalyzer compliant)
6182. Maintain CI integration patterns
6193. Keep scripts testable locally without GitHub Actions
6204. Update documentation in README files
6215. Test thoroughly before creating PR
6226. Get CODEOWNERS approval
623
624## Related Documentation
625
626* [Scripts Documentation](../README.md)
627* [GitHub Workflows Documentation](../../.github/workflows/README.md)
628* [Contributing Guidelines](../../CONTRIBUTING.md)
629
630---
631
632🤖 Crafted with precision by ✨Copilot following brilliant human instruction, then carefully refined by our team of discerning human reviewers.