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.
This commit is contained in:
+10
-1
@@ -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*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>(<scope>)!: <short summary>
|
||||
|
||||
<optional body — the why, not the what>
|
||||
|
||||
<optional footer, e.g. BREAKING CHANGE: ...>
|
||||
```
|
||||
|
||||
- **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 <range/summary>`.
|
||||
|
||||
### 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).
|
||||
@@ -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)
|
||||
@@ -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`).
|
||||
|
||||
@@ -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
|
||||
# "<last-tag>..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
|
||||
Reference in New Issue
Block a user