diff --git a/.claude/skills/ship/SKILL.md b/.claude/skills/ship/SKILL.md new file mode 100644 index 0000000..541c5b7 --- /dev/null +++ b/.claude/skills/ship/SKILL.md @@ -0,0 +1,137 @@ +--- +name: ship +description: Update docs, commit, create PR, monitor CI and reviews, address feedback, merge +user-invocable: true +argument-hint: "[optional PR number to resume monitoring]" +allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent +--- + +# Ship — Commit, Monitor, Fix, Merge + +End-to-end workflow: update documentation, commit, create PR, monitor CI +and code reviews, address feedback, and merge when everything passes. + +If `$ARGUMENTS` contains a PR number, skip to the monitoring phase for +that PR. + +## Phase 1 — Update Documentation + +Before committing, review all staged and unstaged changes to understand +what was modified, then update: + +1. **CLAUDE.md** — If any CI/CD pipelines, hooks, skills, conventions, + or project structure changed, update the relevant sections. +2. **README.md** — If scripts, settings, architecture, or tooling + changed, update the relevant sections. +3. **docs/adr/** — If a significant architectural decision was made + (new pattern, new tool, structural change), create or update an ADR. +4. **MEMORY.md** — Update project memory at + `$HOME/.claude/projects/-Users-gamaware-Documents-Repos-personal-github-org-settings/memory/MEMORY.md` + if there are new gotchas, patterns, or preferences learned. + +Only update files where changes are actually needed. Do not update docs +for trivial changes. + +## Phase 2 — Commit and Push + +1. Stage all changes (including doc updates from Phase 1). +2. Write a conventional commit message summarizing all changes. +3. Push to the current feature branch. +4. Create a PR if one does not exist yet. Use the commit message as + the PR title. Include a summary and test plan in the body. + +## Phase 3 — Monitor CI + +Poll CI status using `gh pr checks ` every 30 seconds until +all checks complete (pass, fail, or skip). Report the final status. + +If any check fails: + +1. Read the failure logs with `gh run view --log-failed`. +2. Diagnose and fix the issue. +3. Commit and push the fix. +4. Return to monitoring. + +## Phase 4 — Monitor Code Reviews + +Check for review comments from CodeRabbit and Copilot: + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/comments +gh api repos/{owner}/{repo}/issues/{number}/comments +``` + +If CodeRabbit is rate-limited, wait for the timeout period then trigger +with `gh pr comment --body "@coderabbitai review"`. + +For each review comment: + +1. Read the comment carefully. +2. Check if the comment is stale (already fixed in a later commit) by + reading the current file state. Dismiss stale comments. +3. If the comment is valid, fix the issue, commit, and push. +4. After fixing, re-monitor CI (return to Phase 3). + +After all fixes are pushed and the incremental review passes, resolve +stale CodeRabbit threads in bulk: + +```bash +gh pr comment --body "@coderabbitai resolve" +``` + +For Copilot threads, resolve them via the GraphQL API: + +```bash +gh api graphql -f query='{ + repository(owner: "gamaware", name: "github-org-settings") { + pullRequest(number: ) { + reviewThreads(first: 100) { nodes { id isResolved } } + } + } +}' +``` + +Then for each unresolved thread ID: + +```bash +gh api graphql -f query='mutation { + resolveReviewThread(input: {threadId: ""}) { + thread { isResolved } + } +}' +``` + +## Phase 5 — Merge + +Once ALL of the following are true: + +- All CI checks pass +- CodeRabbit review has no unaddressed comments +- Copilot review has no unaddressed comments + +Then merge: + +```bash +gh pr merge --squash --admin --delete-branch +``` + +Pull main locally after merge: + +```bash +git checkout main && git pull +``` + +Report the merge commit and confirm the branch was deleted. + +## Rules + +- Never suppress lint violations — fix them. +- No AI attribution in commits. +- Conventional commit messages required. +- CodeRabbit may hit hourly rate limits — wait and retry. +- Copilot comments may be stale after fix commits — verify current file state. +- CodeRabbit auto-reviews incrementally on every push (up to 5 commits, + then pauses). Use `@coderabbitai review` to resume after pause. +- CodeRabbit does NOT auto-resolve its threads — use `@coderabbitai resolve` + after fixes are confirmed. +- Use `--admin` to bypass branch protection for merge. diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml index 8909796..0d4a48b 100644 --- a/.github/workflows/quality-checks.yml +++ b/.github/workflows/quality-checks.yml @@ -129,3 +129,43 @@ jobs: - name: Run zizmor run: zizmor --config zizmor.yml .github/workflows/ + + link-checker: + name: Check Links + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Check markdown links + uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 + with: + config-file: '.markdown-link-check.json' + use-quiet-mode: 'yes' + continue-on-error: true + + prose-lint: + name: Prose Linting (Vale) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Install Vale + env: + VALE_VERSION: "3.13.1" + run: | + tmpdir="$(mktemp -d)" + wget -q "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/vale_${VALE_VERSION}_Linux_64-bit.tar.gz" + tar xzf "vale_${VALE_VERSION}_Linux_64-bit.tar.gz" -C "$tmpdir" vale + sudo mv "$tmpdir/vale" /usr/local/bin/vale + + - name: Run Vale + run: | + vale sync + find . -name '*.md' -not -path './styles/*' -not -path './.git/*' \ + -exec vale {} + diff --git a/.markdown-link-check.json b/.markdown-link-check.json new file mode 100644 index 0000000..bccd705 --- /dev/null +++ b/.markdown-link-check.json @@ -0,0 +1,23 @@ +{ + "ignorePatterns": [ + { + "pattern": "^http://localhost" + }, + { + "pattern": "^http://127.0.0.1" + }, + { + "pattern": "^http://192.168" + }, + { + "pattern": "^http://10\\." + }, + { + "pattern": "^http://172\\.(1[6-9]|2[0-9]|3[0-1])\\." + } + ], + "timeout": "20s", + "retryOn429": true, + "retryCount": 3, + "aliveStatusCodes": [200, 206, 301, 302, 307, 308, 403, 405, 429] +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3ba51ab..dff6b65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: # General - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -44,20 +44,38 @@ repos: # Markdown - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.44.0 + rev: v0.47.0 hooks: - id: markdownlint args: ["--fix"] + # Prose + - repo: local + hooks: + - id: vale + name: vale + entry: bash -c 'vale sync --no-progress 2>/dev/null; vale "$@"' -- + language: system + types: [markdown] + # GitHub Actions - repo: https://github.com/rhysd/actionlint - rev: v1.7.7 + rev: v1.7.11 hooks: - id: actionlint + - repo: local + hooks: + - id: zizmor + name: zizmor + entry: zizmor --config zizmor.yml .github/workflows/ + language: system + files: ^\.github/workflows/.*\.ya?ml$ + pass_filenames: false + # Conventional Commits - repo: https://github.com/compilerla/conventional-pre-commit - rev: v4.1.0 + rev: v4.4.0 hooks: - id: conventional-pre-commit stages: [commit-msg] diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000..e1debc8 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,14 @@ +StylesPath = styles +MinAlertLevel = warning + +Packages = write-good, proselint + +[*.md] +BasedOnStyles = write-good, proselint + +# write-good tuning — too noisy for technical writing +write-good.TooWordy = NO +write-good.So = NO +proselint.Very = NO +proselint.Cliches = NO +proselint.Typography = NO diff --git a/CLAUDE.md b/CLAUDE.md index 81e04fc..abbb858 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -31,8 +31,9 @@ a baseline, apply corrections, and report drift via GitHub Issues. ## Pre-commit Hooks -General, secrets, shell, markdown, GitHub Actions, and conventional -commit hooks — see `.pre-commit-config.yaml` for the full list. +General, secrets, shell, markdown, prose (Vale), GitHub Actions +(actionlint, zizmor), and conventional commit hooks — see +`.pre-commit-config.yaml` for the full list. ## Claude Code Hooks @@ -65,7 +66,8 @@ commit hooks — see `.pre-commit-config.yaml` for the full list. - `sync-settings.yml` — weekly settings sync + GitHub Issue reports - `quality-checks.yml` — markdown, YAML, shell, structure, JSON - schema validation + schema validation, link checking, zizmor (Actions security), + Vale (prose linting) - `security.yml` — Semgrep SAST + Trivy SCA (via composite action) - `update-pre-commit-hooks.yml` — weekly auto-update via PR (via composite action) @@ -83,6 +85,8 @@ commit hooks — see `.pre-commit-config.yaml` for the full list. - `/audit` — run a dry-run settings check across all repos - `/add-repo-override` — add a per-repo exception to overrides.json - `/exclude-repo` — exclude a repository from governance +- `/ship [PR-number]` — end-to-end PR lifecycle: update docs, commit, + create PR, monitor CI, address reviews (CodeRabbit + Copilot), merge ## Code Review diff --git a/README.md b/README.md index 3e4a326..c54de64 100644 --- a/README.md +++ b/README.md @@ -289,8 +289,8 @@ Add repo names to the `excluded` array in `config/overrides.json`: - **CodeRabbit**: auto-review on PRs via `.coderabbit.yaml` > **Note:** CodeRabbit must be enabled manually per repository through -> the [CodeRabbit dashboard](https://app.coderabbit.ai). There is no -> API to automate this. After installing the GitHub App, select "All +> the [CodeRabbit dashboard](https://app.coderabbit.ai). No API exists +> to automate this step. After installing the GitHub App, select "All > repositories" to cover new repos automatically, or add repos > individually through the dashboard.