Communitygithub.com

lguidolin/init-repo-CI

새로운 저장소에 Conventional Commits, Release-Please, CI 자동화를 설정하거나, 자동 버전 관리 및 PR 검증 워크플로가 없는 기존 저장소를 개선할 때 사용합니다.

init-repo-CI란 무엇인가요?

이 스킬은 GitHub 저장소에서 Conventional Commits, Release-Please, CI 자동화를 완전히 설정하는 방법을 제공합니다. 빈 저장소와 기존 콘텐츠가 있는 저장소 모두에서 작동합니다. PR 제목 검증, 자동 레이블링, CI 검사, AI 귀속 확인 등 다양한 워크플로를 생성하고, Release-Please를 통한 자동 릴리스 및 변경 로그 생성을 지원합니다. 이 스킬은 개발 초기부터 자동화된 릴리스와 PR 검증이 필요한 신규 저장소나, 기존 저장소에 자동 버전 관리가 부족한 경우에 특히 유용합니다. 사용자는 프로젝트 이름, 초기 버전, 릴리스 유형, 저장소 레이아웃 등의 파라미터를 제공해야 하며, 스킬은 기존 파일을 감지하고 충돌을 방지합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lguidolin/agent-skills/tree/main/skills/init-repo-CI

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

저장소 자동화 설정

완전한 Conventional Commits + Release-Please + CI 자동화 스택을 모든 저장소에 구성합니다. 빈 저장소 및 기존 콘텐츠가 있는 저장소에서 작동합니다.

개요

Shift Left: 가능한 한 빨리 문제를 찾아내세요. PR 시점에 잘못된 커밋 메시지를 발견하는 데는 몇 초가 걸리지만, 같은 메시지가 릴리스 노트에 남으면 신뢰도를 떨어뜨립니다. 검증을 상류로 옮기세요 — PR 제목에서 커밋 형식을 강제하고, CI에서 설정을 검증하며, main 브랜치에 도달하기 전에 문제를 잡아내세요.

빠를수록 안전: 더 작은 배치와 더 빈번한 릴리스는 위험을 줄입니다. 3개의 변경 사항이 있는 릴리스는 30개가 있는 릴리스보다 디버깅하기 쉽습니다. 자동화된 릴리스는 릴리스 프로세스 자체에 대한 신뢰를 구축합니다.

이 스킬은 검증 메커니즘을 설정합니다: PR 제목 검증은 main에 대한 모든 병합이 의미 있고 파싱 가능한 커밋을 생성하도록 보장합니다. Release-Please는 이러한 커밋을 변경 로그가 포함된 자동 릴리스로 전환합니다. CI는 병합 전에 설정 및 코드 문제를 발견합니다.

사용 시기

  • 새 저장소를 시작하고 첫날부터 릴리스 자동화가 필요한 경우
  • 기존 저장소에 자동 버전 관리 또는 변경 로그 생성이 없는 경우
  • 수동 릴리스 프로세스 또는 다른 릴리스 도구에서 마이그레이션하는 경우
  • 저장소에 PR 제목 검증 및 자동 레이블링이 필요한 경우

사용하지 말아야 할 경우

  • 저장소에 이미 Release-Please 또는 동등한 도구가 구성된 경우 (먼저 확인)
  • 호환되지 않는 릴리스 도구가 있는 모노레포 (예: Lerna 독립 버전 관리가 이미 작동 중)
  • 업스트림이 릴리스 프로세스를 제어하는 포크 저장소

프로세스

1단계: 구성 수집

파일을 생성하기 전에 사용자에게 다음 값을 요청하세요:

파라미터기본값설명
PROJECT_NAME(필수)문서용 사람이 읽을 수 있는 프로젝트 이름
INITIAL_VERSION0.1.0시작 시맨틱 버전
RELEASE_TYPEsimplesimple (단일 패키지) 또는 node / python / 등
REPO_LAYOUTsinglesingle (루트에 하나의 패키지) 또는 monorepo (여러 패키지)
PACKAGE_PATHS.모노레포의 경우: packages/api,packages/ui와 같은 쉼표로 구분된 경로
DEPENDABOT_ECOSYSTEMSgithub-actions쉼표로 구분: github-actions, npm, pip, cargo 등
DEFAULT_BRANCHmain릴리스를 트리거하는 브랜치

적절한 RELEASE_TYPE을 자동으로 감지:

  • package.json이 존재함 → node 제안
  • setup.py 또는 pyproject.toml이 존재함 → python 제안
  • Cargo.toml이 존재함 → rust 제안
  • 위 중 해당 사항 없음 → simple 제안

2단계: 기존 파일 감지

무엇이든 생성하기 전에 충돌을 확인하세요:

for f in .github/workflows/pull-request.yml .github/workflows/main-branch.yml \
         .github/release-please-config.json .release-please-manifest.json \
         .github/dependabot.yml .github/pull_request_template.md docs/DEVELOPMENT.md; do
  [[ -f "$f" ]] && echo "EXISTS: $f"
done

파일이 존재하면 변경될 내용의 diff를 표시하고 덮어쓰기 전에 물어보세요. 자동으로 덮어쓰지 마세요 — 기존 파일에는 프로젝트별 사용자 지정이 포함될 수 있습니다.

3단계: 구성 파일 생성

다음 순서로 파일을 생성하세요 (의존성은 위에서 아래로 흐름):

3a. .github/release-please-config.json

단일 패키지:

{
  "release-type": "{{RELEASE_TYPE}}",
  "bump-minor-pre-major": true,
  "bump-patch-for-minor-pre-major": false,
  "initial-version": "{{INITIAL_VERSION}}",
  "packages": {
    ".": {}
  }
}

모노레포: packages를 경로당 하나의 항목으로 바꾸세요:

{
  "packages": {
    "packages/api": { "release-type": "node" },
    "packages/ui": { "release-type": "node" }
  }
}

각 모노레포 패키지는 자체 release-type을 가집니다 — 패키지가 다를 경우 사용자에게 물어보세요.

3b. .release-please-manifest.json

단일 패키지:

{
  ".": "{{INITIAL_VERSION}}"
}

모노레포: 패키지 경로당 하나의 항목, 각각 자체 버전.

3c. .github/workflows/pull-request.yml

name: Pull Request Validation

on:
  pull_request:
    types: [opened, edited, synchronize, reopened]

permissions:
  pull-requests: write
  contents: read
  statuses: write

jobs:
  validate-pr-title:
    name: Validate PR Title
    runs-on: ubuntu-latest
    steps:
      - uses: amannn/action-semantic-pull-request@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          types: |
            feat
            fix
            docs
            chore
            refactor
            test
            ci
          requireScope: false
          subjectPattern: ^[a-z].+$
          subjectPatternError: |
            The subject "{subject}" found in the pull request title "{title}"
            didn't match the configured pattern. Please ensure that the subject
            starts with a lowercase character (per conventional commits).

  auto-label:
    name: Auto Label PR
    runs-on: ubuntu-latest
    steps:
      - name: Label based on PR title
        uses: actions/github-script@v8
        with:
          script: |
            const title = context.payload.pull_request.title;
            const labelMap = {
              'feat': 'enhancement',
              'fix': 'bug',
              'docs': 'documentation',
              'chore': 'chore',
              'refactor': 'refactor',
              'test': 'test',
              'ci': 'ci'
            };
            for (const [type, label] of Object.entries(labelMap)) {
              if (title.startsWith(`${type}:`) || title.startsWith(`${type}(`)) {
                await github.rest.issues.addLabels({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: context.payload.pull_request.number,
                  labels: [label]
                });
                break;
              }
            }

  no-ai-attribution:
    name: No AI Attribution
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - name: Scan commit messages and PR body
        env:
          PR_BODY: ${{ github.event.pull_request.body }}
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
        run: |
          # Trailer/footer forms only: a commit that merely mentions Claude or
          # Anthropic in prose is fine. Human Co-authored-by trailers are fine.
          PAT='^[[:space:]]*Co-authored-by:.*(Claude|Anthropic|noreply@anthropic)|Generated with \[?(Claude|Anthropic)'
          fail=0
          if git log --format='%B' "$BASE_SHA..$HEAD_SHA" | grep -Eiq "$PAT"; then
            echo "::error::AI attribution found in a commit message on this branch"
            fail=1
          fi
          if printf '%s' "$PR_BODY" | grep -Eiq "$PAT"; then
            echo "::error::AI attribution found in the PR description"
            fail=1
          fi
          [ "$fail" -eq 0 ] && echo "No AI attribution found."
          exit $fail

  ci-checks:
    name: CI Checks
    runs-on: ubuntu-latest
    continue-on-error: true
    steps:
      - uses: actions/checkout@v6
      - name: Validate YAML syntax
        run: |
          sudo apt-get update && sudo apt-get install -y yamllint
          find . -name "*.yml" -o -name "*.yaml" | while read file; do
            echo "Checking $file"
            yamllint -d "{extends: default, rules: {line-length: disable}}" "$file" || true
          done

No AI Attribution은 첫날부터 차단합니다 — 검증할 수 있는 오탐지 표면이 없습니다 (트레일러 및 푸터 형식만 일치시키고 산문은 일치시키지 않음). 따라서 아래의 단계적 적용 경로를 거치지 않습니다.

CI 검사 단계적 적용 경로:

  1. continue-on-error: true로 배포 (정보 제공, 비차단)
  2. 3-5개의 실제 PR에서 검사 통과 확인
  3. continue-on-error 제거 및 브랜치 보호 필수 검사에 추가
  4. 코드베이스가 성장함에 따라 프로젝트별 검사 (린트, 테스트, 빌드) 추가

어떤 관문도 건너뛸 수 없습니다. 린트가 실패하면 린트를 수정하세요 — 규칙을 비활성화하지 마세요. 테스트가 실패하면 코드를 수정하세요 — 테스트를 건너뛰지 마세요. CI가 실패하면 실패 출력을 에이전트에 전달하고 다시 푸시하기 전에 수정하세요.

3d. .github/workflows/main-branch.yml

name: Release Automation

on:
  push:
    branches:
      - {{DEFAULT_BRANCH}}

permissions:
  contents: write
  pull-requests: write

jobs:
  release-please:
    name: Release Please
    runs-on: ubuntu-latest
    outputs:
      release_created: ${{ steps.release.outputs.release_created }}
      tag_name: ${{ steps.release.outputs.tag_name }}
    steps:
      - uses: googleapis/release-please-action@v4
        id: release
        with:
          config-file: .github/release-please-config.json
          manifest-file: .release-please-manifest.json

  update-major-tag:
    name: Update Major Version Tag
    needs: release-please
    if: ${{ needs.release-please.outputs.release_created == 'true' }}
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.release-please.outputs.tag_name }}
      - name: Update major version tag
        env:
          TAG_NAME: ${{ needs.release-please.outputs.tag_name }}
        run: |
          MAJOR_TAG=$(echo "$TAG_NAME" | sed 's/^\(v[0-9]*\).*/\1/')
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git tag -fa "$MAJOR_TAG" -m "Update $MAJOR_TAG tag to $TAG_NAME"
          git push origin "$MAJOR_TAG" --force

3e. .github/dependabot.yml

에코시스템당 하나의 updates 항목을 생성합니다:

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 5
    labels:
      - "dependencies"
    commit-message:
      prefix: "chore"
      include: "scope"

commit-message 구성은 Dependabot PR이 자동으로 Conventional Commits를 따르도록 보장합니다 (예: chore(deps): bump actions/checkout from v5 to v6).

3f. .github/pull_request_template.md

## 변경 사항

[변경 사항을 자세히 설명 - 이것이 변경 로그에 포함됩니다]

## 이유

[변경에 대한 맥락과 동기]

## 체크리스트

- [ ] PR 제목이 Conventional Commits 형식을 따릅니다 (`type: description`)
- [ ] 설명이 무엇과 왜를 설명합니다 (단순히 무엇만 설명하지 않음)
- [ ] 코드, 로그 또는 버전 관리에 비밀이 없습니다
- [ ] 테스트가 로컬에서 통과합니다

"이유" 섹션은 중요합니다 — 변경된 내용만 설명하는 PR 설명은 diff와 중복됩니다. 이유는 향후 git-blame에 유용한 맥락을 제공합니다.

3g. .gitignore (없는 경우)

.gitignore 파일이 있는지 확인합니다. 없으면 프로젝트에 적합한 파일을 만드세요:

# 의존성
node_modules/

# 빌드 출력
сdist/
build/
.next/

# 환경
.env
.env.local
*.pem

# IDE
.idea/

# OS
.DS_Store
Thumbs.db

감지된 스택에 맞게 조정하세요. node_modules/, .env 또는 빌드 아티팩트를 절대 커밋하지 마세요.

3h. docs/DEVELOPMENT.md

다음을 포함하는 개발 가이드를 생성합니다:

  • 브랜치 워크플로 — 트렁크 기반 개발: 짧은 수명의 기능 브랜치 (1-3일), 신속하게 병합. 브랜치 이름: feature/<desc>, fix/<desc>, chore/<desc>.
  • 커밋 규율 — 브랜치 내에서 자유롭게 커밋 (모든 형식). PR 제목만 중요합니다 — 스쿼시 병합 커밋 메시지가 되어 main에 나타나고 변경 로그에 표시됩니다.
  • PR 제목 형식 — 유형 표: feat, fix, docs, chore, refactor, test, ci. 획기적인 변경: feat!: 또는 본문의 BREAKING CHANGE:.
  • 변경 크기 — PR당 ~100줄 목표. 단일 논리적 변경의 경우 ~300줄 허용. ~1000줄 이상은 분할해야 합니다. 리팩터링과 기능 작업을 분리하세요 — 서로 다른 변경입니다.
  • PR 설명 — 첫 번째 줄: 짧고, 명령형이며, 독립적. 본문: 무엇을 변경하고 왜인지. 안티패턴: "Fix bug", "Update file", "Phase 1".
  • 자동화된 검사 — PR 제목 검증 (필수, 병합 차단), 자동 레이블링 (정보 제공), CI 검사 (초기에는 비차단, 이후 필수로 전환).
  • 릴리스 프로세스 — release-please가 릴리스 PR 생성 → 병합 → GitHub 릴리스 + 태그 + 변경 로그. 버전 진행: 1.0 미만 (feat → 마이너, fix → 패치) vs 1.0 이상 (feat → 마이너, fix → 패치, BREAKING CHANGE → 메이저).
  • 문제 해결 — 일반적인 문제: PR 제목 검증 실패 (제목 편집), CI 검사 실패, 병합 차단 (필수 상태 확인).

제목에 {{PROJECT_NAME}}을 사용합니다.

4단계: 브랜치 보호 권장 사항

파일 생성 후, 다음을 수동 단계로 제시합니다 (자동 적용되지 않음):

{{DEFAULT_BRANCH}}에 대한 권장 GitHub 브랜치 보호 설정:
  ✓ 병합 전에 풀 리퀘스트 필요
  ✓ 상태 검사 필요: "Validate PR Title"
  ✓ 브랜치가 최신 상태여야 함 필요
  ✓ 스쿼시 병합만 허용
  ✓ 선형 기록 필요

스쿼시 병합을 사용하는 이유: 브랜치 기록 (WIP 커밋, 수정, 실험)은 PR에 보존됩니다. Main은 깨끗하고 의미 있으며 선형적인 로그를 얻고, 모든 커밋은 Conventional Commit입니다. 이것이 release-please와 git log --oneline을 유용하게 만드는 이유입니다.

5단계: 워크플로 권한 활성화

Release-Please는 GitHub Actions를 통해 풀 리퀘스트를 생성할 수 있는 권한이 필요합니다. 이는 새 저장소에서 기본적으로 비활성화되어 있으며 Release Automation 워크플로가 다음과 함께 실패하게 만듭니다:

GitHub Actions is not permitted to create or approve pull requests.

사용자에게 이 설정을 활성화하도록 안내하세요:

GitHub 레포지토리 → 설정 → 작업 → 일반 → 워크플로 권한:
  ✓ 읽기 및 쓰기 권한 (release-please가 변경 로그 커밋을 푸시하는 데 필요)
  ✓ GitHub Actions가 풀 리퀘스트를 생성 및 승인하도록 허용 (릴리스 PR에 필요)

이 단계는 {{DEFAULT_BRANCH}}에 대한 첫 푸시 전에 완료되어야 합니다. 그렇지 않으면 활성화될 때까지 모든 푸시에서 release-please가 실패합니다.

6단계: 확인

# YAML 구문 검증
yamllint .github/workflows/*.yml .github/dependabot.yml

# JSON 검증
python3 -c "import json; json.load(open('.github/release-please-config.json'))"
python3 -c "import json; json.load(open('.release-please-manifest.json'))"

설계 원칙

이 설정의 기본 설계 원칙:

  1. Shift Left — PR 시점에 문제를 조기에 발견. 커밋 메시지가 main에 도달하면 변경 로그에 영구적으로 남습니다.
  2. 작은 배치 — 더 작은 PR = 더 빠른 검토 = 더 적은 병합 충돌 = 더 안전한 릴리스.
  3. 점진적 전환 — CI 검사는 continue-on-error: true로 시작하여 실제 워크플로를 방해하지 않고 검증합니다.
  4. 관문은 관문 — 검사를 건너뛰지 마세요. 수정하지 않고 우회하지 마세요. CI 실패는 학습 기회입니다.
  5. 사람이 먼저 — 모든 PR 검사가 통과했더라도 사람의 검토가 필요합니다. 자동화는 게이트를 보조하지만 대체하지 않습니다.

Individual skills in this repo

This repo contains 18 individual skills — each has its own dedicated page.

lguidolin/change-hygiene-and-code-craft

Use when writing or refactoring code, structuring a commit or PR, or deciding whether to abstract duplication. Symptoms — mixing reorg with logic changes, a PR doing several things at once, a file growing large, the second copy of similar code, or unsure whether to DRY something up.

lguidolin/cloud-delivery-aks

Use when deploying to Kubernetes or Azure Kubernetes Service (AKS), configuring cloud secrets, setting up progressive rollout/canary, per-PR ephemeral environments, or k8s health probes. Keywords — Kubernetes, AKS, Key Vault, Argo Rollouts, Flagger, canary, blue-green, liveness, readiness, PodDisruptionBudget, HPA, rollback, GHCR.

lguidolin/commit-history-rewrite

Use when an existing repository has messy commit history that needs to conform to conventional commits before adopting release-please, or when intermediate WIP/fixup/merge commits need to be cleaned up.

lguidolin/conventional-commits-and-releases

Use when committing, writing a commit message, opening a PR that will be squash-merged, or configuring automated versioning/changelogs. Keywords — conventional commits, release-please, semver, feat/fix/chore, breaking change, changelog.

lguidolin/defense-in-depth-security

Use when handling untrusted input, secrets, authentication/authorization, or dependencies — or threat-modeling a new surface. Keywords — STRIDE, threat model, least privilege, secrets management, supply chain, dependency scanning, input validation, audit log, defense in depth.

lguidolin/designing-before-building

Use when starting a feature, fixing a non-trivial bug, or about to write implementation code — before any code exists. Symptoms you need this: "this is simple, I'll just code it", reaching for the editor before a design is approved, or an idea that hasn't been turned into a spec and plan.

lguidolin/engineering-constitution

Use when starting work in a project that follows the engineering constitution, orienting to its rules, or deciding which engineering practice applies to a task — spec writing, commits, testing, security, deploys, database, or UI work.

lguidolin/graphql-contract-testing

Use when writing a GraphQL query/mutation that the UI and a test will share, or building route/schema contract or smoke tests. Symptoms — copying a query into a test, a test asserting on query text, schema change that didn't break the UI build, or RLS/permission drift. Keywords — graphql-codegen, typed document, contract test, route smoke test.

lguidolin/interface-craft-and-accessibility

Use when building or styling UI — components, layouts, forms, design tokens — or making accessibility decisions. Keywords — a11y, WCAG, keyboard navigation, focus state, contrast, design system, minimalist UI, component reuse, ARIA, semantic HTML.

lguidolin/merge-gates-and-automation

Use when setting up or changing CI, pre-push hooks, or a task runner, or deciding what must pass before merge. Symptoms — tempted to put authoritative checks only in a local hook, skip CI, bypass with --no-verify, or unsure what gates a merge vs. runs locally.

lguidolin/observability-and-slos

Use when adding logging, metrics, tracing, health checks, SLOs, or alerting — or when building a service surface that needs to be operable and debuggable. Keywords — structured logs, OpenTelemetry, correlation id, RED metrics, liveness, readiness, SLI, SLO, error budget, alerting.

lguidolin/performance-and-scale

Use when working on hot paths, list endpoints, pagination, data-access in loops, or public interfaces/schemas. Symptoms — unbounded queries, N+1 access, no latency budget, optimizing without measuring, or changing an interface many consumers depend on. Keywords — pagination, N+1, Hyrum's Law, performance budget, bundle size.

lguidolin/postgres-postgraphile-rls-and-sql

Use when writing PostgreSQL, PostGraphile config, Row-Level Security policies, SQL schema files, or working on the Browser→App→PostGraphile→Postgres data path. Keywords — RLS, SECURITY DEFINER, search_path, pgSettings, grants, roles, GraphQL depth limit, query cost, statement_timeout, SQL file organization.

lguidolin/recording-decisions

Use when a design or architecture decision has been made and needs to be captured — writing a decision record or ADR, updating a decision index, noting a deferred idea, or superseding a past decision. Keywords — ADR, decision record, rationale, rejected alternatives, dependency index.

lguidolin/resilience-and-deploy-safety

Use when planning a deploy, designing a rollback, or responding to an incident or writing a postmortem. Keywords — deploy safety, rollback, immutable artifact, progressive delivery, canary, blast radius, incident response, blameless postmortem, error budget.

lguidolin/ship-it

Use when the user wants to ship work — push, PR, archive decision records, merge, and clean up. Handles the full lifecycle from committing final changes through post-merge cleanup including converting specs/plans to compact decision records.

lguidolin/tests-as-a-control

Use when writing or modifying tests, when a test breaks during a refactor, or when testing permission/role rules. Symptoms — tempted to edit a test to make it pass, testing only the happy path, a deny-test that started passing, flaky tests, or unsure what to assert.

lguidolin/zero-downtime-migrations

Use when changing a database schema where data must survive the change — adding/removing/renaming columns, constraints, indexes, or backfilling. Symptoms — a destructive migration bundled with a code deploy, a NOT NULL column with a backfill, a table-locking UPDATE, or a rename. Keywords — expand/contract, parallel change, backfill, NOT VALID, CREATE INDEX CONCURRENTLY, graphile-migrate.

관련 스킬