diff --git a/.eslintrc.js b/.eslintrc.js index 580ed71797f97f769a414eac10f498c1c9c32518..87f08fb0cfb5c2f1c0b2d524170f8f8c6e359d19 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -224,5 +224,14 @@ module.exports = { 'import/extensions': 0, }, }, + { + files: ['tools/docs/test/**/*.mjs'], + env: { + jest: false, + }, + rules: { + '@typescript-eslint/no-floating-promises': 0, + }, + }, ], }; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f78625fa2de0b6149762cf2d3f7601a4fa6127d..493af84c3760ce23a93abdf2f59055696e0429fc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -558,6 +558,9 @@ jobs: - name: Build run: pnpm build:docs + - name: Test docs + run: pnpm test:docs + - name: Upload uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 284fdeb33910afaeb4ed02b74a94657e4a646018..2397c16316a08ede2bcef5f88f3006e9fd51fb38 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1272,7 +1272,7 @@ It is valid only as a top-level configuration option and not, for example, withi <!-- prettier-ignore --> !!! warning - The bot administrator must configure a list of allowed environment names in the [`allowedEnv`](./self-hosted-configuration.md#allowedEnv) config option, before users can use those allowed names in the `env` option. + The bot administrator must configure a list of allowed environment names in the [`allowedEnv`](./self-hosted-configuration.md#allowedenv) config option, before users can use those allowed names in the `env` option. Behavior: @@ -1376,7 +1376,7 @@ Renovate can fetch changelogs when they are hosted on one of these platforms: - GitHub (.com and Enterprise Server) - GitLab (.com and CE/EE) -If you are running on any platform except `github.com`, you need to [configure a Personal Access Token](./getting-started/running.md#githubcom-token-for-release-notes) to allow Renovate to fetch changelogs notes from `github.com`. +If you are running on any platform except `github.com`, you need to [configure a Personal Access Token](./getting-started/running.md#githubcom-token-for-changelogs) to allow Renovate to fetch changelogs notes from `github.com`. <!-- prettier-ignore --> !!! note @@ -1869,7 +1869,7 @@ Enable got [http2](https://github.com/sindresorhus/got/blob/v11.5.2/readme.md#ht You can provide a `headers` object that includes fields to be forwarded to the HTTP request headers. By default, all headers starting with "X-" are allowed. -A bot administrator may configure an override for [`allowedHeaders`](./self-hosted-configuration.md#allowedHeaders) to configure more permitted headers. +A bot administrator may configure an override for [`allowedHeaders`](./self-hosted-configuration.md#allowedheaders) to configure more permitted headers. `headers` value(s) configured in the bot admin `hostRules` (for example in a `config.js` file) are _not_ validated, so it may contain any header regardless of `allowedHeaders`. diff --git a/docs/usage/getting-started/private-packages.md b/docs/usage/getting-started/private-packages.md index b1689c6ab7892d980207397ddb894d35363070b4..75d400aa17d990e274456a46746ef5ec3023d3da 100644 --- a/docs/usage/getting-started/private-packages.md +++ b/docs/usage/getting-started/private-packages.md @@ -616,4 +616,4 @@ For instructions on this, see the above section on encrypting secrets for the Me ### hostRules configuration using environment variables -Self-hosted users can enable the option [`detectHostRulesFromEnv`](../self-hosted-configuration.md#detectHostRulesFromEnv) to configure the most common types of `hostRules` via environment variables. +Self-hosted users can enable the option [`detectHostRulesFromEnv`](../self-hosted-configuration.md#detecthostrulesfromenv) to configure the most common types of `hostRules` via environment variables. diff --git a/docs/usage/key-concepts/changelogs.md b/docs/usage/key-concepts/changelogs.md index 8af4280e864286e38e9472d14ede1f08a391debf..ddf5d60983e69caa12c5befcf66dc0db729df83e 100644 --- a/docs/usage/key-concepts/changelogs.md +++ b/docs/usage/key-concepts/changelogs.md @@ -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 diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index 80fed5ff440ddf835a74caa8fe84bc608e811693..ffead1ce362a4e22bf22b8a8ef1ee037d03f9663 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -997,7 +997,7 @@ Defines how the report is exposed: - `<unset>` If unset, no report will be provided, though the debug logs will still have partial information of the report - `logging` The report will be printed as part of the log messages on `INFO` level - `file` The report will be written to a path provided by [`reportPath`](#reportpath) -- `s3` The report is pushed to an S3 bucket defined by [`reportPath`](#reportpath). This option reuses [`RENOVATE_X_S3_ENDPOINT`](./self-hosted-experimental.md#renovatexs3endpoint) and [`RENOVATE_X_S3_PATH_STYLE`](./self-hosted-experimental.md#renovatexs3pathstyle) +- `s3` The report is pushed to an S3 bucket defined by [`reportPath`](#reportpath). This option reuses [`RENOVATE_X_S3_ENDPOINT`](./self-hosted-experimental.md#renovate_x_s3_endpoint) and [`RENOVATE_X_S3_PATH_STYLE`](./self-hosted-experimental.md#renovate_x_s3_path_style) ## repositories diff --git a/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md index 1dc8fd40f5f6a010da95931a8c6a2bcb5cbba0e9..2e59653983c624f52e5f7a799c1b6168fad09135 100644 --- a/docs/usage/self-hosted-experimental.md +++ b/docs/usage/self-hosted-experimental.md @@ -138,7 +138,7 @@ If you use the Mend Renovate Enterprise Edition (Renovate EE) and: Then you must set this variable at the _server_ and the _workers_. -But if you have specified the token as a [`matchConfidence`](https://docs.renovatebot.com/configuration-options/#matchconfidence) `hostRule`, you only need to set this variable at the _workers_. +But if you have specified the token as a [`matchConfidence`](configuration-options.md#matchconfidence) `hostRule`, you only need to set this variable at the _workers_. This feature is in private beta. diff --git a/lib/modules/platform/gerrit/readme.md b/lib/modules/platform/gerrit/readme.md index b6ff385e9f522db7358be4969f8d15ee8f3b3d65..01a539311cf65dadb456f15247cebaf2c8eb531c 100644 --- a/lib/modules/platform/gerrit/readme.md +++ b/lib/modules/platform/gerrit/readme.md @@ -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: ```json { diff --git a/package.json b/package.json index a2132adf054cffe9bae1d5837bef579a0c883318..ba2c898b4feb28def43113b9e5f559577e84ebe6 100644 --- a/package.json +++ b/package.json @@ -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 {@}' --", @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 742d8385c9386a44896ab6bafdea096749a270bc..4d9c8a3c06c8584502da77489904686c43791619 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -475,6 +475,9 @@ importers: '@types/traverse': specifier: 0.6.36 version: 0.6.36 + '@types/unist': + specifier: 2.0.10 + version: 2.0.10 '@types/url-join': specifier: 4.0.3 version: 4.0.3 diff --git a/tools/docs/test/index.test.mjs b/tools/docs/test/index.test.mjs new file mode 100644 index 0000000000000000000000000000000000000000..983c8790310c4475ff8b962d579b8cc53bb0994d --- /dev/null +++ b/tools/docs/test/index.test.mjs @@ -0,0 +1,75 @@ +import assert from 'node:assert'; +import path from 'node:path'; +import { describe, it } from 'node:test'; +import fs from 'fs-extra'; +import { glob } from 'glob'; +import remark from 'remark'; +import github from 'remark-github'; + +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('.') && !/^https?:\/\//.test(link.url)) { + // absolute path + const absPath = path.resolve( + 'tmp/docs', + path.dirname(file), + link.url.replace(/#.*/, ''), + ); + // relative path + const relPath = absPath.substring(root.length + 1); + + assert.ok( + files.has(relPath), + `File not found: ${link.url} in ${file} -> ${relPath}`, + ); + } 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); + } + } +} + +describe('index', async () => { + await describe('validate links', async () => { + const todo = await glob('**/*.md', { cwd: 'tmp/docs' }); + const files = new Set(todo); + + // Files from https://github.com/renovatebot/renovatebot.github.io/tree/main/src + files.add('index.md'); + + let c = 0; + + for (const file of todo) { + c++; + + await it(`${file}`, async () => { + const node = remark() + .use(github) + .parse(await fs.readFile(`tmp/docs/${file}`, 'utf8')); + checkNode(node, files, file); + }); + } + + assert.ok(c > 0, 'Should find at least one file'); + }); +});