静态自述文件重新生成
git-auto-commit 操作
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
原文链接:https://aralroca.com/blog/static-readme-regeneration
GitHub 最近推出了一项“隐藏”功能,可以在个人资料页面上显示 Markdown 模板。你可能已经听说过这项功能了。你只需要创建一个以你的用户名命名的仓库,并README.md在其中创建该文件即可。
提到 GitHub 上的 Markdown 模板,我们通常会想到静态内容。然而,在本文中,我想更进一步。我将告诉你如何添加会不时更新的内容;无论是你最新的推文、最新的 YouTube 视频还是最新的博客文章。
我的 GitHub README 个人资料位于aralroca仓库下
我们将涵盖以下内容:
关于静态自述文件再生(SRR)
所谓“静态 README 重生成”,是指 README 文件README.md由我们的脚本生成,然后我们通过一个机器人(由我们编程)定期更新其内容README.md。这种方式的妙处在于,机器人只有在 README 文件README.md真正发生更改时才会提交到代码仓库。这样一来,README 的内容就不能完全静态,它可以每天、每小时甚至每分钟都发生变化。
为了实现这一点,我们将使用带有 cron 任务的 GitHub Action:
关于使用 GitHub Actions 进行静态重生成的示意图
执行
我以我的个人资料为例。它始终显示我博客的最新五篇文章,并且每天都会更新(如有必要)。这样我就能安心了,因为我知道当我上传新文章时,README.md我的个人资料会自动更新。
README.tpl
我们来创建一个README.md.tpl文件,这种.tpl格式用于模板文件。这个文件将包含所有静态内容README.md。我们将在这里编写 Markdown 代码,就像我们在README.md文件中编写代码一样。
主要区别在于,我们会使用一些插值符号来添加需要动态变化的内容。这样,我们的脚本就能用动态内容替换它们。
用于生成 README.md 文件的脚本
脚本必须:
- 读取文件
README.tpl.md。 - 从https://aralroca.com/rss.xml获取所有帖子。
- 排序方式
pub_date+ 筛选条件 5. - 将
README.md文件中的插值替换README.tpl.md为 5 篇文章,格式为 Markdown 字符串。
这可以用任何语言实现;JavaScript、Rust、Python、Go、C……在这种情况下,我选择了Rust,主要是因为我没有使用经验,所以我借此机会学习了一点(如果您是 Rust 专家,并且看到了可以改进的地方,请随时在仓库中创建一个问题)。
> main.rs
mod create_readme;
use create_readme::create_readme;
fn main() {
match create_readme() {
Ok(_v) => println!("README.md file generated correctly"),
Err(e) => println!("Opps! there was an error: {:?}", e),
}
}
> 创建自述文件
extern crate chrono;
extern crate rss;
use chrono::DateTime;
use rss::Channel;
use std::cmp::Ordering;
use std::fs;
struct FeedItem {
title: String,
link: String,
pub_date: String,
}
pub fn create_readme() -> std::io::Result<()> {
let tpl =
fs::read_to_string("README.md.tpl")
.expect("Something went wrong reading the README.tpl file");
let last_articles = get_latest_articles();
return fs::write(
"README.md",
tpl.replace("%{{latest_articles}}%", &last_articles),
);
}
fn get_latest_articles() -> String {
let mut posts: Vec<FeedItem> = get_blog_rss();
// Sort articles by pub_date
posts.sort_by(|a, b| {
let date_a = DateTime::parse_from_rfc2822(&a.pub_date).unwrap();
let date_b = DateTime::parse_from_rfc2822(&b.pub_date).unwrap();
if date_b < date_a {
Ordering::Less
} else if date_b > date_a {
Ordering::Greater
} else {
Ordering::Equal
}
});
// Filter las 5 articles + format each one as markdown list string
return posts[..5].iter().fold("".to_string(), |acc, item| {
format!("{} \n* [{}]({})", acc, item.title, item.link)
});
}
// Fetch all articles of my blog on rss.xml
fn get_blog_rss() -> Vec<FeedItem> {
let items = Channel::from_url("https://aralroca.com/rss.xml")
.unwrap()
.items()
.iter()
.map(|item| FeedItem {
title: item.title().unwrap().to_string(),
link: item.link().unwrap().to_string(),
pub_date: item.pub_date().unwrap().to_string(),
})
.collect();
items
}
GitHub Action 配合 cron 任务
一旦我们有了构建脚本README.md,我们只需要使用 GitHub Action 生成 cron 任务即可。
要创建 Action,我建议先将脚本上传到 master 分支,然后点击 GitHub 的“Actions”选项卡进行创建。这样,GitHub 就能检测到脚本语言(本例中为 Rust)并创建一个默认的 YAML 文件。
我们将替换默认 YAML 文件中的一些内容,以便:
- 安排一个定时任务
- 运行脚本(
cargo run而不是cargo build && cargo test) - 提交重新生成的 README 文件(仅当其有更改时)
> .github/workflows/rust.yml
name: Rust
on:
# Schedule a cron
schedule:
- cron: "0 0 */1 * *" # each day at 00:00 UTC
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
# Replace "cargo build" to "cargo run" to run the script
run: cargo run
# Commit the regenerated README only when it change
# (git diff --quiet && git diff --staged --quiet )
- run: |
git config user.name aralroca
git config user.email aral-rg@hotmail.com
git add README.md
git diff --quiet && git diff --staged --quiet || git commit -m "[gh-action] Update README"
git push origin master
结论
总之,虽然大多数仓库中的 README 文件始终是静态的,但得益于 GitHub Actions 和 GitHub 的这项新功能,我们可以构建自己的README.md仓库,使其始终包含最新的更新(发布、PR、推文、帖子……)。
参考
- https://www.aboutmonica.com/blog/how-to-create-a-github-profile-readme
- https://github.com/midudev/midudev




