name: Stable release on: # Runs when manually triggered from the GitHub UI, with options to specify the type of release. workflow_dispatch: inputs: release_type: description: Release type required: true type: choice default: auto options: - auto - custom - patch - minor - major custom_version: description: The custom version to bump to (only for "custom" type) required: false type: string default: "" concurrency: group: release cancel-in-progress: false permissions: contents: read jobs: code_checks: name: Code checks uses: ./.github/workflows/_check_code.yaml release_prepare: name: Release prepare needs: [code_checks] runs-on: ubuntu-latest outputs: version_number: ${{ steps.release_prepare.outputs.version_number }} tag_name: ${{ steps.release_prepare.outputs.tag_name }} changelog: ${{ steps.release_prepare.outputs.changelog }} release_notes: ${{ steps.release_prepare.outputs.release_notes }} steps: - uses: apify/actions/git-cliff-release@v1.1.2 name: Release prepare id: release_prepare with: release_type: ${{ inputs.release_type }} custom_version: ${{ inputs.custom_version }} existing_changelog_path: CHANGELOG.md changelog_update: name: Changelog update needs: [release_prepare] permissions: contents: write uses: apify/workflows/.github/workflows/python_bump_and_update_changelog.yaml@main with: version_number: ${{ needs.release_prepare.outputs.version_number }} changelog: ${{ needs.release_prepare.outputs.changelog }} secrets: inherit github_release: name: GitHub release needs: [release_prepare, changelog_update] runs-on: ubuntu-latest permissions: contents: write env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: GitHub release uses: softprops/action-gh-release@v2 with: tag_name: ${{ needs.release_prepare.outputs.tag_name }} name: ${{ needs.release_prepare.outputs.version_number }} target_commitish: ${{ needs.changelog_update.outputs.changelog_commitish }} body: ${{ needs.release_prepare.outputs.release_notes }} pypi_publish: name: PyPI publish needs: [release_prepare, changelog_update] runs-on: ubuntu-latest permissions: contents: write id-token: write # Required for OIDC authentication. environment: name: pypi url: https://pypi.org/project/crawlee steps: - name: Prepare distribution uses: apify/actions/prepare-pypi-distribution@v1.1.2 with: package_name: crawlee is_prerelease: "" version_number: ${{ needs.release_prepare.outputs.version_number }} ref: ${{ needs.changelog_update.outputs.changelog_commitish }} - name: Verify built package uses: apify/actions/python-package-check@v1.1.0 with: package_name: crawlee dist_dir: dist python_version: "3.14" extras: all smoke_code: | from crawlee.crawlers import ( HttpCrawler, BeautifulSoupCrawler, ParselCrawler, PlaywrightCrawler, AdaptivePlaywrightCrawler, ) from crawlee.storages import Dataset, KeyValueStore, RequestQueue from crawlee.http_clients import HttpxHttpClient, ImpitHttpClient from crawlee import Request HttpCrawler() BeautifulSoupCrawler() ParselCrawler() # Publish the package to PyPI using PyPA official GitHub action with OIDC authentication. - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 # TODO: add job for publish package to Conda # https://github.com/apify/crawlee-python/issues/104 version_docs: name: Version docs needs: [release_prepare, changelog_update, pypi_publish] permissions: contents: write uses: ./.github/workflows/manual_version_docs.yaml with: # Pass the bumped version explicitly — the job's checkout uses the dispatch ref (pre-bump), # so `uv version --short` from pyproject.toml would return the old version. version_number: ${{ needs.release_prepare.outputs.version_number }} secrets: inherit doc_release: name: Doc release needs: [changelog_update, pypi_publish, version_docs] permissions: contents: write pages: write id-token: write uses: ./.github/workflows/manual_release_docs.yaml secrets: inherit