chore: consolidate GitHub Actions workflows for v1 branch (#6194)
This commit is contained in:
@@ -1,116 +0,0 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: "Check file contents"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.py'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-file-contents:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Check for logger pattern in all changed Python files
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Changed Python files to check:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo ""
|
||||
|
||||
# Check for 'logger = logging.getLogger(__name__)' in changed .py files.
|
||||
# The grep command will exit with a non-zero status code if the pattern is not found.
|
||||
# We invert the exit code with ! so the step succeeds if the pattern is NOT found.
|
||||
set +e
|
||||
FILES_WITH_FORBIDDEN_LOGGER=$(grep -lE 'logger = logging\.getLogger\(__name__\)' $CHANGED_FILES)
|
||||
GREP_EXIT_CODE=$?
|
||||
set -e
|
||||
|
||||
# grep exits with 0 if matches are found, 1 if no matches are found.
|
||||
# A non-zero exit code other than 1 indicates an error.
|
||||
if [ $GREP_EXIT_CODE -eq 0 ]; then
|
||||
echo "❌ Found forbidden use of 'logger = logging.getLogger(__name__)'. Please use 'logger = logging.getLogger('google_adk.' + __name__)' instead."
|
||||
echo "The following files contain the forbidden pattern:"
|
||||
echo "$FILES_WITH_FORBIDDEN_LOGGER"
|
||||
exit 1
|
||||
elif [ $GREP_EXIT_CODE -eq 1 ]; then
|
||||
echo "✅ No instances of 'logger = logging.getLogger(__name__)' found in changed Python files."
|
||||
fi
|
||||
else
|
||||
echo "✅ No relevant Python files found."
|
||||
fi
|
||||
|
||||
- name: Check for import pattern in certain changed Python files
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' | grep -v -E '__init__.py$|version.py$|tests/.*|contributing/samples/' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Changed Python files to check:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo ""
|
||||
|
||||
# Use grep -L to find files that DO NOT contain the pattern.
|
||||
# This command will output a list of non-compliant files.
|
||||
FILES_MISSING_IMPORT=$(grep -L 'from __future__ import annotations' $CHANGED_FILES || true)
|
||||
|
||||
# Check if the list of non-compliant files is empty
|
||||
if [ -z "$FILES_MISSING_IMPORT" ]; then
|
||||
echo "✅ All modified Python files include 'from __future__ import annotations'."
|
||||
exit 0
|
||||
else
|
||||
echo "❌ The following files are missing 'from __future__ import annotations':"
|
||||
echo "$FILES_MISSING_IMPORT"
|
||||
echo "This import is required to allow forward references in type annotations without quotes."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "✅ No relevant Python files found."
|
||||
fi
|
||||
|
||||
- name: Check for import from cli package in certain changed Python files
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' | grep -v -E 'cli/.*|src/google/adk/tools/apihub_tool/apihub_toolset.py|tests/.*|contributing/samples/' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Changed Python files to check:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo ""
|
||||
|
||||
set +e
|
||||
FILES_WITH_FORBIDDEN_IMPORT=$(grep -lE '^from.*\bcli\b.*import.*$' $CHANGED_FILES)
|
||||
GREP_EXIT_CODE=$?
|
||||
set -e
|
||||
|
||||
if [[ $GREP_EXIT_CODE -eq 0 ]]; then
|
||||
echo "❌ Do not import from the cli package outside of the cli package. If you need to reuse the code elsewhere, please move the code outside of the cli package."
|
||||
echo "The following files contain the forbidden pattern:"
|
||||
echo "$FILES_WITH_FORBIDDEN_IMPORT"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ No instances of importing from the cli package found in relevant changed Python files."
|
||||
fi
|
||||
else
|
||||
echo "✅ No relevant Python files found."
|
||||
fi
|
||||
@@ -0,0 +1,276 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, v1]
|
||||
paths:
|
||||
- '**.py'
|
||||
- '.pre-commit-config.yaml'
|
||||
- 'pyproject.toml'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
branches: [main, v1]
|
||||
paths:
|
||||
- '**.py'
|
||||
- '.pre-commit-config.yaml'
|
||||
- 'pyproject.toml'
|
||||
- 'tests/**'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# 1. Code format and linting (Linter)
|
||||
lint:
|
||||
name: Pre-commit Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run pre-commit checks
|
||||
uses: pre-commit/action@v3.0.1
|
||||
|
||||
# 2. Static type analysis (Mypy Check with Matrix)
|
||||
# Compares new changes against the target base branch dynamically to support v1.
|
||||
type-check:
|
||||
name: Mypy Check (Python ${{ matrix.python-version }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ['3.10', '3.11', '3.12', '3.13']
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
|
||||
- name: Generate Baseline
|
||||
env:
|
||||
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
|
||||
run: |
|
||||
# Switch to target base branch to generate baseline
|
||||
git checkout origin/$TARGET_BRANCH
|
||||
|
||||
git checkout ${{ github.sha }} -- pyproject.toml
|
||||
|
||||
# Install dependencies for target branch
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras
|
||||
|
||||
# Run mypy, filter for errors only, remove line numbers, and sort
|
||||
# We ignore exit code (|| true) because we expect errors on baseline
|
||||
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > baseline_errors.txt || true
|
||||
echo "Found $(wc -l < baseline_errors.txt) errors on $TARGET_BRANCH."
|
||||
|
||||
- name: Check PR Branch
|
||||
run: |
|
||||
# Switch back to the PR commit
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
# Re-sync dependencies in case the PR changed them
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras
|
||||
|
||||
# Run mypy on PR code, apply same processing
|
||||
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > pr_errors.txt || true
|
||||
echo "Found $(wc -l < pr_errors.txt) errors on PR branch."
|
||||
|
||||
- name: Compare and Fail on New Errors
|
||||
run: |
|
||||
# 'comm -13' suppresses unique lines in file1 (baseline) and common lines,
|
||||
# leaving only lines unique to file2 (PR) -> The new errors.
|
||||
comm -13 baseline_errors.txt pr_errors.txt > new_errors.txt
|
||||
|
||||
if [ -s new_errors.txt ]; then
|
||||
echo "::error::The following NEW mypy errors were introduced:"
|
||||
cat new_errors.txt
|
||||
exit 1
|
||||
else
|
||||
echo "Great job! No new mypy errors introduced."
|
||||
fi
|
||||
|
||||
# 3. Unit testing (Unit Tests with Matrix)
|
||||
unit-test:
|
||||
name: Unit Tests (Python ${{ matrix.python-version }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv sync --extra test
|
||||
|
||||
- name: Run unit tests with pytest
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
pytest tests/unittests \
|
||||
-n auto \
|
||||
--ignore=tests/unittests/artifacts/test_artifact_service.py \
|
||||
--ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
|
||||
|
||||
# 4. Custom file content compliance checks (PR only)
|
||||
compliance-check:
|
||||
name: File Content Compliance
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# Fetch full history (depth: 0) instead of shallow clone (depth: 2) to ensure
|
||||
# git diff origin/${base_ref}...HEAD can reliably find the merge base,
|
||||
# preventing fatal git errors on deep PRs or when the target branch has progressed.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check for logger pattern in all changed Python files
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Changed Python files to check:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo ""
|
||||
|
||||
# Check for 'logger = logging.getLogger(__name__)' in changed .py files.
|
||||
set +e
|
||||
FILES_WITH_FORBIDDEN_LOGGER=$(grep -lE 'logger = logging\.getLogger\(__name__\)' $CHANGED_FILES)
|
||||
GREP_EXIT_CODE=$?
|
||||
set -e
|
||||
|
||||
if [ $GREP_EXIT_CODE -eq 0 ]; then
|
||||
echo "❌ Found forbidden use of 'logger = logging.getLogger(__name__)'. Please use 'logger = logging.getLogger('google_adk.' + __name__)' instead."
|
||||
echo "The following files contain the forbidden pattern:"
|
||||
echo "$FILES_WITH_FORBIDDEN_LOGGER"
|
||||
exit 1
|
||||
elif [ $GREP_EXIT_CODE -eq 1 ]; then
|
||||
echo "✅ No instances of 'logger = logging.getLogger(__name__)' found in changed Python files."
|
||||
fi
|
||||
else
|
||||
echo "✅ No relevant Python files found."
|
||||
fi
|
||||
|
||||
- name: Check for import pattern in certain changed Python files
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' | grep -v -E '__init__.py$|version.py$|tests/.*|contributing/samples/' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Changed Python files to check:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo ""
|
||||
|
||||
# Use grep -L to find files that DO NOT contain the pattern.
|
||||
FILES_MISSING_IMPORT=$(grep -L 'from __future__ import annotations' $CHANGED_FILES || true)
|
||||
|
||||
if [ -z "$FILES_MISSING_IMPORT" ]; then
|
||||
echo "✅ All modified Python files include 'from __future__ import annotations'."
|
||||
exit 0
|
||||
else
|
||||
echo "❌ The following files are missing 'from __future__ import annotations':"
|
||||
echo "$FILES_MISSING_IMPORT"
|
||||
echo "This import is required to allow forward references in type annotations without quotes."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "✅ No relevant Python files found."
|
||||
fi
|
||||
|
||||
- name: Check for import from cli package in certain changed Python files
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' | grep -v -E 'cli/.*|src/google/adk/tools/apihub_tool/apihub_toolset.py|tests/.*|contributing/samples/' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Changed Python files to check:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo ""
|
||||
|
||||
set +e
|
||||
FILES_WITH_FORBIDDEN_IMPORT=$(grep -lE '^from.*\bcli\b.*import.*$' $CHANGED_FILES)
|
||||
GREP_EXIT_CODE=$?
|
||||
set -e
|
||||
|
||||
if [[ $GREP_EXIT_CODE -eq 0 ]]; then
|
||||
echo "❌ Do not import from the cli package outside of the cli package. If you need to reuse the code elsewhere, please move the code outside of the cli package."
|
||||
echo "The following files contain the forbidden pattern:"
|
||||
echo "$FILES_WITH_FORBIDDEN_IMPORT"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ No instances of importing from the cli package found in relevant changed Python files."
|
||||
fi
|
||||
else
|
||||
echo "✅ No relevant Python files found."
|
||||
fi
|
||||
|
||||
- name: Check for hardcoded googleapis.com endpoints
|
||||
run: |
|
||||
git fetch origin ${GITHUB_BASE_REF}
|
||||
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "Checking for hardcoded endpoints in: $CHANGED_FILES"
|
||||
|
||||
# 1. Identify files containing any googleapis.com URL.
|
||||
set +e
|
||||
FILES_WITH_ENDPOINTS=$(grep -lE 'https?://[a-zA-Z0-9.-]+\.googleapis\.com' $CHANGED_FILES)
|
||||
|
||||
# 2. From those, identify files that are MISSING the required mTLS version.
|
||||
if [ -n "$FILES_WITH_ENDPOINTS" ]; then
|
||||
FILES_MISSING_MTLS=$(grep -L '.mtls.googleapis.com' $FILES_WITH_ENDPOINTS)
|
||||
fi
|
||||
set -e
|
||||
|
||||
if [ -n "$FILES_MISSING_MTLS" ]; then
|
||||
echo "❌ Found hardcoded googleapis.com endpoints without mTLS support."
|
||||
echo "The following files must define both standard and mTLS (.mtls.googleapis.com) endpoints"
|
||||
echo "to support dynamic endpoint selection as required by security policy:"
|
||||
echo "$FILES_MISSING_MTLS"
|
||||
echo ""
|
||||
echo "To fix this, please follow these steps:"
|
||||
echo "1. Initialize an AuthorizedSession with your credentials."
|
||||
echo "2. Use 'mtls.has_default_client_cert_source() from google-auth' to check for available client certificates."
|
||||
echo "3. If certificates are present, use 'session.configure_mtls_channel()'."
|
||||
echo "4. Dynamically select the '.mtls.' variant of the endpoint when mTLS is active."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ All hardcoded endpoints have corresponding mTLS definitions or no endpoints found."
|
||||
fi
|
||||
fi
|
||||
@@ -1,189 +0,0 @@
|
||||
name: '🔀 Gemini Dispatch'
|
||||
|
||||
on:
|
||||
pull_request_review_comment:
|
||||
types:
|
||||
- 'created'
|
||||
pull_request_review:
|
||||
types:
|
||||
- 'submitted'
|
||||
issue_comment:
|
||||
types:
|
||||
- 'created'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: 'bash'
|
||||
|
||||
jobs:
|
||||
debugger:
|
||||
if: |-
|
||||
${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
steps:
|
||||
- name: 'Print context for debugging'
|
||||
env:
|
||||
DEBUG_event_name: '${{ github.event_name }}'
|
||||
DEBUG_event__action: '${{ github.event.action }}'
|
||||
DEBUG_event__comment__author_association: '${{ github.event.comment.author_association }}'
|
||||
DEBUG_event__issue__author_association: '${{ github.event.issue.author_association }}'
|
||||
DEBUG_event__pull_request__author_association: '${{ github.event.pull_request.author_association }}'
|
||||
DEBUG_event__review__author_association: '${{ github.event.review.author_association }}'
|
||||
DEBUG_event: '${{ toJSON(github.event) }}'
|
||||
run: |-
|
||||
env | grep '^DEBUG_'
|
||||
|
||||
dispatch:
|
||||
# Only trigger if user types @gemini-cli and author association is OWNER, MEMBER, or COLLABORATOR
|
||||
if: |-
|
||||
github.event.sender.type == 'User' &&
|
||||
startsWith(github.event.comment.body || github.event.review.body, '@gemini-cli') &&
|
||||
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association)
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
outputs:
|
||||
command: '${{ steps.extract_command.outputs.command }}'
|
||||
request: '${{ steps.extract_command.outputs.request }}'
|
||||
additional_context: '${{ steps.extract_command.outputs.additional_context }}'
|
||||
issue_number: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
steps:
|
||||
- name: 'Mint identity token'
|
||||
id: 'mint_identity_token'
|
||||
if: |-
|
||||
${{ vars.APP_ID }}
|
||||
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: '${{ vars.APP_ID }}'
|
||||
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
||||
permission-contents: 'read'
|
||||
permission-issues: 'write'
|
||||
permission-pull-requests: 'write'
|
||||
|
||||
- name: 'Extract command'
|
||||
id: 'extract_command'
|
||||
uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8.0.0
|
||||
env:
|
||||
REQUEST: '${{ github.event.comment.body || github.event.review.body }}'
|
||||
IS_PR: '${{ !!(github.event.pull_request || github.event.issue.pull_request) }}'
|
||||
with:
|
||||
script: |
|
||||
const request = process.env.REQUEST;
|
||||
const isPr = process.env.IS_PR === 'true';
|
||||
core.setOutput('request', request);
|
||||
|
||||
// Ensure request is on a PR targeting the main branch
|
||||
let baseRef = '';
|
||||
if (context.eventName === 'pull_request_review' || context.eventName === 'pull_request_review_comment') {
|
||||
baseRef = context.payload.pull_request.base.ref;
|
||||
} else if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) {
|
||||
const pr = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.issue.number
|
||||
});
|
||||
baseRef = pr.data.base.ref;
|
||||
}
|
||||
|
||||
if (isPr && baseRef !== 'main') {
|
||||
console.log(`Skipping: PR targets '${baseRef}', but only 'main' is allowed.`);
|
||||
core.setOutput('command', 'fallthrough');
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.startsWith("@gemini-cli /review")) {
|
||||
if (isPr) {
|
||||
core.setOutput('command', 'review');
|
||||
const additionalContext = request.replace(/^@gemini-cli \/review/, '').trim();
|
||||
core.setOutput('additional_context', additionalContext);
|
||||
} else {
|
||||
core.setOutput('command', 'fallthrough');
|
||||
}
|
||||
} else if (request.startsWith("@gemini-cli")) {
|
||||
const additionalContext = request.replace(/^@gemini-cli/, '').trim();
|
||||
core.setOutput('command', 'invoke');
|
||||
core.setOutput('additional_context', additionalContext);
|
||||
} else {
|
||||
core.setOutput('command', 'fallthrough');
|
||||
}
|
||||
|
||||
- name: 'Acknowledge request'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
||||
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
MESSAGE: |-
|
||||
🤖 Hi @${{ github.actor }}, I've received your request, and I'm working on it now! You can track my progress [in the logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details.
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
run: |-
|
||||
gh issue comment "${ISSUE_NUMBER}" \
|
||||
--body "${MESSAGE}" \
|
||||
--repo "${REPOSITORY}"
|
||||
|
||||
review:
|
||||
needs: 'dispatch'
|
||||
if: |-
|
||||
${{ needs.dispatch.outputs.command == 'review' }}
|
||||
uses: './.github/workflows/gemini-review.yml'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
with:
|
||||
additional_context: '${{ needs.dispatch.outputs.additional_context }}'
|
||||
secrets: 'inherit'
|
||||
|
||||
invoke:
|
||||
needs: 'dispatch'
|
||||
if: |-
|
||||
${{ needs.dispatch.outputs.command == 'invoke' }}
|
||||
uses: './.github/workflows/gemini-invoke.yml'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
with:
|
||||
additional_context: '${{ needs.dispatch.outputs.additional_context }}'
|
||||
secrets: 'inherit'
|
||||
|
||||
fallthrough:
|
||||
needs:
|
||||
- 'dispatch'
|
||||
- 'review'
|
||||
- 'invoke'
|
||||
if: |-
|
||||
${{ always() && !cancelled() && (failure() || needs.dispatch.outputs.command == 'fallthrough') }}
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Mint identity token'
|
||||
id: 'mint_identity_token'
|
||||
if: |-
|
||||
${{ vars.APP_ID }}
|
||||
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: '${{ vars.APP_ID }}'
|
||||
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
||||
permission-contents: 'read'
|
||||
permission-issues: 'write'
|
||||
permission-pull-requests: 'write'
|
||||
|
||||
- name: 'Send failure comment'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
||||
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
MESSAGE: |-
|
||||
🤖 I'm sorry @${{ github.actor }}, but I was unable to process your request. Please [see the logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details.
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
run: |-
|
||||
gh issue comment "${ISSUE_NUMBER}" \
|
||||
--body "${MESSAGE}" \
|
||||
--repo "${REPOSITORY}"
|
||||
@@ -1,104 +0,0 @@
|
||||
name: '▶️ Gemini Invoke'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
additional_context:
|
||||
type: 'string'
|
||||
description: 'Any additional context from the request'
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-invoke-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
cancel-in-progress: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: 'bash'
|
||||
|
||||
jobs:
|
||||
invoke:
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Mint identity token'
|
||||
id: 'mint_identity_token'
|
||||
if: |-
|
||||
${{ vars.APP_ID }}
|
||||
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: '${{ vars.APP_ID }}'
|
||||
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
||||
permission-contents: 'read'
|
||||
permission-issues: 'write'
|
||||
permission-pull-requests: 'write'
|
||||
|
||||
- name: 'Checkout Code'
|
||||
uses: 'actions/checkout@v4' # ratchet:exclude
|
||||
|
||||
- name: 'Run Gemini CLI'
|
||||
id: 'run_gemini'
|
||||
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
|
||||
env:
|
||||
TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
|
||||
DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}'
|
||||
EVENT_NAME: '${{ github.event_name }}'
|
||||
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
||||
IS_PULL_REQUEST: '${{ !!github.event.pull_request }}'
|
||||
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
|
||||
# Required to allow the Gemini CLI to process files in the ephemeral GitHub Actions runner
|
||||
GEMINI_CLI_TRUST_WORKSPACE: 'true'
|
||||
with:
|
||||
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
|
||||
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
||||
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
||||
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
||||
gemini_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
||||
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
|
||||
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
|
||||
gemini_model: '${{ vars.GEMINI_MODEL }}'
|
||||
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
||||
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
|
||||
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
|
||||
upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
|
||||
workflow_name: 'gemini-invoke'
|
||||
# Assistant workflows can be triggered by comments on either Issues or PRs.
|
||||
# We explicitly map both fields so the CLI can correctly categorize the interaction.
|
||||
github_pr_number: '${{ github.event.pull_request.number }}'
|
||||
github_issue_number: '${{ github.event.issue.number }}'
|
||||
settings: |-
|
||||
{
|
||||
"model": {
|
||||
"maxSessionTurns": 25
|
||||
},
|
||||
"telemetry": {
|
||||
"enabled": true,
|
||||
"target": "local",
|
||||
"outfile": ".gemini/telemetry.log"
|
||||
},
|
||||
"mcpServers": {
|
||||
"github": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-e",
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
||||
"ghcr.io/github/github-mcp-server:v0.27.0"
|
||||
],
|
||||
"env": {
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
prompt: |-
|
||||
/gemini-invoke
|
||||
[IMPORTANT] Do not generate execution plans and do not ask for approval (such as suggesting `@gemini-cli /approve`). Perform the requested task or answer the question directly and immediately.
|
||||
@@ -1,100 +0,0 @@
|
||||
name: '🔎 Gemini Review'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
additional_context:
|
||||
type: 'string'
|
||||
description: 'Any additional context from the request'
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: '${{ github.workflow }}-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: 'bash'
|
||||
|
||||
jobs:
|
||||
review:
|
||||
runs-on: 'ubuntu-latest'
|
||||
timeout-minutes: 7
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: 'Mint identity token'
|
||||
id: 'mint_identity_token'
|
||||
if: |-
|
||||
${{ vars.APP_ID }}
|
||||
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: '${{ vars.APP_ID }}'
|
||||
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
||||
permission-contents: 'read'
|
||||
permission-issues: 'write'
|
||||
permission-pull-requests: 'write'
|
||||
|
||||
- name: 'Checkout repository'
|
||||
uses: 'actions/checkout@v4' # ratchet:exclude
|
||||
|
||||
- name: 'Run Gemini pull request review'
|
||||
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
|
||||
id: 'gemini_pr_review'
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
||||
ISSUE_TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
|
||||
ISSUE_BODY: '${{ github.event.pull_request.body || github.event.issue.body }}'
|
||||
PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
REPOSITORY: '${{ github.repository }}'
|
||||
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
|
||||
GEMINI_API_KEY: '${{ secrets.GOOGLE_API_KEY }}'
|
||||
# Required to allow the Gemini CLI to process files in the ephemeral GitHub Actions runner
|
||||
GEMINI_CLI_TRUST_WORKSPACE: 'true'
|
||||
with:
|
||||
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
|
||||
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
||||
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
||||
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
||||
gemini_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
||||
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
|
||||
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
|
||||
gemini_model: '${{ vars.GEMINI_MODEL }}'
|
||||
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
||||
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
|
||||
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
|
||||
upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
|
||||
workflow_name: 'gemini-review'
|
||||
# Explicitly set the PR number to handle `issue_comment` triggers (which GitHub treats as issues, not PRs)
|
||||
github_pr_number: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
||||
settings: |-
|
||||
{
|
||||
"model": {
|
||||
"maxSessionTurns": 25
|
||||
},
|
||||
"telemetry": {
|
||||
"enabled": true,
|
||||
"target": "local",
|
||||
"outfile": ".gemini/telemetry.log"
|
||||
},
|
||||
"mcpServers": {
|
||||
"github": {
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"-e",
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
||||
"ghcr.io/github/github-mcp-server:v0.27.0"
|
||||
],
|
||||
"env": {
|
||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
prompt: 'Please use the pull_request_read tool to read pull request #${{ github.event.pull_request.number || github.event.issue.number }}. Analyze the code for bugs, security issues, and best practices. Then, use the add_comment_to_pending_review and pull_request_review_write tools to post your review directly on pull request #${{ github.event.pull_request.number || github.event.issue.number }}.'
|
||||
@@ -1,77 +0,0 @@
|
||||
name: Mypy New Error Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
mypy-diff:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.10', '3.11', '3.12', '3.13',]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
|
||||
- name: Generate Baseline (Main)
|
||||
run: |
|
||||
# Switch to main branch to generate baseline
|
||||
git checkout origin/main
|
||||
|
||||
git checkout ${{ github.sha }} -- pyproject.toml
|
||||
|
||||
# Install dependencies for main
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras
|
||||
|
||||
# Run mypy, filter for errors only, remove line numbers (file:123: -> file::), and sort
|
||||
# We ignore exit code (|| true) because we expect errors on main
|
||||
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > main_errors.txt || true
|
||||
|
||||
echo "Found $(wc -l < main_errors.txt) errors on main."
|
||||
|
||||
- name: Check PR Branch
|
||||
run: |
|
||||
# Switch back to the PR commit
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
# Re-sync dependencies in case the PR changed them
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras
|
||||
|
||||
# Run mypy on PR code, apply same processing
|
||||
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > pr_errors.txt || true
|
||||
|
||||
echo "Found $(wc -l < pr_errors.txt) errors on PR branch."
|
||||
|
||||
- name: Compare and Fail on New Errors
|
||||
run: |
|
||||
# 'comm -13' suppresses unique lines in file1 (main) and common lines,
|
||||
# leaving only lines unique to file2 (PR) -> The new errors.
|
||||
comm -13 main_errors.txt pr_errors.txt > new_errors.txt
|
||||
|
||||
if [ -s new_errors.txt ]; then
|
||||
echo "::error::The following NEW mypy errors were introduced:"
|
||||
cat new_errors.txt
|
||||
exit 1
|
||||
else
|
||||
echo "Great job! No new mypy errors introduced."
|
||||
fi
|
||||
@@ -1,42 +0,0 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: Pre-commit Checks
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, v1, v2]
|
||||
paths:
|
||||
- '**.py'
|
||||
- '.pre-commit-config.yaml'
|
||||
- 'pyproject.toml'
|
||||
pull_request:
|
||||
branches: [main, v1, v2]
|
||||
paths:
|
||||
- '**.py'
|
||||
- '.pre-commit-config.yaml'
|
||||
- 'pyproject.toml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run pre-commit checks
|
||||
uses: pre-commit/action@v3.0.1
|
||||
@@ -1,56 +0,0 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: Python Unit Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, v1 ]
|
||||
pull_request:
|
||||
branches: [ main, v1 ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv sync --extra test
|
||||
|
||||
- name: Run unit tests with pytest
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
pytest tests/unittests \
|
||||
--ignore=tests/unittests/artifacts/test_artifact_service.py \
|
||||
--ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
|
||||
Reference in New Issue
Block a user