기술 포스트

GitHub Actions로 블로그 운영을 자동화했다


Article

이 블로그의 구조는 좀 특이하다. 글은 별도의 GitHub 저장소에 마크다운으로 쌓이고, 블로그 본체가 그걸 API로 가져와 렌더링한다. ISR 주기는 1시간. 그러니까 글을 push하고 나면 최대 1시간을 기다려야 사이트에 반영됐다. 오타 하나 고치고 한 시간 기다리는 건 꽤 사람을 초조하게 만든다.

push하면 배포되게

해결책은 단순하다. 콘텐츠 저장소에 push가 일어나면 GitHub Actions가 Vercel의 Deploy Hook을 때리게 했다. 마크다운 파일이 바뀔 때만 동작하도록 paths 필터를 걸었다.

name: Deploy on content push

on:
  push:
    branches: [main]
    paths: ["**/*.md"]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Vercel deploy hook
        run: curl -sf -X POST "${{ secrets.VERCEL_DEPLOY_HOOK }}"

이게 전부다. 워크플로 파일 15줄로 "글 쓰고 push하면 몇 분 안에 반영"이 됐다. ISR은 그대로 두고, 훅은 그 위에 얹는 부스터 역할만 한다.

형식 검증도 CI에 맡긴다

두 번째 문제는 frontmatter였다. createdAt 날짜 형식을 틀리거나 category에 오타를 내면 빌드는 통과하는데 글이 목록에서 조용히 사라진다. 이런 건 사람이 눈으로 잡는 게 아니라 기계가 잡아야 한다.

name: Validate content

on:
  pull_request:
    paths: ["**/*.md"]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: node scripts/validate-frontmatter.mjs

검증 스크립트는 별거 없다. 필수 필드 존재 여부, 날짜 형식(YYYY-MM-DD), category가 허용된 값인지 정도를 확인하고 틀리면 exit 1로 죽는다.

const REQUIRED = ["title", "description", "createdAt", "category"];
const CATEGORIES = ["tech", "philosophy"];

if (!CATEGORIES.includes(data.category)) {
  console.error(`${file}: invalid category "${data.category}"`);
  process.exitCode = 1;
}

혼자 운영해도 시스템은 팀처럼

에이전시에서 협업할 때는 리뷰어가 있고 QA가 있었다. 혼자가 되면 그 역할이 전부 사라지는데, 실수하는 습관까지 사라지는 건 아니다. 그래서 사람이 하던 검증을 시스템에 옮겨 심는 것이 혼자 일하는 사람의 생존 전략이라고 생각한다.

CI가 초록불을 주면 merge하고, 빨간불이면 고친다. 나 자신과 협업하는 셈인데, 이 동료는 피곤해하지도 않고 대충 넘어가지도 않는다. 자동화는 시간을 아끼는 도구이기 전에 내 실수를 대신 기억해주는 동료다.

GitHub Actions로 블로그 운영을 자동화했다 — 디코드랩(DCODELAB)