Skip to content

Commit

Permalink
test(docs-infra): modify verify-guide-codeownership.js to also chec…
Browse files Browse the repository at this point in the history
…k API docs examples (angular#32360)

This script can be used for manually checking that all docs
guides/examples/images have owners in `.github/CODEOWNERS`.

This commit adds support for also checking codeownership of API docs
examples (in `packages/examples/*`). The script is also renamed to the
more generic (and accurate) `verify-docs-codeownership.js`.

PR Close angular#32360
  • Loading branch information
gkalpak authored and mhevery committed Aug 30, 2019
1 parent c56c241 commit afc6ab5
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 87 deletions.
126 changes: 126 additions & 0 deletions aio/scripts/verify-docs-codeownership.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
'use strict';

// Imports
const fs = require('fs');
const path = require('path');

// Constants
const PROJECT_ROOT_DIR = path.resolve(__dirname, '../..');
const CODEOWNERS_PATH = path.resolve(PROJECT_ROOT_DIR, '.github/CODEOWNERS');
const PKG_EXAMPLES_DIR = path.resolve(PROJECT_ROOT_DIR, 'packages/examples');
const AIO_CONTENT_DIR = path.resolve(PROJECT_ROOT_DIR, 'aio/content');
const AIO_GUIDES_DIR = path.resolve(AIO_CONTENT_DIR, 'guide');
const AIO_GUIDE_IMAGES_DIR = path.resolve(AIO_CONTENT_DIR, 'images/guide');
const AIO_GUIDE_EXAMPLES_DIR = path.resolve(AIO_CONTENT_DIR, 'examples');

// Run
_main();

// Functions - Definitions
function _main() {
const {examples: pkgExamplePaths} = getPathsFromPkgExamples();
const {guides: aioGuidePaths, images: aioGuideImagesPaths, examples: aioExamplePaths} = getPathsFromAioContent();
const {
aioGuides: coAioGuidePaths,
aioImages: coAioGuideImagesPaths,
aioExamples: coAioExamplePaths,
pkgExamples: coPkgExamplePaths,
} = getPathsFromCodeowners();

const aioGuidesDiff = arrayDiff(aioGuidePaths, coAioGuidePaths);
const aioImagesDiff = arrayDiff(aioGuideImagesPaths, coAioGuideImagesPaths);
const aioExamplesDiff = arrayDiff(aioExamplePaths, coAioExamplePaths);
const pkgExamplesDiff = arrayDiff(pkgExamplePaths, coPkgExamplePaths);
const hasDiff = (aioGuidesDiff.diffCount > 0) || (aioImagesDiff.diffCount> 0) || (aioExamplesDiff.diffCount > 0) ||
(pkgExamplesDiff.diffCount > 0);

if (hasDiff) {
const expectedAioGuidesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDES_DIR);
const expectedAioImagesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDE_IMAGES_DIR);
const expectedAioExamplesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDE_EXAMPLES_DIR);
const expectedPkgExamplesSrc = path.relative(PROJECT_ROOT_DIR, PKG_EXAMPLES_DIR);
const actualSrc = path.relative(PROJECT_ROOT_DIR, CODEOWNERS_PATH);

reportDiff(aioGuidesDiff, expectedAioGuidesSrc, actualSrc);
reportDiff(aioImagesDiff, expectedAioImagesSrc, actualSrc);
reportDiff(aioExamplesDiff, expectedAioExamplesSrc, actualSrc);
reportDiff(pkgExamplesDiff, expectedPkgExamplesSrc, actualSrc);
}

process.exit(hasDiff ? 1 : 0);
}

function arrayDiff(expected, actual) {
const missing = expected.filter(x => !actual.includes(x)).sort();
const extra = actual.filter(x => !expected.includes(x)).sort();

return {missing, extra, diffCount: missing.length + extra.length};
}

function getPathsFromAioContent() {
return {
guides: fs.readdirSync(AIO_GUIDES_DIR),
images: fs.readdirSync(AIO_GUIDE_IMAGES_DIR),
examples: fs.readdirSync(AIO_GUIDE_EXAMPLES_DIR).
filter(name => fs.statSync(`${AIO_GUIDE_EXAMPLES_DIR}/${name}`).isDirectory()),
};
}

function getPathsFromCodeowners() {
// Use capturing groups for `images/` and `examples` to be able to differentiate between the
// different kinds of matches (guide, image, example) later (see `isImage`/`isExample` below).
const aioGuidesOrImagesPathRe = /^\/aio\/content\/(?:(images\/)?guide|(examples))\/([^\s\*/]+)/;
const pkgExamplesPathRe = /^\/packages\/examples\/([^\s\*/]+)/;

const aioGuides = [];
const aioImages = [];
const aioExamples = [];
const pkgExamples = [];

// Read `CODEOWNERS` and split into lines.
const lines = fs.
readFileSync(CODEOWNERS_PATH, 'utf8').
split('\n').
map(l => l.trim());

// Collect `aio/` guides/images/examples.
lines.
map(l => l.match(aioGuidesOrImagesPathRe)).
filter(m => m).
forEach(([, isImage, isExample, path]) => {
const list = isExample ? aioExamples :
isImage ? aioImages :
aioGuides;
list.push(path);
});

// Collect API docs examples (`packages/examples/`).
lines.
map(l => l.match(pkgExamplesPathRe)).
filter(m => m).
forEach(([, path]) => pkgExamples.push(path));

return {aioGuides, aioImages, aioExamples, pkgExamples};
}

function getPathsFromPkgExamples() {
return {
examples: fs.readdirSync(PKG_EXAMPLES_DIR).
filter(name => fs.statSync(`${PKG_EXAMPLES_DIR}/${name}`).isDirectory()),
};
}


function reportDiff(diff, expectedSrc, actualSrc) {
if (diff.missing.length) {
console.error(
`\nEntries in '${expectedSrc}' but not in '${actualSrc}':\n` +
diff.missing.map(x => ` - ${x}`).join('\n'));
}

if (diff.extra.length) {
console.error(
`\nEntries in '${actualSrc}' but not in '${expectedSrc}':\n` +
diff.extra.map(x => ` - ${x}`).join('\n'));
}
}
87 changes: 0 additions & 87 deletions aio/scripts/verify-guide-codeownership.js

This file was deleted.

0 comments on commit afc6ab5

Please sign in to comment.