From 440e52812176db9d9749c89b701e4900e2ae8c78 Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Sun, 29 May 2022 23:44:31 +0300 Subject: [PATCH 01/10] feat(docs): Autogenerated manager bug & feat lists - init commit --- tools/docs/github-query-items.ts | 81 ++++++++++++++++++++++++++++++++ tools/docs/manager.ts | 43 +++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 tools/docs/github-query-items.ts diff --git a/tools/docs/github-query-items.ts b/tools/docs/github-query-items.ts new file mode 100644 index 00000000000000..704d55dc1e69ce --- /dev/null +++ b/tools/docs/github-query-items.ts @@ -0,0 +1,81 @@ +export type GithubApiQueryResponse = { + total_count: number; + incomplete_results: boolean; + items?: ItemsEntity[] | null; +}; + +export type ItemsEntity = { + url: string; + repository_url: string; + labels_url: string; + comments_url: string; + events_url: string; + html_url: string; + id: number; + node_id: string; + number: number; + title: string; + user: User; + labels?: LabelsEntity[] | null; + state: string; + locked: boolean; + assignee?: null; + assignees?: null[] | null; + milestone?: null; + comments: number; + created_at: string; + updated_at: string; + closed_at?: null; + author_association: string; + active_lock_reason?: null; + body: string; + reactions: Reactions; + timeline_url: string; + performed_via_github_app?: null; + state_reason?: null; + score: number; +}; + +export type User = { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; +}; + +export type LabelsEntity = { + id: number; + node_id: string; + url: string; + name: string; + color: string; + default: boolean; + description: string; +}; + +export type Reactions = { + url: string; + total_count: number; + '+1': number; + '-1': number; + laugh: number; + hooray: number; + confused: number; + heart: number; + rocket: number; + eyes: number; +}; diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index b8bb426982b174..55f0e14f5f7631 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -1,8 +1,14 @@ +import got from 'got'; import type { RenovateConfig } from '../../lib/config/types'; +import { logger } from '../../lib/logger'; import { getManagers } from '../../lib/modules/manager'; +import { getQueryString } from '../../lib/util/url'; import { readFile, updateFile } from '../utils'; +import type { GithubApiQueryResponse } from './github-query-items'; import { getDisplayName, getNameWithUrl, replaceContent } from './utils'; +const gitHubApi = 'https://api.github.com/search/issues?'; + function getTitle(manager: string, displayName: string): string { if (manager === 'regex') { return `Custom Manager Support using Regex`; @@ -14,6 +20,26 @@ function getManagerLink(manager: string): string { return `[\`${manager}\`](${manager}/)`; } +export async function getManagerGitHubIssues( + ty: 'bug' | 'feature', + manager: string +): Promise { + const q = `repo:renovatebot/renovate type:issue is:open label:type:${ty} -label:priority-5-triage label:manager:${manager}`; + const query = getQueryString({ q, per_page: 30 }); + let ret = ''; + try { + const res = await got(gitHubApi + query).json(); + const items = res.items ?? []; + for (const item of items) { + ret += ` - ${item.title} [#${item.number}](${item.html_url})\n`; + } + } catch (err) { + logger.warn({ err }, 'Error getting query results'); + throw err; + } + return ret; +} + export async function generateManagers(dist: string): Promise { const managers = getManagers(); const allLanguages: Record = {}; @@ -24,6 +50,9 @@ export async function generateManagers(dist: string): Promise { const { defaultConfig, supportedDatasources } = definition; const { fileMatch } = defaultConfig as RenovateConfig; const displayName = getDisplayName(manager, definition); + // if (manager !== 'npm') { + // continue + // } let md = `--- title: ${getTitle(manager, displayName)} sidebar_label: ${displayName} @@ -73,6 +102,20 @@ sidebar_label: ${displayName} } md += managerReadmeContent + '\n\n'; + const bugList = await getManagerGitHubIssues('bug', manager); + if (bugList) { + md += '## Known open bugs\n\n'; + md += await getManagerGitHubIssues('bug', manager); + md += '\n'; + } + + const featureList = await getManagerGitHubIssues('feature', manager); + if (featureList) { + md += '## Upcoming features\n\n'; + md += featureList; + md += '\n'; + } + await updateFile(`${dist}/modules/manager/${manager}/index.md`, md); } const languages = Object.keys(allLanguages).filter( From c0e6fd8b2ec0dc22c2ac391eabf9da2ed2d4af3a Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Mon, 30 May 2022 15:20:18 +0300 Subject: [PATCH 02/10] feat(docs): Autogenerated manager bug & feat lists - now querying once --- tools/docs/github-query-items.ts | 18 +++--- tools/docs/manager.ts | 98 +++++++++++++++++++++++++------- 2 files changed, 85 insertions(+), 31 deletions(-) diff --git a/tools/docs/github-query-items.ts b/tools/docs/github-query-items.ts index 704d55dc1e69ce..df1bcb033ffba6 100644 --- a/tools/docs/github-query-items.ts +++ b/tools/docs/github-query-items.ts @@ -1,7 +1,7 @@ export type GithubApiQueryResponse = { total_count: number; incomplete_results: boolean; - items?: ItemsEntity[] | null; + items: ItemsEntity[]; }; export type ItemsEntity = { @@ -16,23 +16,23 @@ export type ItemsEntity = { number: number; title: string; user: User; - labels?: LabelsEntity[] | null; + labels: LabelsEntity[]; state: string; locked: boolean; - assignee?: null; - assignees?: null[] | null; - milestone?: null; + assignee: User; + assignees: User[]; + milestone: string; comments: number; created_at: string; updated_at: string; - closed_at?: null; + closed_at: string; author_association: string; - active_lock_reason?: null; + active_lock_reason?: string; body: string; reactions: Reactions; timeline_url: string; - performed_via_github_app?: null; - state_reason?: null; + performed_via_github_app: boolean; + state_reason: string; score: number; }; diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 55f0e14f5f7631..a7ce3b0a8a7ca6 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -4,11 +4,16 @@ import { logger } from '../../lib/logger'; import { getManagers } from '../../lib/modules/manager'; import { getQueryString } from '../../lib/util/url'; import { readFile, updateFile } from '../utils'; -import type { GithubApiQueryResponse } from './github-query-items'; +import type { GithubApiQueryResponse, ItemsEntity } from './github-query-items'; import { getDisplayName, getNameWithUrl, replaceContent } from './utils'; const gitHubApi = 'https://api.github.com/search/issues?'; +interface ManagerIssues { + bugs: ItemsEntity[]; + features: ItemsEntity[]; +} + function getTitle(manager: string, displayName: string): string { if (manager === 'regex') { return `Custom Manager Support using Regex`; @@ -20,28 +25,78 @@ function getManagerLink(manager: string): string { return `[\`${manager}\`](${manager}/)`; } -export async function getManagerGitHubIssues( - ty: 'bug' | 'feature', - manager: string -): Promise { - const q = `repo:renovatebot/renovate type:issue is:open label:type:${ty} -label:priority-5-triage label:manager:${manager}`; - const query = getQueryString({ q, per_page: 30 }); - let ret = ''; +function stringifyIssues(items: ItemsEntity[]): string { + if (!items) { + return ''; + } + let list = ''; + for (const item of items) { + list += ` - ${item.title} [#${item.number}](${item.html_url})\n`; + } + return list; +} + +function extractIssues( + managerIssuesMap: Record, + items: ItemsEntity[] +): void { + if (!items || !managerIssuesMap) { + return; + } + for (const item of items) { + const type = item.labels + .find((l) => l.name.startsWith('type')) + ?.name.split(':')[1]; + if (!type) { + continue; + } + const manager = item.labels + .find((l) => l.name.startsWith('manager')) + ?.name.split(':')[1]; + if (!manager) { + continue; + } + if (!managerIssuesMap[manager]) { + managerIssuesMap[manager] = { bugs: [], features: [] }; + } + switch (type) { + case 'bug': + managerIssuesMap[manager].bugs.push(item); + break; + case 'feature': + managerIssuesMap[manager].features.push(item); + break; + default: + break; + } + } +} + +export async function getManagersGitHubIssues(): Promise< + Record +> { + const q = `repo:renovatebot/renovate type:issue is:open -label:priority-5-triage`; + const per_page = 100; + const managerIssuesMap: Record = {}; try { - const res = await got(gitHubApi + query).json(); - const items = res.items ?? []; - for (const item of items) { - ret += ` - ${item.title} [#${item.number}](${item.html_url})\n`; + let previouslyFound = per_page; + for (let page = 1; previouslyFound === per_page; page++) { + const query = getQueryString({ q, per_page, page }); + const res = await got(gitHubApi + query).json(); + const items = res.items ?? []; + previouslyFound = items.length; + extractIssues(managerIssuesMap, items); } } catch (err) { - logger.warn({ err }, 'Error getting query results'); + logger.error({ err }, 'Error getting query results'); throw err; } - return ret; + return managerIssuesMap; } export async function generateManagers(dist: string): Promise { const managers = getManagers(); + const managerIssuesMap = await getManagersGitHubIssues(); const allLanguages: Record = {}; for (const [manager, definition] of managers) { const language = definition.language ?? 'other'; @@ -50,9 +105,6 @@ export async function generateManagers(dist: string): Promise { const { defaultConfig, supportedDatasources } = definition; const { fileMatch } = defaultConfig as RenovateConfig; const displayName = getDisplayName(manager, definition); - // if (manager !== 'npm') { - // continue - // } let md = `--- title: ${getTitle(manager, displayName)} sidebar_label: ${displayName} @@ -102,16 +154,18 @@ sidebar_label: ${displayName} } md += managerReadmeContent + '\n\n'; - const bugList = await getManagerGitHubIssues('bug', manager); + const bugList = stringifyIssues(managerIssuesMap[manager]?.bugs); if (bugList) { - md += '## Known open bugs\n\n'; - md += await getManagerGitHubIssues('bug', manager); + md += '\n'; + md += '??? note "Click me to see the list of open bug reports"\n'; + md += bugList; md += '\n'; } - const featureList = await getManagerGitHubIssues('feature', manager); + const featureList = stringifyIssues(managerIssuesMap[manager]?.features); if (featureList) { - md += '## Upcoming features\n\n'; + md += '\n'; + md += '??? note "Click me to see the list of upcoming features"\n'; md += featureList; md += '\n'; } From 3a789a108efb7d8d7fee5f5880cbf751af13ea0e Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti <97394622+Gabriel-Ladzaretti@users.noreply.github.com> Date: Mon, 30 May 2022 17:50:46 +0300 Subject: [PATCH 03/10] Apply suggestions from code review Co-authored-by: Michael Kriese --- tools/docs/manager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index a7ce3b0a8a7ca6..9d2dea15ffe2e9 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -45,13 +45,13 @@ function extractIssues( } for (const item of items) { const type = item.labels - .find((l) => l.name.startsWith('type')) + .find((l) => l.name.startsWith('type:')) ?.name.split(':')[1]; if (!type) { continue; } const manager = item.labels - .find((l) => l.name.startsWith('manager')) + .find((l) => l.name.startsWith('manager:')) ?.name.split(':')[1]; if (!manager) { continue; From 15686fe9289e707efc0430b5726fd9af593e1525 Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Mon, 30 May 2022 18:28:47 +0300 Subject: [PATCH 04/10] feat(docs): Autogenerated manager bug & feat lists - use own GithubHttp --- tools/docs/github-query-items.ts | 65 -------------------------------- tools/docs/manager.ts | 23 ++++++----- 2 files changed, 13 insertions(+), 75 deletions(-) diff --git a/tools/docs/github-query-items.ts b/tools/docs/github-query-items.ts index df1bcb033ffba6..f9668ce59bbe18 100644 --- a/tools/docs/github-query-items.ts +++ b/tools/docs/github-query-items.ts @@ -5,77 +5,12 @@ export type GithubApiQueryResponse = { }; export type ItemsEntity = { - url: string; - repository_url: string; - labels_url: string; - comments_url: string; - events_url: string; html_url: string; - id: number; - node_id: string; number: number; title: string; - user: User; labels: LabelsEntity[]; - state: string; - locked: boolean; - assignee: User; - assignees: User[]; - milestone: string; - comments: number; - created_at: string; - updated_at: string; - closed_at: string; - author_association: string; - active_lock_reason?: string; - body: string; - reactions: Reactions; - timeline_url: string; - performed_via_github_app: boolean; - state_reason: string; - score: number; -}; - -export type User = { - login: string; - id: number; - node_id: string; - avatar_url: string; - gravatar_id: string; - url: string; - html_url: string; - followers_url: string; - following_url: string; - gists_url: string; - starred_url: string; - subscriptions_url: string; - organizations_url: string; - repos_url: string; - events_url: string; - received_events_url: string; - type: string; - site_admin: boolean; }; export type LabelsEntity = { - id: number; - node_id: string; - url: string; name: string; - color: string; - default: boolean; - description: string; -}; - -export type Reactions = { - url: string; - total_count: number; - '+1': number; - '-1': number; - laugh: number; - hooray: number; - confused: number; - heart: number; - rocket: number; - eyes: number; }; diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 9d2dea15ffe2e9..1652221bbfff18 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -1,13 +1,13 @@ -import got from 'got'; import type { RenovateConfig } from '../../lib/config/types'; import { logger } from '../../lib/logger'; import { getManagers } from '../../lib/modules/manager'; +import { GithubHttp } from '../../lib/util/http/github'; import { getQueryString } from '../../lib/util/url'; import { readFile, updateFile } from '../utils'; import type { GithubApiQueryResponse, ItemsEntity } from './github-query-items'; import { getDisplayName, getNameWithUrl, replaceContent } from './utils'; -const gitHubApi = 'https://api.github.com/search/issues?'; +const gitHubApiUrl = 'https://api.github.com/search/issues?'; interface ManagerIssues { bugs: ItemsEntity[]; @@ -78,15 +78,18 @@ export async function getManagersGitHubIssues(): Promise< const q = `repo:renovatebot/renovate type:issue is:open -label:priority-5-triage`; const per_page = 100; const managerIssuesMap: Record = {}; + const githubApi = new GithubHttp('manager-issues'); try { - let previouslyFound = per_page; - for (let page = 1; previouslyFound === per_page; page++) { - const query = getQueryString({ q, per_page, page }); - const res = await got(gitHubApi + query).json(); - const items = res.items ?? []; - previouslyFound = items.length; - extractIssues(managerIssuesMap, items); - } + const query = getQueryString({ q, per_page }); + const res = await githubApi.getJson( + gitHubApiUrl + query, + { + paginationField: 'items', + paginate: true, + } + ); + const items = res.body?.items ?? []; + extractIssues(managerIssuesMap, items); } catch (err) { logger.error({ err }, 'Error getting query results'); throw err; From 4942d40bc76cb19c459f08a776e19659ff06af47 Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Mon, 30 May 2022 23:23:00 +0300 Subject: [PATCH 05/10] bug(manager/circleci): add android to machine image skipping - sort asd - show count --- tools/docs/manager.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 1652221bbfff18..639a0f645a84c1 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -25,15 +25,15 @@ function getManagerLink(manager: string): string { return `[\`${manager}\`](${manager}/)`; } -function stringifyIssues(items: ItemsEntity[]): string { +function stringifyIssues(items: ItemsEntity[]): [string, number] { if (!items) { - return ''; + return ['', 0]; } let list = ''; for (const item of items) { list += ` - ${item.title} [#${item.number}](${item.html_url})\n`; } - return list; + return [list, items.length]; } function extractIssues( @@ -89,7 +89,10 @@ export async function getManagersGitHubIssues(): Promise< } ); const items = res.body?.items ?? []; - extractIssues(managerIssuesMap, items); + extractIssues( + managerIssuesMap, + items.sort((a, b) => a.number - b.number) + ); } catch (err) { logger.error({ err }, 'Error getting query results'); throw err; @@ -157,18 +160,20 @@ sidebar_label: ${displayName} } md += managerReadmeContent + '\n\n'; - const bugList = stringifyIssues(managerIssuesMap[manager]?.bugs); + const [bugList, bugsLen] = stringifyIssues(managerIssuesMap[manager]?.bugs); if (bugList) { md += '\n'; - md += '??? note "Click me to see the list of open bug reports"\n'; + md += `??? note "Click me to see the list of ${bugsLen} open bug reports"\n`; md += bugList; md += '\n'; } - const featureList = stringifyIssues(managerIssuesMap[manager]?.features); + const [featureList, featureLen] = stringifyIssues( + managerIssuesMap[manager]?.features + ); if (featureList) { md += '\n'; - md += '??? note "Click me to see the list of upcoming features"\n'; + md += `??? note "Click me to see the list of ${featureLen} upcoming features"\n`; md += featureList; md += '\n'; } From 357d7814352630b8f54c7bb4c4dd85e81e6c17c6 Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Tue, 31 May 2022 09:26:13 +0300 Subject: [PATCH 06/10] feat(docs): Autogenerated manager bug & feat lists - show features first --- tools/docs/manager.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 639a0f645a84c1..7797a429570ab6 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -160,14 +160,6 @@ sidebar_label: ${displayName} } md += managerReadmeContent + '\n\n'; - const [bugList, bugsLen] = stringifyIssues(managerIssuesMap[manager]?.bugs); - if (bugList) { - md += '\n'; - md += `??? note "Click me to see the list of ${bugsLen} open bug reports"\n`; - md += bugList; - md += '\n'; - } - const [featureList, featureLen] = stringifyIssues( managerIssuesMap[manager]?.features ); @@ -178,6 +170,14 @@ sidebar_label: ${displayName} md += '\n'; } + const [bugList, bugsLen] = stringifyIssues(managerIssuesMap[manager]?.bugs); + if (bugList) { + md += '\n'; + md += `??? note "Click me to see the list of ${bugsLen} open bug reports"\n`; + md += bugList; + md += '\n'; + } + await updateFile(`${dist}/modules/manager/${manager}/index.md`, md); } const languages = Object.keys(allLanguages).filter( From fcccf0fa7d0c430e6cf47b8f48465a7cd83ae81d Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Wed, 1 Jun 2022 11:10:32 +0300 Subject: [PATCH 07/10] feat(docs): Autogenerated manager bug & feat lists - added date footnote --- tools/docs/manager.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 7797a429570ab6..efd8390a1297a2 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -1,3 +1,4 @@ +import { DateTime } from 'luxon'; import type { RenovateConfig } from '../../lib/config/types'; import { logger } from '../../lib/logger'; import { getManagers } from '../../lib/modules/manager'; @@ -160,24 +161,29 @@ sidebar_label: ${displayName} } md += managerReadmeContent + '\n\n'; - const [featureList, featureLen] = stringifyIssues( - managerIssuesMap[manager]?.features - ); + const [featureList] = stringifyIssues(managerIssuesMap[manager]?.features); if (featureList) { - md += '\n'; - md += `??? note "Click me to see the list of ${featureLen} upcoming features"\n`; + md += '## Upcoming features\n\n'; md += featureList; md += '\n'; } - const [bugList, bugsLen] = stringifyIssues(managerIssuesMap[manager]?.bugs); + const [bugList] = stringifyIssues(managerIssuesMap[manager]?.bugs); if (bugList) { - md += '\n'; - md += `??? note "Click me to see the list of ${bugsLen} open bug reports"\n`; + md += '## Open bug reports\n\n'; md += bugList; md += '\n'; } + if (featureList || bugList) { + const now = DateTime.utc().toFormat('MMMM dd, yyyy'); + const lists = `list of ${featureList ? 'features' : ''}${ + featureList && bugList ? ' and ' : '' + }${bugList ? 'bugs' : ''}`; + md += '\n\n'; + md += `The above ${lists} were current at time of page generation on ${now}.\n`; + } + await updateFile(`${dist}/modules/manager/${manager}/index.md`, md); } const languages = Object.keys(allLanguages).filter( From 0bce494bc4af83be85867e0ca6ab6c7e6008532c Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Wed, 1 Jun 2022 22:50:18 +0300 Subject: [PATCH 08/10] feat(docs): Autogenerated manager bug & feat lists --- tools/docs/manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index efd8390a1297a2..bd66dcab6e654f 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -163,7 +163,7 @@ sidebar_label: ${displayName} const [featureList] = stringifyIssues(managerIssuesMap[manager]?.features); if (featureList) { - md += '## Upcoming features\n\n'; + md += '## Related feature requests awaiting implementation\n\n'; md += featureList; md += '\n'; } From fffbee9e94877eda2976123b476ad1f33a5cccdb Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti Date: Thu, 2 Jun 2022 18:56:57 +0300 Subject: [PATCH 09/10] feat(docs): Autogenerated manager bug & feat lists --- tools/docs/manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index bd66dcab6e654f..6c93b9ebf339a0 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -163,7 +163,7 @@ sidebar_label: ${displayName} const [featureList] = stringifyIssues(managerIssuesMap[manager]?.features); if (featureList) { - md += '## Related feature requests awaiting implementation\n\n'; + md += '## Open feature requests\n\n'; md += featureList; md += '\n'; } From 2cd5634f96532f9eab987b4ea2ccb683063f567e Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Tue, 7 Jun 2022 11:26:37 +0200 Subject: [PATCH 10/10] Update tools/docs/manager.ts Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> --- tools/docs/manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docs/manager.ts b/tools/docs/manager.ts index 6c93b9ebf339a0..bbf6ce0a420209 100644 --- a/tools/docs/manager.ts +++ b/tools/docs/manager.ts @@ -181,7 +181,7 @@ sidebar_label: ${displayName} featureList && bugList ? ' and ' : '' }${bugList ? 'bugs' : ''}`; md += '\n\n'; - md += `The above ${lists} were current at time of page generation on ${now}.\n`; + md += `The above ${lists} were current when this page was generated on ${now}.\n`; } await updateFile(`${dist}/modules/manager/${manager}/index.md`, md);