21 |
22 |
{issue.title}
23 |
24 |
25 |
26 |
27 | {issue.title}
28 |
29 |
37 |
38 |
39 | {issueComments.map((issueComment) => (
40 |
41 |
42 |
43 | ))}
44 |
45 | );
46 | };
47 |
48 | export default ShowArticle;
49 |
50 | export async function getStaticPaths() {
51 | const issues = await listIssues();
52 | const paths = issues.map((issue: any) => {
53 | return {
54 | params: {
55 | issueNumber: issue.number.toString(),
56 | },
57 | };
58 | });
59 | return {
60 | paths,
61 | fallback: false,
62 | };
63 | }
64 |
65 | export async function getStaticProps({ params }: any) {
66 | const issueNumber = parseInt(params.issueNumber, 10);
67 | const issue = await getIssue({ issueNumber });
68 | const issueComments = await listIssueComments({ issueNumber });
69 | return {
70 | props: {
71 | issue,
72 | issueComments,
73 | },
74 | };
75 | }
76 |
--------------------------------------------------------------------------------
/scripts/migrate_data_from_gialog_v0_to_v1.rb:
--------------------------------------------------------------------------------
1 | # This is a migration script from gialog v0 (JSON data version) from v1 (Markdown data version).
2 | #
3 | # Run this script like this:
4 | #
5 | # ```
6 | # git pull
7 | # git checkout -t origin/data
8 | # ruby /path/to/migrate_data_from_gialog_v0_to_v1.rb
9 | # git add issues
10 | # git commit -m "Migrate data from v0 format to v1 format"
11 | # git push
12 | #````
13 | #
14 | # Then switch gialog-sync@v0 to gialog-sync@v1 by modifying .github/workflows/sync.yml as follows:
15 | #
16 | # ```
17 | # diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
18 | # index 07c99a2..7339de2 100644
19 | # --- a/.github/workflows/sync.yml
20 | # +++ b/.github/workflows/sync.yml
21 | # @@ -31,7 +31,7 @@ jobs:
22 | # path: data
23 | # ref: data
24 | # continue-on-error: true
25 | # - - uses: r7kamura/gialog-sync@v0
26 | # + - uses: r7kamura/gialog-sync@v1
27 | # env:
28 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29 | # - uses: peaceiris/actions-gh-pages@v3
30 | # ```
31 |
32 | require 'json'
33 | require 'pathname'
34 | require 'yaml'
35 |
36 | data_path = '.'
37 |
38 | issues_data_path = "#{data_path}/issues.json"
39 | issues_data_pathname = Pathname.new(issues_data_path)
40 | issues_data_content = issues_data_pathname.read
41 | issues_data = JSON.parse(issues_data_content)
42 |
43 | issues_data['issues'].each do |issue_number, issue|
44 | issue.delete('bodyHTML')
45 | body = issue.delete('body')
46 | issue_file_content = [
47 | issue.to_yaml,
48 | body
49 | ].join("\n---\n")
50 | issue_file_path = "#{data_path}/issues/#{issue_number}/issue.md"
51 | issue_file_pathname = Pathname.new(issue_file_path)
52 | issue_file_pathname.parent.mkpath
53 | issue_file_pathname.write(issue_file_content)
54 | end
55 |
56 | issue_comments_data_path = "#{data_path}/issue_comments.json"
57 | issue_comments_data_pathname = Pathname.new(issue_comments_data_path)
58 | issue_comments_data_content = issue_comments_data_pathname.read
59 | issue_comments_data = JSON.parse(issue_comments_data_content)
60 |
61 | issue_comments_data['issue_comments'].each do |issue_number, hash|
62 | hash.each do |issue_comment_id, issue_comment|
63 | issue_comment.delete('bodyHTML')
64 | body = issue_comment.delete('body')
65 | issue_comment_file_content = [
66 | issue_comment.to_yaml,
67 | body
68 | ].join("\n---\n")
69 | issue_comment_file_path = "#{data_path}/issues/#{issue_number}/issue_comments/#{issue_comment_id}.md"
70 | issue_comment_file_pathname = Pathname.new(issue_comment_file_path)
71 | issue_comment_file_pathname.parent.mkpath
72 | issue_comment_file_pathname.write(issue_comment_file_content)
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/lib/issue.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import glob from "glob-promise";
3 | import matter from "gray-matter";
4 | import { remark } from "remark";
5 | import remarkGfm from "remark-gfm";
6 | import remarkGithub from "remark-github";
7 | import remarkParse from "remark-parse";
8 | import remarkRehype from "remark-rehype";
9 | import rehypeStringify from "rehype-stringify";
10 |
11 | export type Issue = any;
12 |
13 | export type IssueComment = any;
14 |
15 | const dataDirectoryPath = process.env.DATA_DIRECTORY_PATH || "./data";
16 |
17 | export async function getIssue({ issueNumber }: { issueNumber: number }) {
18 | const filePath = `${dataDirectoryPath}/issues/${issueNumber}/issue.md`;
19 | const content = fs.readFileSync(filePath, { encoding: "utf-8" });
20 | const issueMatter = matter(content);
21 | const body = issueMatter.content;
22 | const bodyHTML = await renderMarkdown(body);
23 | return {
24 | body,
25 | bodyHTML,
26 | ...issueMatter.data,
27 | };
28 | }
29 |
30 | export async function listIssues() {
31 | const paths = await glob.promise(`${dataDirectoryPath}/issues/*/issue.md`);
32 | return paths
33 | .map((filePath) => {
34 | const content = fs.readFileSync(filePath, { encoding: "utf-8" });
35 | const issueMatter = matter(content);
36 | const body = issueMatter.content;
37 | return {
38 | body,
39 | ...issueMatter.data,
40 | };
41 | })
42 | .sort(byCreatedAt)
43 | .reverse();
44 | }
45 |
46 | export async function listIssueComments({
47 | issueNumber,
48 | }: {
49 | issueNumber: number;
50 | }) {
51 | const paths = await glob.promise(
52 | `${dataDirectoryPath}/issues/${issueNumber}/issue_comments/*.md`
53 | );
54 | const issueComments = await Promise.all(
55 | paths.map(async (filePath: string) => {
56 | const content = fs.readFileSync(filePath, { encoding: "utf-8" });
57 | const issueMatter = matter(content);
58 | const body = issueMatter.content;
59 | const bodyHTML = await renderMarkdown(body);
60 | return {
61 | body,
62 | bodyHTML,
63 | ...issueMatter.data,
64 | };
65 | })
66 | );
67 | return issueComments.sort(byCreatedAt);
68 | }
69 |
70 | function byCreatedAt(a: any, b: any) {
71 | if (a.created_at < b.created_at) {
72 | return -1;
73 | } else if (a.created_at > b.created_at) {
74 | return 1;
75 | } else {
76 | return 0;
77 | }
78 | }
79 |
80 | async function renderMarkdown(content: string) {
81 | const result = await remark()
82 | .use(remarkParse)
83 | .use(remarkGfm)
84 | .use(remarkGithub, {
85 | repository: process.env.GITHUB_REPOSITORY || "github/dummy",
86 | })
87 | .use(remarkRehype)
88 | .use(rehypeStringify)
89 | .use(remarkGfm)
90 | .process(content);
91 | return result.toString();
92 | }
93 |
--------------------------------------------------------------------------------