Skip to content
Open
Changes from all 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
168 changes: 168 additions & 0 deletions .github/workflows/regenerate_models.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# This workflow regenerates Pydantic models (src/apify_client/_models.py) from the OpenAPI spec whenever
# the spec changes in an 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_workflow_run_id:
description: Workflow run ID in apify/apify-docs that built the OpenAPI spec artifact
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:
DOCS_PR_NUMBER: ${{ inputs.docs_pr_number }}

steps:
- name: Validate inputs
run: |
if ! [[ "$DOCS_PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::docs_pr_number must be a positive integer, got: $DOCS_PR_NUMBER"
exit 1
fi
if ! [[ "${{ inputs.docs_workflow_run_id }}" =~ ^[0-9]+$ ]]; then
echo "::error::docs_workflow_run_id must be a numeric run ID, got: ${{ inputs.docs_workflow_run_id }}"
exit 1
fi

- name: Checkout apify-client-python
uses: actions/checkout@v6
with:
token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}

# Download the pre-built OpenAPI spec artifact from the apify-docs workflow run.
- name: Download OpenAPI spec artifact
uses: actions/download-artifact@v4
with:
name: openapi-bundles
path: openapi-spec
repository: apify/apify-docs
run-id: ${{ inputs.docs_workflow_run_id }}
github-token: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.14"

- name: Install dependencies
run: uv run poe install-dev

- name: Generate models from OpenAPI spec
run: uv run datamodel-codegen --input openapi-spec/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
env:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
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:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
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()
env:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
run: |
if [[ -z "$DOCS_PR_NUMBER" ]]; then
echo "DOCS_PR_NUMBER is not set; skipping failure comment on apify/apify-docs PR."
exit 0
fi

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 }})." \
|| echo "Warning: Failed to post failure comment to apify/apify-docs PR #$DOCS_PR_NUMBER."