microsoft/hve-core

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feat/1637-d-skill-paths

Branches

Tags

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

Clone

HTTPS

Download ZIP

scripts/evals/Get-ChangedAIArtifact.ps1

184lines · modecode

1#!/usr/bin/env pwsh
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4#Requires -Version 7.0
5
6<#
7.SYNOPSIS
8 Emits a JSON manifest of AI customization artifacts changed between two git refs.
9
10.DESCRIPTION
11 Runs `git diff --name-status <BaseRef>...<HeadRef>` (three-dot diff to use the merge base)
12 and classifies each entry as an agent / prompt / instruction / skill artifact via the
13 ArtifactDetection module. Writes a manifest JSON array to `-OutFile` (default
14 `logs/changed-ai-artifacts.json`) where each entry has `kind`, `path`, `artifactId`,
15 `status`, and (for renames/copies) `previousPath`. Repo-root-only artifacts and nested
16 collection-scoped artifacts are both detected.
17
18 Exit codes:
19 0 = manifest written successfully (manifest may be empty).
20 2 = git invocation failed.
21
22.PARAMETER BaseRef
23 Base git ref for the diff. Defaults to `origin/main`.
24
25.PARAMETER HeadRef
26 Head git ref for the diff. Defaults to `HEAD`.
27
28.PARAMETER OutFile
29 Output JSON path. Defaults to `logs/changed-ai-artifacts.json` (relative to RepoRoot).
30
31.PARAMETER RepoRoot
32 Repository root. Defaults to the git toplevel or this script's parent directory.
33
34.EXAMPLE
35 pwsh -File scripts/evals/Get-ChangedAIArtifact.ps1
36 Diff origin/main...HEAD and emit logs/changed-ai-artifacts.json.
37
38.EXAMPLE
39 pwsh -File scripts/evals/Get-ChangedAIArtifact.ps1 -BaseRef origin/main -HeadRef feature/branch
40 Diff a specific branch pair.
41
42.NOTES
43 Used by the PR-time eval coverage workflow to feed Test-StimulusPresence.ps1.
44#>
45
46[CmdletBinding()]
47param(
48 [Parameter(Mandatory = $false)]
49 [string]$BaseRef = 'origin/main',
50
51 [Parameter(Mandatory = $false)]
52 [string]$HeadRef = 'HEAD',
53
54 [Parameter(Mandatory = $false)]
55 [string]$OutFile,
56
57 [Parameter(Mandatory = $false)]
58 [string]$RepoRoot
59)
60
61$ErrorActionPreference = 'Stop'
62
63Import-Module (Join-Path $PSScriptRoot 'Modules/ArtifactDetection.psm1') -Force
64Import-Module (Join-Path $PSScriptRoot 'Modules/AffectedAgents.psm1') -Force
65
66function Resolve-RepoRoot {
67 [CmdletBinding()]
68 [OutputType([string])]
69 param([string]$Hint)
70
71 if (-not [string]::IsNullOrWhiteSpace($Hint)) {
72 return (Resolve-Path -LiteralPath $Hint).ProviderPath
73 }
74
75 try {
76 $gitRoot = git rev-parse --show-toplevel 2>$null
77 if ($LASTEXITCODE -eq 0 -and -not [string]::IsNullOrWhiteSpace($gitRoot)) {
78 return (Resolve-Path -LiteralPath $gitRoot.Trim()).ProviderPath
79 }
80 }
81 catch {
82 $null = $_
83 }
84
85 return (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '../..')).ProviderPath
86}
87
88function Invoke-ChangedArtifactScan {
89 <#
90 .SYNOPSIS
91 Runs git diff and classifies the results into an artifact manifest.
92
93 .OUTPUTS
94 [hashtable] `@{ baseRef; headRef; artifacts = @(...) }`.
95 #>
96 [CmdletBinding()]
97 [OutputType([hashtable])]
98 param(
99 [Parameter(Mandatory = $true)]
100 [string]$BaseRef,
101
102 [Parameter(Mandatory = $true)]
103 [string]$HeadRef,
104
105 [Parameter(Mandatory = $true)]
106 [string]$RepoRoot
107 )
108
109 Push-Location -LiteralPath $RepoRoot
110 try {
111 $diffOutput = & git diff --name-status "$BaseRef...$HeadRef" 2>&1
112 $exit = $LASTEXITCODE
113 }
114 finally {
115 Pop-Location
116 }
117
118 if ($exit -ne 0) {
119 throw "git diff failed (exit $exit): $($diffOutput -join [Environment]::NewLine)"
120 }
121
122 $lines = @($diffOutput | Where-Object { $_ -is [string] -and -not [string]::IsNullOrWhiteSpace($_) })
123 $changes = ConvertFrom-GitDiffNameStatus -Lines $lines
124
125 $artifacts = [System.Collections.Generic.List[hashtable]]::new()
126 $changedPaths = [System.Collections.Generic.List[string]]::new()
127 foreach ($change in $changes) {
128 $record = Get-ChangedArtifactRecord -Change $change
129 if ($null -ne $record) {
130 $artifacts.Add($record)
131 }
132 if ($change.path) { $changedPaths.Add([string]$change.path) }
133 if ($change.previousPath) { $changedPaths.Add([string]$change.previousPath) }
134 }
135
136 $affectedAgents = [string[]]@()
137 if ($changedPaths.Count -gt 0) {
138 try {
139 $affectedAgents = Get-AffectedAgentSlugs -ChangedFiles $changedPaths.ToArray() -RepoRoot $RepoRoot
140 }
141 catch {
142 Write-Warning "Failed to resolve affected agents: $($_.Exception.Message)"
143 $affectedAgents = [string[]]@()
144 }
145 }
146
147 return @{
148 baseRef = $BaseRef
149 headRef = $HeadRef
150 artifacts = $artifacts.ToArray()
151 affectedAgents = [string[]]$affectedAgents
152 }
153}
154
155if ($MyInvocation.InvocationName -ne '.') {
156 $resolvedRepoRoot = Resolve-RepoRoot -Hint $RepoRoot
157
158 if ([string]::IsNullOrWhiteSpace($OutFile)) {
159 $OutFile = Join-Path -Path $resolvedRepoRoot -ChildPath 'logs/changed-ai-artifacts.json'
160 }
161 elseif (-not [System.IO.Path]::IsPathRooted($OutFile)) {
162 $OutFile = Join-Path -Path $resolvedRepoRoot -ChildPath $OutFile
163 }
164
165 try {
166 $manifest = Invoke-ChangedArtifactScan -BaseRef $BaseRef -HeadRef $HeadRef -RepoRoot $resolvedRepoRoot
167 }
168 catch {
169 Write-Error $_.Exception.Message
170 exit 2
171 }
172
173 $outDir = Split-Path -Path $OutFile -Parent
174 if (-not [string]::IsNullOrWhiteSpace($outDir) -and -not (Test-Path -LiteralPath $outDir -PathType Container)) {
175 New-Item -ItemType Directory -Path $outDir -Force | Out-Null
176 }
177
178 $manifest | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $OutFile -Encoding UTF8
179
180 Write-Host "Detected $($manifest.artifacts.Count) changed AI artifact(s) between $BaseRef and $HeadRef."
181 Write-Host "Affected agent slugs: $($manifest.affectedAgents.Count)"
182 Write-Host "Manifest: $OutFile"
183 exit 0
184}
185