build(docs-infra): fix CLI command github links (#30889)

The "view" links were broken because the version used to
compute the git tag for the GitHub URL included a build SHA.
Now we clean that off before using it in the URL.

The links are to the JSON schema that defines the documentation for
the command. This is accurate but confusing because the content for the
long description is stored in a separate markdown file referenced from this
schema file.
This commit adds a second set of links for the long description, if it exists,
which links directly to the markdown file.

Closes #30700

PR Close #30889
This commit is contained in:
Pete Bacon Darwin 2019-06-06 09:45:07 +01:00 committed by Miško Hevery
parent 3859bcc70c
commit f440bd1793
5 changed files with 123 additions and 62 deletions

View File

@ -1,4 +1,5 @@
const {resolve} = require('canonical-path'); const {resolve} = require('canonical-path');
const semver = require('semver');
const Package = require('dgeni').Package; const Package = require('dgeni').Package;
const basePackage = require('../angular-base-package'); const basePackage = require('../angular-base-package');
const contentPackage = require('../content-package'); const contentPackage = require('../content-package');
@ -8,59 +9,60 @@ const CLI_SOURCE_PATH = resolve(CLI_SOURCE_ROOT, 'node_modules/@angular/cli');
const CLI_SOURCE_HELP_PATH = resolve(CLI_SOURCE_PATH, 'help'); const CLI_SOURCE_HELP_PATH = resolve(CLI_SOURCE_PATH, 'help');
// Define the dgeni package for generating the docs // Define the dgeni package for generating the docs
module.exports = new Package('cli-docs', [basePackage, contentPackage]) module.exports =
new Package('cli-docs', [basePackage, contentPackage])
// Register the services and file readers // Register the services and file readers
.factory(require('./readers/cli-command')) .factory(require('./readers/cli-command'))
// Register the processors // Register the processors
.processor(require('./processors/processCliContainerDoc')) .processor(require('./processors/processCliContainerDoc'))
.processor(require('./processors/processCliCommands')) .processor(require('./processors/processCliCommands'))
.processor(require('./processors/filterHiddenCommands')) .processor(require('./processors/filterHiddenCommands'))
// Configure file reading // Configure file reading
.config(function(readFilesProcessor, cliCommandFileReader) { .config(function(readFilesProcessor, cliCommandFileReader) {
readFilesProcessor.fileReaders.push(cliCommandFileReader); readFilesProcessor.fileReaders.push(cliCommandFileReader);
readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([ readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([
{ {
basePath: CLI_SOURCE_HELP_PATH, basePath: CLI_SOURCE_HELP_PATH,
include: resolve(CLI_SOURCE_HELP_PATH, '*.json'), include: resolve(CLI_SOURCE_HELP_PATH, '*.json'),
fileReader: 'cliCommandFileReader' fileReader: 'cliCommandFileReader'
}, },
{ {
basePath: CONTENTS_PATH, basePath: CONTENTS_PATH,
include: resolve(CONTENTS_PATH, 'cli/**'), include: resolve(CONTENTS_PATH, 'cli/**'),
fileReader: 'contentFileReader' fileReader: 'contentFileReader'
}, },
]); ]);
}) })
.config(function(templateFinder, templateEngine, getInjectables) { .config(function(templateFinder, templateEngine, getInjectables) {
// Where to find the templates for the CLI doc rendering // Where to find the templates for the CLI doc rendering
templateFinder.templateFolders.unshift(resolve(TEMPLATES_PATH, 'cli')); templateFinder.templateFolders.unshift(resolve(TEMPLATES_PATH, 'cli'));
// Add in templating filters and tags // Add in templating filters and tags
templateEngine.filters = templateEngine.filters.concat(getInjectables(requireFolder(__dirname, './rendering'))); templateEngine.filters = templateEngine.filters.concat(
}) getInjectables(requireFolder(__dirname, './rendering')));
})
.config(function(renderDocsProcessor) { .config(function(renderDocsProcessor) {
const cliPackage = require(resolve(CLI_SOURCE_PATH, 'package.json')); const cliPackage = require(resolve(CLI_SOURCE_PATH, 'package.json'));
const repoUrlParts = cliPackage.repository.url.replace(/\.git$/, '').split('/'); const repoUrlParts = cliPackage.repository.url.replace(/\.git$/, '').split('/');
const version = `v${cliPackage.version}`; const version = `v${semver.clean(cliPackage.version)}`;
const repo = repoUrlParts.pop(); const repo = repoUrlParts.pop();
const owner = repoUrlParts.pop(); const owner = repoUrlParts.pop();
const cliVersionInfo = { const cliVersionInfo = {gitRepoInfo: {owner, repo}, currentVersion: {raw: version}};
gitRepoInfo: { owner, repo },
currentVersion: { raw: version }
};
// Add the cli version data to the renderer, for use in things like github links // Add the cli version data to the renderer, for use in things like github links
renderDocsProcessor.extraData.cliVersionInfo = cliVersionInfo; renderDocsProcessor.extraData.cliVersionInfo = cliVersionInfo;
}) })
.config(function(convertToJsonProcessor, postProcessHtml) { .config(function(convertToJsonProcessor, postProcessHtml) {
convertToJsonProcessor.docTypes = convertToJsonProcessor.docTypes.concat(['cli-command', 'cli-overview']); convertToJsonProcessor.docTypes =
postProcessHtml.docTypes = postProcessHtml.docTypes.concat(['cli-command', 'cli-overview']); convertToJsonProcessor.docTypes.concat(['cli-command', 'cli-overview']);
}); postProcessHtml.docTypes =
postProcessHtml.docTypes.concat(['cli-command', 'cli-overview']);
});

View File

@ -26,22 +26,59 @@ module.exports = function cliCommandFileReader(log) {
docType: 'cli-command', docType: 'cli-command',
id: `cli-${doc.name}`, id: `cli-${doc.name}`,
commandAliases: doc.aliases || [], commandAliases: doc.aliases || [],
aliases: computeAliases(doc), aliases: computeAliases(doc), path,
path,
outputPath: `${path}.json`, outputPath: `${path}.json`,
breadCrumbs: [ breadCrumbs: [
{ text: 'CLI', path: 'cli' }, {text: 'CLI', path: 'cli'},
{ text: name, path }, {text: name, path},
] ]
}); });
if (doc.longDescription) {
doc.longDescriptionDoc = createLongDescriptionDoc(fileInfo);
}
return [result]; return [result];
} catch (e) { } catch (e) {
log.warn(`Failed to read cli command file: "${fileInfo.relativePath}" - ${e.message}`); log.warn(`Failed to read cli command file: "${fileInfo.relativePath}" - ${e.message}`);
} }
} }
}; };
}; function computeAliases(doc) {
return [doc.name].concat(doc.aliases || []).map(alias => `cli-${alias}`);
}
function computeAliases(doc) { /**
return [doc.name].concat(doc.aliases || []).map(alias => `cli-${alias}`); * Synthesize a doc for the CLI command long description, which is used to generate links
} * for viewing and editing the long description in GitHub.
*
* The long description is stored in a markdown file that is referenced from the original
* schema file for the command, via the `$longDescription` field. The field is a relative path
* to the markdown file from the schema file.
*
* This function tries to retrieve that original schema based on the file path of the help JSON
* file, which was passed to the `cliCommandFileReader.getDocs()` method.
*/
function createLongDescriptionDoc(fileInfo) {
try {
const path = require('canonical-path');
const fs = require('fs');
const json5 = require('json5');
const schemaJsonPath = path.resolve(fileInfo.basePath, '../commands', fileInfo.relativePath);
const schemaJson = fs.readFileSync(schemaJsonPath);
const schema = json5.parse(schemaJson);
if (schema.$longDescription) {
return {
docType: 'content',
startingLine: 0,
fileInfo: {
realProjectRelativePath:
path.join(path.dirname(fileInfo.realProjectRelativePath), schema.$longDescription)
}
};
}
} catch (e) {
log.warn('Unable to read CLI long description file info', e, fileInfo);
return undefined;
}
}
};

View File

@ -40,7 +40,12 @@ const content = `
} }
`; `;
const fileInfo = {content, baseName: 'add'}; const fileInfo = {
content,
baseName: 'add',
relativePath: 'add.json',
basePath: __dirname + '/mocks/help',
};
describe('cli-command reader', () => { describe('cli-command reader', () => {
describe('getDocs', () => { describe('getDocs', () => {
@ -77,8 +82,8 @@ describe('cli-command reader', () => {
it('should compute the bread crumbs', () => { it('should compute the bread crumbs', () => {
const docs = reader.getDocs(fileInfo); const docs = reader.getDocs(fileInfo);
expect(docs[0].breadCrumbs).toEqual([ expect(docs[0].breadCrumbs).toEqual([
{ text: 'CLI', path: 'cli' }, {text: 'CLI', path: 'cli'},
{ text: 'add', path: 'cli/add' }, {text: 'add', path: 'cli/add'},
]); ]);
}); });
@ -89,7 +94,9 @@ describe('cli-command reader', () => {
it('should extract the long description', () => { it('should extract the long description', () => {
const docs = reader.getDocs(fileInfo); const docs = reader.getDocs(fileInfo);
expect(docs[0].longDescription).toEqual('Add support for a library in your project, for example adding `@angular/pwa` which would configure\nyour project for PWA support.\n'); expect(docs[0].longDescription)
.toEqual(
'Add support for a library in your project, for example adding `@angular/pwa` which would configure\nyour project for PWA support.\n');
}); });
it('should extract the command type', () => { it('should extract the command type', () => {
@ -110,10 +117,19 @@ describe('cli-command reader', () => {
it('should extract the options', () => { it('should extract the options', () => {
const docs = reader.getDocs(fileInfo); const docs = reader.getDocs(fileInfo);
expect(docs[0].options).toEqual([ expect(docs[0].options).toEqual([
jasmine.objectContaining({ name: 'collection' }), jasmine.objectContaining({name: 'collection'}),
jasmine.objectContaining({ name: 'help' }), jasmine.objectContaining({name: 'help'}),
jasmine.objectContaining({ name: 'helpJson' }), jasmine.objectContaining({name: 'helpJson'}),
]); ]);
}); });
it('should extract file info for the long description', () => {
const [doc] = reader.getDocs(fileInfo);
expect(doc.longDescriptionDoc).toEqual({
docType: 'content',
startingLine: 0,
fileInfo: {realProjectRelativePath: 'packages/angular/cli/commands/add-long.md'}
});
});
}); });
}); });

View File

@ -0,0 +1,3 @@
{
"$longDescription": "./add-long.md"
}

View File

@ -14,7 +14,10 @@
{$ cli.renderSyntax(doc) $} {$ cli.renderSyntax(doc) $}
{% if doc.longDescription.length %} {% if doc.longDescription.length %}
<h2 class="no-anchor">Description</h2> <h2 class="no-anchor">
{$ github.githubLinks(doc.longDescriptionDoc, cliVersionInfo) $}
Description
</h2>
{$ doc.longDescription | marked $} {$ doc.longDescription | marked $}
{% endif%} {% endif%}