
使用github action定时同步obsidian内容到astro博客仓库
/ 4 min read
Updated: View more blogs with the tag github action , View more blogs with the tag build docs , View more blogs with the tag obsidian模板
摘要(由llm生成)
这个 GitHub Action 通过 Node.js 脚本在每次推送到 content 目录和 build_docs.cjs 脚本时更新博客内容,并将其复制到另一个目标仓库。它支持多个环境,包括本地和服务器。该过程依赖于 Obsidian 模板和 Gray Matter 脚本。 此 Action 通过在每次推送中运行其特定步骤来保持 blog 内容的最新。这些步骤包括: - 运行 npm install 和 npm run build:docs:server 批量安装并构建博客内容。 - 复制更新的 content 到目标仓库。 - 运行 npm install 和 npm run sort 批量安装和排序博客内容。 该 Action 通过使用 Gray Matter 脚本来处理 Markdown文件,并根据其 frontMatter 信息决定是否需要将其复制到目标仓库中。它还支持从特定目录忽略某些文件或文件夹。 该 Action 的主要功能是自动化 blog 内容的更新和复制,确保 content ALWAYS 是最新的。
github action
目标仓库以及具体目录可以根据自己的项目来定
name: Update Docs
on: push: paths: - "content/**" - "scripts/build_docs.cjs" workflow_dispatch:
jobs: build-and-deploy: runs-on: ubuntu-latest
steps: - name: Checkout source repository uses: actions/checkout@v2 with: token: ${{ secrets.PAT_TOKEN }}
- name: Set up Node.js uses: actions/setup-node@v2 with: node-version: "20"
- name: Install dependencies run: | echo "Installing dependencies in source repository..." npm install echo "Dependencies installed successfully"
- name: Build docs run: | echo "Starting docs build..." npm run build:docs:server echo "Docs built successfully"
- name: Checkout target repository uses: actions/checkout@v2 with: repository: kazoottt/kazoottt-blog path: kazoottt-blog token: ${{ secrets.PAT_TOKEN }}
- name: Copy built docs to target repository run: | echo "Starting copy process..." echo "Content of astroContent before copy:" cp -rv astroContent/* kazoottt-blog/src/content/post/ echo "Content of astroContent copy done"
- name: Setup target repository run: | cd kazoottt-blog echo "Configuring git..." git config --global user.name 'github-actions[bot]' git config --global user.email 'github-actions[bot]@users.noreply.github.com' echo "Installing dependencies in target repository..." npm install echo "Running sort..." npm run sort
- name: Check for changes and commit run: | cd kazoottt-blog if [[ -n $(git status -s) ]]; then git add . git commit -m "Update docs and sort content" git push else echo "No changes to commit" fi env: GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}
PAT_TOKEN 申请
Sign in to GitHub · GitHub
需要权限:repo, workflow

obsidian 模板
published 是 true 且 notAstro 不为 true 的时候,会被发布到另外一个仓库
---title: {{title}}date: {{date}}author: KazooTTTtype: Poststatus: Publishedtags: []finished: falsepublished: falsecategory:slug:description:notAstro:---
脚本 scripts/build_docs.cjs
依赖安装
npm install gray-matter
可以配置一些不想同步的文件夹
const fs = require("fs").promisesconst fsSync = require("fs")const path = require("path")const matter = require("gray-matter")const { execSync } = require("child_process")
const CONFIG = { outputDir: "astroContent", inputDir: "./content", ignoreList: [ ".github", ".obsidian", "草稿箱", "模板", "attachment", "记录", "导航用", "微信读书", ], validExtensions: [".md"], // Local specific config localDestinationRoot: "", // to edit localDestination: "", // to edit}
/** * Ensures output directory exists */function initializeOutputDir() { if (!fsSync.existsSync(CONFIG.outputDir)) { fsSync.mkdirSync(CONFIG.outputDir, { recursive: true }) }}
/** * Validates if a file should be processed based on its metadata */function shouldProcessFile(frontMatter) { return frontMatter.published === true && !frontMatter.notAstro}
/** * Processes a single markdown file */async function processMarkdownFile(fullPath, outputPath) { try { const fileContent = await fs.readFile(fullPath, "utf8") const { data } = matter(fileContent)
if (shouldProcessFile(data)) { await fs.copyFile(fullPath, outputPath) console.log(`✓ Copied: ${path.relative(CONFIG.inputDir, fullPath)}`) } } catch (error) { console.error(`Error processing file ${fullPath}:`, error.message) }}
/** * Recursively processes directories and files */async function processDirectory(dir) { try { const files = await fs.readdir(dir)
await Promise.all( files.map(async (file) => { const fullPath = path.join(dir, file) const relativePath = path.relative(CONFIG.inputDir, fullPath) const outputPath = path.join(CONFIG.outputDir, relativePath)
const stats = await fs.stat(fullPath)
if (stats.isDirectory()) { if (CONFIG.ignoreList.includes(file)) return await fs.mkdir(outputPath, { recursive: true }) await processDirectory(fullPath) } else if (path.extname(file) === ".md" && file !== "index.md") { await processMarkdownFile(fullPath, outputPath) } }), ) } catch (error) { console.error(`Error processing directory ${dir}:`, error.message) }}
/** * Copies processed files to final destination and commits changes */async function copyToLocalDestination() { try { // Remove existing content if (fsSync.existsSync(CONFIG.localDestination)) { await fs.rm(CONFIG.localDestination, { recursive: true }) }
// Create destination directory await fs.mkdir(CONFIG.localDestination, { recursive: true })
// Copy files const files = await fs.readdir(CONFIG.outputDir) await Promise.all( files.map(async (file) => { const sourcePath = path.join(CONFIG.outputDir, file) const destPath = path.join(CONFIG.localDestination, file) await fs.rename(sourcePath, destPath) }), )
console.log("Content has been successfully copied to the local destination.")
// Commit changes execSync(`cd ${path.dirname(CONFIG.localDestination)} && npm run sort`) execSync(`git add ${CONFIG.localDestination} && git commit -m "update content"`) // push changes // execSync(`git push`) } catch (error) { console.error("Error copying to destination:", error.message) }}
/** * Cleans up the temporary output directory */async function cleanupOutputDir() { try { if (fsSync.existsSync(CONFIG.outputDir)) { await fs.rm(CONFIG.outputDir, { recursive: true }) } console.log("Cleaned up temporary directory.") } catch (error) { console.error("Error cleaning up:", error.message) }}
/** * Main execution */async function main() { try { const isLocalBuild = process.argv.includes("--local") console.log(`Starting document processing... (${isLocalBuild ? "local" : "server"} build)`)
initializeOutputDir() await processDirectory(CONFIG.inputDir)
if (isLocalBuild) { await copyToLocalDestination() await cleanupOutputDir() }
console.log("Document processing completed successfully!") } catch (error) { console.error("Fatal error:", error.message) }}
main()
感谢阅读到这里,期待收到更多的反馈
欢迎关注公众号
kazoottt
