Merge pull request #11518 from lawrencegripper/lg/require-pinned
Add workflows to require `pinnedDetails` when minor version of a tool is pinned in a toolset file
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
name: Check Outdated Version Pinning
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 12 * * 1' # Run at 12:00 UTC every Monday
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-pinning-dates:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Validate JSON Schema
|
||||||
|
shell: pwsh
|
||||||
|
run: ./helpers/CheckOutdatedVersionPinning.ps1
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
name: Validate JSON Schema
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-json-schema:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Validate JSON Schema
|
||||||
|
shell: pwsh
|
||||||
|
run: ./helpers/CheckJsonSchema.ps1
|
||||||
Vendored
+9
@@ -21,5 +21,14 @@
|
|||||||
],
|
],
|
||||||
"shellcheck.customArgs": [
|
"shellcheck.customArgs": [
|
||||||
"-x"
|
"-x"
|
||||||
|
],
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": [
|
||||||
|
"**/toolset-*.json"
|
||||||
|
],
|
||||||
|
"url": "./schemas/toolset-schema.json"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# A JSON schema validator which supports outputting line numbers for errors
|
||||||
|
# this allows us to put annotations on builds for errors in the JSON files
|
||||||
|
# `Test-Json` built in cmdline doesn't. No existing cli tool supports this
|
||||||
|
# that I could find either. See: https://github.com/lawrencegripper/gripdev-json-schema-validator
|
||||||
|
Install-Module -Name GripDevJsonSchemaValidator -Force -Scope CurrentUser
|
||||||
|
|
||||||
|
# Find all toolset JSON files
|
||||||
|
$toolsetFiles = Get-ChildItem -Recurse -Filter "toolset-*.json" | Where-Object { $_.Name -notlike "*schema.json" }
|
||||||
|
$schemaFilePath = "./schemas/toolset-schema.json"
|
||||||
|
|
||||||
|
$toolsetHasErrors = $false
|
||||||
|
foreach ($file in $toolsetFiles) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "🔍 Validating $($file.FullName)" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$validationResult = Test-JsonSchema -SchemaPath $schemaFilePath -JsonPath $file.FullName -PrettyPrint $false
|
||||||
|
|
||||||
|
if ($validationResult.Valid) {
|
||||||
|
Write-Host "✅ JSON is valid." -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
# File has been modified since the commit, enforce validation
|
||||||
|
$toolsetHasErrors = $true
|
||||||
|
Write-Host "`n❌ JSON validation failed!" -ForegroundColor Red
|
||||||
|
Write-Host " Found the following errors:`n" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$validationResult.Errors | ForEach-Object {
|
||||||
|
Write-Host $_.UserMessage
|
||||||
|
if ($env:GITHUB_ACTIONS -eq 'true') {
|
||||||
|
Write-Host "Adding annotation"
|
||||||
|
Write-Host "::error file=$($file.Name),line=$($_.LineNumber)::$($_.UserMessage.Replace("`n", '%0A'))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($toolsetHasErrors) {
|
||||||
|
Write-Error "One or more toolset JSON files failed schema validation. See the error output above for more details."
|
||||||
|
} else {
|
||||||
|
Write-Host "Schema validation completed successfully"
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# Find all toolset JSON files
|
||||||
|
$toolsetFiles = Get-ChildItem -Recurse -Filter "toolset-*.json" | Where-Object { $_.Name -notlike "*schema.json" }
|
||||||
|
|
||||||
|
$expiringPins = @()
|
||||||
|
$now = Get-Date
|
||||||
|
$warningDays = 30 # Warn if expiring within 30 days
|
||||||
|
|
||||||
|
foreach ($file in $toolsetFiles) {
|
||||||
|
Write-Host "Processing $($file.Name)"
|
||||||
|
$content = Get-Content $file.FullName | ConvertFrom-Json
|
||||||
|
|
||||||
|
# Recursively search for pinnedDetails in the JSON
|
||||||
|
function Search-PinnedDetails {
|
||||||
|
param($obj, $path)
|
||||||
|
|
||||||
|
$foundPins = @()
|
||||||
|
|
||||||
|
if ($obj -is [System.Management.Automation.PSCustomObject]) {
|
||||||
|
foreach ($prop in $obj.PSObject.Properties) {
|
||||||
|
if ($prop.Name -eq "pinnedDetails") {
|
||||||
|
Write-Host "Found pinned version at $path"
|
||||||
|
$reviewAt = [DateTime]::Parse($prop.Value.'review-at')
|
||||||
|
$daysUntilExpiry = ($reviewAt - $now).Days
|
||||||
|
|
||||||
|
if ($daysUntilExpiry -lt $warningDays) {
|
||||||
|
Write-Host "Adding to expiringPins array"
|
||||||
|
$foundPins += @{
|
||||||
|
Path = $path
|
||||||
|
File = $file.Name
|
||||||
|
ReviewAt = $reviewAt
|
||||||
|
DaysUntilExpiry = $daysUntilExpiry
|
||||||
|
Reason = $prop.Value.reason
|
||||||
|
Link = $prop.Value.link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$foundPins += Search-PinnedDetails -obj $prop.Value -path "$path.$($prop.Name)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($obj -is [Array]) {
|
||||||
|
for ($i = 0; $i -lt $obj.Count; $i++) {
|
||||||
|
$foundPins += Search-PinnedDetails -obj $obj[$i] -path "$path[$i]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $foundPins
|
||||||
|
}
|
||||||
|
|
||||||
|
$expiringPins += Search-PinnedDetails -obj $content -path $file.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expiringPins) {
|
||||||
|
$issueBody = "# Version Pinning Review Required`n`n"
|
||||||
|
$issueBody += "The following pinned versions need review:`n`n"
|
||||||
|
|
||||||
|
foreach ($pin in $expiringPins) {
|
||||||
|
$status = if ($pin.DaysUntilExpiry -lt 0) { "EXPIRED" } else { "Expiring Soon" }
|
||||||
|
$issueBody += "## $($status) - $($pin.Path)`n"
|
||||||
|
$issueBody += "- **File**: $($pin.File)`n"
|
||||||
|
$issueBody += "- **Review Date**: $($pin.ReviewAt.ToString('yyyy-MM-dd'))`n"
|
||||||
|
$issueBody += "- **Days until expiry**: $($pin.DaysUntilExpiry)`n"
|
||||||
|
$issueBody += "- **Reason**: $($pin.Reason)`n"
|
||||||
|
$issueBody += "- **Original PR**: $($pin.Link)`n`n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:GITHUB_ACTIONS -eq 'true') {
|
||||||
|
# In GitHub Actions, create an issue
|
||||||
|
Write-Host "Creating issue"
|
||||||
|
$tempFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
Set-Content -Path $tempFile -Value $issueBody
|
||||||
|
gh issue create --title "Version Pinning Review Found Expired Pinned Versions" --body-file $tempFile
|
||||||
|
Remove-Item -Path $tempFile
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`nIssue Content:`n"
|
||||||
|
Write-Host $issueBody
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "No expiring pins found."
|
||||||
|
if ($env:GITHUB_ACTIONS -eq 'true') {
|
||||||
|
"expired_pins=0" >> $env:GITHUB_OUTPUT
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -381,10 +381,21 @@
|
|||||||
},
|
},
|
||||||
"aliyunCli": {
|
"aliyunCli": {
|
||||||
"version": "3.0.174",
|
"version": "3.0.174",
|
||||||
"sha256": "0c51028a7a32fc02c8de855f73e273556f957115eb5624565738f9b9f83a50ba"
|
"sha256": "0c51028a7a32fc02c8de855f73e273556f957115eb5624565738f9b9f83a50ba",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/actions/runner-images-internal/pull/6702",
|
||||||
|
"reason": "Meaningful reason must be added at next update.",
|
||||||
|
"review-at": "2025-06-01",
|
||||||
|
"type": "preexisting-pinned-version-without-reason"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ocCli": {
|
"ocCli": {
|
||||||
"version": "4.15.19"
|
"version": "4.15.19",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/actions/runner-images-internal/pull/6702",
|
||||||
|
"reason": "Meaningful reason must be added at next update.",
|
||||||
|
"review-at": "2025-06-01",
|
||||||
|
"type": "preexisting-pinned-version-without-reason"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,7 +474,12 @@
|
|||||||
"version": "latest"
|
"version": "latest"
|
||||||
},
|
},
|
||||||
"openssl": {
|
"openssl": {
|
||||||
"version": "1.1.1"
|
"version": "1.1.1",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/somelink",
|
||||||
|
"reason": "this was pinned due to a downstream issue with the installer",
|
||||||
|
"review-at": "2025-01-30"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pwsh": {
|
"pwsh": {
|
||||||
"version": "7.4"
|
"version": "7.4"
|
||||||
|
|||||||
@@ -150,7 +150,13 @@
|
|||||||
},
|
},
|
||||||
"mingw": {
|
"mingw": {
|
||||||
"version": "12.2.0",
|
"version": "12.2.0",
|
||||||
"runtime": "ucrt"
|
"runtime": "ucrt",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/actions/runner-images-internal/pull/6702",
|
||||||
|
"reason": "Meaningful reason must be added at next update.",
|
||||||
|
"review-at": "2025-06-01",
|
||||||
|
"type": "preexisting-pinned-version-without-reason"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsysPackages": {
|
"MsysPackages": {
|
||||||
"msys2": [],
|
"msys2": [],
|
||||||
@@ -384,7 +390,13 @@
|
|||||||
"version": "latest"
|
"version": "latest"
|
||||||
},
|
},
|
||||||
"openssl": {
|
"openssl": {
|
||||||
"version": "1.1.1"
|
"version": "1.1.1",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/actions/runner-images-internal/pull/6702",
|
||||||
|
"reason": "Meaningful reason must be added at next update.",
|
||||||
|
"review-at": "2024-06-01",
|
||||||
|
"type": "preexisting-pinned-version-without-reason"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pwsh": {
|
"pwsh": {
|
||||||
"version": "7.4"
|
"version": "7.4"
|
||||||
|
|||||||
@@ -107,7 +107,13 @@
|
|||||||
},
|
},
|
||||||
"mingw": {
|
"mingw": {
|
||||||
"version": "14.2.0",
|
"version": "14.2.0",
|
||||||
"runtime": "ucrt"
|
"runtime": "ucrt",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/actions/runner-images-internal/pull/6702",
|
||||||
|
"reason": "Meaningful reason must be added at next update.",
|
||||||
|
"review-at": "2025-06-01",
|
||||||
|
"type": "preexisting-pinned-version-without-reason"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"MsysPackages": {
|
"MsysPackages": {
|
||||||
"msys2": [],
|
"msys2": [],
|
||||||
@@ -318,7 +324,13 @@
|
|||||||
"version": "latest"
|
"version": "latest"
|
||||||
},
|
},
|
||||||
"openssl": {
|
"openssl": {
|
||||||
"version": "3.4.0"
|
"version": "3.4.0",
|
||||||
|
"pinnedDetails": {
|
||||||
|
"link": "https://github.com/actions/runner-images-internal/pull/6702",
|
||||||
|
"reason": "Meaningful reason must be added at next update.",
|
||||||
|
"review-at": "2025-06-01",
|
||||||
|
"type": "preexisting-pinned-version-without-reason"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"pwsh": {
|
"pwsh": {
|
||||||
"version": "7.4"
|
"version": "7.4"
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
"^.*$": {
|
||||||
|
"if": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+.*$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"required": [
|
||||||
|
"pinnedDetails"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"pinnedDetails": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"reason": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"review-at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user