mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
docs: Fix all credential documentation urls, and add a CI job to regularly validate these urls (#5012)
* add or update documentation URLs for all credentials * add UTM params to documentation urls even when they are absolute urls * Setup a CI job to validate documentation urls after every release * Fix FacebookGraphApi documentation URL * also validate node documentation urls Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
parent
0333b053ee
commit
c738aa53e9
41
.github/workflows/check-documentation-urls.yml
vendored
Normal file
41
.github/workflows/check-documentation-urls.yml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
name: Check Documentation URLs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- n8n@*
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
timeout-minutes: 5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16.x
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build nodes-base
|
||||||
|
run: pnpm --filter n8n-workflow --filter=n8n-core --filter=n8n-nodes-base build
|
||||||
|
|
||||||
|
- name: Test URLS
|
||||||
|
run: node scripts/validate-docs-links.js
|
||||||
|
|
||||||
|
- name: Notify Slack on failure
|
||||||
|
uses: act10ns/slack@v2.0.0
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
status: ${{ job.status }}
|
||||||
|
channel: '#updates-build-alerts'
|
||||||
|
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
message: Documentation URLs check failed (${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
@ -124,7 +124,7 @@ import OauthButton from './OauthButton.vue';
|
||||||
import { restApi } from '@/mixins/restApi';
|
import { restApi } from '@/mixins/restApi';
|
||||||
import { addCredentialTranslation } from '@/plugins/i18n';
|
import { addCredentialTranslation } from '@/plugins/i18n';
|
||||||
import mixins from 'vue-typed-mixins';
|
import mixins from 'vue-typed-mixins';
|
||||||
import { BUILTIN_CREDENTIALS_DOCS_URL, EnterpriseEditionFeature } from '@/constants';
|
import { BUILTIN_CREDENTIALS_DOCS_URL, DOCS_DOMAIN, EnterpriseEditionFeature } from '@/constants';
|
||||||
import { IPermissions } from '@/permissions';
|
import { IPermissions } from '@/permissions';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useUIStore } from '@/stores/ui';
|
import { useUIStore } from '@/stores/ui';
|
||||||
|
@ -229,20 +229,29 @@ export default mixins(restApi).extend({
|
||||||
const activeNode = this.ndvStore.activeNode;
|
const activeNode = this.ndvStore.activeNode;
|
||||||
const isCommunityNode = activeNode ? isCommunityPackageName(activeNode.type) : false;
|
const isCommunityNode = activeNode ? isCommunityPackageName(activeNode.type) : false;
|
||||||
|
|
||||||
if (!type || !type.documentationUrl) {
|
const documentationUrl = type && type.documentationUrl;
|
||||||
|
|
||||||
|
if (!documentationUrl) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
let url: URL;
|
||||||
type.documentationUrl.startsWith('https://') ||
|
if (documentationUrl.startsWith('https://') || documentationUrl.startsWith('http://')) {
|
||||||
type.documentationUrl.startsWith('http://')
|
url = new URL(documentationUrl);
|
||||||
) {
|
if (url.hostname !== DOCS_DOMAIN) return documentationUrl;
|
||||||
return type.documentationUrl;
|
} else {
|
||||||
|
// Don't show documentation link for community nodes if the URL is not an absolute path
|
||||||
|
if (isCommunityNode) return '';
|
||||||
|
else url = new URL(`${BUILTIN_CREDENTIALS_DOCS_URL}${documentationUrl}/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isCommunityNode
|
if (url.hostname === DOCS_DOMAIN) {
|
||||||
? '' // Don't show documentation link for community nodes if the URL is not an absolute path
|
url.searchParams.set('utm_source', 'n8n_app');
|
||||||
: `${BUILTIN_CREDENTIALS_DOCS_URL}${type.documentationUrl}/?utm_source=n8n_app&utm_medium=left_nav_menu&utm_campaign=create_new_credentials_modal`;
|
url.searchParams.set('utm_medium', 'left_nav_menu');
|
||||||
|
url.searchParams.set('utm_campaign', 'create_new_credentials_modal');
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.href;
|
||||||
},
|
},
|
||||||
isGoogleOAuthType(): boolean {
|
isGoogleOAuthType(): boolean {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -57,21 +57,22 @@ export const BREAKPOINT_LG = 1200;
|
||||||
export const BREAKPOINT_XL = 1920;
|
export const BREAKPOINT_XL = 1920;
|
||||||
|
|
||||||
export const N8N_IO_BASE_URL = `https://api.n8n.io/api/`;
|
export const N8N_IO_BASE_URL = `https://api.n8n.io/api/`;
|
||||||
export const BUILTIN_NODES_DOCS_URL = `https://docs.n8n.io/integrations/builtin/`;
|
export const DOCS_DOMAIN = 'docs.n8n.io';
|
||||||
export const BUILTIN_CREDENTIALS_DOCS_URL = `https://docs.n8n.io/integrations/builtin/credentials/`;
|
export const BUILTIN_NODES_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/builtin/`;
|
||||||
export const DATA_PINNING_DOCS_URL = 'https://docs.n8n.io/data/data-pinning/';
|
export const BUILTIN_CREDENTIALS_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/builtin/credentials/`;
|
||||||
export const DATA_EDITING_DOCS_URL = 'https://docs.n8n.io/data/data-editing/';
|
export const DATA_PINNING_DOCS_URL = `https://${DOCS_DOMAIN}/data/data-pinning/`;
|
||||||
|
export const DATA_EDITING_DOCS_URL = `https://${DOCS_DOMAIN}/data/data-editing/`;
|
||||||
export const NPM_COMMUNITY_NODE_SEARCH_API_URL = `https://api.npms.io/v2/`;
|
export const NPM_COMMUNITY_NODE_SEARCH_API_URL = `https://api.npms.io/v2/`;
|
||||||
export const NPM_PACKAGE_DOCS_BASE_URL = `https://www.npmjs.com/package/`;
|
export const NPM_PACKAGE_DOCS_BASE_URL = `https://www.npmjs.com/package/`;
|
||||||
export const NPM_KEYWORD_SEARCH_URL = `https://www.npmjs.com/search?q=keywords%3An8n-community-node-package`;
|
export const NPM_KEYWORD_SEARCH_URL = `https://www.npmjs.com/search?q=keywords%3An8n-community-node-package`;
|
||||||
export const N8N_QUEUE_MODE_DOCS_URL = `https://docs.n8n.io/hosting/scaling/queue-mode/`;
|
export const N8N_QUEUE_MODE_DOCS_URL = `https://${DOCS_DOMAIN}/hosting/scaling/queue-mode/`;
|
||||||
export const COMMUNITY_NODES_INSTALLATION_DOCS_URL = `https://docs.n8n.io/integrations/community-nodes/installation/`;
|
export const COMMUNITY_NODES_INSTALLATION_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/community-nodes/installation/`;
|
||||||
export const COMMUNITY_NODES_NPM_INSTALLATION_URL =
|
export const COMMUNITY_NODES_NPM_INSTALLATION_URL =
|
||||||
'https://docs.npmjs.com/downloading-and-installing-node-js-and-npm';
|
'https://docs.npmjs.com/downloading-and-installing-node-js-and-npm';
|
||||||
export const COMMUNITY_NODES_RISKS_DOCS_URL = `https://docs.n8n.io/integrations/community-nodes/risks/`;
|
export const COMMUNITY_NODES_RISKS_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/community-nodes/risks/`;
|
||||||
export const COMMUNITY_NODES_BLOCKLIST_DOCS_URL = `https://docs.n8n.io/integrations/community-nodes/blocklist/`;
|
export const COMMUNITY_NODES_BLOCKLIST_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/community-nodes/blocklist/`;
|
||||||
export const CUSTOM_NODES_DOCS_URL = `https://docs.n8n.io/integrations/creating-nodes/code/create-n8n-nodes-module/`;
|
export const CUSTOM_NODES_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/creating-nodes/code/create-n8n-nodes-module/`;
|
||||||
export const EXPRESSIONS_DOCS_URL = 'https://docs.n8n.io/code-examples/expressions/';
|
export const EXPRESSIONS_DOCS_URL = `https://${DOCS_DOMAIN}/code-examples/expressions/`;
|
||||||
|
|
||||||
// node types
|
// node types
|
||||||
export const BAMBOO_HR_NODE_TYPE = 'n8n-nodes-base.bambooHr';
|
export const BAMBOO_HR_NODE_TYPE = 'n8n-nodes-base.bambooHr';
|
||||||
|
|
|
@ -7,6 +7,8 @@ export class BaserowApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Baserow API';
|
displayName = 'Baserow API';
|
||||||
|
|
||||||
|
documentationUrl = 'baserow';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Host',
|
displayName: 'Host',
|
||||||
|
|
|
@ -7,6 +7,8 @@ export class CiscoWebexOAuth2Api implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Cisco Webex OAuth2 API';
|
displayName = 'Cisco Webex OAuth2 API';
|
||||||
|
|
||||||
|
documentationUrl = 'ciscowebex';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Grant Type',
|
displayName: 'Grant Type',
|
||||||
|
|
|
@ -10,7 +10,7 @@ export class CitrixAdcApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Citrix ADC API';
|
displayName = 'Citrix ADC API';
|
||||||
|
|
||||||
documentationUrl = 'citrix';
|
documentationUrl = 'citrixadc';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ export class FacebookGraphApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Facebook Graph API';
|
displayName = 'Facebook Graph API';
|
||||||
|
|
||||||
documentationUrl = 'facebookGraph';
|
documentationUrl = 'facebookgraph';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ export class FacebookGraphAppApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Facebook Graph API (App)';
|
displayName = 'Facebook Graph API (App)';
|
||||||
|
|
||||||
documentationUrl = 'facebookGraphApp';
|
documentationUrl = 'facebookapp';
|
||||||
|
|
||||||
extends = ['facebookGraphApi'];
|
extends = ['facebookGraphApi'];
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ export class GetResponseOAuth2Api implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'GetResponse OAuth2 API';
|
displayName = 'GetResponse OAuth2 API';
|
||||||
|
|
||||||
|
documentationUrl = 'getresponse';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Grant Type',
|
displayName: 'Grant Type',
|
||||||
|
|
|
@ -7,7 +7,7 @@ export class GoogleOAuth2Api implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Google OAuth2 API';
|
displayName = 'Google OAuth2 API';
|
||||||
|
|
||||||
documentationUrl = 'google/oauth-generic/';
|
documentationUrl = 'google/oauth-generic';
|
||||||
|
|
||||||
icon = 'file:Google.svg';
|
icon = 'file:Google.svg';
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ export class HarvestOAuth2Api implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Harvest OAuth2 API';
|
displayName = 'Harvest OAuth2 API';
|
||||||
|
|
||||||
|
documentationUrl = 'harvest';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Grant Type',
|
displayName: 'Grant Type',
|
||||||
|
|
|
@ -9,7 +9,7 @@ export class MondayComOAuth2Api implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Monday.com OAuth2 API';
|
displayName = 'Monday.com OAuth2 API';
|
||||||
|
|
||||||
documentationUrl = 'monday';
|
documentationUrl = 'mondaycom';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ export class SendInBlueApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'SendInBlue';
|
displayName = 'SendInBlue';
|
||||||
|
|
||||||
documentationUrl = 'sendInBlueApi';
|
documentationUrl = 'sendinblue';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ export class Smtp implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'SMTP';
|
displayName = 'SMTP';
|
||||||
|
|
||||||
documentationUrl = 'smtp';
|
documentationUrl = 'sendemail';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,8 @@ export class SshPassword implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'SSH Password';
|
displayName = 'SSH Password';
|
||||||
|
|
||||||
|
documentationUrl = 'ssh';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Host',
|
displayName: 'Host',
|
||||||
|
|
|
@ -5,6 +5,8 @@ export class SshPrivateKey implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'SSH Private Key';
|
displayName = 'SSH Private Key';
|
||||||
|
|
||||||
|
documentationUrl = 'ssh';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Host',
|
displayName: 'Host',
|
||||||
|
|
|
@ -10,6 +10,8 @@ export class VenafiTlsProtectCloudApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Venafi TLS Protect Cloud';
|
displayName = 'Venafi TLS Protect Cloud';
|
||||||
|
|
||||||
|
documentationUrl = 'venafitlsprotectcloud';
|
||||||
|
|
||||||
properties = [
|
properties = [
|
||||||
{
|
{
|
||||||
displayName: 'API Key',
|
displayName: 'API Key',
|
||||||
|
|
|
@ -12,6 +12,8 @@ export class VenafiTlsProtectDatacenterApi implements ICredentialType {
|
||||||
|
|
||||||
displayName = 'Venafi TLS Protect Datacenter API';
|
displayName = 'Venafi TLS Protect Datacenter API';
|
||||||
|
|
||||||
|
documentationUrl = 'venafitlsprotectdatacenter';
|
||||||
|
|
||||||
properties: INodeProperties[] = [
|
properties: INodeProperties[] = [
|
||||||
{
|
{
|
||||||
displayName: 'Domain',
|
displayName: 'Domain',
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
],
|
],
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awsCertificateManager/"
|
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awscertificatemanager/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generic": [
|
"generic": [
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
],
|
],
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awsElb/"
|
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.awselb/"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
],
|
],
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.citrixAdc/"
|
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.citrixadc/"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"resources": {
|
"resources": {
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.cron/"
|
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generic": [
|
"generic": [
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
],
|
],
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.imapemail/"
|
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.emailimap/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generic": [
|
"generic": [
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"resources": {
|
"resources": {
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.function/"
|
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generic": [
|
"generic": [
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"resources": {
|
"resources": {
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.functionitem/"
|
"url": "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generic": [
|
"generic": [
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
],
|
],
|
||||||
"primaryDocumentation": [
|
"primaryDocumentation": [
|
||||||
{
|
{
|
||||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.venafiTlsProtectCloud/"
|
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.venafitlsprotectcloud/"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
64
scripts/validate-docs-links.js
Normal file
64
scripts/validate-docs-links.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const https = require('https');
|
||||||
|
const glob = require('fast-glob');
|
||||||
|
const pLimit = require('p-limit');
|
||||||
|
|
||||||
|
const nodesBaseDir = path.resolve(__dirname, '../packages/nodes-base');
|
||||||
|
|
||||||
|
const validateUrl = async (kind, name, documentationUrl) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
if (!documentationUrl) resolve([name, null]);
|
||||||
|
const url = new URL(
|
||||||
|
/^https?:\/\//.test(documentationUrl)
|
||||||
|
? documentationUrl
|
||||||
|
: `https://docs.n8n.io/integrations/builtin/${kind}/${documentationUrl.toLowerCase()}/`,
|
||||||
|
);
|
||||||
|
https
|
||||||
|
.request(
|
||||||
|
{
|
||||||
|
hostname: url.hostname,
|
||||||
|
port: 443,
|
||||||
|
path: url.pathname,
|
||||||
|
method: 'HEAD',
|
||||||
|
},
|
||||||
|
(res) => resolve([name, res.statusCode]),
|
||||||
|
)
|
||||||
|
.on('error', (e) => reject(e))
|
||||||
|
.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkLinks = async (kind) => {
|
||||||
|
let types = require(path.join(nodesBaseDir, `dist/types/${kind}.json`));
|
||||||
|
if (kind === 'nodes')
|
||||||
|
types = types.filter(({ codex }) => !!codex?.resources?.primaryDocumentation);
|
||||||
|
const limit = pLimit(30);
|
||||||
|
const statuses = await Promise.all(
|
||||||
|
types.map((type) =>
|
||||||
|
limit(() => {
|
||||||
|
const documentationUrl =
|
||||||
|
kind === 'credentials'
|
||||||
|
? type.documentationUrl
|
||||||
|
: type.codex?.resources?.primaryDocumentation?.[0]?.url;
|
||||||
|
return validateUrl(kind, type.displayName, documentationUrl);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const missingDocs = [];
|
||||||
|
const invalidUrls = [];
|
||||||
|
for (const [name, statusCode] of statuses) {
|
||||||
|
if (statusCode === null) missingDocs.push(name);
|
||||||
|
if (statusCode !== 200) invalidUrls.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingDocs.length) console.log('Documentation URL missing for %s', kind, missingDocs);
|
||||||
|
if (invalidUrls.length) console.log('Documentation URL invalid for %s', kind, invalidUrls);
|
||||||
|
if (missingDocs.length || invalidUrls.length) process.exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await checkLinks('credentials');
|
||||||
|
await checkLinks('nodes');
|
||||||
|
})();
|
Loading…
Reference in a new issue