Split plugins/external.json into per-plugin files for CODEOWNERS support#1245
Split plugins/external.json into per-plugin files for CODEOWNERS support#1245tmeschter wants to merge 1 commit intogithub:stagedfrom
Conversation
Split the monolithic plugins/external.json into individual files under plugins/external/ (one per external plugin) to support per-file CODEOWNERS entries. Updated all scripts that scan the plugins directory to exclude the new external/ subdirectory and read individual JSON files instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Splits the external plugin registry from a single plugins/external.json file into per-plugin JSON files under plugins/external/ to enable granular CODEOWNERS ownership and updates build/validation scripts to load external plugins from the new directory.
Changes:
- Added 8 per-plugin external manifests under
plugins/external/and removedplugins/external.json - Updated marketplace/website generation scripts to read external plugins from the new directory layout
- Updated plugin-scanning scripts and docs/CODEOWNERS to account for the
external/directory structure
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/external/azure.json | New per-plugin external manifest (Azure) |
| plugins/external/dataverse.json | New per-plugin external manifest (Dataverse) |
| plugins/external/dotnet.json | New per-plugin external manifest (.NET) |
| plugins/external/dotnet-diag.json | New per-plugin external manifest (.NET diagnostics) |
| plugins/external/figma.json | New per-plugin external manifest (Figma) |
| plugins/external/microsoft-docs.json | New per-plugin external manifest (Microsoft Docs) |
| plugins/external/modernize-dotnet.json | New per-plugin external manifest (Modernize .NET) |
| plugins/external/skills-for-copilot-studio.json | New per-plugin external manifest (Copilot Studio skills) |
| plugins/external.json | Removed monolithic external plugins array file |
| eng/generate-marketplace.mjs | Read/validate external plugins from directory of per-plugin JSON files; exclude external/ from local scanning |
| eng/generate-website-data.mjs | Read external plugins from plugins/external/ directory instead of external.json |
| eng/update-readme.mjs | Exclude plugins/external/ from local plugin directory scanning |
| eng/validate-plugins.mjs | Exclude plugins/external/ from local plugin directory scanning |
| eng/materialize-plugins.mjs | Exclude plugins/external/ from local plugin directory scanning |
| eng/clean-materialized-plugins.mjs | Exclude plugins/external/ from local plugin directory scanning |
| eng/update-plugin-commands-to-skills.mjs | Exclude plugins/external/ from local plugin directory scanning |
| CONTRIBUTING.md | Updated external plugin contribution instructions to per-file manifests |
| AGENTS.md | Updated external plugin workflow instructions to per-file manifests |
| CODEOWNERS | Added per-external-plugin ownership entries |
| if (typeof plugin !== "object" || Array.isArray(plugin)) { | ||
| console.error(`Error: external/${file} must contain a single JSON object`); | ||
| hasErrors = true; | ||
| continue; | ||
| } |
There was a problem hiding this comment.
typeof null === "object", so a file containing null will pass this check and then validateExternalPlugin(plugin, file) will throw when accessing plugin.name. Update the guard to explicitly reject null (and ideally any non-plain-object values) before calling validation.
| const pluginDirs = fs | ||
| .readdirSync(PLUGINS_DIR, { withFileTypes: true }) | ||
| .filter((d) => d.isDirectory()) | ||
| .filter((d) => d.isDirectory() && d.name !== "external") |
There was a problem hiding this comment.
The "external" directory exclusion is duplicated across multiple scripts in this PR. Consider centralizing the directory name (e.g., a shared constant in eng/constants.mjs) or a small helper (e.g., isPluginDirEntry(entry)) to avoid drift if the folder name or exclusion rules change again.
Split the monolithic
plugins/external.jsoninto individual files underplugins/external/(one JSON file per external plugin) to enable per-file CODEOWNERS entries.Changes
New files (8): Individual JSON files in
plugins/external/:azure.json,dataverse.json,dotnet.json,dotnet-diag.json,figma.json,microsoft-docs.json,modernize-dotnet.json,skills-for-copilot-studio.jsonDeleted:
plugins/external.jsonUpdated scripts (7) - all now read from the directory and exclude
plugins/external/from plugin directory scanning:eng/generate-marketplace.mjs- reads individual files from directory instead of single array fileeng/generate-website-data.mjs- same directory-based readingeng/update-readme.mjs- excludesexternaldir from plugin scanningeng/clean-materialized-plugins.mjs- excludesexternaldireng/materialize-plugins.mjs- excludesexternaldireng/update-plugin-commands-to-skills.mjs- excludesexternaldireng/validate-plugins.mjs- excludesexternaldirUpdated docs (3):
CODEOWNERS- per-file ownership entries based on git historyCONTRIBUTING.md- updated external plugin instructions to reference new directory structureAGENTS.md- same updateValidation
npm run buildpasses cleanly: 62 plugins (54 local + 8 external)npm run plugin:validatepasses: all 54 local plugins valid