docs: Added automated freshness check (#2428)
* docs: created freshness check script * added github action
This commit is contained in:
36
.github/workflows/docs-freshness-check.yml
vendored
Normal file
36
.github/workflows/docs-freshness-check.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# Checks for outdated documentation content and sends notification about it
|
||||
name: Docs Freshness Check
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *' # once a month
|
||||
|
||||
jobs:
|
||||
freshness-check:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REFERENCE_PAT }}
|
||||
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2.3.5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v2.4.1
|
||||
with:
|
||||
node-version: "14"
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/cache-deps
|
||||
with:
|
||||
extension: docs-freshness-check
|
||||
|
||||
- name: Perform Freshness Check
|
||||
run: yarn check:freshness
|
||||
@@ -70,11 +70,13 @@
|
||||
"generate:js-client": "typedoc --options typedoc.js-client.js",
|
||||
"generate:entities": "typedoc --options typedoc.entities.js",
|
||||
"release:snapshot": "changeset publish --no-git-tags --snapshot --tag snapshot",
|
||||
"generate:announcement": "node ./scripts/doc-change-release.js"
|
||||
"generate:announcement": "node ./scripts/doc-change-release.js",
|
||||
"check:freshness": "node ./scripts/freshness-check.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@changesets/changelog-github": "^0.4.5",
|
||||
"@changesets/cli": "^2.23.0",
|
||||
"@linear/sdk": "^1.22.0",
|
||||
"@octokit/core": "^4.0.5",
|
||||
"global": "^4.4.0",
|
||||
"import-from": "^3.0.0",
|
||||
|
||||
154
scripts/freshness-check.js
Normal file
154
scripts/freshness-check.js
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const { LinearClient } = require("@linear/sdk");
|
||||
const { Octokit } = require("@octokit/core");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.GH_TOKEN
|
||||
});
|
||||
|
||||
const linearClient = new LinearClient({
|
||||
apiKey: process.env.LINEAR_API_KEY
|
||||
});
|
||||
|
||||
const repoPath = path.join('docs', 'content');
|
||||
let freshnessCheckLabelId = "";
|
||||
let documentationTeamId = "";
|
||||
|
||||
async function scanDirectory (startPath) {
|
||||
const files = fs.readdirSync(path.join(startPath), {
|
||||
withFileTypes: true
|
||||
});
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(startPath, file.name);
|
||||
if (file.isDirectory()) {
|
||||
//if it's references directory, skip
|
||||
if (file.name !== 'references' && file.name !== 'upgrade-guides') {
|
||||
await scanDirectory(filePath);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//check that the file is a markdown file
|
||||
if (file.name.indexOf('.md') === -1 && file.name.indexOf('.mdx') === -1 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if it is a file, check its commits in GitHub
|
||||
const commitResponse = await octokit.request('GET /repos/{owner}/{repo}/commits', {
|
||||
owner: 'medusajs',
|
||||
repo: 'medusa',
|
||||
path: filePath,
|
||||
per_page: 1
|
||||
})
|
||||
|
||||
if (!commitResponse.data.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
const lastEditedDate = new Date(commitResponse.data[0].commit.committer.date);
|
||||
const monthsSinceEdited = getMonthDifference(lastEditedDate, today);
|
||||
|
||||
if (monthsSinceEdited > 6) {
|
||||
//file was edited more than 6 months ago.
|
||||
//check if there's an issue created for this file since the commit date
|
||||
const existingIssue = await linearClient.issues({
|
||||
filter: {
|
||||
createdAt: {
|
||||
gte: subtractMonths(monthsSinceEdited - 6, today)
|
||||
},
|
||||
title: {
|
||||
containsIgnoreCase: `Freshness check for ${filePath}`
|
||||
},
|
||||
labels: {
|
||||
some: {
|
||||
id: {
|
||||
eq: freshnessCheckLabelId
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
first: 1
|
||||
});
|
||||
|
||||
if (existingIssue.nodes.length) {
|
||||
//an issue has been created for the past 6 months. Don't create an issue for it.
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`Creating an issue for ${filePath}...`);
|
||||
|
||||
//there are no issues in the past 6 months. Create an issue
|
||||
await linearClient.issueCreate({
|
||||
teamId: documentationTeamId,
|
||||
title: `Freshness check for ${filePath}`,
|
||||
labelIds: [
|
||||
freshnessCheckLabelId
|
||||
],
|
||||
description: `File \`${filePath}\` was last edited on ${lastEditedDate.toDateString()}.`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main () {
|
||||
//fetch documentation team ID from linear
|
||||
const documentationTeam = await linearClient.teams({
|
||||
filter: {
|
||||
name: {
|
||||
eqIgnoreCase: 'Documentation'
|
||||
}
|
||||
},
|
||||
first: 1
|
||||
});
|
||||
|
||||
if (!documentationTeam.nodes.length) {
|
||||
console.log("Please add Documentation team in Linear first then try again");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
documentationTeamId = documentationTeam.nodes[0].id;
|
||||
|
||||
//fetch freshness check label ID from linear
|
||||
const freshnessCheckLabel = await linearClient.issueLabels({
|
||||
filter: {
|
||||
name: {
|
||||
eqIgnoreCase: 'type: freshness-check'
|
||||
},
|
||||
team: {
|
||||
id: {
|
||||
eq: documentationTeamId
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!freshnessCheckLabel.nodes.length) {
|
||||
console.log("Please add freshness check label in Linear under the documentation team first then try again");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
freshnessCheckLabelId = freshnessCheckLabel.nodes[0].id;
|
||||
|
||||
await scanDirectory(repoPath);
|
||||
}
|
||||
|
||||
function getMonthDifference(startDate, endDate) {
|
||||
return (
|
||||
endDate.getMonth() -
|
||||
startDate.getMonth() +
|
||||
12 * (endDate.getFullYear() - startDate.getFullYear())
|
||||
);
|
||||
}
|
||||
|
||||
function subtractMonths(numOfMonths, date = new Date()) {
|
||||
date.setMonth(date.getMonth() - numOfMonths);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
main()
|
||||
23
yarn.lock
23
yarn.lock
@@ -2891,6 +2891,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@graphql-typed-document-node/core@npm:^3.1.0":
|
||||
version: 3.1.1
|
||||
resolution: "@graphql-typed-document-node/core@npm:3.1.1"
|
||||
peerDependencies:
|
||||
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
|
||||
checksum: c186e5adceb0dfdaa770856d2f17c831a474f5927d79f984326ecb3d8680ba3c1ee2314f7def1d863692cd9cbe4dffc8bb52fc74ee0aa9b31e9491f24ef59f90
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@hapi/address@npm:^2.1.2":
|
||||
version: 2.1.4
|
||||
resolution: "@hapi/address@npm:2.1.4"
|
||||
@@ -4165,6 +4174,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@linear/sdk@npm:^1.22.0":
|
||||
version: 1.22.0
|
||||
resolution: "@linear/sdk@npm:1.22.0"
|
||||
dependencies:
|
||||
"@graphql-typed-document-node/core": ^3.1.0
|
||||
graphql: ^15.4.0
|
||||
isomorphic-unfetch: ^3.1.0
|
||||
checksum: 7e8f24f617631d027fd606334a498b04014d4c33603bcb3e08073d14f86260d116597983567f8bc147a935e4557180158175b52b9a9a8a270a234b946894a82b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lmdb/lmdb-darwin-arm64@npm:2.5.2":
|
||||
version: 2.5.2
|
||||
resolution: "@lmdb/lmdb-darwin-arm64@npm:2.5.2"
|
||||
@@ -18218,7 +18238,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql@npm:^15.5.1, graphql@npm:^15.7.2":
|
||||
"graphql@npm:^15.4.0, graphql@npm:^15.5.1, graphql@npm:^15.7.2":
|
||||
version: 15.8.0
|
||||
resolution: "graphql@npm:15.8.0"
|
||||
checksum: 30cc09b77170a9d1ed68e4c017ec8c5265f69501c96e4f34f8f6613f39a886c96dd9853eac925f212566ed651736334c8fe24ceae6c44e8d7625c95c3009a801
|
||||
@@ -30050,6 +30070,7 @@ __metadata:
|
||||
"@babel/runtime": ^7.11.2
|
||||
"@changesets/changelog-github": ^0.4.5
|
||||
"@changesets/cli": ^2.23.0
|
||||
"@linear/sdk": ^1.22.0
|
||||
"@octokit/core": ^4.0.5
|
||||
"@redocly/cli": latest
|
||||
"@typescript-eslint/eslint-plugin": ^5.36.2
|
||||
|
||||
Reference in New Issue
Block a user