开始使用 note 做笔记后,大事小事都记录在笔记里,已经不怎么屁大点事都会发博客了。
痛点在于,需要手动同步文章和关联的图片到博客项目,push 到 github 后,触发自动部署更新静态页面。
想做一个类似点击公开,自动分享到博客项目的持续继承功能。
设想如下:
- 本身 markdown 有 attribute 数据。
- 增加 article: true 表示是需要发表到博客的项目。
- 每 次提交的时候,通过 github 提供的免费的 CI 功能 actions,扫描带有 article: true 的 markdown 文件,发送到博客项目单独分支。
- 博客项目生成一个 pr , 方便检查文章格式等,通过人工审核后,同意合并至 master 分支,更新静态页面。
下面讲讲各个步骤细节,方便大佬们抄作业。
博客项目 同步相关
博客相关 actions 配置
- 需要获取一个提交用的 github token , 我这里设置的名称为 blog_sync
name: sync-note
on:
push:
branches:
- develop # Change this to your default branch
paths:
- "note/docs/articles/*.md"
jobs:
make-html-send-email:
name: make-time-file
runs-on: ubuntu-latest
steps:
- name: get blog repository
uses: actions/checkout@master
- run: |
cd ..
git config --global user.email "z740713651@outlook.com"
git config --global user.name "AngusWG"
git config --global credential.helper cache
git clone https://${{secrets.blog_sync}}@github.com/AngusWG/AngusWG
cd AngusWG
git checkout dev_auto 2>/dev/null || git checkout -b dev_auto
- name: cd into note repo
run: cd ../WG & pwd
- name: install python script requirement
run: pip install .
- name: run the script sync note to blog repo
run: python wg sync_note note /home/runner/work/WG/AngusWG/docs
- name: commit note
run: |
cd /home/runner/work/WG/AngusWG
git add .
git commit -m "sync note $(date +"%Y-%m-%d %H:%M:%S")" || true
git push origin dev_auto
同步博客的 python 脚本
- 直接用的话 需要做入参适当修改。
- 设置 article: true 的文章会自动发表到博客。
- 当 date 不一样时,会自动同步笔记的内容到博客。
需要笔记文件夹和博客有以下目录结构
- sorce_note_dir: 笔记文件夹
- articles: 可以发布的文章文件夹
- a.md (article: true)
- b.md (article: true)
- c.md (article: false)
- images: 笔记图片文件夹
- a1.png
- a2.png
- c1.png
- articles: 可以发布的文章文件夹
- target_note_dir: 笔记文件夹
- articles: 已经发布的博客文件夹
- a.md (article: true)
- b.md (article: true)
- images: 博客图片文件夹
- a1.png
- a2.png
- articles: 已经发布的博客文件夹
#!/usr/bin/env python
# encoding: utf-8
# @Time : 2022/04/18 18:22:22
# @author : zza
# @Email : z740713651@outlook.com
# @File : sync_markdown_note.py
"""同步笔记用"""
import os
import frontmatter
import re
import shutil
default_dir = "articles"
article_attribute = "article"
def _need_sync(file_path: str, output_dir: str) -> bool:
"""
判断是否要同步笔记
1 笔记里存在 属性 publish:true
2 笔记日期 > 已发布笔记日期
"""
post = frontmatter.load(file_path)
# publish
if not post.get(article_attribute):
return False
# update date
old_file = os.path.join(output_dir, default_dir, os.path.basename(file_path))
if os.path.exists(old_file):
current_date = post.get("date")
old_date = frontmatter.load(old_file).get("date")
if current_date == old_date:
return False
return True
def sync_pic(file_path: str, output_dir: str) -> None:
"""copy pic to output dir"""
# find pic in markdown file
with open(file_path, "r", encoding="utf-8") as f:
markdown_body = f.read()
pic_str_list = re.findall(r"\!\[.*\]\((.*)\)", markdown_body)
for pic_str in pic_str_list:
print(f" find pic {pic_str}")
pic_file = os.path.join(os.path.dirname(file_path), pic_str)
if not os.path.exists(pic_file):
continue
# copy pic
output_pic_file = os.path.join(output_dir, "images", os.path.basename(pic_file))
print(f" copy {os.path.abspath(pic_file)} to {output_pic_file}")
shutil.copyfile(pic_file, output_pic_file)
return
def handler_file(root: str, file: str, output_dir: str) -> None:
"""处理单个 markdown 文件"""
file_path = os.path.join(root, file)
if not _need_sync(file_path, output_dir):
return
# copy file
output_file_path = os.path.join(output_dir, default_dir, file)
print(f"copy {file_path} to {output_file_path}")
shutil.copyfile(file_path, output_file_path)
# copy pic
sync_pic(file_path, output_dir)
def main(
markdown_path: str = r"E:\PycharmProjects\WG\note",
output_dir: str = r"E:\PycharmProjects\AngusWG\docs",
) -> None:
"""
遍历 note 文件夹 articles 文件夹下所有的 md 文件
并同步到另一边文件夹下的 articles 文件夹下
- sorce_note_dir: 笔记文件夹
- articles: 可以发布的文章文件夹
- a.md (article: true)
- b.md (article: true)
- c.md (article: false)
- images: 笔记图片文件夹
- a1.png
- a2.png
- c1.png
- target_note_dir: 笔记文件夹
- articles: 已经发布的博客文件夹
- a.md (article: true)
- b.md (article: true)
- images: 博客图片文件夹
- a1.png
- a2.png
"""
# walk directory
root = os.path.join(markdown_path, default_dir)
for file in os.listdir(root):
if file.endswith(".md"):
handler_file(root, file, output_dir)
if __name__ == "__main__":
main()
# handler_file(
# r"E:\PycharmProjects\WG\note\docs\创作",
# "笔记自动发布。md",
# r"E:\PycharmProjects\AngusWG\docs",
# )
博客项目生成 pr
name: SYNC NOTE
on:
push:
branches:
- dev_auto
jobs:
SYNC_NOTE:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: master
- run: ls
- name: Reset main branch
run: |
git fetch origin dev_auto:dev_auto
git reset --hard dev_auto
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
id: cpr
with:
commit-message: publish note to blog
title: sync note pull request
body: $(date +"%Y-%m-%dT%H:%M:%S%z")
branch: dev_auto
base: master
小坑:
报错 Branch 'X' no longer differs from base branch 'Y'
actions 好像将本地的分支提交一次,最开始的时候写错了, 导致反向 master 覆盖了 dev_auto 分支, 然后因为没有 git fetch ,认为无修改不生成 pr。 看 action 日志+看 issus 解决的。 action 的运行方式有点想当然了。
总结
最开始想用 tag: publish 去识别是否要发布,但是刷 attribute 的脚本不支持增加,支持覆盖, 想了想还是新弄个属性,反正人也看不到。
目前还有一个问题是,这个 action 是每次提交就会检测一遍,然后装 python 依赖的时候,其实挺慢的, 找了一下,并没有限制最小部署间隔的参数(有知道的小伙伴请告诉我)想想机器又不累,不要在乎这么多。