diff --git a/.github/.release-please-manifest.json b/.github/.release-please-manifest.json new file mode 100644 index 00000000..d0f8c0ee --- /dev/null +++ b/.github/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.24.1" +} diff --git a/.github/release-please-config.json b/.github/release-please-config.json new file mode 100644 index 00000000..e9fbda4b --- /dev/null +++ b/.github/release-please-config.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "python", + "package-name": "google-adk", + "include-component-in-tag": false, + "skip-github-release": true, + "changelog-path": "CHANGELOG.md", + "changelog-sections": [ + {"type": "feat", "section": "Features"}, + {"type": "fix", "section": "Bug Fixes"}, + {"type": "perf", "section": "Performance Improvements"}, + {"type": "refactor", "section": "Code Refactoring"}, + {"type": "docs", "section": "Documentation"}, + {"type": "test", "section": "Tests", "hidden": true}, + {"type": "build", "section": "Build System", "hidden": true}, + {"type": "ci", "section": "CI/CD", "hidden": true}, + {"type": "style", "section": "Styles", "hidden": true}, + {"type": "chore", "section": "Miscellaneous Chores", "hidden": true} + ] + } + } +} diff --git a/.github/release-please.yml b/.github/release-please.yml deleted file mode 100644 index 65cfbe96..00000000 --- a/.github/release-please.yml +++ /dev/null @@ -1,5 +0,0 @@ -releaseType: python -handleGHRelease: true -bumpMinorPreMajor: false -extraFiles: - - src/google/adk/version.py \ No newline at end of file diff --git a/.github/release-trigger.yml b/.github/release-trigger.yml deleted file mode 100644 index 7fe36225..00000000 --- a/.github/release-trigger.yml +++ /dev/null @@ -1 +0,0 @@ -enabled: true \ No newline at end of file diff --git a/.github/workflows/release-cherry-pick.yml b/.github/workflows/release-cherry-pick.yml new file mode 100644 index 00000000..fd25f734 --- /dev/null +++ b/.github/workflows/release-cherry-pick.yml @@ -0,0 +1,46 @@ +# Cherry-picks a commit from main to the release/candidate branch. +# Use this to include bug fixes in an in-progress release. +name: "Release: Cherry-pick" + +on: + workflow_dispatch: + inputs: + commit_sha: + description: 'Commit SHA to cherry-pick' + required: true + type: string + +permissions: + contents: write + actions: write + +jobs: + cherry-pick: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: release/candidate + fetch-depth: 0 + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Cherry-pick commit + run: | + echo "Cherry-picking ${{ inputs.commit_sha }} to release/candidate" + git cherry-pick ${{ inputs.commit_sha }} + + - name: Push changes + run: | + git push origin release/candidate + echo "Successfully cherry-picked commit to release/candidate" + + - name: Trigger Release Please + env: + GH_TOKEN: ${{ github.token }} + run: | + gh workflow run release-please.yml --repo ${{ github.repository }} + echo "Triggered Release Please workflow" diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml new file mode 100644 index 00000000..3e8643b6 --- /dev/null +++ b/.github/workflows/release-cut.yml @@ -0,0 +1,46 @@ +# Starts the release process by creating a release/candidate branch. +# Triggers release-please to generate a changelog PR. +name: "Release: Cut" + +on: + workflow_dispatch: + inputs: + commit_sha: + description: 'Commit SHA to cut from (leave empty for latest main)' + required: false + type: string + +permissions: + contents: write + actions: write + +jobs: + cut-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.commit_sha || 'main' }} + + - name: Check for existing release/candidate branch + env: + GH_TOKEN: ${{ github.token }} + run: | + if git ls-remote --exit-code --heads origin release/candidate &>/dev/null; then + echo "Error: release/candidate branch already exists" + echo "Please finalize or delete the existing release candidate before starting a new one" + exit 1 + fi + + - name: Create and push release/candidate branch + run: | + git checkout -b release/candidate + git push origin release/candidate + echo "Created branch: release/candidate" + + - name: Trigger Release Please + env: + GH_TOKEN: ${{ github.token }} + run: | + gh workflow run release-please.yml --repo ${{ github.repository }} + echo "Triggered Release Please workflow" diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml new file mode 100644 index 00000000..9864aaab --- /dev/null +++ b/.github/workflows/release-finalize.yml @@ -0,0 +1,66 @@ +# Triggers when release-please PR is merged to release/candidate. +# Creates the final release/v{version} branch and deletes the candidate branch. +name: "Release: Finalize" + +on: + pull_request: + types: [closed] + branches: + - release/candidate + +permissions: + contents: write + pull-requests: write + +jobs: + finalize: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Check for release-please PR + id: check + env: + LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }} + run: | + if echo "$LABELS" | grep -q "autorelease: pending"; then + echo "is_release_pr=true" >> $GITHUB_OUTPUT + else + echo "Not a release-please PR, skipping" + echo "is_release_pr=false" >> $GITHUB_OUTPUT + fi + + - uses: actions/checkout@v4 + if: steps.check.outputs.is_release_pr == 'true' + with: + ref: release/candidate + + - name: Extract version from manifest + if: steps.check.outputs.is_release_pr == 'true' + id: version + run: | + VERSION=$(jq -r '.["."]' .github/.release-please-manifest.json) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Extracted version: $VERSION" + + - name: Create release branch + if: steps.check.outputs.is_release_pr == 'true' + run: | + git checkout -b "release/v${{ steps.version.outputs.version }}" + git push origin "release/v${{ steps.version.outputs.version }}" + echo "Created branch: release/v${{ steps.version.outputs.version }}" + + - name: Delete release/candidate branch + if: steps.check.outputs.is_release_pr == 'true' + run: | + git push origin --delete release/candidate + echo "Deleted branch: release/candidate" + + - name: Update PR label to tagged + if: steps.check.outputs.is_release_pr == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + gh pr edit ${{ github.event.pull_request.number }} \ + --remove-label "autorelease: pending" \ + --add-label "autorelease: tagged" + echo "Updated PR label to autorelease: tagged" diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..b2540e9f --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,30 @@ +# Runs release-please to create/update a PR with version bump and changelog. +# Triggered by pushes to release/candidate or manually. +name: "Release: Please" + +on: + push: + branches: + - release/candidate + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + # Skip if this is a release-please PR merge (handled by Release: Finalize) + if: "!startsWith(github.event.head_commit.message, 'chore(release')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: release/candidate + + - uses: googleapis/release-please-action@v4 + with: + token: ${{ secrets.RELEASE_PAT }} + config-file: .github/release-please-config.json + manifest-file: .github/.release-please-manifest.json + target-branch: release/candidate diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 00000000..51623d57 --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,59 @@ +# Builds and publishes the package to PyPI from a release branch. +# Creates a merge-back PR to sync release changes to main. +name: "Release: Publish to PyPi" + +on: + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Validate branch + run: | + if [[ ! "${{ github.ref_name }}" =~ ^release/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: Must run from a release/v* branch (e.g., release/v0.3.0)" + exit 1 + fi + + - name: Extract version + id: version + run: | + VERSION="${{ github.ref_name }}" + VERSION="${VERSION#release/v}" + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Publishing version: $VERSION" + + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + version: "latest" + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Build package + run: uv build + + - name: Publish to PyPI + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }} + run: uv publish + + - name: Create merge-back PR + env: + GH_TOKEN: ${{ secrets.RELEASE_PAT }} + run: | + gh pr create \ + --base main \ + --head "${{ github.ref_name }}" \ + --title "chore: merge release v${{ steps.version.outputs.version }} to main" \ + --body "Syncs version bump and CHANGELOG from release v${{ steps.version.outputs.version }} to main."