Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🏗 Ignore markdown templates in link checker by convention #25226

Merged
merged 2 commits into from
Oct 23, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 47 additions & 59 deletions build-system/tasks/check-links.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,68 +51,51 @@ function getMarkdownFiles() {
async function checkLinks() {
maybeUpdatePackages();
const markdownFiles = getMarkdownFiles();
const linkCheckers = markdownFiles.map(function(markdownFile) {
return runLinkChecker(markdownFile);
});
return BBPromise.all(linkCheckers).then(function(allResults) {
let deadLinksFound = false;
const filesWithDeadLinks = [];
allResults.map(function(results, index) {
// Skip files that were deleted by the PR.
if (!fs.existsSync(markdownFiles[index])) {
return;
}
const allResults = await Promise.all(markdownFiles.map(runLinkChecker));
rsimha marked this conversation as resolved.
Show resolved Hide resolved

const filesWithDeadLinks = allResults
.map((results, index) => {
let deadLinksFoundInFile = false;
results.forEach(function(result) {
for (const {link, status, statusCode} of results || []) {
// Skip links to files that were introduced by the PR.
if (isLinkToFileIntroducedByPR(result.link)) {
return;
if (isLinkToFileIntroducedByPR(link)) {
continue;
}
if (result.status === 'dead') {
deadLinksFound = true;
if (status === 'dead') {
deadLinksFoundInFile = true;
log(`[${red('✖')}] ${result.link} (${red(result.statusCode)})`);
log(`[${red('✖')}] ${link} (${red(statusCode)})`);
} else if (!isTravisBuild()) {
log(`[${green('✔')}] ${result.link}`);
log(`[${green('✔')}] ${link}`);
}
});
}
const filename = markdownFiles[index];
if (deadLinksFoundInFile) {
filesWithDeadLinks.push(markdownFiles[index]);
log(
red('ERROR'),
'Possible dead link(s) found in',
magenta(markdownFiles[index])
);
} else {
log(
green('SUCCESS'),
'All links in',
magenta(markdownFiles[index]),
'are alive.'
);
log(red('ERROR'), 'Possible dead link(s) found in', magenta(filename));
return filename;
}
});
if (deadLinksFound) {
log(
red('ERROR'),
'Please update dead link(s) in',
magenta(filesWithDeadLinks.join(',')),
'or whitelist them in build-system/tasks/check-links.js'
);
log(
yellow('NOTE'),
'If the link(s) above are not meant to resolve to a real webpage',
'surrounding them with backticks will exempt them from the link',
'checker.'
);
process.exitCode = 1;
} else {
log(
green('SUCCESS'),
'All links in all markdown files in this branch are alive.'
);
}
});
log(green('SUCCESS'), 'All links in', magenta(filename), 'are alive.');
})
.filter(filenameOrUndef => filenameOrUndef);

if (filesWithDeadLinks.length > 0) {
log(
red('ERROR'),
'Please update dead link(s) in',
magenta(filesWithDeadLinks.join(',')),
'or add them to allow-list in build-system/tasks/check-links.js'
);
log(
yellow('NOTE'),
'If the link(s) above are not meant to resolve to a real webpage,',
'surrounding them with backticks will exempt them from the link checker.'
);
process.exitCode = 1;
return;
}
log(
green('SUCCESS'),
'All links in all markdown files in this branch are alive.'
);
}

/**
Expand All @@ -128,12 +111,12 @@ function isLinkToFileIntroducedByPR(link) {
}

/**
* Filters out whitelisted links before running the link checker.
* Filters out links in allow-list before running the link checker.
*
* @param {string} markdown Original markdown.
* @return {string} Markdown after filtering out whitelisted links.
* @return {string} Markdown after filtering out allowed links.
*/
function filterWhitelistedLinks(markdown) {
function filterAllowedLinks(markdown) {
rsimha marked this conversation as resolved.
Show resolved Hide resolved
let filteredMarkdown = markdown;

// localhost links optionally preceded by ( or [ (not served on Travis)
Expand All @@ -151,7 +134,7 @@ function filterWhitelistedLinks(markdown) {
// Links inside a <pre> block (illustrative, and not always valid)
filteredMarkdown = filteredMarkdown.replace(/<pre>([^]*?)<\/pre>/g, '');

// After all whitelisting is done, clean up any remaining empty blocks bounded
// After allow-listing is done, clean up any remaining empty blocks bounded
// by backticks. Otherwise, `` will be treated as the start of a code block
// and confuse the link extractor.
filteredMarkdown = filteredMarkdown.replace(/\ \`\`\ /g, '');
Expand All @@ -167,12 +150,17 @@ function filterWhitelistedLinks(markdown) {
* @return {Promise} Used to wait until the async link checker is done.
*/
function runLinkChecker(markdownFile) {
// `.template.md` is a common suffix for files that may have interpolation
// tokens, possibly as part of their links. So we skip them.
if (path.basename(markdownFile).endsWith('.template.md')) {
return Promise.resolve();
}
// Skip files that were deleted by the PR.
if (!fs.existsSync(markdownFile)) {
return Promise.resolve();
}
const markdown = fs.readFileSync(markdownFile).toString();
const filteredMarkdown = filterWhitelistedLinks(markdown);
const filteredMarkdown = filterAllowedLinks(markdown);
const opts = {
baseUrl: 'file://' + path.dirname(path.resolve(markdownFile)),
};
Expand Down