Skip to content

Commit 3940cd7

Browse files
authored
[suppressions.yaml] Create shared component "get-suppressions" (#28927)
- Usage: `npx get-suppressions <tool-name> <path-to-file>` - Returns: JSON array of suppressions, with specified tool name, applying to file (may be empty) - Example: `npm get-suppressions TypeSpecRequirement specification/foo/data-plane/Foo/stable/2023-01-01/Foo.json` - Fixes #28069
1 parent a9ace5a commit 3940cd7

File tree

14 files changed

+2113
-203
lines changed

14 files changed

+2113
-203
lines changed

.github/workflows/suppressions.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Suppressions
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- typespec-next
8+
pull_request:
9+
branches:
10+
- main
11+
- typespec-next
12+
paths:
13+
- package-lock.json
14+
- package.json
15+
- tsconfig.json
16+
- eng/tools/package.json
17+
- eng/tools/tsconfig.json
18+
- eng/tools/suppressions
19+
20+
jobs:
21+
ci:
22+
strategy:
23+
matrix:
24+
os: [ubuntu-latest, windows-latest]
25+
node: [18, 20]
26+
exclude:
27+
- os: ubuntu-latest
28+
node: 20
29+
- os: windows-latest
30+
node: 18
31+
32+
runs-on: ${{ matrix.os }}
33+
34+
steps:
35+
- name: Enable git long paths
36+
if: runner.os == 'Windows'
37+
run: git config --system core.longpaths true
38+
39+
- uses: actions/checkout@v4
40+
with:
41+
sparse-checkout: eng
42+
43+
- name: Use Node ${{ matrix.node }}.x
44+
uses: actions/setup-node@v4
45+
with:
46+
node-version: '${{ matrix.node }}.x'
47+
48+
- run: npm ci
49+
50+
- run: npm run build
51+
working-directory: ./eng/tools/suppressions
52+
53+
- run: npm test
54+
working-directory: ./eng/tools/suppressions

eng/scripts/TypeSpec-Requirement.ps1

Lines changed: 16 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -5,88 +5,37 @@ param (
55
[Parameter(Position = 1)]
66
[string] $TargetCommitish = "HEAD",
77
[Parameter(Position = 2)]
8-
[string] $SpecType = "data-plane|resource-manager"
8+
[string] $SpecType = "data-plane|resource-manager",
9+
[string] $CheckAllUnder
910
)
1011
Set-StrictMode -Version 3
1112

1213
. $PSScriptRoot/ChangedFiles-Functions.ps1
1314
. $PSScriptRoot/Logging-Functions.ps1
1415

15-
$script:psYamlInstalled = $false
16-
function Ensure-PowerShell-Yaml-Installed {
17-
if ($script:psYamlInstalled) {
18-
# If already checked once in this script, don't log anything further
19-
return;
20-
}
21-
22-
$script:psYamlInstalled = [bool] (Get-Module -ListAvailable -Name powershell-yaml | Where-Object { $_.Version -eq "0.4.7" })
23-
24-
if ($script:psYamlInstalled) {
25-
LogInfo "Module [email protected] already installed"
26-
}
27-
else {
28-
LogInfo "Installing module [email protected]"
29-
Install-Module -Name powershell-yaml -RequiredVersion 0.4.7 -Force -Scope CurrentUser
30-
$script:psYamlInstalled = $true
31-
}
32-
}
33-
34-
function Find-Suppressions-Yaml {
35-
param (
36-
[string]$fileInSpecFolder
37-
)
38-
39-
$currentDirectory = Get-Item (Split-Path -Path $fileInSpecFolder)
40-
41-
while ($currentDirectory) {
42-
$suppressionsFile = Join-Path -Path $currentDirectory.FullName -ChildPath "suppressions.yaml"
43-
44-
if (Test-Path $suppressionsFile) {
45-
return $suppressionsFile
46-
} else {
47-
$currentDirectory = $currentDirectory.Parent
48-
}
49-
}
50-
51-
return $null
52-
}
53-
5416
function Get-Suppression {
5517
param (
5618
[string]$fileInSpecFolder
5719
)
5820

59-
$suppressionsFile = Find-Suppressions-Yaml $fileInSpecFolder
60-
if ($suppressionsFile) {
61-
Ensure-PowerShell-Yaml-Installed
62-
63-
$suppressions = Get-Content -Path $suppressionsFile -Raw | ConvertFrom-Yaml
64-
foreach ($suppression in $suppressions) {
65-
$tool = $suppression["tool"]
66-
$path = $suppression["path"]
67-
68-
if ($tool -eq "TypeSpecRequirement") {
69-
# Paths in suppressions.yml are relative to the file itself
70-
$fullPath = Join-Path -Path (Split-Path -Path $suppressionsFile) -ChildPath $path
21+
# -NoEnumerate to prevent single-element arrays from being collapsed to a single object
22+
# -AsHashtable is closer to raw JSON than PSCustomObject
23+
$suppressions = npx get-suppressions TypeSpecRequirement $fileInSpecFolder | ConvertFrom-Json -NoEnumerate -AsHashtable
7124

72-
# If path is not specified, suppression applies to all files
73-
if (!$path -or ($fileInSpecFolder -like $fullPath)) {
74-
return $suppression
75-
}
76-
}
77-
}
78-
}
79-
80-
return $null
25+
return $suppressions ? $suppressions[0] : $null;
8126
}
8227

8328
$repoPath = Resolve-Path "$PSScriptRoot/../.."
8429
$pathsWithErrors = @()
8530

86-
$filesToCheck = (Get-ChangedSwaggerFiles (Get-ChangedFiles $BaseCommitish $TargetCommitish)).Where({
31+
$filesToCheck = $CheckAllUnder ?
32+
(Get-ChildItem -Path $CheckAllUnder -Recurse -File | Resolve-Path -Relative | ForEach-Object { $_ -replace '\\', '/' }) :
33+
(Get-ChangedSwaggerFiles (Get-ChangedFiles $BaseCommitish $TargetCommitish))
34+
35+
$filesToCheck = $filesToCheck.Where({
8736
($_ -notmatch "/(examples|scenarios|restler|common|common-types)/") -and
8837
($_ -match "specification/[^/]+/($SpecType).*?/(preview|stable)/[^/]+/[^/]+\.json$")
89-
})
38+
})
9039

9140
if (!$filesToCheck) {
9241
LogInfo "No OpenAPI files found to check"
@@ -138,7 +87,7 @@ else {
13887
}
13988
else {
14089
LogError ("OpenAPI was generated from TypeSpec, but folder 'specification/$rpFolder' contains no files named 'tspconfig.yaml'." `
141-
+ " The TypeSpec used to generate OpenAPI must be added to this folder.")
90+
+ " The TypeSpec used to generate OpenAPI must be added to this folder.")
14291
LogJobFailure
14392
exit 1
14493
}
@@ -170,7 +119,7 @@ else {
170119
$urlToStableFolder = "https://github.com/Azure/azure-rest-api-specs/tree/main/specification/$servicePath/stable"
171120

172121
# Avoid conflict with pipeline secret
173-
$logUrlToStableFolder = $urlToStableFolder -replace '^https://',''
122+
$logUrlToStableFolder = $urlToStableFolder -replace '^https://', ''
174123

175124
LogInfo " Checking $logUrlToStableFolder"
176125

@@ -209,15 +158,13 @@ else {
209158
}
210159
}
211160

212-
if ($pathsWithErrors.Count -gt 0)
213-
{
161+
if ($pathsWithErrors.Count -gt 0) {
214162
# DevOps only adds the first 4 errors to the github checks list so lets always add the generic one first
215163
# and then as many of the individual ones as can be found afterwards
216164
LogError "New specs must use TypeSpec. For more detailed docs see https://aka.ms/azsdk/typespec"
217165
LogJobFailure
218166

219-
foreach ($path in $pathsWithErrors)
220-
{
167+
foreach ($path in $pathsWithErrors) {
221168
LogErrorForFile $path "OpenAPI was not generated from TypeSpec, and spec appears to be new"
222169
}
223170
exit 1

eng/tools/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "azure-rest-api-specs-eng-tools",
33
"devDependencies": {
4+
"@azure-tools/suppressions": "file:suppressions",
45
"@azure-tools/typespec-validation": "file:typespec-validation"
56
},
67
"private": true
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env node
2+
3+
import { main } from "../dist/src/index.js"
4+
5+
await main();

eng/tools/suppressions/package.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "@azure-tools/suppressions",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"main": "dist/src/index.js",
7+
"bin": {
8+
"get-suppressions": "cmd/get-suppressions.js"
9+
},
10+
"dependencies": {
11+
"minimatch": "^9.0.4",
12+
"yaml": "^2.4.2",
13+
"zod": "^3.23.6",
14+
"zod-validation-error": "^3.2.0"
15+
},
16+
"devDependencies": {
17+
"@types/node": "^18.19.31",
18+
"typescript": "~5.4.5",
19+
"vitest": "^1.5.3"
20+
},
21+
"scripts": {
22+
"build": "tsc",
23+
"postinstall": "npm run build",
24+
"test": "vitest"
25+
},
26+
"engines": {
27+
"node": ">= 18.0.0"
28+
}
29+
}

0 commit comments

Comments
 (0)