Files
copilotkit__copilotkit/.github/workflows/vscode-extension-changelog-sync.yml

201 lines
8.1 KiB
YAML

name: VS Code Extension — Metadata Sync
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "packages/vscode-extension/CHANGELOG.md"
- "packages/vscode-extension/README.md"
concurrency:
group: changelog-sync-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: read
jobs:
sync:
runs-on: ubuntu-latest
# Don't run on forks — GITHUB_TOKEN can't push to fork PR branches
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Checkout PR head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Extract top CHANGELOG version
id: changelog
run: |
set -euo pipefail
FILE=packages/vscode-extension/CHANGELOG.md
# Match lines like: "## 0.1.1 — 2026-04-22" (em-dash, en-dash, or ASCII hyphen)
TOP=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+/ { print; exit }' "$FILE")
if [ -z "$TOP" ]; then
echo "::error file=$FILE::No valid '## X.Y.Z — DATE' heading found"
exit 1
fi
VERSION=$(echo "$TOP" | grep -oE '^## [0-9]+\.[0-9]+\.[0-9]+' | sed 's/^## //')
if [ -z "$VERSION" ]; then
echo "::error file=$FILE::Could not parse semver from top heading: $TOP"
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Top CHANGELOG version: $VERSION"
- name: Compare with package.json
id: compare
run: |
set -euo pipefail
PJ=packages/vscode-extension/package.json
CURRENT=$(jq -r '.version' "$PJ")
TARGET=${{ steps.changelog.outputs.version }}
echo "package.json: $CURRENT"
echo "changelog: $TARGET"
# Compare via sort -V (semver-ish)
newest=$(printf '%s\n%s\n' "$CURRENT" "$TARGET" | sort -V | tail -1)
if [ "$CURRENT" = "$TARGET" ]; then
echo "status=in-sync" >> "$GITHUB_OUTPUT"
elif [ "$newest" = "$TARGET" ] && [ "$CURRENT" != "$TARGET" ]; then
echo "status=bump-needed" >> "$GITHUB_OUTPUT"
else
echo "::error file=$PJ::CHANGELOG top version ($TARGET) is lower than package.json ($CURRENT). Did you edit CHANGELOG history instead of prepending?"
exit 1
fi
- name: Extract README description
id: readme
run: |
set -euo pipefail
README=packages/vscode-extension/README.md
if [ ! -f "$README" ]; then
echo "README not found; skipping description extraction"
echo "status=missing" >> "$GITHUB_OUTPUT"
exit 0
fi
SCRIPT=$(mktemp)
cat > "$SCRIPT" <<'PY'
import re, sys
path = sys.argv[1]
with open(path) as f:
md = f.read()
lines = md.splitlines()
i = 0
while i < len(lines) and not re.match(r'^#\s+\S', lines[i]):
i += 1
if i >= len(lines):
sys.stderr.write("ERROR: no H1 title found in README\n")
sys.exit(2)
i += 1
while i < len(lines) and lines[i].strip() == "":
i += 1
if i >= len(lines) or lines[i].lstrip().startswith("#"):
sys.stderr.write("ERROR: no description paragraph after H1 title\n")
sys.exit(2)
para = []
while i < len(lines) and lines[i].strip() != "" and not lines[i].lstrip().startswith("#"):
para.append(lines[i].strip())
i += 1
p = " ".join(para)
p = re.sub(r'!\[([^\]]*)\]\([^)]*\)', r'\1', p)
p = re.sub(r'\[([^\]]+)\]\([^)]*\)', r'\1', p)
p = re.sub(r'`([^`]+)`', r'\1', p)
p = re.sub(r'\*\*([^*]+)\*\*', r'\1', p)
p = re.sub(r'\*([^*]+)\*', r'\1', p)
p = re.sub(r'__([^_]+)__', r'\1', p)
p = re.sub(r'_([^_]+)_', r'\1', p)
p = re.sub(r'\s+', ' ', p).strip()
if not p:
sys.stderr.write("ERROR: empty description paragraph after stripping markdown\n")
sys.exit(2)
if len(p) > 200:
sys.stderr.write(f"ERROR: description too long ({len(p)} chars > 200). Shorten the first paragraph of README.md.\n")
sys.exit(2)
sys.stdout.write(p)
PY
DESC=$(python3 "$SCRIPT" "$README")
echo "description<<__README_EOF__" >> "$GITHUB_OUTPUT"
echo "$DESC" >> "$GITHUB_OUTPUT"
echo "__README_EOF__" >> "$GITHUB_OUTPUT"
echo "status=extracted" >> "$GITHUB_OUTPUT"
echo "Extracted description (${#DESC} chars): $DESC"
- name: Compare with package.json description
id: compare_desc
if: steps.readme.outputs.status == 'extracted'
env:
TARGET_DESC: ${{ steps.readme.outputs.description }}
run: |
set -euo pipefail
PJ=packages/vscode-extension/package.json
CURRENT=$(jq -r '.description' "$PJ")
if [ "$CURRENT" = "$TARGET_DESC" ]; then
echo "status=description-ok" >> "$GITHUB_OUTPUT"
echo "Description already in sync"
else
echo "status=description-sync-needed" >> "$GITHUB_OUTPUT"
echo "Description drift detected:"
echo " package.json: $CURRENT"
echo " README: $TARGET_DESC"
fi
- name: Bump package.json and commit
if: steps.compare.outputs.status == 'bump-needed' || steps.compare_desc.outputs.status == 'description-sync-needed'
env:
TARGET: ${{ steps.changelog.outputs.version }}
TARGET_DESC: ${{ steps.readme.outputs.description }}
VERSION_STATUS: ${{ steps.compare.outputs.status }}
DESC_STATUS: ${{ steps.compare_desc.outputs.status }}
run: |
set -euo pipefail
PJ=packages/vscode-extension/package.json
# Apply version bump if needed
if [ "$VERSION_STATUS" = "bump-needed" ]; then
jq --arg v "$TARGET" '.version = $v' "$PJ" > "$PJ.tmp"
mv "$PJ.tmp" "$PJ"
fi
# Apply description sync if needed
if [ "$DESC_STATUS" = "description-sync-needed" ]; then
jq --arg d "$TARGET_DESC" '.description = $d' "$PJ" > "$PJ.tmp"
mv "$PJ.tmp" "$PJ"
fi
# Priority rule: version bump wins the commit message
if [ "$VERSION_STATUS" = "bump-needed" ]; then
MSG="chore: release v$TARGET"
elif [ "$DESC_STATUS" = "description-sync-needed" ]; then
MSG="chore(vscode-extension): sync description from README"
else
echo "Nothing to commit"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add "$PJ"
git commit -m "$MSG"
git push origin HEAD:${{ github.event.pull_request.head.ref }}
- name: Summary
run: |
echo "### Metadata sync result" >> $GITHUB_STEP_SUMMARY
echo "- CHANGELOG top version: \`${{ steps.changelog.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
echo "- Version status: \`${{ steps.compare.outputs.status }}\`" >> $GITHUB_STEP_SUMMARY
echo "- README status: \`${{ steps.readme.outputs.status }}\`" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.readme.outputs.status }}" = "extracted" ]; then
echo "- Description status: \`${{ steps.compare_desc.outputs.status }}\`" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ steps.compare.outputs.status }}" = "bump-needed" ]; then
echo "- Auto-committed \`chore: release v${{ steps.changelog.outputs.version }}\` to this PR branch." >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.compare_desc.outputs.status }}" = "description-sync-needed" ]; then
echo "- Auto-committed \`chore(vscode-extension): sync description from README\` to this PR branch." >> $GITHUB_STEP_SUMMARY
fi