-
Notifications
You must be signed in to change notification settings - Fork 0
160 lines (128 loc) · 6.13 KB
/
build.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# This script creates a nice README.md with an index of all TIL files.
# TIL files are Markdown files named anything other than README.md.
#
# The readme is split into two sections: the "header" and the "index",
# separated by three hyphens on their own line.
# Anything above the three hyphens is the "header" and will be kept as is.
# Anything below will be replaced by the "index".
name: Build README
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v3
with:
fetch-depth: 0 # get full history or else it'll be overwritten
- name: Regenerate README
uses: actions/github-script@v6
with:
script: |
const { readFile, writeFile } = require("node:fs/promises");
console.log("Building index…");
// load readme
let readme = await readFile("README.md").then(file => file.toString());
// add header separator
const separator = "\n---\n";
const index = readme.indexOf(separator);
if (index === -1) readme += separator;
else readme = readme.substring(0, index + separator.length);
// collect entries
const files = await glob.create("./**/*.md").then(globber => globber.glob());
const entries = files
.filter(name => !name.endsWith("/README.md")) // exclude README.md
.sort()
.map(name => name.split("/").slice(-2));
// add summary
readme += `\n${entries.length} TILs so far:\n`;
// create category map
const categories = new Map();
for (const [category, file] of entries) {
const list = categories.get(category) || [];
categories.set(category, [...list, file]);
}
// create a section for each category
for (const [category, entries] of categories.entries()) {
// write category header
readme += `\n## ${category}\n\n`;
// write link for each file
for (const file of entries) {
const filepath = [category, file].join("/");
const contents = await readFile(filepath).then(file => file.toString());
const [, title] = contents.match(/^# (.+)$/m);
readme += `- [${title}](/${filepath})\n`;
}
}
// write readme
await writeFile("README.md", readme);
- name: Install NPM libraries
run: npm install marked he
- name: Generate RSS
uses: actions/github-script@v6
with:
script: |
const { readFile, writeFile, stat } = require("node:fs/promises");
const { promisify } = require("node:util");
const run = promisify(require("node:child_process").exec);
const marked = require("marked").marked;
const he = require("he");
console.log("Building feed…");
// collect entries
const files = await glob.create("./**/*.md").then(globber => globber.glob());
const modified = files
.filter(name => !name.includes("/node_modules/")) // exclude node_modules
.filter(name => !name.endsWith("/README.md")) // exclude README.md
.map(name => name.split("/").slice(-2).join("/"))
.map(async file => [file, await run("git log --follow --format=%ad --date=unix " + file)]);
const entries = await Promise.all(modified);
const sorted = entries
.map(([name, created]) => [name, created.stdout.trim().split("\n").at(-1)])
.sort(([, a], [, b]) => b.localeCompare(a))
.slice(0, 10)
.map(async ([name, date]) => ({
name,
date: new Date(Number(date) * 1000),
content: await readFile(name).then(buf => buf.toString())
}));
const feed = await Promise.all(sorted);
const user = context.repo.owner;
const repo = context.repo.repo;
const branch = context.payload.repository.default_branch;
const link = `https://github.com/${user}/${repo}`;
const rss = [];
rss.push(`<?xml version="1.0" encoding="UTF-8"?>`);
rss.push(`<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">`);
rss.push(`<channel>`);
rss.push(`<title>${user} TIL</title>`);
rss.push(`<description>A collection of useful things I've learned.</description>`);
rss.push(`<link>${link}</link>`);
const dateOptions = { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: "short" };
for (const item of feed) {
rss.push(`<item>`);
const itemLink = `${link}/blob/${branch}/${item.name}`;
rss.push(`<guid>${itemLink}</guid>`);
rss.push(`<link>${itemLink}</link>`);
const category = item.name.split("/")[0];
const [, title] = item.content.match(/^# (.+)$/m);
rss.push(`<title>TIL (${category}): ${he.escape(title)}</title>`);
const pubDate = new Intl.DateTimeFormat("en-US", dateOptions).format(item.date);
rss.push(`<pubDate>${item.date.toUTCString()}</pubDate>`);
const content = item.content.split("\n").slice(1).join("\n").trim();
const encoded = he.escape(marked(content));
rss.push(`<content:encoded>${encoded}</content:encoded>`);
rss.push(`</item>`);
}
rss.push(`</channel>`);
rss.push(`</rss>`);
// write feed
await writeFile("rss.xml", rss.join("\n"));
- name: Commit and push if README or RSS changed
run: |-
git config --global user.email "[email protected]"
git config --global user.name "tilbot"
git diff --quiet || git commit --all --message "Update README.md or rss.xml"
git push