diff --git a/.github/gen-page-preview/main.spec.ts b/.github/gen-page-preview/main.spec.ts index 5f390374..f9ab1c7e 100644 --- a/.github/gen-page-preview/main.spec.ts +++ b/.github/gen-page-preview/main.spec.ts @@ -96,7 +96,8 @@ test("page screenshot", async ({ page }) => { } const images = screenshot_urls.map( - (o) => `## ${o.file} \n\n![${o.file}](${o.url})\n` + (o) => + `
\n${o.file}\n\n## ${o.file} \n\n![${o.file}](${o.url})\n
\n` ); const comments = await octokit.issues.listComments({ owner: OWNER, diff --git a/.github/markdown-header-check/markdown-header.ts b/.github/markdown-header-check/markdown-header.ts index c0a978c8..5b999856 100644 --- a/.github/markdown-header-check/markdown-header.ts +++ b/.github/markdown-header-check/markdown-header.ts @@ -1,11 +1,30 @@ import axios from "axios"; +import * as crypto from "crypto"; import * as fs from "fs"; import * as matter from "gray-matter"; import * as path from "path"; import { exit } from "process"; +interface FileDetails { + filePath: string; + fields: { + [key: string]: any; + }; + oldFile: string | null; + isChanged: boolean; +} + +function getGrayMatter(content: string): { + data: { + [key: string]: any; + }; +} { + // @ts-ignore + return matter(content); +} + (async () => { - const getAllFiles = (searchPath: string) => { + function getAllFiles(searchPath: string) { const files = fs.readdirSync(searchPath); const results: string[] = []; @@ -20,17 +39,28 @@ import { exit } from "process"; } }); return results; - }; - const getHeaderFields = (filePath: string) => { + } + + function getHeaderFields(filePath: string): { + [key: string]: any; + } { const content = fs.readFileSync(filePath, "utf8"); - const { data } = matter(content); + const { data } = getGrayMatter(content); return data; - }; + } - const getHTTPContent = async (url: string) => { - const response = await axios.get(url); - return response.data; - }; + async function getHTTPContent(url: string): Promise { + try { + const response = await axios.get(url); + if (response.status !== 200) { + return null; + } + return response.data; + } catch (error) { + console.warn(error); + return null; + } + } const files = getAllFiles(".") .filter((x) => x.endsWith(".md")) @@ -42,32 +72,60 @@ import { exit } from "process"; other: ["title", "description", "createdAt", "updatedAt"], }; - const forBlog = async ( - file: string, - fields: { [key: string]: any }, + async function forBlog( + fileDetails: FileDetails, authors: [{ [key: string]: any }], categories: [{ [key: string]: any }] - ) => { + ) { + const file = fileDetails.filePath; + const oldFile = fileDetails.oldFile; + const fields = fileDetails.fields; + const isChanged = fileDetails.isChanged; + // 執筆者の確認 const author = fields["author"]; if (authors.findIndex((x) => x.slug === author) === -1) { - console.log(`${file}: 執筆者が正しくありません (${author})`); + console.warn(`${file}: 執筆者が正しくありません (${author})`); return false; } // カテゴリーの確認 const category = fields["category"]; if (categories.findIndex((x) => x.slug === category) === -1) { - console.log(`${file}: カテゴリが正しくありません (${category})`); + console.warn(`${file}: カテゴリが正しくありません (${category})`); return false; } + if (oldFile !== null && isChanged) { + const oldFields = getGrayMatter(oldFile).data; + if (oldFields["updatedAt"] == fields["updatedAt"]) { + console.warn( + `${file}: 更新日時が変更されていません (${fields["updatedAt"]})` + ); + return false; + } + } + return true; - }; + } + + async function forOther(fileDetails: FileDetails) { + const file = fileDetails.filePath; + const oldFile = fileDetails.oldFile; + const fields = fileDetails.fields; + const isChanged = fileDetails.isChanged; - const forOther = (file: string, fields: { [key: string]: any }) => { + if (oldFile !== null && isChanged) { + const oldFields = getGrayMatter(oldFile).data; + if (oldFields["updatedAt"].toString() == fields["updatedAt"].toString()) { + console.warn( + `${file}: 更新日時が変更されていません (${fields["updatedAt"]})` + ); + return false; + } + } return true; - }; + } const authors = await getHTTPContent( "https://raw.githubusercontent.com/jaoafa/jaoweb/master/content/blog/authors.json" @@ -84,16 +142,33 @@ import { exit } from "process"; const requiredFieldsForFile = requiredFields[fileType]; for (const field of requiredFieldsForFile) { if (!fields[field]) { - console.log(`${file}: 必要なフィールド ${field} がありません。`); + console.warn(`${file}: 必要なフィールド ${field} がありません。`); isValid = false; } } + const oldFile = await getHTTPContent( + `https://raw.githubusercontent.com/jaoafa/jaoweb-docs/main/${file.replace( + /\\/g, + "/" + )}` + ); + const content = fs.readFileSync(file, "utf8"); + + const fileDetails: FileDetails = { + filePath: file, + fields: fields, + oldFile: oldFile, + isChanged: + crypto.createHash("sha256").update(oldFile).digest("hex") != + crypto.createHash("sha256").update(content).digest("hex"), + }; + if (fileType == "blog") { - const vaild = forBlog(file, fields, authors, categories); + const vaild = await forBlog(fileDetails, authors, categories); if (!vaild) isValid = false; } else { - const vaild = forOther(file, fields); + const vaild = await forOther(fileDetails); if (!vaild) isValid = false; } } diff --git a/.github/workflows/markdown-header-check.yml b/.github/workflows/markdown-header-check.yml index c4b90df0..8299121d 100644 --- a/.github/workflows/markdown-header-check.yml +++ b/.github/workflows/markdown-header-check.yml @@ -43,7 +43,9 @@ jobs: - name: Run markdown-header run: | - node .github/markdown-header-check/markdown-header.js | tee markdown-header-output.txt - cat markdown-header-output.txt | reviewdog -efm="%f: %m" -name="markdown-header" -reporter=github-pr-review + node .github/markdown-header-check/markdown-header.js 2>&1 | tee markdown-header-output.txt + EXITCODE=$? + cat markdown-header-output.txt 1>&2 | reviewdog -efm="%f: %m" -name="markdown-header" -reporter=github-pr-review + if [ $EXITCODE -ne 0 ]; then exit 1; fi env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}