Daisy S. Hollman 66dacfc456
ci: fail validate when a plugin name is removed without a renames entry (#3177)
Adds a step to the validate job that diffs plugins[].name against the
PR base and fails if any name disappeared without a corresponding key
in the top-level "renames" map. Prevents the next airwallex-style
plugin-not-found regression.

Part of CC-2871. Depends on the renames map (PR A).

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-03 19:18:32 -05:00

68 lines
2.9 KiB
YAML

name: Validate Plugins
on:
pull_request:
paths:
- '.claude-plugin/**'
- '*/.claude-plugin/**'
- '*/agents/**'
- '*/skills/**'
- '*/commands/**'
# `validate` is a required status check, so a PR that touches ONLY workflow
# files (e.g. an action-SHA re-pin) would otherwise never trigger validate
# and sit "Expected — Waiting for status to be reported" forever (workflow_dispatch
# check runs aren't associated with the PR, so they don't satisfy it). Run
# validate on workflow changes too so those PRs can clear the gate in-context.
- '.github/workflows/**'
push:
branches: [main]
paths:
- '.claude-plugin/**'
# `validate` is a required status check on main. Bump PRs are opened with
# GITHUB_TOKEN, which doesn't fire on:pull_request (recursion guard), so the
# path-filtered trigger above never reports on them and the PR would be
# blocked forever. The bump workflow dispatches this against each per-entry
# bump branch instead; the check run lands on the branch HEAD (= PR head)
# and satisfies the required check. The validate job runs unconditionally,
# so a dispatch always reports.
workflow_dispatch:
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for renamed plugins without renames entry
run: |
set -euo pipefail
base="${{ github.event.pull_request.base.sha || 'origin/main' }}"
# Names removed from plugins[] in this diff
removed=$(comm -23 \
<(git show "$base:.claude-plugin/marketplace.json" | jq -r '.plugins[].name' | sort) \
<(jq -r '.plugins[].name' .claude-plugin/marketplace.json | sort))
[ -z "$removed" ] && { echo "No plugin names removed."; exit 0; }
# Renames keys present in HEAD
rename_keys=$(jq -r '.renames // {} | keys[]' .claude-plugin/marketplace.json | sort)
missing=$(comm -23 <(echo "$removed" | sort) <(echo "$rename_keys"))
if [ -n "$missing" ]; then
echo "::error::Plugin name(s) removed without a renames entry: $missing"
echo "Add to .claude-plugin/marketplace.json top-level \"renames\": {\"<old>\": \"<new>\"} (or null if intentionally removed)."
exit 1
fi
echo "All removed names have renames entries."
- uses: anthropics/claude-plugins-community/.github/actions/validate-plugins@426e469f322952061102b286b378c0c9733a0934
with:
marketplace-path: .claude-plugin/marketplace.json
# Official curated marketplace: SHA-pin (I5) is a HARD error.
# I8/I11 are warnings until the 15 known vendored-path/name issues
# are cleaned up (see PR body); tighten to "I1 I3" after.
warn-invariants: "I1 I3 I8 I11"
claude-cli-version: latest