Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions .github/workflows/regenerate_models.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# This workflow regenerates Pydantic models (src/apify_client/_models.py) from the OpenAPI spec whenever
# the spec changes in a apify/apify-docs PR. It is triggered via workflow_dispatch from the apify-docs CI pipeline.

name: Regenerate models from OpenAPI spec

on:
workflow_dispatch:
inputs:
docs_pr_number:
description: PR number in apify/apify-docs that triggered this workflow
required: true
type: string
docs_pr_sha:
description: Commit SHA from the apify/apify-docs PR
required: true
type: string

permissions:
contents: write
pull-requests: write

concurrency:
group: regenerate-models-${{ inputs.docs_pr_number }}
cancel-in-progress: true

jobs:
regenerate-models:
name: Regenerate models
runs-on: ubuntu-latest

env:
GITHUB_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
DOCS_PR_NUMBER: ${{ inputs.docs_pr_number }}
DOCS_PR_SHA: ${{ inputs.docs_pr_sha }}

steps:
- name: Validate inputs
run: |
if ! [[ "$DOCS_PR_NUMBER" =~ ^[0-9]+$ ]]; then
echo "::error::docs_pr_number must be a positive integer, got: $DOCS_PR_NUMBER"
exit 1
fi
if ! [[ "$DOCS_PR_SHA" =~ ^[a-f0-9]{40}$ ]]; then
echo "::error::docs_pr_sha must be a 40-character hex SHA, got: $DOCS_PR_SHA"
exit 1
fi

- name: Checkout apify-client-python
uses: actions/checkout@v6

- name: Checkout apify-docs at PR commit
uses: actions/checkout@v6
with:
repository: apify/apify-docs
ref: ${{ inputs.docs_pr_sha }}
path: apify-docs
token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}

- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: apify-docs/package-lock.json

# Build the bundled OpenAPI JSON from the docs repo sources. This requires Node.js because the spec
# is assembled by the docs build tooling.
- name: Build OpenAPI spec bundle
run: |
cd apify-docs
corepack enable
npm ci --force
npm run openapi:build:json
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Set up uv
uses: astral-sh/setup-uv@v6

# We call datamodel-codegen with --input pointing at the locally built spec.
- name: Generate models from local spec
run: uv run datamodel-codegen --input apify-docs/static/api/openapi.json

- name: Check for changes
id: changes
run: |
if git diff --exit-code src/apify_client/_models.py; then
echo "No changes in generated models"
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "Models have changed"
echo "changed=true" >> "$GITHUB_OUTPUT"
fi

- name: Configure git
if: steps.changes.outputs.changed == 'true'
run: |
git config user.name "apify-service-account"
git config user.email "apify-service-account@users.noreply.github.com"

- name: Create or update PR
if: steps.changes.outputs.changed == 'true'
id: pr
run: |
BRANCH="update-models-docs-pr-${DOCS_PR_NUMBER}"
DOCS_PR_URL="https://github.com/apify/apify-docs/pull/${DOCS_PR_NUMBER}"
TITLE="[TODO]: update generated models from apify-docs PR #${DOCS_PR_NUMBER}"

# -B creates the branch or resets it if it already exists (re-runs for the same docs PR).
git checkout -B "$BRANCH"
git add src/apify_client/_models.py
git commit -m "$TITLE"
git push --force origin "$BRANCH"

EXISTING_PR=$(gh pr list --head "$BRANCH" --json url --jq '.[0].url' 2>/dev/null || true)

if [ -n "$EXISTING_PR" ]; then
echo "PR already exists: $EXISTING_PR"
echo "pr_url=$EXISTING_PR" >> "$GITHUB_OUTPUT"
echo "created=false" >> "$GITHUB_OUTPUT"
else
BODY=$(cat <<EOF
This PR updates the auto-generated Pydantic models based on OpenAPI specification changes in [apify-docs PR #${DOCS_PR_NUMBER}](${DOCS_PR_URL}).

## Changes

- Regenerated \`src/apify_client/_models.py\` using \`datamodel-codegen\`

## Source

- apify-docs PR: ${DOCS_PR_URL}
EOF
)

PR_URL=$(gh pr create \
--title "$TITLE" \
--body "$BODY" \
--head "$BRANCH" \
--base master)
echo "Created PR: $PR_URL"
echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT"
echo "created=true" >> "$GITHUB_OUTPUT"
fi

# Post a cross-repo comment on the original docs PR so reviewers know about the corresponding client-python PR.
- name: Comment on apify-docs PR
if: steps.changes.outputs.changed == 'true'
env:
PR_CREATED: ${{ steps.pr.outputs.created }}
PR_URL: ${{ steps.pr.outputs.pr_url }}
run: |
if [ "$PR_CREATED" = "true" ]; then
COMMENT="A PR to update the Python client models has been created: ${PR_URL}

This was automatically triggered by OpenAPI specification changes in this PR."
else
COMMENT="The Python client model PR has been updated with the latest OpenAPI spec changes: ${PR_URL}"
fi

gh pr comment "$DOCS_PR_NUMBER" \
--repo apify/apify-docs \
--body "$COMMENT"

- name: Comment on failure
if: failure()
run: |
gh pr comment "$DOCS_PR_NUMBER" \
--repo apify/apify-docs \
--body "Python client model regeneration failed. [See workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})."
Loading