From 5a1f9a2e50f37b1f2525f070e6ad57857c3c6864 Mon Sep 17 00:00:00 2001 From: Devil Date: Tue, 11 Aug 2026 12:53:35 +0200 Subject: [PATCH] chore: add automated git commit/push workflow and changelog generation Adds the git-workflow skill (Conventional Commits, auto-commit/push policy, changelog process), CHANGELOG.md seeded from history, and scripts/generate-changelog.sh to group commits by type. PRs remain manual by design. --- .claude/settings.json | 11 +++- .claude/skills/git-workflow/SKILL.md | 86 ++++++++++++++++++++++++++++ CHANGELOG.md | 13 +++++ CLAUDE.md | 10 ++++ scripts/generate-changelog.sh | 74 ++++++++++++++++++++++++ 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/git-workflow/SKILL.md create mode 100644 CHANGELOG.md create mode 100644 scripts/generate-changelog.sh diff --git a/.claude/settings.json b/.claude/settings.json index 03da275..97f6a62 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -3,7 +3,16 @@ "allow": [ "Bash(winget search *)", "Bash(docker compose ps *)", - "Bash(docker compose logs *)" + "Bash(docker compose logs *)", + "Bash(git status*)", + "Bash(git diff*)", + "Bash(git log*)", + "Bash(git add *)", + "Bash(git commit *)", + "Bash(git push origin main)", + "Bash(git push origin *)", + "Bash(git tag *)", + "Bash(bash scripts/generate-changelog.sh*)" ] } } diff --git a/.claude/skills/git-workflow/SKILL.md b/.claude/skills/git-workflow/SKILL.md new file mode 100644 index 0000000..0646c36 --- /dev/null +++ b/.claude/skills/git-workflow/SKILL.md @@ -0,0 +1,86 @@ +--- +name: git-workflow +description: Use automatically after any code change is completed in this repository (youtube-studio-flow) to commit and push to git.devils.zone, and whenever the user asks to "update the changelog", "generate a changelog", "what's changed", or "prepare release notes". Also covers Conventional Commit message format used throughout this repo. Does NOT cover pull requests — those are always created and merged manually by the user, never by Claude. +tools: Bash, Read, Edit, Write, Glob, Grep +--- + +# Git Workflow — commit, push, changelog + +This repo (`devil/youtube-studio-flow` on git.devils.zone) has opted into fully automatic +commits and pushes by Claude. This skill is the standing policy — apply it without asking +for confirmation each time. The one carve-out: **pull requests are always manual.** Never +create, merge, close, or comment on a PR — only the user does that, via the Gitea UI or by +explicitly asking. + +## Commit & push policy + +After finishing a discrete unit of work (a fix, a feature slice, a doc update — not every +single file save), do this without asking permission first: + +1. `git status` to see what actually changed. Never blanket `git add -A` without looking — + check nothing unexpected (stray debug files, `.env`, logs) is included. +2. Stage the files that belong to this unit of work. +3. Commit with a **Conventional Commits** message (format below). +4. `git push` to `origin main` immediately — don't leave commits unpushed. +5. Tell the user what was committed/pushed in one line (e.g. `Committed & pushed: fix(youtube-sync): handle 50-ID batch quota check`). This is a notification, not a confirmation request. + +Still apply the general git safety rules underneath this: never `--force` push, never +rewrite history that's already pushed, never skip hooks, never commit anything that +matches `.gitignore` (secrets, `node_modules`, build output). If a pre-commit/pre-push +hook fails, fix the underlying issue and make a new commit — don't bypass it. + +If a change is exploratory/uncommitted work the user is still iterating on and explicitly +says so ("don't commit this yet", "let me look first"), skip the auto-commit for that turn. + +## Conventional Commit format + +``` +()!: + + + + +``` + +- **type** — one of `feat`, `fix`, `refactor`, `perf`, `style`, `docs`, `test`, `build`, `ci`, `chore`, `revert` +- **scope** — optional, the module or folder touched: `backend`, `frontend`, `infrastructure`, `docs`, `youtube-sync`, `render-engine`, etc. Omit if the change is repo-wide. +- **!** — append right before the colon for a breaking change, and add a `BREAKING CHANGE:` footer explaining it. +- Summary is imperative mood, lowercase after the colon, no trailing period. + +Examples: +- `feat(playlists): add YouTube playlist sync on video publish` +- `fix(render-engine): stop orphaned block IDs from silently skipping` +- `chore: bump prisma to 6.x` +- `docs: document quota batching cost model` + +This convention exists specifically so `scripts/generate-changelog.sh` can group commits +automatically — don't drift from it. + +## Changelog generation + +`CHANGELOG.md` lives at the repo root, `[Unreleased]` section on top, Keep-a-Changelog +style sections (`Added`, `Changed`, `Fixed`, `Removed`, `Docs`, `Chore`, `Other`) mapped +from Conventional Commit types. + +To update it (on request, or periodically — e.g. after a batch of related commits): + +1. Run `bash scripts/generate-changelog.sh` (defaults to everything since the last git + tag, or full history if no tag exists yet). Pass an explicit range like + `bash scripts/generate-changelog.sh v0.1.0..HEAD` to target something else. +2. Merge the output into `CHANGELOG.md` under `[Unreleased]`, combining with existing + section content rather than duplicating section headers. +3. If a `GITEA_TOKEN` env var is set, the script also appends a `### Pull Requests` + section listing merged PRs since the last tag (via the Gitea API). This is best-effort + — if the token isn't set or `jq`/`curl` are missing, that section is silently skipped. + Don't block changelog generation on this being available. +4. Commit the changelog update itself with `docs(changelog): update for `. + +### Cutting a release + +When the user asks to cut a release / tag a version: + +1. Rename `[Unreleased]` to `## [vX.Y.Z] - YYYY-MM-DD`, add a fresh empty `[Unreleased]` + heading above it. +2. Commit: `chore(release): vX.Y.Z`. +3. `git tag vX.Y.Z` and `git push origin vX.Y.Z` (tags don't push automatically with + `git push` alone). diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..53078f6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +All notable changes to this project are documented here. + +Format is loosely based on [Keep a Changelog](https://keepachangelog.com/), grouped by +[Conventional Commits](https://www.conventionalcommits.org/) type. Regenerate the grouped +entries for a range with `scripts/generate-changelog.sh`; see `.claude/skills/git-workflow/SKILL.md` +for the full process. + +## [Unreleased] + +### Chore +- Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs) (d5af006) diff --git a/CLAUDE.md b/CLAUDE.md index e579924..189a375 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,3 +20,13 @@ Start with `00 - Index.md` for a full navigation overview of all topics. | `06 - Backlog/` | Tech debt and planned features | **Read the relevant vault documents before starting any task.** The vault is the authoritative source for architecture decisions, conventions, and known gotchas. + +## Git Workflow + +This repo is tracked at `devil/youtube-studio-flow` on git.devils.zone (SSH, port 222). +**Commits and pushes to `main` are fully automated — do them without asking for +confirmation each time.** Pull requests are the one exception: never create, merge, or +close a PR automatically, that's always a manual, user-driven action. + +Use the `git-workflow` skill for the full policy, Conventional Commit message format, and +changelog generation process (`CHANGELOG.md` + `scripts/generate-changelog.sh`). diff --git a/scripts/generate-changelog.sh b/scripts/generate-changelog.sh new file mode 100644 index 0000000..c74fb7d --- /dev/null +++ b/scripts/generate-changelog.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Groups commits since the last tag (or full history if no tag exists) into +# Keep-a-Changelog sections by Conventional Commit type. Prints Markdown to +# stdout for review before pasting into CHANGELOG.md under [Unreleased]. +# +# Usage: scripts/generate-changelog.sh [range] +# range git revision range, e.g. "v0.1.0..HEAD". Defaults to +# "..HEAD", or full history if no tag exists yet. +# +# Optional: set GITEA_TOKEN to also list merged PRs since the last tag +# (requires curl + jq; silently skipped if either is unavailable). + +set -euo pipefail + +REPO_OWNER="devil" +REPO_NAME="youtube-studio-flow" +GITEA_HOST="https://git.devils.zone" + +RANGE="${1:-}" +if [ -z "$RANGE" ]; then + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true) + if [ -n "$LAST_TAG" ]; then + RANGE="${LAST_TAG}..HEAD" + else + RANGE="HEAD" + fi +fi + +section_for_type() { + case "$1" in + feat) echo "Added" ;; + fix) echo "Fixed" ;; + refactor|perf|style) echo "Changed" ;; + docs) echo "Docs" ;; + chore|build|ci) echo "Chore" ;; + revert) echo "Removed" ;; + *) echo "Other" ;; + esac +} + +TMP_DIR=$(mktemp -d) +trap 'rm -rf "$TMP_DIR"' EXIT + +while IFS='|' read -r hash subject; do + [ -z "$hash" ] && continue + type=$(echo "$subject" | sed -nE 's/^([a-z]+)(\([^)]*\))?!?:.*/\1/p') + [ -z "$type" ] && type="other" + breaking="" + if echo "$subject" | grep -qE '^[a-z]+(\([^)]*\))?!:'; then + breaking=" **BREAKING**" + fi + section=$(section_for_type "$type") + echo "- ${subject}${breaking} (${hash})" >> "$TMP_DIR/$section" +done < <(git log "$RANGE" --pretty=format:'%h|%s' --no-merges; echo) + +for section in Added Changed Fixed Removed Docs Chore Other; do + if [ -f "$TMP_DIR/$section" ]; then + echo "### $section" + cat "$TMP_DIR/$section" + echo "" + fi +done + +if [ -n "${GITEA_TOKEN:-}" ] && command -v curl >/dev/null && command -v jq >/dev/null; then + SINCE_DATE=$(git log -1 --format=%aI $(echo "$RANGE" | sed 's/\.\.HEAD//') 2>/dev/null || echo "1970-01-01T00:00:00Z") + PRS=$(curl -s -H "Authorization: token ${GITEA_TOKEN}" \ + "${GITEA_HOST}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/pulls?state=closed&limit=50" \ + | jq -r --arg since "$SINCE_DATE" '[.[] | select(.merged == true and .merged_at > $since)] | .[] | "- #\(.number) \(.title)"') + if [ -n "$PRS" ]; then + echo "### Pull Requests" + echo "$PRS" + echo "" + fi +fi