Refactored into a script using zod based on feedback

Signed-off-by: Andre Wanlin <awanlin@spotify.com>
This commit is contained in:
Andre Wanlin
2026-01-27 19:14:44 -06:00
parent ed3bcf377c
commit 4977f58b9a
6 changed files with 94 additions and 127 deletions
+4 -16
View File
@@ -3,8 +3,8 @@ on:
# NOTE: If you change these you must update ci-noop.yml as well
pull_request:
paths-ignore:
- 'microsite/**'
- 'beps/**'
- "microsite/**"
- "beps/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -121,20 +121,8 @@ jobs:
- name: verify doc links
run: node scripts/verify-links.js
- name: verify plugin directory files
run: |
if find ./microsite/data/plugins -maxdepth 1 -type f ! \( -name "*.yaml" \) | grep -q .; then
find ./microsite/data/plugins -maxdepth 1 -type f ! \( -name "*.yaml" \)
echo "Error: Non-YAML files found"
exit 1
else
echo "Success: All files in are YAML files (based on extension)."
exit 0
fi
- name: verify plugin directory schema
run: yarn ajv validate -s microsite/data/plugin-schema.json -d "microsite/data/plugins/*.yaml" -c ajv-formats
- name: verify plugin directory
run: node scripts/verify-plugin-directory.js
- name: build all packages
run: yarn backstage-cli repo build --all
+1 -1
View File
@@ -28,7 +28,7 @@ addedDate: # The date plugin added to directory E.g. '2022-10-01' quotes are req
You can validate your YAML file is correct by running the following from the root of the repo:
1. First run `yarn install`
2. Then run `yarn ajv validate -s microsite/data/plugin-schema.json -d "microsite/data/plugins/<plugin-name>.yaml" -c ajv-formats` where `<plugin-name>` is the name of your plugin
2. Then run `node ./scripts/verify-plugin-directory.js`
If there are any errors they will be listed and you will need to correct them. We run this same check as part of the CI.
-56
View File
@@ -1,56 +0,0 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$ref": "#/definitions/plugin",
"definitions": {
"plugin": {
"type": "object",
"additionalProperties": false,
"properties": {
"title": {
"type": "string"
},
"author": {
"type": "string"
},
"authorUrl": {
"type": "string",
"format": "uri"
},
"category": {
"type": "string"
},
"description": {
"type": "string"
},
"documentation": {
"type": "string",
"format": "uri"
},
"iconUrl": {
"type": "string"
},
"npmPackageName": {
"type": "string"
},
"addedDate": {
"type": "string",
"format": "date"
},
"order": {
"type": "number"
}
},
"required": [
"addedDate",
"author",
"authorUrl",
"category",
"description",
"documentation",
"npmPackageName",
"title"
],
"title": "plugin"
}
}
}
+2 -3
View File
@@ -152,8 +152,6 @@
"@types/memjs": "^1.3.3",
"@types/node": "^22.13.14",
"@types/webpack": "^5.28.0",
"ajv-cli": "^5.0.0",
"ajv-formats": "^3.0.1",
"array-to-table": "^1.0.1",
"command-exists": "^1.2.9",
"cross-env": "^10.0.0",
@@ -181,7 +179,8 @@
"ts-morph": "^24.0.0",
"typedoc": "^0.28.0",
"typescript": "~5.7.0",
"vite": "^7.1.5"
"vite": "^7.1.5",
"zod": "^3.25.76"
},
"packageManager": "yarn@4.8.1",
"engines": {
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env node
/*
* Copyright 2026 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs-extra');
const { resolve, join } = require('node:path');
const yaml = require('js-yaml');
const z = require('zod');
const configSchema = z.object({
title: z.string(),
author: z.string(),
authorUrl: z.string().url(),
category: z.string(),
description: z.string(),
documentation: z.string().url(),
iconUrl: z.string().optional(),
npmPackageName: z.string(),
addedDate: z.coerce.date(),
order: z.number().optional(),
});
async function main() {
const rootPath = resolve(__dirname, '..');
const pluginDirectoryPath = resolve(rootPath, 'microsite', 'data', 'plugins');
const pluginDirectoryFiles = await fs.readdir(pluginDirectoryPath);
let hasErrors = false;
for (const pluginDirectoryFile of pluginDirectoryFiles) {
if (!pluginDirectoryFile.toLocaleLowerCase().includes('.yaml')) {
hasErrors = true;
console.log(`${pluginDirectoryFile} is missing the '.yaml' extension`);
}
const pluginDirectoryFilePath = join(
pluginDirectoryPath,
pluginDirectoryFile,
);
const pluginDataYaml = yaml.load(
fs.readFileSync(pluginDirectoryFilePath, { encoding: 'utf-8' }),
);
try {
configSchema.parse(pluginDataYaml);
} catch (error) {
if (error instanceof z.ZodError) {
console.log(
`YAML data validation failed for ${pluginDirectoryFile}:`,
error.errors,
);
} else {
console.log(
`An unexpected error occurred for ${pluginDirectoryFile}:`,
error,
);
}
}
}
if (hasErrors) {
throw new Error(
'There was an error verifying the Plugin Directory data files, review the output for guidance on what corrections are needed',
);
}
}
main(process.argv.slice(2)).catch(error => {
console.error(error.stack || error);
process.exit(1);
});
+3 -51
View File
@@ -24306,28 +24306,6 @@ __metadata:
languageName: node
linkType: hard
"ajv-cli@npm:^5.0.0":
version: 5.0.0
resolution: "ajv-cli@npm:5.0.0"
dependencies:
ajv: "npm:^8.0.0"
fast-json-patch: "npm:^2.0.0"
glob: "npm:^7.1.0"
js-yaml: "npm:^3.14.0"
json-schema-migrate: "npm:^2.0.0"
json5: "npm:^2.1.3"
minimist: "npm:^1.2.0"
peerDependencies:
ts-node: ">=9.0.0"
peerDependenciesMeta:
ts-node:
optional: true
bin:
ajv: dist/index.js
checksum: 10/bd755f7f34602356c5c65bf947f3ba8d73b31859296b275eb3b112d2c14e125fcfca71bac9c8d4242a006fc62e9c868be3cf4652ebc6a8df08fe16f83ee9080c
languageName: node
linkType: hard
"ajv-draft-04@npm:^1.0.0, ajv-draft-04@npm:~1.0.0":
version: 1.0.0
resolution: "ajv-draft-04@npm:1.0.0"
@@ -31196,13 +31174,6 @@ __metadata:
languageName: node
linkType: hard
"fast-deep-equal@npm:^2.0.1":
version: 2.0.1
resolution: "fast-deep-equal@npm:2.0.1"
checksum: 10/b701835a87985e0ec4925bdf1f0c1e7eb56309b5d12d534d5b4b69d95a54d65bb16861c081781ead55f73f12d6c60ba668713391ee7fbf6b0567026f579b7b0b
languageName: node
linkType: hard
"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
version: 3.1.3
resolution: "fast-deep-equal@npm:3.1.3"
@@ -31237,15 +31208,6 @@ __metadata:
languageName: node
linkType: hard
"fast-json-patch@npm:^2.0.0":
version: 2.2.1
resolution: "fast-json-patch@npm:2.2.1"
dependencies:
fast-deep-equal: "npm:^2.0.1"
checksum: 10/802924e8f6e50267c1c92c9a52de59e9e4d448a383c32119e228a17ef17fe90e54f52bb4211a616a9c93e708f873cc39d5df10ae77fe32cd5a22c4b9cb69cae9
languageName: node
linkType: hard
"fast-json-patch@npm:^3.0.0-1, fast-json-patch@npm:^3.1.0, fast-json-patch@npm:^3.1.1":
version: 3.1.1
resolution: "fast-json-patch@npm:3.1.1"
@@ -32642,7 +32604,7 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:^7.1.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.3":
"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.3":
version: 7.2.3
resolution: "glob@npm:7.2.3"
dependencies:
@@ -36058,7 +36020,7 @@ __metadata:
languageName: node
linkType: hard
"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.0, js-yaml@npm:^3.6.1, js-yaml@npm:^3.8.3":
"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.6.1, js-yaml@npm:^3.8.3":
version: 3.14.2
resolution: "js-yaml@npm:3.14.2"
dependencies:
@@ -36309,15 +36271,6 @@ __metadata:
languageName: node
linkType: hard
"json-schema-migrate@npm:^2.0.0":
version: 2.0.0
resolution: "json-schema-migrate@npm:2.0.0"
dependencies:
ajv: "npm:^8.0.0"
checksum: 10/bb32718273e0a1bcce5f3926f5c93559ceb209af19abb5af441fc1af937cfba39bab9884ae5461d91c5ba6019ea80067226b7c7a5b073fd8ab53133a981c387f
languageName: node
linkType: hard
"json-schema-to-ts@npm:^3.0.0":
version: 3.1.1
resolution: "json-schema-to-ts@npm:3.1.1"
@@ -45561,8 +45514,6 @@ __metadata:
"@types/node": "npm:^22.13.14"
"@types/webpack": "npm:^5.28.0"
"@useoptic/optic": "npm:^1.0.0"
ajv-cli: "npm:^5.0.0"
ajv-formats: "npm:^3.0.1"
array-to-table: "npm:^1.0.1"
command-exists: "npm:^1.2.9"
cross-env: "npm:^10.0.0"
@@ -45592,6 +45543,7 @@ __metadata:
typescript: "npm:~5.7.0"
vite: "npm:^7.1.5"
yaml: "npm:^2.7.0"
zod: "npm:^3.25.76"
languageName: unknown
linkType: soft