Skip to content

Pydantic AI Release Watcher #112

Pydantic AI Release Watcher

Pydantic AI Release Watcher #112

name: Pydantic AI Release Watcher
on:
schedule:
- cron: '0 9 * * *' # Every day at 9am UTC
workflow_dispatch:
inputs:
force:
description: 'Force create issue even if version unchanged'
required: false
default: 'false'
jobs:
check-release:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Fetch latest pydantic-ai version
id: fetch-version
run: |
LATEST=$(curl -fsSL https://pypi.org/pypi/pydantic-ai/json | python3 -c "import sys,json; print(json.load(sys.stdin)['info']['version'])")
echo "latest=$LATEST" >> "$GITHUB_OUTPUT"
echo "Latest pydantic-ai version: $LATEST"
- name: Read stored version
id: stored-version
run: |
STORED=$(cat .github/pydantic-ai-version.txt | tr -d '[:space:]')
echo "stored=$STORED" >> "$GITHUB_OUTPUT"
echo "Stored version: $STORED"
- name: Check for new release and duplicates
id: check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LATEST="${{ steps.fetch-version.outputs.latest }}"
STORED="${{ steps.stored-version.outputs.stored }}"
FORCE="${{ github.event.inputs.force }}"
if [[ "$LATEST" == "$STORED" && "$FORCE" != "true" ]]; then
echo "No new release (still $LATEST). Exiting."
echo "should_run=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "New release detected: $STORED -> $LATEST"
# Check for existing open issue for this version
EXISTING=$(gh api "repos/${{ github.repository }}/issues?state=open&labels=pydantic-ai-update" \
--jq ".[] | select(.title | contains(\"v${LATEST}\")) | .number" 2>/dev/null | head -1)
if [[ -n "$EXISTING" ]]; then
echo "Issue already exists for v${LATEST}: #${EXISTING} — skipping."
echo "should_run=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "should_run=true" >> "$GITHUB_OUTPUT"
- name: Analyze release
if: steps.check.outputs.should_run == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
OLD="${{ steps.stored-version.outputs.stored }}"
NEW="${{ steps.fetch-version.outputs.latest }}"
chmod +x .github/scripts/analyze-pydantic-release.sh
.github/scripts/analyze-pydantic-release.sh "$OLD" "$NEW" > /tmp/release-summary.md
- name: Create issue and assign Copilot
if: steps.check.outputs.should_run == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
OLD="${{ steps.stored-version.outputs.stored }}"
NEW="${{ steps.fetch-version.outputs.latest }}"
OLD="$OLD" \
NEW_VERSION="$NEW" \
SUMMARY="$(cat /tmp/release-summary.md)" \
python3 .github/scripts/create-issue-body.py
RESPONSE=$(gh api repos/${{ github.repository }}/issues \
--method POST \
--field title="chore: port pydantic-ai v${NEW} changes" \
--field body=@/tmp/issue-body.md \
--field labels[]="pydantic-ai-update")
ISSUE_NUMBER=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['number'])")
ISSUE_URL=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['html_url'])")
echo "Opened issue: $ISSUE_URL"
# Assign Copilot via GraphQL using PAT (GITHUB_TOKEN lacks bot-assignee permission)
ISSUE_NODE_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['node_id'])")
GH_TOKEN=${{ secrets.VIBES_GH_PAT }} gh api graphql -f query="
mutation {
addAssigneesToAssignable(input: {
assignableId: \"${ISSUE_NODE_ID}\",
assigneeIds: [\"BOT_kgDOC9w8XQ\"]
}) {
assignable { ... on Issue { number assignees(first: 3) { nodes { login } } } }
}
}
"