Skip to content

chore(deps): Bump @google/genai from 2.9.0 to 2.10.0 in the deps group #433

chore(deps): Bump @google/genai from 2.9.0 to 2.10.0 in the deps group

chore(deps): Bump @google/genai from 2.9.0 to 2.10.0 in the deps group #433

Workflow file for this run

name: CI
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths-ignore:
- 'docs/**'
- 'poc/**'
- '**/*.md'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build_and_test:
name: Build & Test
runs-on: ubuntu-latest
# 20 not 15: the SonarCloud quality-gate wait adds blocking time on top of build + e2e.
timeout-minutes: 20
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 0 # full history so SonarCloud has SCM blame — avoids the shallow-clone warning
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 26
- name: Install pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10
run_install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Format Check
run: make format-check
- name: Lint
run: make lint
- name: Typecheck
run: make typecheck
- name: Resolve Playwright version
id: pw
# Key the browser cache on the exact installed version: a bump misses (fresh browsers), a
# match restores them so a healthy run never reaches the network for the download.
run: echo "version=$(node -p 'require("@playwright/test/package.json").version')" >> "$GITHUB_OUTPUT"
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.pw.outputs.version }}
- name: Install Playwright (chromium only)
# The suite drives chromium only (vitest browser tests + e2e), so install just that — fewer
# browsers and system libs to fetch. Bounded + retried: a transient apt/mirror hang must fail
# THIS step fast and self-heal, not stall until the job timeout cancels the whole run (which
# reads as a CI failure, not the infra flake it is). Browsers restore from the cache on a hit;
# the apt system libs reinstall every run, so the retry is what guards the flaky part.
timeout-minutes: 10
run: |
set -euo pipefail
for attempt in 1 2 3; do
if timeout 180 pnpm exec playwright install --with-deps chromium; then
exit 0
fi
echo "::warning::playwright install attempt ${attempt} failed or timed out; retrying"
sleep 10
done
echo "::error::playwright install failed after 3 attempts"
exit 1
- name: Unit Tests
run: make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: anchildress1/save-the-sun
files: ./coverage/lcov.info
- name: Upload test results to Codecov
# Runs even when the suite failed, so Test Analytics still sees the failures. The standalone
# test-results-action is deprecated (and still on Node 20); the coverage action now carries
# test results too via report_type, so reuse it.
if: ${{ !cancelled() }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: anchildress1/save-the-sun
files: ./test-report.junit.xml
report_type: test_results
- name: Build
run: make build
- name: E2E Tests
run: make e2e
- name: SonarQube Cloud Scan
# The 40-char hex is the action's pinned commit SHA (per our SHA-pin convention),
# not a SonarQube API key — suppress the generic secret matcher's false positive.
# nosemgrep: generic.secrets.security.detected-sonarqube-docs-api-key.detected-sonarqube-docs-api-key
uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: https://sonarcloud.io
with:
# Block until the Compute Engine finishes so the issue count below is final, not stale.
# Bounded wait so a slow Sonar queue fails this step deterministically instead of via the
# GitHub job timeout (which would read as an infra flake, not a gate failure).
args: >
-Dsonar.qualitygate.wait=true
-Dsonar.qualitygate.timeout=600
- name: Enforce zero Sonar issues
# Why this exists instead of a quality-gate condition: the free SonarCloud plan only allows
# the built-in "Sonar way" gate (no custom gate can be created or assigned), and that gate
# is rating-based — a MINOR issue keeps the maintainability rating at A, so it passes with
# issues present. We want zero issues of ANY severity, so we assert it here from the issues
# API. Runs after the scan's qualitygate.wait, so the analysis is computed and the count is
# authoritative. Replace with a gate condition (new_violations > 0) if the plan is upgraded.
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "pull_request" ]; then
scope="pullRequest=${PR_NUMBER}"
else
scope="branch=main"
fi
api="https://sonarcloud.io/api/issues/search?componentKeys=anchildress1_save-the-sun&${scope}&resolved=false&ps=500"
first=$(curl -sfSL -u "${SONAR_TOKEN}:" "${api}&p=1")
count=$(echo "$first" | jq -r '.total')
echo "Unresolved Sonar issues for ${scope}: ${count}"
[ "${count}" = "0" ] && exit 0
# Page through ALL issues (ps=500 max) so the failure output annotates every offending
# issue, not just the first page — debuggability when clearing a backlog.
pages=$(( (count + 499) / 500 ))
for p in $(seq 1 "${pages}"); do
if [ "${p}" = "1" ]; then
page="$first"
else
page=$(curl -sfSL -u "${SONAR_TOKEN}:" "${api}&p=${p}")
fi
echo "$page" | jq -r '.issues[] | "::error::[\(.severity)] \(.component | sub("^[^:]+:";"")):\(.textRange.startLine // 0) \(.rule) — \(.message)"'
done
echo "::error::SonarCloud reports ${count} unresolved issue(s); CI fails on any severity."
exit 1