Skip to content

Regenerate models

Regenerate models #22

# This workflow regenerates Pydantic models (src/apify_client/_models.py) from the OpenAPI spec.
#
# It can be triggered in two ways:
# 1. Automatically via workflow_dispatch from the apify-docs CI pipeline (with docs_pr_number and docs_workflow_run_id).
# 2. Manually from the GitHub UI (without any inputs) to regenerate from the live published spec.
name: Regenerate models
on:
workflow_dispatch:
inputs:
docs_pr_number:
description: PR number in apify/apify-docs that triggered this workflow (optional for manual runs)
required: false
type: string
docs_workflow_run_id:
description: Workflow run ID in apify/apify-docs that built the OpenAPI spec artifact (optional for manual runs)
required: false
type: string
docs_pr_author:
description: GitHub login of the apify-docs PR author (optional for manual runs)
required: false
type: string
permissions:
contents: write
pull-requests: write
concurrency:
group: regenerate-models-${{ inputs.docs_pr_number || 'manual' }}
cancel-in-progress: true
jobs:
regenerate-models:
name: Regenerate models
runs-on: ubuntu-latest
env:
DOCS_PR_NUMBER: ${{ inputs.docs_pr_number }}
BRANCH: ${{ inputs.docs_pr_number && format('update-models-docs-pr-{0}', inputs.docs_pr_number) || 'update-models-manual' }}
TITLE: "${{ inputs.docs_pr_number && format('[TODO]: update generated models from apify-docs PR #{0}', inputs.docs_pr_number) || '[TODO]: update generated models from published OpenAPI spec' }}"
ASSIGNEE: ${{ inputs.docs_pr_author || github.actor }}
REVIEWER: vdusek
LABEL: t-tooling
steps:
- name: Validate inputs
if: inputs.docs_pr_number || inputs.docs_workflow_run_id
run: |
if [[ -n "$DOCS_PR_NUMBER" ]] && ! [[ "$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 [[ -n "${{ inputs.docs_workflow_run_id }}" ]] && ! [[ "${{ 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 }}
# If the branch already exists on the remote (e.g. from a previous run, possibly with
# reviewer commits), check it out to build on top of it instead of starting fresh.
- name: Switch to existing branch or create a new one
run: |
if git ls-remote --exit-code --heads origin "$BRANCH" > /dev/null 2>&1; then
git fetch origin "$BRANCH"
git switch "$BRANCH"
else
git switch -c "$BRANCH"
fi
# Download the pre-built OpenAPI spec artifact from the apify-docs workflow run.
# Skipped for manual runs — datamodel-codegen will fetch from the published spec URL instead.
- name: Download OpenAPI spec artifact
if: inputs.docs_workflow_run_id
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
# When a docs workflow run ID is provided, use the downloaded artifact.
# Otherwise, datamodel-codegen fetches from the default URL configured in pyproject.toml.
- name: Generate models from OpenAPI spec
run: |
if [[ -f openapi-spec/openapi.json ]]; then
uv run poe generate-models-from-file openapi-spec/openapi.json
else
uv run poe generate-models
fi
- name: Commit and push model changes
id: commit
uses: EndBug/add-and-commit@v10
with:
add: src/apify_client/_models.py
author_name: apify-service-account
author_email: apify-service-account@users.noreply.github.com
message: ${{ env.TITLE }}
commit: --no-verify
push: -u origin ${{ env.BRANCH }}
- name: Create or update PR
if: steps.commit.outputs.committed == 'true'
id: pr
env:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
run: |
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
if [[ -n "$DOCS_PR_NUMBER" ]]; then
DOCS_PR_URL="https://github.com/apify/apify-docs/pull/${DOCS_PR_NUMBER}"
BODY="This PR updates the auto-generated Pydantic models based on OpenAPI specification changes in [apify-docs PR #${DOCS_PR_NUMBER}](${DOCS_PR_URL})."
else
BODY="This PR updates the auto-generated Pydantic models from the [published OpenAPI specification](https://docs.apify.com/api/openapi.json)."
fi
PR_URL=$(gh pr create \
--title "$TITLE" \
--body "$BODY" \
--head "$BRANCH" \
--base master \
--reviewer "$REVIEWER" \
--assignee "$ASSIGNEE" \
--label "$LABEL")
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.commit.outputs.committed == 'true' && inputs.docs_pr_number
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() && inputs.docs_pr_number
env:
GH_TOKEN: ${{ secrets.APIFY_SERVICE_ACCOUNT_GITHUB_TOKEN }}
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 }})." \
|| echo "Warning: Failed to post failure comment to apify/apify-docs PR #$DOCS_PR_NUMBER."