diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml deleted file mode 100644 index 26c511b1..00000000 --- a/.github/workflows/create-release.yml +++ /dev/null @@ -1,104 +0,0 @@ -name: Create GitHub Release - -on: - workflow_dispatch: - inputs: - branch: - description: 'Branch to release from' - required: true - default: 'beta' - workflow_run: - workflows: ['Test PR'] - types: [completed] - branches: ['main', 'beta', 'httpx'] - -# The release is created with a GitHub App token. This workflow no longer -# commits anything back to the branch (the changelog is rendered in the -# regeneration PR), so the default token only needs read access for checkout. -permissions: - contents: read - -jobs: - create-release: - if: github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch || github.event.workflow_run.head_branch }} - - - name: Generate app token - id: app-token - uses: actions/create-github-app-token@v3 - with: - app-id: ${{ secrets.RELEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - - - name: Read version - id: version - run: | - VERSION=$(grep '^version' pyproject.toml | sed 's/version = "\(.*\)"/\1/') - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - if [[ "$VERSION" == *"b"* || "$VERSION" == *"rc"* || "$VERSION" == *"a"* ]]; then - echo "prerelease=true" >> "$GITHUB_OUTPUT" - else - echo "prerelease=false" >> "$GITHUB_OUTPUT" - fi - - - name: Check if release already exists - id: check-release - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION="${{ steps.version.outputs.version }}" - if gh release view "$VERSION" > /dev/null 2>&1; then - echo "Release $VERSION already exists, skipping." - echo "exists=true" >> "$GITHUB_OUTPUT" - else - echo "exists=false" >> "$GITHUB_OUTPUT" - fi - - - name: Validate version matches branch - if: steps.check-release.outputs.exists == 'false' - run: | - BRANCH="${{ inputs.branch || github.event.workflow_run.head_branch }}" - VERSION="${{ steps.version.outputs.version }}" - PRERELEASE="${{ steps.version.outputs.prerelease }}" - - if [[ "$BRANCH" == "beta" && "$PRERELEASE" == "false" ]]; then - echo "::error::Beta branch must have a prerelease version (e.g. 3.1.0b0), got '$VERSION'" - exit 1 - fi - - if [[ "$BRANCH" == "httpx" && "$PRERELEASE" == "false" ]]; then - echo "::error::httpx branch must have a prerelease version (e.g. 4.0.0b1), got '$VERSION'" - exit 1 - fi - - if [[ "$BRANCH" == "main" && "$PRERELEASE" == "true" ]]; then - echo "::error::Main branch must not have a prerelease version, got '$VERSION'" - exit 1 - fi - - # CHANGELOG.md is rendered from changelog.d/ fragments inside the - # regeneration PR (see regenerate-library.yml), so it is already on the - # branch by the time the release is cut. Committing/pushing here would - # bypass the branch's required status checks and be rejected by the - # ruleset, so no git write happens in this workflow. --generate-notes - # below produces the GitHub release body. - - name: Create release - if: steps.check-release.outputs.exists == 'false' - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - FLAGS="" - if [ "${{ steps.version.outputs.prerelease }}" = "true" ]; then - FLAGS="--prerelease" - fi - - gh release create "${{ steps.version.outputs.version }}" \ - --target "${{ inputs.branch || github.event.workflow_run.head_branch }}" \ - --title "${{ steps.version.outputs.version }}" \ - --generate-notes \ - $FLAGS diff --git a/.github/workflows/enable-early-access.yml b/.github/workflows/enable-early-access.yml deleted file mode 100644 index 2814c64f..00000000 --- a/.github/workflows/enable-early-access.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Enable early access features - -on: - workflow_dispatch: - schedule: - - cron: '0 18 * * 3' - -permissions: - contents: read - -jobs: - enable-early-access: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Install uv - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - - - name: Set up Python - run: uv python install 3.13 - - - name: Install dependencies - run: uv sync --python 3.13 - - - name: Enable all early access features - env: - MERAKI_DASHBOARD_API_KEY: ${{ secrets.TEST_ORG_API_KEY }} - EA_ORG_0: ${{ secrets.TEST_ORG_BETA_00_ID }} - EA_ORG_1: ${{ secrets.TEST_ORG_BETA_01_ID }} - EA_ORG_2: ${{ secrets.TEST_ORG_BETA_02_ID }} - EA_ORG_3: ${{ secrets.TEST_ORG_BETA_03_ID }} - EA_ORG_4: ${{ secrets.TEST_ORG_DEV_00_ID }} - EA_ORG_5: ${{ secrets.TEST_ORG_DEV_01_ID }} - EA_ORG_6: ${{ secrets.TEST_ORG_DEV_02_ID }} - EA_ORG_7: ${{ secrets.TEST_ORG_DEV_03_ID }} - run: uv run python examples/ci/enable_all_early_access.py diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml deleted file mode 100644 index fabf50c7..00000000 --- a/.github/workflows/publish-release.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Publish release to PyPI -on: - release: - types: [created] - workflow_dispatch: - inputs: - tag: - description: 'Release tag to publish (e.g. 3.1.0b0)' - required: true - -permissions: - id-token: write - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.tag || github.event.release.tag_name }} - - - name: Install uv - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - - - name: Set up Python - run: uv python install 3.13 - - - name: Build package - run: uv build - - - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/regenerate-library.yml b/.github/workflows/regenerate-library.yml deleted file mode 100644 index 4b73b6c5..00000000 --- a/.github/workflows/regenerate-library.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: Regenerate Python Library -on: - workflow_dispatch: - inputs: - library_version: - description: 'The version of the new library' - required: true - api_version: - description: 'The corresponding version of the API' - required: true - release_stage: - description: 'Release stage' - required: true - type: choice - options: - - ga - - beta - - dev - -# Writes (commit, PR, auto-merge) are performed with a GitHub App token, not -# GITHUB_TOKEN, so the default token only needs read access for checkout. -permissions: - contents: read - -jobs: - regenerate: - runs-on: ubuntu-latest - steps: - - name: Resolve branches - id: branches - run: | - case "${{ github.event.inputs.release_stage }}" in - dev) - echo "checkout_branch=httpx" >> "$GITHUB_OUTPUT" - echo "release_branch=httpx-release" >> "$GITHUB_OUTPUT" - echo "pr_base=httpx" >> "$GITHUB_OUTPUT" - ;; - beta) - echo "checkout_branch=beta" >> "$GITHUB_OUTPUT" - echo "release_branch=beta-release" >> "$GITHUB_OUTPUT" - echo "pr_base=beta" >> "$GITHUB_OUTPUT" - ;; - ga) - echo "checkout_branch=main" >> "$GITHUB_OUTPUT" - echo "release_branch=release" >> "$GITHUB_OUTPUT" - echo "pr_base=main" >> "$GITHUB_OUTPUT" - ;; - esac - - # Generate the App token before checkout so checkout persists *it* (not the - # read-only GITHUB_TOKEN) as the git credential used for the later push. - - name: Generate app token - id: app-token - uses: actions/create-github-app-token@v3 - with: - app-id: ${{ secrets.RELEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - - - uses: actions/checkout@v6 - with: - ref: ${{ steps.branches.outputs.checkout_branch }} - # Persist the App token (write access) so EndBug/add-and-commit can push. - # add-and-commit does NOT set up push auth from its github_token input — - # it relies on whatever credential checkout wrote to git config. - token: ${{ steps.app-token.outputs.token }} - - - name: Install uv - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true - - - name: Set up Python - run: uv python install 3.13 - - - name: Install dependencies - run: uv sync --group generator - - - name: Delete folder - run: rm -rf meraki - - - name: Regenerate Python Library - env: - LIBRARY_VERSION: ${{ github.event.inputs.library_version }} - API_VERSION: ${{ github.event.inputs.api_version }} - MERAKI_DASHBOARD_API_KEY: ${{ (github.event.inputs.release_stage == 'beta' || github.event.inputs.release_stage == 'dev') && secrets.TEST_ORG_API_KEY || '' }} - BETA_ORG_ID: ${{ (github.event.inputs.release_stage == 'beta' || github.event.inputs.release_stage == 'dev') && secrets.TEST_ORG_BETA_00_ID || '' }} - run: | - ARGS="-g true -v $LIBRARY_VERSION -a $API_VERSION" - if [ "${{ github.event.inputs.release_stage }}" = "dev" ]; then - ARGS="$ARGS -b httpx" - fi - if [ -n "$BETA_ORG_ID" ]; then - ARGS="$ARGS -o $BETA_ORG_ID" - fi - uv run python generator/generate_library.py $ARGS - - - name: Set new version - env: - LIBRARY_VERSION: ${{ github.event.inputs.library_version }} - run: | - sed -i "s/^version = \".*\"/version = \"$LIBRARY_VERSION\"/" pyproject.toml - uv lock - - # Render changelog.d/ fragments into CHANGELOG.md here so the update rides - # the regeneration PR (and its required checks) instead of being pushed - # straight to a protected branch later. towncrier is in the dev group, so - # `uv sync --group generator` (default-groups = dev) already installed it. - - name: Build changelog - env: - LIBRARY_VERSION: ${{ github.event.inputs.library_version }} - run: | - if ls changelog.d/*.md >/dev/null 2>&1; then - uv run towncrier build --yes --version "$LIBRARY_VERSION" - else - echo "No changelog fragments; skipping towncrier build." - fi - - - name: Commit changes to new branch - uses: EndBug/add-and-commit@v10 - with: - author_name: GitHub Action - author_email: support@meraki.com - message: Auto-generated library v${{ github.event.inputs.library_version }} for API v${{ github.event.inputs.api_version }}. - new_branch: ${{ steps.branches.outputs.release_branch }} - - - name: Create pull request - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - gh pr create \ - --base "${{ steps.branches.outputs.pr_base }}" \ - --head "${{ steps.branches.outputs.release_branch }}" \ - --title "Release v${{ github.event.inputs.library_version }} (API v${{ github.event.inputs.api_version }})" \ - --body "Auto-generated library v${{ github.event.inputs.library_version }} for API v${{ github.event.inputs.api_version }}." - - - name: Enable auto-merge - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - gh pr merge "${{ steps.branches.outputs.release_branch }}" \ - --auto --squash diff --git a/.github/workflows/watch-openapi-release.yml b/.github/workflows/watch-openapi-release.yml deleted file mode 100644 index 7c3e25e9..00000000 --- a/.github/workflows/watch-openapi-release.yml +++ /dev/null @@ -1,198 +0,0 @@ -name: Watch OpenAPI Releases - -on: - schedule: - - cron: '0 14 * * *' - workflow_dispatch: - -permissions: - contents: read - -jobs: - check-ga: - runs-on: ubuntu-latest - outputs: - has_new_release: ${{ steps.check.outputs.has_new_release }} - api_version: ${{ steps.check.outputs.api_version }} - new_sdk_version: ${{ steps.version.outputs.new_sdk_version }} - steps: - - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Get latest GA release - id: check - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - LATEST=$(gh release list --repo meraki/openapi --exclude-pre-releases --limit 1 --json tagName -q '.[0].tagName') - API_VERSION="${LATEST#v}" - # Reject anything that isn't a clean semver tag before it flows into - # downstream run: steps / workflow_dispatch inputs (script injection guard). - if ! [[ "$API_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then - echo "::error::Unexpected OpenAPI release tag: '$LATEST'" - exit 1 - fi - echo "api_version=$API_VERSION" >> "$GITHUB_OUTPUT" - - LAST_PROCESSED=$(cat .github/.last-openapi-ga-release 2>/dev/null || echo "") - if [ "$LATEST" = "$LAST_PROCESSED" ]; then - echo "has_new_release=false" >> "$GITHUB_OUTPUT" - else - echo "has_new_release=true" >> "$GITHUB_OUTPUT" - fi - - - name: Compute next SDK version - if: steps.check.outputs.has_new_release == 'true' - id: version - run: | - CURRENT=$(git show "origin/main:pyproject.toml" | grep '^version' | sed 's/version = "\(.*\)"/\1/') - BASE=$(echo "$CURRENT" | sed 's/\(a\|b\|rc\).*//') - IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" - NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" - echo "new_sdk_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" - - check-beta: - runs-on: ubuntu-latest - outputs: - has_new_release: ${{ steps.check.outputs.has_new_release }} - api_version: ${{ steps.check.outputs.api_version }} - new_sdk_version: ${{ steps.version.outputs.new_sdk_version }} - steps: - - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Get latest beta release - id: check - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - LATEST=$(gh release list --repo meraki/openapi --limit 20 --json tagName,isPrerelease -q '[.[] | select(.isPrerelease)] | .[0].tagName') - if [ -z "$LATEST" ]; then - echo "has_new_release=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - API_VERSION="${LATEST#v}" - # Reject anything that isn't a clean semver tag before it flows into - # downstream run: steps / workflow_dispatch inputs (script injection guard). - if ! [[ "$API_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then - echo "::error::Unexpected OpenAPI release tag: '$LATEST'" - exit 1 - fi - echo "api_version=$API_VERSION" >> "$GITHUB_OUTPUT" - - LAST_PROCESSED=$(cat .github/.last-openapi-beta-release 2>/dev/null || echo "") - if [ "$LATEST" = "$LAST_PROCESSED" ]; then - echo "has_new_release=false" >> "$GITHUB_OUTPUT" - else - echo "has_new_release=true" >> "$GITHUB_OUTPUT" - fi - - - name: Compute next SDK version - if: steps.check.outputs.has_new_release == 'true' - id: version - env: - API_VERSION: ${{ steps.check.outputs.api_version }} - run: | - CURRENT=$(git show "origin/beta:pyproject.toml" | grep '^version' | sed 's/version = "\(.*\)"/\1/') - - # Parse API version: e.g. "1.81.2-beta.3" -> minor=81, patch=2, beta=3 - API_MINOR=$(echo "$API_VERSION" | cut -d. -f2) - API_PATCH=$(echo "$API_VERSION" | cut -d. -f3 | sed 's/-.*//') - API_BETA=$(echo "$API_VERSION" | sed 's/.*beta\.\?//') - - LAST_TAG=$(cat .github/.last-openapi-beta-release 2>/dev/null || echo "") - LAST_API_MINOR=$(echo "$LAST_TAG" | sed 's/^v//' | cut -d. -f2) - - # Determine library minor: bump if API minor changed - BASE=$(echo "$CURRENT" | sed 's/\(a\|b\|rc\).*//') - IFS='.' read -r MAJOR LIB_MINOR LIB_PATCH <<< "$BASE" - - if [ "$API_MINOR" != "$LAST_API_MINOR" ]; then - LIB_MINOR=$((LIB_MINOR + 1)) - fi - - NEW_VERSION="${MAJOR}.${LIB_MINOR}.${API_PATCH}b${API_BETA}" - echo "new_sdk_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" - - trigger-ga: - needs: check-ga - if: needs.check-ga.outputs.has_new_release == 'true' - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v6 - - - name: Record processed release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_VERSION: ${{ needs.check-ga.outputs.api_version }} - run: | - echo "v$API_VERSION" > .github/.last-openapi-ga-release - git config user.name "GitHub Action" - git config user.email "support@meraki.com" - git add .github/.last-openapi-ga-release - git commit -m "Record processed GA release v$API_VERSION" - git push - - - name: Trigger regeneration - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh workflow run regenerate-library.yml \ - -f library_version="${{ needs.check-ga.outputs.new_sdk_version }}" \ - -f api_version="${{ needs.check-ga.outputs.api_version }}" \ - -f branch_name="release" \ - -f target_branch="main" - - trigger-beta: - needs: [check-beta, trigger-ga] - if: always() && needs.check-beta.outputs.has_new_release == 'true' - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v6 - - - name: Record processed release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - API_VERSION: ${{ needs.check-beta.outputs.api_version }} - run: | - echo "v$API_VERSION" > .github/.last-openapi-beta-release - git config user.name "GitHub Action" - git config user.email "support@meraki.com" - git add .github/.last-openapi-beta-release - git commit -m "Record processed beta release v$API_VERSION" - git push - - - name: Enable early access - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - BEFORE_ID=$(gh run list --workflow=enable-early-access.yml --limit=1 --json databaseId -q '.[0].databaseId') - gh workflow run enable-early-access.yml - - for i in $(seq 1 30); do - sleep 10 - NEW_ID=$(gh run list --workflow=enable-early-access.yml --limit=1 --json databaseId -q '.[0].databaseId') - if [ "$NEW_ID" != "$BEFORE_ID" ]; then - gh run watch "$NEW_ID" - exit 0 - fi - done - echo "Timed out waiting for enable-early-access run to appear" - exit 1 - - - name: Trigger regeneration - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh workflow run regenerate-library.yml \ - -f library_version="${{ needs.check-beta.outputs.new_sdk_version }}" \ - -f api_version="${{ needs.check-beta.outputs.api_version }}" \ - -f branch_name="beta-release" \ - -f target_branch="beta"