311 lines
9.4 KiB
YAML
311 lines
9.4 KiB
YAML
name: Skills Registry CI
|
|
|
|
on:
|
|
push:
|
|
branches: ["main"]
|
|
pull_request:
|
|
branches: ["main"]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
pr-policy:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
primary_category: ${{ steps.intake.outputs.primary_category }}
|
|
categories: ${{ steps.intake.outputs.categories }}
|
|
requires_references: ${{ steps.intake.outputs.requires_references }}
|
|
direct_derived_changes_count: ${{ steps.intake.outputs.direct_derived_changes_count }}
|
|
has_quality_checklist: ${{ steps.intake.outputs.has_quality_checklist }}
|
|
has_issue_link: ${{ steps.intake.outputs.has_issue_link }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "lts/*"
|
|
|
|
- name: Fetch base branch
|
|
run: git fetch origin "${{ github.base_ref }}"
|
|
|
|
- name: Intake PR change
|
|
id: intake
|
|
run: |
|
|
node tools/scripts/pr_preflight.cjs \
|
|
--base "origin/${{ github.base_ref }}" \
|
|
--head "HEAD" \
|
|
--event-path "$GITHUB_EVENT_PATH" \
|
|
--no-run \
|
|
--write-github-output \
|
|
--write-step-summary
|
|
|
|
- name: Enforce PR source-only contract
|
|
run: |
|
|
if [ "${{ steps.intake.outputs.direct_derived_changes_count }}" != "0" ]; then
|
|
echo "Pull requests must stay source-only."
|
|
echo "Remove derived files and let main regenerate them after merge."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${{ steps.intake.outputs.has_quality_checklist }}" != "true" ]; then
|
|
echo "PR body must include the Quality Bar Checklist from the template."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${{ steps.intake.outputs.has_issue_link }}" != "true" ]; then
|
|
echo "::notice::No Closes/Fixes issue link detected in the PR body."
|
|
fi
|
|
|
|
source-validation:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
needs: pr-policy
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.10"
|
|
|
|
- name: Install Python dependencies
|
|
run: pip install -r tools/requirements.txt
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "lts/*"
|
|
|
|
- name: Fetch base branch
|
|
run: git fetch origin "${{ github.base_ref }}"
|
|
|
|
- name: Install npm dependencies
|
|
run: npm ci
|
|
|
|
- name: Verify directory structure
|
|
run: |
|
|
test -d skills/
|
|
test -d apps/web-app/
|
|
test -d tools/scripts/
|
|
test -d tools/lib/
|
|
test -f README.md
|
|
test -f CONTRIBUTING.md
|
|
|
|
- name: Validate source changes
|
|
run: npm run validate
|
|
|
|
- name: Enforce validation warning budget
|
|
run: npm run check:warning-budget
|
|
|
|
- name: Verify README source credits for changed skills
|
|
run: npm run check:readme-credits -- --base "origin/${{ github.base_ref }}" --head HEAD
|
|
|
|
- name: Validate references
|
|
if: needs.pr-policy.outputs.requires_references == 'true'
|
|
run: npm run validate:references
|
|
|
|
- name: Audit npm dependencies
|
|
run: npm audit --audit-level=high
|
|
|
|
- name: Run tests
|
|
env:
|
|
ENABLE_NETWORK_TESTS: "1"
|
|
run: npm run test
|
|
|
|
- name: Install web-app dependencies
|
|
run: npm run app:install
|
|
|
|
- name: Run web app coverage
|
|
run: npm run app:test:coverage
|
|
|
|
- name: Run docs security checks
|
|
run: npm run security:docs
|
|
|
|
artifact-preview:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
needs: [pr-policy, source-validation]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.10"
|
|
|
|
- name: Install Python dependencies
|
|
run: pip install -r tools/requirements.txt
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "lts/*"
|
|
|
|
- name: Install npm dependencies
|
|
run: npm ci
|
|
|
|
- name: Generate canonical artifacts preview
|
|
run: |
|
|
npm run chain
|
|
npm run catalog
|
|
|
|
- name: Report generated drift
|
|
run: |
|
|
mapfile -t managed_files < <(node tools/scripts/generated_files.js --include-mixed)
|
|
if [ "${#managed_files[@]}" -eq 0 ]; then
|
|
echo "::error::No managed files resolved from generated_files contract."
|
|
exit 1
|
|
fi
|
|
drift_files=$(git diff --name-only -- "${managed_files[@]}")
|
|
|
|
{
|
|
echo "## Artifact Preview"
|
|
echo
|
|
echo "- Primary change: \`${{ needs.pr-policy.outputs.primary_category }}\`"
|
|
echo "- Categories: \`${{ needs.pr-policy.outputs.categories }}\`"
|
|
echo "- Derived-file policy: PRs remain source-only; main will canonicalize final generated outputs."
|
|
echo
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
if [ -z "$drift_files" ]; then
|
|
echo "No generated drift detected after preview."
|
|
echo "- Generated drift: none" >> "$GITHUB_STEP_SUMMARY"
|
|
exit 0
|
|
fi
|
|
|
|
echo "::notice::Generated drift detected in artifact preview."
|
|
{
|
|
echo "- Generated drift: detected"
|
|
echo
|
|
echo "Predicted file updates:"
|
|
printf '%s\n' "$drift_files" | sed "s/^/- \`/; s/\$/\`/"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
main-validation-and-sync:
|
|
if: github.event_name != 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
concurrency:
|
|
group: canonical-main-sync
|
|
cancel-in-progress: false
|
|
permissions:
|
|
contents: write
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.10"
|
|
|
|
- name: Install Python dependencies
|
|
run: pip install -r tools/requirements.txt
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "lts/*"
|
|
|
|
- name: Install npm dependencies
|
|
run: npm ci
|
|
|
|
- name: Verify directory structure
|
|
run: |
|
|
test -d skills/
|
|
test -d apps/web-app/
|
|
test -d tools/scripts/
|
|
test -d tools/lib/
|
|
test -f README.md
|
|
test -f CONTRIBUTING.md
|
|
|
|
- name: Validate references
|
|
run: npm run validate:references
|
|
|
|
- name: Run repo-state sync
|
|
run: npm run sync:repo-state
|
|
|
|
- name: Audit npm dependencies
|
|
run: npm audit --audit-level=high
|
|
|
|
- name: Run tests
|
|
env:
|
|
ENABLE_NETWORK_TESTS: "1"
|
|
run: npm run test
|
|
|
|
- name: Install web-app dependencies
|
|
run: npm run app:install
|
|
|
|
- name: Run web app coverage
|
|
run: npm run app:test:coverage
|
|
|
|
- name: Run docs security checks
|
|
run: npm run security:docs
|
|
|
|
- name: Set up GitHub credentials
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
run: |
|
|
set -euo pipefail
|
|
git config user.name 'github-actions[bot]'
|
|
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
|
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
|
git fetch origin main
|
|
|
|
- name: Auto-commit canonical artifacts
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
run: |
|
|
set -euo pipefail
|
|
mapfile -t managed_files < <(node tools/scripts/generated_files.js --include-mixed)
|
|
if [ "${#managed_files[@]}" -eq 0 ]; then
|
|
echo "No managed files resolved from generated_files contract."
|
|
exit 1
|
|
fi
|
|
|
|
if git diff --quiet && [ -z "$(git ls-files --others --exclude-standard)" ]; then
|
|
echo "No canonical repo-state drift detected."
|
|
exit 0
|
|
fi
|
|
|
|
git add -- "${managed_files[@]}" || true
|
|
|
|
if git diff --cached --quiet; then
|
|
echo "Repo-state sync produced unmanaged drift only."
|
|
git status --short
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$(git diff --name-only)" ] || [ -n "$(git ls-files --others --exclude-standard)" ]; then
|
|
echo "Repo-state sync produced unmanaged drift alongside canonical changes."
|
|
git status --short
|
|
exit 1
|
|
fi
|
|
|
|
git commit -m "chore: sync repo state [ci skip]"
|
|
git pull origin main --rebase
|
|
git push origin HEAD
|
|
|
|
- name: Check for uncommitted drift
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
run: |
|
|
if ! git diff --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]; then
|
|
echo "❌ Detected leftover drift after the canonical bot sync."
|
|
echo
|
|
echo "The bot may only commit managed canonical files and must leave a clean tree."
|
|
echo "To fix locally, run the canonical maintainer flow:"
|
|
echo " npm run release:preflight"
|
|
echo " npm run sync:repo-state"
|
|
echo " git status"
|
|
git status --short
|
|
exit 1
|
|
fi
|