Skip to content

ci: auto-sync skills to duyet/skills on push to master (#67) #1

ci: auto-sync skills to duyet/skills on push to master (#67)

ci: auto-sync skills to duyet/skills on push to master (#67) #1

Workflow file for this run

---
name: Sync skills to duyet/skills
# yamllint disable rule:truthy
"on":
push:
branches: [master]
paths:
- "clickhouse/**"
- "clickhouse-monitoring/**"
- "frontend-design/**"
- "orchestration/**"
- "prompt-engineering/**"
- "unsloth-training/**"
- "duyetbot/**"
- "github/**"
- "good-html/**"
- "anyrouter/**"
- "marketplace.json"
- ".github/workflows/sync-skills.yml"
workflow_dispatch:
permissions:
contents: read
# Plugins whose skills/ subdirs (or root SKILL.md, for good-html) flatten
# into duyet/skills. Edit this list to add or remove synced plugins.
env:
SOURCE_PLUGINS: >-
clickhouse clickhouse-monitoring frontend-design orchestration
prompt-engineering unsloth-training duyetbot github good-html anyrouter
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout source (codex-claude-plugins)
# actions/checkout v4.2.2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: source
fetch-depth: 1
persist-credentials: false
- name: Checkout target (duyet/skills)
# actions/checkout v4.2.2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
repository: duyet/skills
path: target
token: ${{ secrets.SKILLS_SYNC_TOKEN }}
fetch-depth: 0
- name: Flatten plugin skills into target layout
id: flatten
run: |
set -euo pipefail
cd source
# Collect target skill dirs we are about to replace, so we
# can prune them cleanly before copying fresh content.
declare -a TARGET_SKILLS=()
for plugin in $SOURCE_PLUGINS; do
if [ -f "$plugin/SKILL.md" ]; then
# Root-level SKILL.md (e.g. good-html). Use plugin name.
TARGET_SKILLS+=("$plugin")
elif [ -d "$plugin/skills" ]; then
while IFS= read -r -d '' dir; do
TARGET_SKILLS+=("$(basename "$dir")")
done < <(find "$plugin/skills" -mindepth 2 -maxdepth 2 \
-name SKILL.md -printf '%h\0')
fi
done
echo "Refreshing: ${TARGET_SKILLS[*]}"
# Remove existing copies so deletions propagate.
for name in "${TARGET_SKILLS[@]}"; do
rm -rf "../target/$name"
done
# Copy each skill dir flat into the target.
for plugin in $SOURCE_PLUGINS; do
if [ -f "$plugin/SKILL.md" ]; then
mkdir -p "../target/$plugin"
cp "$plugin/SKILL.md" "../target/$plugin/SKILL.md"
for extra in assets references reference rules; do
if [ -d "$plugin/$extra" ]; then
cp -r "$plugin/$extra" "../target/$plugin/$extra"
fi
done
elif [ -d "$plugin/skills" ]; then
while IFS= read -r -d '' dir; do
name="$(basename "$dir")"
cp -r "$dir" "../target/$name"
done < <(find "$plugin/skills" -mindepth 2 -maxdepth 2 \
-name SKILL.md -printf '%h\0')
fi
done
sha="$(git rev-parse HEAD)"
{
echo "source_sha=$sha"
echo "source_short=$(git rev-parse --short HEAD)"
} >> "$GITHUB_OUTPUT"
- name: Detect changes
id: diff
working-directory: target
run: |
set -euo pipefail
git add -A
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No skill changes to sync."
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Changed files:"
git diff --cached --name-status
fi
- name: Open PR on duyet/skills
if: steps.diff.outputs.changed == 'true'
working-directory: target
env:
GH_TOKEN: ${{ secrets.SKILLS_SYNC_TOKEN }}
SOURCE_SHA: ${{ steps.flatten.outputs.source_sha }}
SHORT: ${{ steps.flatten.outputs.source_short }}
run: |
set -euo pipefail
BRANCH="sync/codex-${SHORT}"
MSG="chore: sync skills from codex-claude-plugins@${SHORT}"
git config user.name "duyetbot"
git config user.email "bot@duyet.net"
git checkout -b "$BRANCH"
git commit -m "$MSG"
git push -u origin "$BRANCH" --force-with-lease
LINK="https://github.com/duyet/codex-claude-plugins"
DIFF="$(git diff --name-status HEAD~1 2>/dev/null || \
git show --stat HEAD)"
# shellcheck disable=SC2016
BODY=$(printf '%s\n\n%s\n\n%s\n\n```\n%s\n```\n' \
"Automated sync from [${SHORT}](${LINK}/commit/${SOURCE_SHA})." \
"Triggered by \`${GITHUB_EVENT_NAME}\` on ${GITHUB_REF}." \
"Changed files:" \
"$DIFF")
# Reuse existing PR for this branch if one is already open.
existing="$(gh pr list --head "$BRANCH" --state open \
--json number --jq '.[0].number' || true)"
if [ -n "$existing" ]; then
gh pr edit "$existing" --body "$BODY"
else
gh pr create --base master --head "$BRANCH" \
--title "Sync skills from codex@${SHORT}" --body "$BODY"
fi