前一阵子一直在捣鼓 VitePress,想着之前看到有人用 Github Issues 来做静态页面的评论系统,于是就去了解了一下,目前这类项目有 gitalk、gitment 以及 vssue。在这个过程中发现很早之前就有人开始用 Github Issues 来写博客。本人比较懒,我想着能不能把它和 VitePress 结合起来再通过 GitHub Pages 实现嫖上加嫖,后经过搜索也确实有人这么干。
仓库设置
首先,新建一个仓库,由于是用到 GitHub Pages,就将仓库名设置为 <yourname>.github.io,当然也可以随便命名,只是后面在
vitepress 部署 的时候会有所不同。
设置密钥
首先申请 Personal access token ,
左上角头像 ->Settings-> 下拉找到 Developer settings->Personal access tokens->Generate new token 我这里申请的都是带有
classic 标识的 token,权限建议全选,时间设置无限制。点击 Generate token 之后页面中会出现一个 ghp_开头的字符串,复制保存好。
然后将 token 写入仓库密钥中,就在我们刚刚创建的仓库主页
左边 Settings->Secrets and variables->Actions->New repository secret 这里 name 自己设置,value 填写刚刚复制的字符串之后点击
Add secrets 就可以了。
设置变量
这边设置的变量主要是方便工作流中的判断,在刚刚创建仓库密钥的页面有个 variables 选项卡点击 New repository variable,name
自定义,value 就写你 github 的用户名,比如我的就是 ttdly,填好后点击 Add variable 就行。
Pages
由于后面会用到 GitHub Actions 进行 Pages 的发布,所以在仓库 Settings->Pages->Build and deployment->source 选择 Github
Actions。
新建分支
创建一个分支,存储 md 文件,我这里就以 md 命名了,然后删除 main 分支中的文件,也就是说这个分支里什么文件都不要留,当然.git
文件夹不要删。清空之后,新建 posts 文件夹里面新建一个 placeholder 文件,什么都不要写。(主要是懒得做文件夹是否存在这个判断)最后将分支同步到
github 仓库里。
处理 Issues
把仓库设置好后,就可以开始编写 工作流程 以及代码来把你写好的 Issue 写入到 md 文档中然后上传回仓库了。
初始化
在 main 分支中,新建 .github/workflows/copyissue.yml
name: cpoyIssues
# 在新建、更新、重新开启、关闭 issues 的时候触发工作流程
on:
issues:
types:
- "opened"
- "edited"
- "reopened"
- "closed"
# 给予所有写权限,这个在后面上传文件的时候会用到。
permissions: write-all
过滤 issues
由于 Issues 谁都能来写,这又是个人博客,所以第一步就需要把不是自己开的 Issues 给过滤掉。而 Github REST API 提供了许多的接口,其中就有对 Issues 操作的接口,这里会用到 issues update 和 issues lock。因为 GitHub Action 能够直接执行命令,所以过滤 issues 直接用 curl 调用接口:
# .github/workflows/copyissue.yml
jobs:
lockissue:
runs-on: ubuntu-latest
# vars.OWNER 中的 OWNER 是前面设置变量一节中设置的变量名
if: ${{ github.event.action == 'opened' && github.actor != vars.OWNER }}
steps:
- name: Close and Lock Issues
run: |
curl -L \
-X PATCH \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{secrets.TOKEN}}"\
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${{github.repository}}/issues/${{github.event.issue.number}} \
-d '{"state":"close","state_reason":"not_planned"}'
curl -L \
-X PUT \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{secrets.TOKEN}}"\
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${{github.repository}}/issues/${{github.event.issue.number}}/lock \
-d '{"lock_reason":"off-topic"}'
编写转换脚本
这一步的转换脚本用啥语言写都行,只要能正常请求网络接口,我这里用 js 演示。
首先切换到 md 分支,安装 vitepress,在 package.json 中的
scripts 加上一行 "write": "node ./<name>.js",在 ** 根目录 ** 新建 js 文件,名字随意,但是 wirte 好像不行。
// <name>.js
const fs = require('fs');
// 获取命令行传递的参数
const repo = process.argv [2],
number = process.argv [3],
token = process.argv [4];
const wirteD = function (response) {
// 把 labels 转成我想要的形式,不需要可以不写
let tags = 'tags: ["';
let labels = response.labels;
let text;
if (labels.length !== 0) {
labels = labels.map(ele => ele.name);
tags += labels.join('","');
tags += '"]\n';
} else {
tags = '';
}
// 拼接 frontmatter
text = `---\ntitle: ${response.title}\ndate: ${response.created_at}\n${tags}---\n${response.body}`
fs.writeFile(`./posts/${response.number}.md`, text, (err) => {
if (err) {
console.log("posts:", err);
return
}
console.log("写入 posts 成功")
});
fs.writeFile(`./index.md`, text, (err) => {
if (err) {
console.log("index:", err);
return
}
console.log("写入 index 成功")
});
}
// 获取 issue 信息
const url = `https://api.github.com/repos/${repo}/issues/${number}`;
const headers = new Headers({
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'Authorization': "Bearer" + token
});
fetch(url, {method: 'GET', headers}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => {
// 这里就是调用写入的函数了,你可以打印获取到的信息,决定怎么写这个文件
wirteD(response);
});
自动上传并且发布
这一步就要用到一些别人写好的 actions 了
# .github/workflows/copyissue.yml
# 这是 jobs 中的一个 job,注意缩进
issue2page:
runs-on: ubuntu-latest
if: ${{ github.actor == vars.OWNER && github.event.action != 'closed' }}
steps:
# ref:<name > 填写你存放 md 文件的分支
- name: Checkout md
uses: actions/checkout@v3
with:
ref: md
fetch-depth: 0
# 用的是 pnpm,这里安装 pnpm 但不安装依赖
- uses: pnpm/action-setup@v2
name: Install pnpm
id: pnpm-install
with:
version: 7.27.0
run_install: false
# 获取 pnpm cache 存储路径
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
# 查找是否存在 cache,并且把 cache 还原,这个主要是加快依赖安装
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles ('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
# 安装依赖
- name: Install dependencies
run: pnpm install
# 执行写入脚本
- name: Run Issue to Md Script
run: pnpm run write ${{github.repository}} ${{github.event.issue.number}} ${{secrets.GITHUB_TOKEN}}
# 存储修改
- name: Commit files
run: |
git config --local user.email "github-actions [bot]@users.noreply.github.com"
git config --local user.name "github-actions [bot]"
git add .
git commit -m "auto copy /posts/${{github.event.issue.number}}.md"
# branch 是要上传 md 文件的分支
- name: Push changes
uses: ad-m/github-push-action@master
with:
branch: md
github_token: ${{secrets.GITHUB_TOKEN}}
- name: Build
run: pnpm run build
# 发布 GitHub Pages,VitePress 官方提供的方案
- uses: actions/configure-pages@v2
- uses: actions/upload-pages-artifact@v1
with:
path: ./.vitepress/dist
- name: Deploy
id: deployment
uses: actions/deploy-pages@v1
完成
到这里不出意外,不管是新建 issue 还是修改 issue 都会自动更新文件,上传分支。想要在关闭 issues 的时候删除文件,可以自己尝试一下,我现在还没写,然后 pages 页面也会更新。