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/linting/Invoke-PythonTests.ps1

220lines · modecode

1#!/usr/bin/env pwsh
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4#
5# Invoke-PythonTests.ps1
6#
7# Purpose: Dynamically discovers and tests Python skills using pytest
8# Author: HVE Core Team
9
10#Requires -Version 7.0
11
12[CmdletBinding()]
13param(
14 [Parameter(Mandatory = $false)]
15 [string]$RepoRoot = (Get-Location).Path,
16
17 [Parameter(Mandatory = $false)]
18 [string]$OutputPath,
19
20 [Parameter(Mandatory = $false)]
21 [string]$Verbosity = '-v'
22)
23
24$ErrorActionPreference = 'Stop'
25
26#region Functions
27
28function Invoke-PythonTests {
29 [CmdletBinding()]
30 param(
31 [Parameter(Mandatory = $true)]
32 [string]$RepoRoot,
33
34 [Parameter(Mandatory = $false)]
35 [string]$OutputPath,
36
37 [Parameter(Mandatory = $false)]
38 [string]$Verbosity = '-v'
39 )
40
41 Push-Location $RepoRoot
42 try {
43 # Find all directories with pyproject.toml
44 $pythonSkills = Get-ChildItem -Path . -Filter 'pyproject.toml' -Recurse -Force -File |
45 Where-Object { $_.FullName -notmatch 'node_modules' } |
46 ForEach-Object { $_.Directory.FullName }
47
48 if (-not $pythonSkills) {
49 Write-Host 'No Python skills found (no pyproject.toml files detected)' -ForegroundColor Yellow
50 return @{ success = $true; skillsTested = 0; passed = 0; failed = 0; errors = @() }
51 }
52
53 Write-Host "Found $($pythonSkills.Count) Python skill(s):" -ForegroundColor Cyan
54 $pythonSkills | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray }
55
56 # Prefer locked uv environments when available; pytest remains the fallback for unlocked projects.
57 $uvCommand = Get-Command uv -ErrorAction SilentlyContinue
58 $globalPytest = Get-Command pytest -ErrorAction SilentlyContinue
59
60 $results = @{
61 success = $true
62 skillsTested = 0
63 passed = 0
64 failed = 0
65 errors = @()
66 details = @()
67 }
68
69 foreach ($skillPath in $pythonSkills) {
70 Write-Host "`nRunning pytest in $skillPath..." -ForegroundColor Cyan
71
72 Push-Location $skillPath
73 try {
74 # Check if tests directory exists
75 $testsDir = Join-Path $skillPath 'tests'
76 if (-not (Test-Path $testsDir)) {
77 Write-Host '⚠ No tests directory found, skipping' -ForegroundColor Yellow
78 continue
79 }
80
81 $uvLockPath = Join-Path $skillPath 'uv.lock'
82 $runner = 'pytest'
83 $syncOutput = $null
84
85 # use uv if the command is available, regardless of whether uv.lock exists
86 if ($uvCommand) {
87 $runner = 'uv'
88
89 if (Test-Path $uvLockPath) {
90 Write-Host ' Using uv locked environment' -ForegroundColor Gray
91 $syncOutput = & uv sync --locked --dev 2>&1
92 } else {
93 Write-Host ' Using uv environment (syncing dev dependencies)' -ForegroundColor Gray
94 $syncOutput = & uv sync --dev 2>&1
95 }
96
97 $syncExitCode = $LASTEXITCODE
98 Write-Host "$syncOutput"
99
100 if ($syncExitCode -ne 0) {
101 $result = @{
102 path = $skillPath
103 passed = $false
104 runner = $runner
105 phase = 'sync'
106 output = $syncOutput | Out-String
107 }
108
109 $results.details += $result
110 $results.skillsTested++
111 $results.success = $false
112 $results.failed++
113 $results.errors += $skillPath
114 Write-Host '❌ uv sync failed' -ForegroundColor Red
115 continue
116 }
117
118 $output = & uv run pytest tests/ $Verbosity --tb=short 2>&1
119 $exitCode = $LASTEXITCODE
120 } else {
121 # Resolve pytest: prefer skill venv, fall back to global
122 $pytestCmd = $null
123 $venvPytest = Join-Path $skillPath '.venv/bin/pytest'
124 $venvPytestWin = Join-Path $skillPath '.venv/Scripts/pytest.exe'
125 if (Test-Path $venvPytest) {
126 $pytestCmd = $venvPytest
127 Write-Host ' Using venv pytest' -ForegroundColor Gray
128 } elseif (Test-Path $venvPytestWin) {
129 $pytestCmd = $venvPytestWin
130 Write-Host ' Using venv pytest' -ForegroundColor Gray
131 } elseif ($globalPytest) {
132 $pytestCmd = 'pytest'
133 }
134
135 if (-not $pytestCmd) {
136 # Updated error message to reflect that uv is the primary check
137 Write-Host '❌ pytest not available (uv not found, no .venv, and not installed globally)' -ForegroundColor Red
138 $results.success = $false
139 $results.failed++
140 $results.errors += $skillPath
141 continue
142 }
143
144 $output = & $pytestCmd tests/ $Verbosity --tb=short 2>&1
145 $exitCode = $LASTEXITCODE
146 }
147
148 $result = @{
149 path = $skillPath
150 passed = ($exitCode -eq 0)
151 runner = $runner
152 output = $output | Out-String
153 }
154
155 $results.details += $result
156 $results.skillsTested++
157
158 Write-Host "$output"
159
160 if ($exitCode -ne 0) {
161 Write-Host '❌ Tests failed' -ForegroundColor Red
162 $results.success = $false
163 $results.failed++
164 $results.errors += $skillPath
165 } else {
166 Write-Host '✓ All tests passed' -ForegroundColor Green
167 $results.passed++
168 }
169 } catch {
170 Write-Host "Error running pytest: $_" -ForegroundColor Red
171 $results.success = $false
172 $results.failed++
173 $results.errors += "$skillPath - error: $_"
174 } finally {
175 Pop-Location
176 }
177 }
178
179 # Default to logs directory when no OutputPath specified
180 if (-not $OutputPath) {
181 $logsDir = Join-Path -Path $RepoRoot -ChildPath 'logs'
182 if (-not (Test-Path $logsDir)) {
183 New-Item -ItemType Directory -Path $logsDir -Force | Out-Null
184 }
185 $OutputPath = Join-Path -Path $logsDir -ChildPath 'python-test-results.json'
186 }
187 $results | ConvertTo-Json -Depth 3 | Out-File $OutputPath -Encoding UTF8
188 Write-Host "📊 Results written to: $OutputPath" -ForegroundColor Cyan
189
190 return $results
191 } finally {
192 Pop-Location
193 }
194}
195
196#endregion
197
198#region Main Execution
199
200# Don't run main logic if dot-sourced for testing
201if ($MyInvocation.InvocationName -ne '.') {
202 $result = Invoke-PythonTests -RepoRoot $RepoRoot -OutputPath $OutputPath -Verbosity $Verbosity
203
204 Write-Host "`n========================================" -ForegroundColor Cyan
205 Write-Host 'Test Summary:' -ForegroundColor Cyan
206 Write-Host " Total: $($result.skillsTested)" -ForegroundColor White
207 Write-Host " Passed: $($result.passed)" -ForegroundColor Green
208 Write-Host " Failed: $($result.failed)" -ForegroundColor $(if ($result.failed -gt 0) { 'Red' } else { 'Green' })
209 Write-Host '========================================' -ForegroundColor Cyan
210
211 if ($result.success) {
212 Write-Host '✅ All tests passed' -ForegroundColor Green
213 exit 0
214 } else {
215 Write-Host '❌ Testing completed with failures' -ForegroundColor Red
216 exit 1
217 }
218}
219
220#endregion Main Execution