Skip to content

Commit 93ca9fe

Browse files
authored
chore: consolidate GitHub Actions workflows for v1 branch (#6194)
1 parent 7a9152a commit 93ca9fe

8 files changed

Lines changed: 276 additions & 684 deletions

.github/workflows/check-file-contents.yml

Lines changed: 0 additions & 116 deletions
This file was deleted.
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: Continuous Integration
16+
17+
on:
18+
push:
19+
branches: [main, v1]
20+
paths:
21+
- '**.py'
22+
- '.pre-commit-config.yaml'
23+
- 'pyproject.toml'
24+
- 'tests/**'
25+
pull_request:
26+
branches: [main, v1]
27+
paths:
28+
- '**.py'
29+
- '.pre-commit-config.yaml'
30+
- 'pyproject.toml'
31+
- 'tests/**'
32+
33+
permissions:
34+
contents: read
35+
36+
jobs:
37+
# 1. Code format and linting (Linter)
38+
lint:
39+
name: Pre-commit Linter
40+
runs-on: ubuntu-latest
41+
steps:
42+
- name: Checkout Code
43+
uses: actions/checkout@v6
44+
45+
- name: Run pre-commit checks
46+
uses: pre-commit/action@v3.0.1
47+
48+
# 2. Static type analysis (Mypy Check with Matrix)
49+
# Compares new changes against the target base branch dynamically to support v1.
50+
type-check:
51+
name: Mypy Check (Python ${{ matrix.python-version }})
52+
runs-on: ubuntu-latest
53+
strategy:
54+
fail-fast: false
55+
matrix:
56+
python-version: ['3.10', '3.11', '3.12', '3.13']
57+
steps:
58+
- name: Checkout code
59+
uses: actions/checkout@v6
60+
with:
61+
fetch-depth: 0
62+
63+
- name: Set up Python
64+
uses: actions/setup-python@v6
65+
with:
66+
python-version: ${{ matrix.python-version }}
67+
68+
- name: Install uv
69+
uses: astral-sh/setup-uv@v7
70+
71+
- name: Generate Baseline
72+
env:
73+
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
74+
run: |
75+
# Switch to target base branch to generate baseline
76+
git checkout origin/$TARGET_BRANCH
77+
78+
git checkout ${{ github.sha }} -- pyproject.toml
79+
80+
# Install dependencies for target branch
81+
uv venv .venv
82+
source .venv/bin/activate
83+
uv sync --all-extras
84+
85+
# Run mypy, filter for errors only, remove line numbers, and sort
86+
# We ignore exit code (|| true) because we expect errors on baseline
87+
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > baseline_errors.txt || true
88+
echo "Found $(wc -l < baseline_errors.txt) errors on $TARGET_BRANCH."
89+
90+
- name: Check PR Branch
91+
run: |
92+
# Switch back to the PR commit
93+
git checkout ${{ github.sha }}
94+
95+
# Re-sync dependencies in case the PR changed them
96+
source .venv/bin/activate
97+
uv sync --all-extras
98+
99+
# Run mypy on PR code, apply same processing
100+
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > pr_errors.txt || true
101+
echo "Found $(wc -l < pr_errors.txt) errors on PR branch."
102+
103+
- name: Compare and Fail on New Errors
104+
run: |
105+
# 'comm -13' suppresses unique lines in file1 (baseline) and common lines,
106+
# leaving only lines unique to file2 (PR) -> The new errors.
107+
comm -13 baseline_errors.txt pr_errors.txt > new_errors.txt
108+
109+
if [ -s new_errors.txt ]; then
110+
echo "::error::The following NEW mypy errors were introduced:"
111+
cat new_errors.txt
112+
exit 1
113+
else
114+
echo "Great job! No new mypy errors introduced."
115+
fi
116+
117+
# 3. Unit testing (Unit Tests with Matrix)
118+
unit-test:
119+
name: Unit Tests (Python ${{ matrix.python-version }})
120+
runs-on: ubuntu-latest
121+
strategy:
122+
fail-fast: false
123+
matrix:
124+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
125+
timeout-minutes: 10
126+
steps:
127+
- name: Checkout code
128+
uses: actions/checkout@v6
129+
130+
- name: Set up Python ${{ matrix.python-version }}
131+
uses: actions/setup-python@v6
132+
with:
133+
python-version: ${{ matrix.python-version }}
134+
135+
- name: Install the latest version of uv
136+
uses: astral-sh/setup-uv@v7
137+
138+
- name: Install dependencies
139+
run: |
140+
uv venv .venv
141+
source .venv/bin/activate
142+
uv sync --extra test
143+
144+
- name: Run unit tests with pytest
145+
run: |
146+
source .venv/bin/activate
147+
pytest tests/unittests \
148+
-n auto \
149+
--ignore=tests/unittests/artifacts/test_artifact_service.py \
150+
--ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
151+
152+
# 4. Custom file content compliance checks (PR only)
153+
compliance-check:
154+
name: File Content Compliance
155+
runs-on: ubuntu-latest
156+
if: github.event_name == 'pull_request'
157+
steps:
158+
- name: Checkout Code
159+
uses: actions/checkout@v6
160+
with:
161+
# Fetch full history (depth: 0) instead of shallow clone (depth: 2) to ensure
162+
# git diff origin/${base_ref}...HEAD can reliably find the merge base,
163+
# preventing fatal git errors on deep PRs or when the target branch has progressed.
164+
fetch-depth: 0
165+
166+
- name: Check for logger pattern in all changed Python files
167+
run: |
168+
git fetch origin ${GITHUB_BASE_REF}
169+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
170+
if [ -n "$CHANGED_FILES" ]; then
171+
echo "Changed Python files to check:"
172+
echo "$CHANGED_FILES"
173+
echo ""
174+
175+
# Check for 'logger = logging.getLogger(__name__)' in changed .py files.
176+
set +e
177+
FILES_WITH_FORBIDDEN_LOGGER=$(grep -lE 'logger = logging\.getLogger\(__name__\)' $CHANGED_FILES)
178+
GREP_EXIT_CODE=$?
179+
set -e
180+
181+
if [ $GREP_EXIT_CODE -eq 0 ]; then
182+
echo "❌ Found forbidden use of 'logger = logging.getLogger(__name__)'. Please use 'logger = logging.getLogger('google_adk.' + __name__)' instead."
183+
echo "The following files contain the forbidden pattern:"
184+
echo "$FILES_WITH_FORBIDDEN_LOGGER"
185+
exit 1
186+
elif [ $GREP_EXIT_CODE -eq 1 ]; then
187+
echo "✅ No instances of 'logger = logging.getLogger(__name__)' found in changed Python files."
188+
fi
189+
else
190+
echo "✅ No relevant Python files found."
191+
fi
192+
193+
- name: Check for import pattern in certain changed Python files
194+
run: |
195+
git fetch origin ${GITHUB_BASE_REF}
196+
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)
197+
if [ -n "$CHANGED_FILES" ]; then
198+
echo "Changed Python files to check:"
199+
echo "$CHANGED_FILES"
200+
echo ""
201+
202+
# Use grep -L to find files that DO NOT contain the pattern.
203+
FILES_MISSING_IMPORT=$(grep -L 'from __future__ import annotations' $CHANGED_FILES || true)
204+
205+
if [ -z "$FILES_MISSING_IMPORT" ]; then
206+
echo "✅ All modified Python files include 'from __future__ import annotations'."
207+
exit 0
208+
else
209+
echo "❌ The following files are missing 'from __future__ import annotations':"
210+
echo "$FILES_MISSING_IMPORT"
211+
echo "This import is required to allow forward references in type annotations without quotes."
212+
exit 1
213+
fi
214+
else
215+
echo "✅ No relevant Python files found."
216+
fi
217+
218+
- name: Check for import from cli package in certain changed Python files
219+
run: |
220+
git fetch origin ${GITHUB_BASE_REF}
221+
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)
222+
if [ -n "$CHANGED_FILES" ]; then
223+
echo "Changed Python files to check:"
224+
echo "$CHANGED_FILES"
225+
echo ""
226+
227+
set +e
228+
FILES_WITH_FORBIDDEN_IMPORT=$(grep -lE '^from.*\bcli\b.*import.*$' $CHANGED_FILES)
229+
GREP_EXIT_CODE=$?
230+
set -e
231+
232+
if [[ $GREP_EXIT_CODE -eq 0 ]]; then
233+
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."
234+
echo "The following files contain the forbidden pattern:"
235+
echo "$FILES_WITH_FORBIDDEN_IMPORT"
236+
exit 1
237+
else
238+
echo "✅ No instances of importing from the cli package found in relevant changed Python files."
239+
fi
240+
else
241+
echo "✅ No relevant Python files found."
242+
fi
243+
244+
- name: Check for hardcoded googleapis.com endpoints
245+
run: |
246+
git fetch origin ${GITHUB_BASE_REF}
247+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
248+
if [ -n "$CHANGED_FILES" ]; then
249+
echo "Checking for hardcoded endpoints in: $CHANGED_FILES"
250+
251+
# 1. Identify files containing any googleapis.com URL.
252+
set +e
253+
FILES_WITH_ENDPOINTS=$(grep -lE 'https?://[a-zA-Z0-9.-]+\.googleapis\.com' $CHANGED_FILES)
254+
255+
# 2. From those, identify files that are MISSING the required mTLS version.
256+
if [ -n "$FILES_WITH_ENDPOINTS" ]; then
257+
FILES_MISSING_MTLS=$(grep -L '.mtls.googleapis.com' $FILES_WITH_ENDPOINTS)
258+
fi
259+
set -e
260+
261+
if [ -n "$FILES_MISSING_MTLS" ]; then
262+
echo "❌ Found hardcoded googleapis.com endpoints without mTLS support."
263+
echo "The following files must define both standard and mTLS (.mtls.googleapis.com) endpoints"
264+
echo "to support dynamic endpoint selection as required by security policy:"
265+
echo "$FILES_MISSING_MTLS"
266+
echo ""
267+
echo "To fix this, please follow these steps:"
268+
echo "1. Initialize an AuthorizedSession with your credentials."
269+
echo "2. Use 'mtls.has_default_client_cert_source() from google-auth' to check for available client certificates."
270+
echo "3. If certificates are present, use 'session.configure_mtls_channel()'."
271+
echo "4. Dynamically select the '.mtls.' variant of the endpoint when mTLS is active."
272+
exit 1
273+
else
274+
echo "✅ All hardcoded endpoints have corresponding mTLS definitions or no endpoints found."
275+
fi
276+
fi

0 commit comments

Comments
 (0)