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

docs: validate relative links #28690

Merged
merged 12 commits into from
Apr 30, 2024
11 changes: 11 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { jest } = require('@jest/globals');
viceice marked this conversation as resolved.
Show resolved Hide resolved

viceice marked this conversation as resolved.
Show resolved Hide resolved
module.exports = {
root: true,
env: {
Expand Down Expand Up @@ -224,5 +226,14 @@ module.exports = {
'import/extensions': 0,
},
},
{
files: ['tools/docs/test/**/*.mjs'],
env: {
jest: false,
},
rules: {
'@typescript-eslint/no-floating-promises': 0,
},
},
],
};
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@ jobs:
- name: Build
run: pnpm build:docs

- name: Test
viceice marked this conversation as resolved.
Show resolved Hide resolved
run: pnpm test:docs

- name: Upload
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
Expand Down
4 changes: 2 additions & 2 deletions docs/usage/key-concepts/changelogs.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ If your repository uses the monorepo pattern make sure _each_ `package.json` fil

### maven package maintainers

Read [`maven` datasource, making your changelogs fetchable](https://docs.renovatebot.com/modules/datasource/maven/#making-your-changelogs-fetchable).
Read [`maven` datasource, making your changelogs fetchable](../modules/datasource/maven/index.md#making-your-changelogs-fetchable).

### Docker image maintainers

Read the [Docker datasource](https://docs.renovatebot.com/modules/datasource/docker/) docs.
Read the [Docker datasource](../modules/datasource/docker/index.md) docs.

### Nuget package maintainers

Expand Down
2 changes: 1 addition & 1 deletion lib/modules/platform/gerrit/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ It works similar to the default option `"pr"`.

You can use the `statusCheckNames` configuration to map any of the available branch checks (like `minimumReleaseAge`, `mergeConfidence`, and so on) to a Gerrit label.

For example, if you want to use the [Merge Confidence](https://docs.renovatebot.com/merge-confidence/) feature and map the result of the Merge Confidence check to your Gerrit label "Renovate-Merge-Confidence" you can configure:
For example, if you want to use the [Merge Confidence](../../../merge-confidence.md) feature and map the result of the Merge Confidence check to your Gerrit label "Renovate-Merge-Confidence" you can configure:
viceice marked this conversation as resolved.
Show resolved Hide resolved

```json
{
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"test-e2e:install": "cd test/e2e && npm install --no-package-lock --prod",
"test-e2e:run": "cd test/e2e && npm test",
"test-schema": "run-s create-json-schema",
"test:docs": "node --test tools/docs/test/",
"schedule-test-shards": "SCHEDULE_TEST_SHARDS=true ts-node jest.config.ts",
"tsc": "tsc",
"type-check": "run-s 'generate:*' 'tsc --noEmit {@}' --",
Expand Down Expand Up @@ -300,6 +301,7 @@
"@types/semver-utils": "1.1.3",
"@types/tar": "6.1.13",
"@types/traverse": "0.6.36",
"@types/unist": "2.0.10",
"@types/url-join": "4.0.3",
"@types/validate-npm-package-name": "4.0.2",
"@types/xmldoc": "1.1.9",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions tools/docs/test/index.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import test from 'node:test';
viceice marked this conversation as resolved.
Show resolved Hide resolved
import fs from 'fs-extra';
import { glob } from 'glob';
import assert from 'node:assert';
import MarkdownIt from 'markdown-it';
import remark from 'remark';
import path from 'node:path';

const markdown = new MarkdownIt('zero');
markdown.enable(['fence']);

const root = path.resolve('tmp/docs');

/**
* @param {any} node
* @param {Set<string>} files
* @param {string} file
*/
function checkNode(node, files, file) {
if (node.type === 'link') {
/** @type {import('mdast').Link} */
const link = node;
assert.ok(
!link.url.startsWith('/'),
'Link should be external or relative: ' + link.url,
);

if (link.url.startsWith('.')) {
const abs = path.resolve(
viceice marked this conversation as resolved.
Show resolved Hide resolved
'tmp/docs',
path.dirname(file),
link.url.replace(/#.*/, ''),
);
// relative url
viceice marked this conversation as resolved.
Show resolved Hide resolved
const target = abs.substring(root.length + 1);

assert.ok(
files.has(target),
`File not found: ${link.url} in ${file} -> ${target}`,
);
} else {
assert.ok(
!link.url.startsWith('https://docs.renovatebot.com/'),
'Docs links should be relative: ' + link.url,
);
}
} else if ('children' in node) {
for (const child of node.children) {
checkNode(child, files, file);
}
}
}

test('index', async (t) => {
await t.test('validate links', async (t) => {
const todo = await glob('**/*.md', { cwd: 'tmp/docs' });
const files = new Set(todo);

// add generated files
files.add('index.md');
files.add('release-notes-for-major-versions.md');
files.add('merge-confidence.md');
viceice marked this conversation as resolved.
Show resolved Hide resolved

let c = 0;

for (const file of todo) {
c++;
await t.test(`${file}`, async () => {
const node = remark().parse(
await fs.readFile(`tmp/docs/${file}`, 'utf8'),
);
checkNode(node, files, file);
});
}

assert.ok(c > 0, 'Should find at least one file');
});
});