Update .github directory from main branch (#9155)

This commit is contained in:
Tommaso Sciortino
2025-09-22 15:11:27 -07:00
committed by GitHub
parent 4fb8dfe258
commit 0ca8669a80
23 changed files with 1520 additions and 739 deletions

View File

@@ -1,4 +1,4 @@
name: 'Gemini CLI CI'
name: 'Testing: CI'
on:
push:
@@ -10,6 +10,7 @@ on:
- 'main'
- 'release/**'
merge_group:
workflow_dispatch:
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
@@ -25,63 +26,10 @@ defaults:
run:
shell: 'bash'
env:
ACTIONLINT_VERSION: '1.7.7'
SHELLCHECK_VERSION: '0.11.0'
YAMLLINT_VERSION: '1.35.1'
jobs:
#
# Lint: GitHub Actions
#
lint_github_actions:
name: 'Lint (GitHub Actions)'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
fetch-depth: 1
- name: 'Install shellcheck' # Actionlint uses shellcheck
run: |-
mkdir -p "${RUNNER_TEMP}/shellcheck"
curl -sSLo "${RUNNER_TEMP}/.shellcheck.txz" "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz"
tar -xf "${RUNNER_TEMP}/.shellcheck.txz" -C "${RUNNER_TEMP}/shellcheck" --strip-components=1
echo "${RUNNER_TEMP}/shellcheck" >> "${GITHUB_PATH}"
- name: 'Install actionlint'
run: |-
mkdir -p "${RUNNER_TEMP}/actionlint"
curl -sSLo "${RUNNER_TEMP}/.actionlint.tgz" "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
tar -xzf "${RUNNER_TEMP}/.actionlint.tgz" -C "${RUNNER_TEMP}/actionlint"
echo "${RUNNER_TEMP}/actionlint" >> "${GITHUB_PATH}"
# For actionlint, we specifically ignore shellcheck rules that are
# annoying or unhelpful. See the shellcheck action for a description.
- name: 'Run actionlint'
run: |-
actionlint \
-color \
-format '{{range $err := .}}::error file={{$err.Filepath}},line={{$err.Line}},col={{$err.Column}}::{{$err.Filepath}}@{{$err.Line}} {{$err.Message}}%0A```%0A{{replace $err.Snippet "\\n" "%0A"}}%0A```\n{{end}}' \
-ignore 'SC2002:' \
-ignore 'SC2016:' \
-ignore 'SC2129:' \
-ignore 'label ".+" is unknown'
- name: 'Run ratchet'
uses: 'sethvargo/ratchet@8b4ca256dbed184350608a3023620f267f0a5253' # ratchet:sethvargo/ratchet@v0.11.4
with:
files: |-
.github/workflows/*.yml
.github/actions/**/*.yml
#
# Lint: Javascript
#
lint_javascript:
name: 'Lint (Javascript)'
runs-on: 'ubuntu-latest'
lint:
name: 'Lint'
runs-on: 'gemini-cli-ubuntu-16-core'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
@@ -94,161 +42,33 @@ jobs:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Run lockfile check'
run: |-
npm run check:lockfile
- name: 'Install dependencies'
run: |-
npm ci
run: 'npm ci'
- name: 'Run formatter check'
run: |-
npm run format
git diff --exit-code
- name: 'Check lockfile'
run: 'npm run check:lockfile'
- name: 'Run linter'
run: |-
npm run lint:ci
- name: 'Install linters'
run: 'node scripts/lint.js --setup'
- name: 'Run linter on integration tests'
run: |-
npx eslint integration-tests --max-warnings 0
- name: 'Run ESLint'
run: 'node scripts/lint.js --eslint'
- name: 'Run formatter on integration tests'
run: |-
npx prettier --check integration-tests
git diff --exit-code
- name: 'Run actionlint'
run: 'node scripts/lint.js --actionlint'
- name: 'Build project'
run: |-
npm run build
- name: 'Run type check'
run: |-
npm run typecheck
#
# Lint: Shell
#
lint_shell:
name: 'Lint (Shell)'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
fetch-depth: 1
- name: 'Install shellcheck'
run: |-
mkdir -p "${RUNNER_TEMP}/shellcheck"
curl -sSLo "${RUNNER_TEMP}/.shellcheck.txz" "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz"
tar -xf "${RUNNER_TEMP}/.shellcheck.txz" -C "${RUNNER_TEMP}/shellcheck" --strip-components=1
echo "${RUNNER_TEMP}/shellcheck" >> "${GITHUB_PATH}"
- name: 'Install shellcheck problem matcher'
run: |-
cat > "${RUNNER_TEMP}/shellcheck/problem-matcher-lint-shell.json" <<"EOF"
{
"problemMatcher": [
{
"owner": "lint_shell",
"pattern": [
{
"regexp": "^(.*):(\\\\d+):(\\\\d+):\\\\s+(?:fatal\\\\s+)?(warning|error):\\\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
}
]
}
EOF
echo "::add-matcher::${RUNNER_TEMP}/shellcheck/problem-matcher-lint-shell.json"
# Note that only warning and error severity show up in the github files
# page. So we replace 'style' and 'note' with 'warning' to make it show
# up.
#
# We also try and find all bash scripts even if they don't have an
# explicit extension.
#
# We explicitly ignore the following rules:
#
# - SC2002: This rule suggests using "cmd < file" instead of "cat | cmd".
# While < is more efficient, pipes are much more readable and expected.
#
# - SC2129: This rule suggests grouping multiple writes to a file in
# braces like "{ cmd1; cmd2; } >> file". This is unexpected and less
# readable.
#
# - SC2310: This is an optional warning that only appears with "set -e"
# and when a command is used as a conditional.
- name: 'Run shellcheck'
run: |-
git ls-files | grep -E '^([^.]+|.*\.(sh|zsh|bash))$' | xargs file --mime-type \
| grep "text/x-shellscript" | awk '{ print substr($1, 1, length($1)-1) }' \
| xargs shellcheck \
--check-sourced \
--enable=all \
--exclude=SC2002,SC2129,SC2310 \
--severity=style \
--format=gcc \
--color=never | sed -e 's/note:/warning:/g' -e 's/style:/warning:/g'
#
# Lint: YAML
#
lint_yaml:
name: 'Lint (YAML)'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
fetch-depth: 1
- name: 'Setup Python'
uses: 'actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065' # ratchet:actions/setup-python@v5
with:
python-version: '3'
- name: 'Install yamllint'
run: |-
pip install --user "yamllint==${YAMLLINT_VERSION}"
run: 'node scripts/lint.js --shellcheck'
- name: 'Run yamllint'
run: |-
git ls-files | grep -E '\.(yaml|yml)' | xargs yamllint --format github
run: 'node scripts/lint.js --yamllint'
#
# Lint: All
#
# This is a virtual job that other jobs depend on to wait for all linters to
# finish. It's also used to ensure linting happens on CI via required
# workflows.
lint:
name: 'Lint'
needs:
- 'lint_github_actions'
- 'lint_javascript'
- 'lint_shell'
- 'lint_yaml'
runs-on: 'ubuntu-latest'
steps:
- run: |-
echo 'All linters finished!'
- name: 'Run Prettier'
run: 'node scripts/lint.js --prettier'
#
# Test: Node
#
test:
name: 'Test'
runs-on: '${{ matrix.os }}'
test_linux:
name: 'Test (Linux)'
runs-on: 'gemini-cli-ubuntu-16-core'
needs:
- 'lint'
permissions:
@@ -256,12 +76,7 @@ jobs:
checks: 'write'
pull-requests: 'write'
strategy:
fail-fast: false # So we can see all test failures
matrix:
os:
- 'macos-latest'
- 'ubuntu-latest'
- 'windows-latest'
node-version:
- '20.x'
- '22.x'
@@ -277,18 +92,19 @@ jobs:
cache: 'npm'
- name: 'Build project'
run: |-
npm run build
run: 'npm run build'
- name: 'Install dependencies for testing'
run: |-
npm ci
run: 'npm ci'
- name: 'Run tests and generate reports'
env:
NO_COLOR: true
run: 'npm run test:ci'
- name: 'Wait for file system sync'
run: 'sleep 2'
- name: 'Publish Test Report (for non-forks)'
if: |-
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
@@ -304,7 +120,67 @@ jobs:
${{ always() && (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'test-results-fork-${{ matrix.node-version }}-${{ matrix.os }}'
name: 'test-results-fork-${{ matrix.node-version }}-${{ runner.os }}'
path: 'packages/*/junit.xml'
test_slow_platforms:
name: 'Slow Test - Mac'
runs-on: '${{ matrix.os }}'
needs:
- 'lint'
permissions:
contents: 'read'
checks: 'write'
pull-requests: 'write'
continue-on-error: true
strategy:
matrix:
os:
- 'macos-latest'
node-version:
- '20.x'
- '22.x'
- '24.x'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version: '${{ matrix.node-version }}'
cache: 'npm'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies for testing'
run: 'npm ci'
- name: 'Run tests and generate reports'
env:
NO_COLOR: true
run: 'npm run test:ci -- --coverage.enabled=false'
- name: 'Wait for file system sync'
run: 'sleep 2'
- name: 'Publish Test Report (for non-forks)'
if: |-
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
uses: 'dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3' # ratchet:dorny/test-reporter@v2
with:
name: 'Test Results (Node ${{ matrix.node-version }})'
path: 'packages/*/junit.xml'
reporter: 'java-junit'
fail-on-error: 'false'
- name: 'Upload Test Results Artifact (for forks)'
if: |-
${{ always() && (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'test-results-fork-${{ matrix.node-version }}-${{ runner.os }}'
path: 'packages/*/junit.xml'
- name: 'Upload coverage reports'
@@ -315,47 +191,9 @@ jobs:
name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}'
path: 'packages/*/coverage'
post_coverage_comment:
name: 'Post Coverage Comment'
runs-on: 'ubuntu-latest'
needs: 'test'
if: |-
${{ always() && github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name == github.repository) }}
continue-on-error: true
permissions:
contents: 'read' # For checkout
pull-requests: 'write' # For commenting
strategy:
matrix:
# Reduce noise by only posting the comment once
os:
- 'ubuntu-latest'
node-version:
- '22.x'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Download coverage reports artifact'
uses: 'actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0' # ratchet:actions/download-artifact@v5
with:
name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}'
path: 'coverage_artifact' # Download to a specific directory
- name: 'Post Coverage Comment using Composite Action'
uses: './.github/actions/post-coverage-comment' # Path to the composite action directory
with:
cli_json_file: 'coverage_artifact/cli/coverage/coverage-summary.json'
core_json_file: 'coverage_artifact/core/coverage/coverage-summary.json'
cli_full_text_summary_file: 'coverage_artifact/cli/coverage/full-text-summary.txt'
core_full_text_summary_file: 'coverage_artifact/core/coverage/full-text-summary.txt'
node_version: '${{ matrix.node-version }}'
os: '${{ matrix.os }}'
github_token: '${{ secrets.GITHUB_TOKEN }}'
codeql:
name: 'CodeQL'
runs-on: 'ubuntu-latest'
runs-on: 'gemini-cli-ubuntu-16-core'
permissions:
actions: 'read'
contents: 'read'
@@ -375,9 +213,8 @@ jobs:
# Check for changes in bundle size.
bundle_size:
name: 'Check Bundle Size'
if: |-
${{ github.event_name != 'merge_group' }}
runs-on: 'ubuntu-latest'
if: "github.event_name == 'pull_request'"
runs-on: 'gemini-cli-ubuntu-16-core'
permissions:
contents: 'read' # For checkout
pull-requests: 'write' # For commenting
@@ -395,3 +232,79 @@ jobs:
minimum-change-threshold: '1000'
compression: 'none'
clean-script: 'clean'
test_windows:
name: 'Slow Test - Win'
runs-on: 'gemini-cli-windows-16-core'
continue-on-error: true
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: 'Configure Windows Defender exclusions'
run: |
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
shell: 'pwsh'
- name: 'Configure npm for Windows performance'
run: |
npm config set progress false
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set maxsockets 32
npm config set registry https://registry.npmjs.org/
shell: 'pwsh'
- name: 'Install dependencies'
run: 'npm ci'
shell: 'pwsh'
- name: 'Build project'
run: 'npm run build'
shell: 'pwsh'
env:
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'production'
- name: 'Run tests and generate reports'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
NO_COLOR: true
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'test'
run: 'npm run test:ci -- --coverage.enabled=false'
shell: 'pwsh'
ci:
name: 'CI'
if: 'always()'
needs:
- 'lint'
- 'test_linux'
- 'codeql'
- 'bundle_size'
runs-on: 'gemini-cli-ubuntu-16-core'
steps:
- name: 'Check all job results'
run: |
if [[ (${{ needs.lint.result }} != 'success' && ${{ needs.lint.result }} != 'skipped') || \
(${{ needs.test_linux.result }} != 'success' && ${{ needs.test_linux.result }} != 'skipped') || \
(${{ needs.codeql.result }} != 'success' && ${{ needs.codeql.result }} != 'skipped') || \
(${{ needs.bundle_size.result }} != 'success' && ${{ needs.bundle_size.result }} != 'skipped') ]]; then
echo "One or more CI jobs failed."
exit 1
fi
echo "All CI jobs passed!"

View File

@@ -1,58 +0,0 @@
name: 'Create Patch PR'
on:
workflow_dispatch:
inputs:
commit:
description: 'The commit SHA to cherry-pick for the patch.'
required: true
type: 'string'
channel:
description: 'The release channel to patch.'
required: true
type: 'choice'
options:
- 'stable'
- 'preview'
dry_run:
description: 'Whether to run in dry-run mode.'
required: false
type: 'boolean'
default: false
jobs:
create-patch:
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
pull-requests: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
fetch-depth: 0
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
run: 'npm ci'
- name: 'Configure Git User'
run: |-
git config user.name "gemini-cli-robot"
git config user.email "gemini-cli-robot@google.com"
- name: 'Create Patch for Stable'
if: "github.event.inputs.channel == 'stable'"
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: 'node scripts/create-patch-pr.js --commit=${{ github.event.inputs.commit }} --channel=stable --dry-run=${{ github.event.inputs.dry_run }}'
- name: 'Create Patch for Preview'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: 'node scripts/create-patch-pr.js --commit=${{ github.event.inputs.commit }} --channel=${{ github.event.inputs.channel }} --dry-run=${{ github.event.inputs.dry_run }}'

View File

@@ -1,4 +1,4 @@
name: 'E2E Tests'
name: 'Testing: E2E'
on:
push:
@@ -14,11 +14,15 @@ on:
types: ['labeled']
merge_group:
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: |-
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
jobs:
e2e-test:
name: 'E2E Test (${{ matrix.os }}) - ${{ matrix.sandbox }}'
# This condition ensures the job runs for pushes to main, merge groups,
# PRs from the base repo, OR PRs from forks with the correct label.
build:
name: 'Build Project'
runs-on: 'gemini-cli-ubuntu-16-core'
if: |
github.event_name == 'push' ||
github.event_name == 'merge_group' ||
@@ -62,21 +66,11 @@ jobs:
strategy:
fail-fast: false
matrix:
os:
- 'ubuntu-latest'
- 'macos-latest'
- 'gemini-cli-windows-16-core'
sandbox:
- 'sandbox:none'
- 'sandbox:docker'
node-version:
- '20.x'
exclude:
# Docker tests are not supported on macOS or Windows
- os: 'macos-latest'
sandbox: 'sandbox:docker'
- os: 'gemini-cli-windows-16-core'
sandbox: 'sandbox:docker'
steps:
- name: 'Checkout (fork)'
@@ -90,22 +84,22 @@ jobs:
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
if: "github.event_name != 'pull_request_target'"
- name: 'Download build artifacts'
uses: 'actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093'
with:
name: 'build-artifacts-${{ github.run_id }}'
path: '.'
- name: 'Extract build artifacts'
run: 'tar -xvf build-artifacts.tar'
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '${{ matrix.node-version }}'
- name: 'Install dependencies'
run: |-
npm ci
- name: 'Build project'
run: |-
npm run build
- name: 'Set up Docker'
if: |-
matrix.os == 'ubuntu-latest' && matrix.sandbox == 'sandbox:docker'
if: "matrix.sandbox == 'sandbox:docker'"
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
- name: 'Run E2E tests'
@@ -114,6 +108,153 @@ jobs:
KEEP_OUTPUT: 'true'
SANDBOX: '${{ matrix.sandbox }}'
VERBOSE: 'true'
GEMINI_SANDBOX: 'docker'
shell: 'bash'
run: |-
npm run "test:integration:${SANDBOX}"
run: |
if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then
npm run build:sandbox
fi
npx vitest run --root ./integration-tests
e2e_slow_platforms:
name: 'Slow E2E - Mac'
needs:
- 'build'
if: |
github.event_name == 'push' ||
github.event_name == 'merge_group' ||
(github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event.label.name == 'maintainer:e2e:ok')
runs-on: '${{ matrix.os }}'
continue-on-error: true
strategy:
fail-fast: false
matrix:
os:
- 'macos-latest'
node-version:
- '20.x'
steps:
- name: 'Checkout (fork)'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
if: "github.event_name == 'pull_request_target'"
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.event.pull_request.head.repo.full_name }}'
- name: 'Checkout (internal)'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
if: "github.event_name != 'pull_request_target'"
- name: 'Download build artifacts'
uses: 'actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093'
with:
name: 'build-artifacts-${{ github.run_id }}'
path: '.'
- name: 'Extract build artifacts'
run: 'tar -xvf build-artifacts.tar'
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '${{ matrix.node-version }}'
- name: 'Fix rollup optional dependencies on macOS'
if: "runner.os == 'macOS'"
run: |
npm cache clean --force
npm install --no-save @rollup/rollup-darwin-arm64 || true
- name: 'Run E2E tests (non-Windows)'
if: "runner.os != 'Windows'"
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
SANDBOX: 'sandbox:none'
VERBOSE: 'true'
run: 'npx vitest run --root ./integration-tests'
e2e_windows:
name: 'Slow E2E - Win'
if: |
github.event_name == 'push' ||
github.event_name == 'merge_group' ||
(github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event.label.name == 'maintainer:e2e:ok')
runs-on: 'gemini-cli-windows-16-core'
continue-on-error: true
steps:
- name: 'Checkout (fork)'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
if: "github.event_name == 'pull_request_target'"
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.event.pull_request.head.repo.full_name }}'
- name: 'Checkout (internal)'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
if: "github.event_name != 'pull_request_target'"
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: 'Configure Windows Defender exclusions'
run: |
Add-MpPreference -ExclusionPath $env:GITHUB_WORKSPACE -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\node_modules" -Force
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\packages" -Force
Add-MpPreference -ExclusionPath "$env:TEMP" -Force
shell: 'pwsh'
- name: 'Configure npm for Windows performance'
run: |
npm config set progress false
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set maxsockets 32
npm config set registry https://registry.npmjs.org/
shell: 'pwsh'
- name: 'Install dependencies'
run: 'npm ci'
shell: 'pwsh'
- name: 'Run E2E tests'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
SANDBOX: 'sandbox:none'
VERBOSE: 'true'
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'test'
shell: 'pwsh'
run: 'npx vitest run --root ./integration-tests'
e2e:
name: 'E2E'
if: |
always() && (
github.event_name == 'push' ||
github.event_name == 'merge_group' ||
(github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event.label.name == 'maintainer:e2e:ok')
)
needs:
- 'e2e_linux'
runs-on: 'gemini-cli-ubuntu-16-core'
steps:
- name: 'Check E2E test results'
run: |
if [[ ${{ needs.e2e_linux.result }} != 'success' ]]; then
echo "The required E2E test job failed."
exit 1
fi
echo "All required E2E test jobs passed!"

View File

@@ -1,56 +0,0 @@
name: 'Patch from Comment'
on:
issue_comment:
types: ['created']
jobs:
slash-command:
runs-on: 'ubuntu-latest'
steps:
- name: 'Slash Command Dispatch'
id: 'slash_command'
uses: 'peter-evans/slash-command-dispatch@40877f718dce0101edfc7aea2b3800cc192f9ed5'
with:
token: '${{ secrets.GITHUB_TOKEN }}'
commands: 'patch'
permission: 'write'
issue-type: 'pull-request'
static-args: |
dry_run=false
- name: 'Get PR Status'
id: 'pr_status'
if: "steps.slash_command.outputs.dispatched == 'true'"
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
gh pr view "${{ github.event.issue.number }}" --json mergeCommit,state > pr_status.json
echo "MERGE_COMMIT_SHA=$(jq -r .mergeCommit.oid pr_status.json)" >> "$GITHUB_OUTPUT"
echo "STATE=$(jq -r .state pr_status.json)" >> "$GITHUB_OUTPUT"
- name: 'Dispatch if Merged'
if: "steps.pr_status.outputs.STATE == 'MERGED'"
uses: 'actions/github-script@00f12e3e20659f42342b1c0226afda7f7c042325'
with:
script: |
const args = JSON.parse('${{ steps.slash_command.outputs.command-arguments }}');
github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'create-patch-pr.yml',
ref: 'main',
inputs: {
commit: '${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}',
channel: args.channel,
dry_run: args.dry_run
}
})
- name: 'Comment on Failure'
if: "steps.pr_status.outputs.STATE != 'MERGED'"
uses: 'peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d'
with:
issue-number: '${{ github.event.issue.number }}'
body: |
:x: The `/patch` command failed. This pull request must be merged before a patch can be created.

View File

@@ -1,94 +0,0 @@
name: 'Patch Release'
on:
workflow_dispatch:
inputs:
type:
description: 'The type of release to patch from.'
required: true
type: 'choice'
options:
- 'stable'
- 'preview'
ref:
description: 'The branch or ref (full git sha) to release from.'
required: true
type: 'string'
default: 'main'
dry_run:
description: 'Run a dry-run of the release process; no branches, npm packages or GitHub releases will be created.'
required: true
type: 'boolean'
default: true
force_skip_tests:
description: 'Select to skip the "Run Tests" step in testing. Prod releases should run tests'
required: false
type: 'boolean'
default: false
jobs:
release:
runs-on: 'ubuntu-latest'
environment:
name: 'production-release'
url: '${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ steps.version.outputs.RELEASE_TAG }}'
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
permissions:
contents: 'write'
packages: 'write'
id-token: 'write'
issues: 'write' # For creating issues on failure
outputs:
RELEASE_TAG: '${{ steps.version.outputs.RELEASE_TAG }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
run: |-
npm ci
- name: 'Get the version'
id: 'version'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |-
VERSION_JSON="$(node scripts/get-release-version.js --type=patch --patch-from=${{ github.event.inputs.type }})"
echo "${VERSION_JSON}"
echo "RELEASE_TAG=$(echo "${VERSION_JSON}" | jq -r .releaseTag)" >> "${GITHUB_OUTPUT}"
echo "RELEASE_VERSION=$(echo "${VERSION_JSON}" | jq -r .releaseVersion)" >> "${GITHUB_OUTPUT}"
echo "NPM_TAG=$(echo "${VERSION_JSON}" | jq -r .npmTag)" >> "${GITHUB_OUTPUT}"
echo "PREVIOUS_TAG=$(echo "${VERSION_JSON}" | jq -r .previousReleaseTag)" >> "${GITHUB_OUTPUT}"
- name: 'Print Calculated Version'
run: |-
echo "Calculated version: ${{ steps.version.outputs.RELEASE_VERSION }}"
- name: 'Run Tests'
uses: './.github/actions/run-tests'
with:
force_skip_tests: '${{ github.event.inputs.force_skip_tests }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
with:
release-version: '${{ steps.version.outputs.RELEASE_VERSION }}'
release-tag: '${{ steps.version.outputs.RELEASE_TAG }}'
npm-tag: '${{ steps.version.outputs.NPM_TAG }}'
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
github-token: '${{ secrets.GITHUB_TOKEN }}'
dry-run: '${{ github.event.inputs.dry_run }}'
previous-tag: '${{ steps.version.outputs.PREVIOUS_TAG }}'

View File

@@ -0,0 +1,56 @@
name: 'Release: Change Tags'
on:
workflow_dispatch:
inputs:
version:
description: 'The package version to tag (e.g., 0.5.0-preview-2). This version must already exist on the npm registry.'
required: true
type: 'string'
channel:
description: 'The npm dist-tag to apply (e.g., latest, preview, nightly).'
required: true
type: 'choice'
options:
- 'latest'
- 'preview'
- 'nightly'
ref:
description: 'The branch, tag, or SHA to run from.'
required: false
type: 'string'
default: 'main'
dry-run:
description: 'Whether to run in dry-run mode.'
required: false
type: 'boolean'
default: true
jobs:
change-tags:
runs-on: 'ubuntu-latest'
permissions:
packages: 'write'
issues: 'write'
steps:
- name: 'Checkout repository'
uses: 'actions/checkout@v4'
with:
ref: '${{ github.event.inputs.ref }}'
fetch-depth: 0
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '.nvmrc'
registry-url: 'https://wombat-dressing-room.appspot.com'
scope: '@google'
- name: 'Change tag'
uses: './.github/actions/tag-npm-release'
with:
channel: '${{ github.event.inputs.channel }}'
version: '${{ github.event.inputs.version }}'
dry-run: '${{ github.event.inputs.dry-run }}'
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'

89
.github/workflows/release-manual.yml vendored Normal file
View File

@@ -0,0 +1,89 @@
name: 'Release: Manual'
on:
workflow_dispatch:
inputs:
version:
description: 'The version to release (e.g., v0.1.11). Must be a valid semver string with a "v" prefix.'
required: true
type: 'string'
ref:
description: 'The branch, tag, or SHA to release from.'
required: true
type: 'string'
npm_channel:
description: 'The npm channel to publish to.'
required: true
type: 'choice'
options:
- 'preview'
- 'nightly'
- 'latest'
- 'dev'
default: 'dev'
dry_run:
description: 'Run a dry-run of the release process; no branches, npm packages or GitHub releases will be created.'
required: true
type: 'boolean'
default: true
force_skip_tests:
description: 'Select to skip the "Run Tests" step in testing. Prod releases should run tests'
required: false
type: 'boolean'
default: false
skip_github_release:
description: 'Select to skip creating a GitHub release and create a npm release only.'
required: false
type: 'boolean'
default: false
jobs:
release:
runs-on: 'self-hosted'
permissions:
contents: 'write'
packages: 'write'
issues: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: '${{ github.event.inputs.ref }}'
fetch-depth: 0
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
run: 'npm ci'
- name: 'Prepare Release Info'
id: 'release_info'
run: |
RELEASE_VERSION="${{ github.event.inputs.version }}"
echo "RELEASE_VERSION=${RELEASE_VERSION#v}" >> "${GITHUB_OUTPUT}"
echo "PREVIOUS_TAG=$(git describe --tags --abbrev=0)" >> "${GITHUB_OUTPUT}"
- name: 'Run Tests'
if: |-
${{ github.event.inputs.force_skip_tests != true }}
uses: './.github/actions/run-tests'
with:
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
with:
force-skip-tests: '${{ github.event.inputs.force_skip_tests }}'
release-version: '${{ steps.release_info.outputs.RELEASE_VERSION }}'
release-tag: '${{ github.event.inputs.version }}'
npm-tag: '${{ github.event.inputs.npm_channel }}'
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
github-token: '${{ secrets.GITHUB_TOKEN }}'
dry-run: '${{ github.event.inputs.dry_run }}'
previous-tag: '${{ steps.release_info.outputs.PREVIOUS_TAG }}'
skip-github-release: '${{ github.event.inputs.skip_github_release }}'

View File

@@ -1,4 +1,4 @@
name: 'Nightly Release'
name: 'Release: Nightly'
on:
schedule:
@@ -25,7 +25,10 @@ jobs:
release:
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
packages: 'write'
issues: 'write'
pull-requests: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
@@ -71,6 +74,16 @@ jobs:
dry-run: '${{ github.event.inputs.dry_run }}'
previous-tag: '${{ steps.nightly_version.outputs.PREVIOUS_TAG }}'
- name: 'Create and Merge Pull Request'
uses: './.github/actions/create-pull-request'
with:
branch-name: 'release/${{ steps.nightly_version.outputs.RELEASE_TAG }}'
pr-title: 'chore(release): bump version to ${{ steps.nightly_version.outputs.RELEASE_VERSION }}'
pr-body: 'Automated version bump for nightly release.'
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
dry-run: '${{ github.event.inputs.dry_run }}'
- name: 'Create Issue on Failure'
if: '${{ failure() && github.event.inputs.dry_run == false }}'
env:

View File

@@ -0,0 +1,109 @@
name: 'Release: Patch (1) Create PR'
on:
workflow_dispatch:
inputs:
commit:
description: 'The commit SHA to cherry-pick for the patch.'
required: true
type: 'string'
channel:
description: 'The release channel to patch.'
required: true
type: 'choice'
options:
- 'stable'
- 'preview'
dry_run:
description: 'Whether to run in dry-run mode.'
required: false
type: 'boolean'
default: false
ref:
description: 'The branch, tag, or SHA to test from.'
required: false
type: 'string'
default: 'main'
original_pr:
description: 'The original PR number to comment back on.'
required: false
type: 'string'
jobs:
create-patch:
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
pull-requests: 'write'
actions: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.ref }}'
fetch-depth: 0
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Script Dependencies'
run: 'npm install yargs'
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b'
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-pull-requests: 'write'
permission-contents: 'write'
- name: 'Configure Git User'
run: |-
git config user.name "gemini-cli-robot"
git config user.email "gemini-cli-robot@google.com"
# Configure git to use GITHUB_TOKEN for remote operations (has actions:write for workflow files)
git remote set-url origin "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
- name: 'Create Patch'
id: 'create_patch'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
GH_TOKEN: '${{ steps.generate_token.outputs.token }}'
continue-on-error: true
run: |
# Capture output and display it in logs using tee
{
node scripts/releasing/create-patch-pr.js --commit=${{ github.event.inputs.commit }} --channel=${{ github.event.inputs.channel }} --dry-run=${{ github.event.inputs.dry_run }}
echo "EXIT_CODE=$?" >> "$GITHUB_OUTPUT"
} 2>&1 | tee >(
echo "LOG_CONTENT<<EOF" >> "$GITHUB_ENV"
cat >> "$GITHUB_ENV"
echo "EOF" >> "$GITHUB_ENV"
)
- name: 'Comment on Original PR'
if: 'always() && inputs.original_pr'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ORIGINAL_PR: '${{ github.event.inputs.original_pr }}'
EXIT_CODE: '${{ steps.create_patch.outputs.EXIT_CODE }}'
COMMIT: '${{ github.event.inputs.commit }}'
CHANNEL: '${{ github.event.inputs.channel }}'
REPOSITORY: '${{ github.repository }}'
GITHUB_RUN_ID: '${{ github.run_id }}'
LOG_CONTENT: '${{ env.LOG_CONTENT }}'
continue-on-error: true
run: |
git checkout '${{ github.event.inputs.ref }}'
node scripts/releasing/patch-create-comment.js
- name: 'Fail Workflow if Main Task Failed'
if: 'always() && steps.create_patch.outputs.EXIT_CODE != 0'
run: |
echo "Patch creation failed with exit code: ${{ steps.create_patch.outputs.EXIT_CODE }}"
echo "Check the logs above and the comment posted to the original PR for details."
exit 1

View File

@@ -0,0 +1,72 @@
name: 'Release: Patch (2) Trigger'
on:
pull_request:
types:
- 'closed'
branches:
- 'release/**'
workflow_dispatch:
inputs:
ref:
description: 'The head ref of the merged hotfix PR to trigger the release for (e.g. hotfix/v1.2.3/cherry-pick-abc).'
required: true
type: 'string'
workflow_ref:
description: 'The ref to checkout the workflow code from.'
required: false
type: 'string'
default: 'main'
workflow_id:
description: 'The workflow to trigger. Defaults to patch-release.yml'
required: false
type: 'string'
default: 'release-patch-3-release.yml'
dry_run:
description: 'Whether this is a dry run.'
required: false
type: 'boolean'
default: false
force_skip_tests:
description: 'Select to skip the "Run Tests" step in testing. Prod releases should run tests'
required: false
type: 'boolean'
default: false
jobs:
trigger-patch-release:
if: "(github.event_name == 'pull_request' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'hotfix/')) || github.event_name == 'workflow_dispatch'"
runs-on: 'ubuntu-latest'
permissions:
actions: 'write'
contents: 'write'
pull-requests: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: "${{ github.event.inputs.workflow_ref || 'main' }}"
fetch-depth: 1
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
run: 'npm ci'
- name: 'Trigger Patch Release'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
HEAD_REF: "${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.event.inputs.ref }}"
PR_BODY: "${{ github.event_name == 'pull_request' && github.event.pull_request.body || '' }}"
WORKFLOW_ID: '${{ github.event.inputs.workflow_id }}'
GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'
GITHUB_REPOSITORY_NAME: '${{ github.event.repository.name }}'
GITHUB_EVENT_NAME: '${{ github.event_name }}'
GITHUB_EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
FORCE_SKIP_TESTS: '${{ github.event.inputs.force_skip_tests }}'
run: |
node scripts/releasing/patch-trigger.js

View File

@@ -0,0 +1,219 @@
name: 'Release: Patch (3) Release'
on:
workflow_dispatch:
inputs:
type:
description: 'The type of release to perform.'
required: true
type: 'choice'
options:
- 'stable'
- 'preview'
dry_run:
description: 'Run a dry-run of the release process; no branches, npm packages or GitHub releases will be created.'
required: true
type: 'boolean'
default: true
force_skip_tests:
description: 'Select to skip the "Run Tests" step in testing. Prod releases should run tests'
required: false
type: 'boolean'
default: false
release_ref:
description: 'The branch, tag, or SHA to release from.'
required: true
type: 'string'
original_pr:
description: 'The original PR number to comment back on.'
required: false
type: 'string'
jobs:
release:
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
packages: 'write'
issues: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
fetch-depth: 0
fetch-tags: true
- name: 'Checkout Release Code'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: '${{ github.event.inputs.release_ref }}'
path: 'release'
fetch-depth: 0
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
working-directory: './release'
run: |-
npm ci
- name: 'Print Inputs'
shell: 'bash'
run: |-
echo "${{ toJSON(inputs) }}"
- name: 'Get Patch Version'
id: 'patch_version'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
# Use the existing get-release-version.js script to calculate patch version
# Run from main checkout which has full git history and access to npm
PATCH_JSON=$(node scripts/get-release-version.js --type=patch --patch-from=${{ github.event.inputs.type }})
echo "Patch version calculation result: ${PATCH_JSON}"
RELEASE_VERSION=$(echo "${PATCH_JSON}" | jq -r .releaseVersion)
RELEASE_TAG=$(echo "${PATCH_JSON}" | jq -r .releaseTag)
NPM_TAG=$(echo "${PATCH_JSON}" | jq -r .npmTag)
PREVIOUS_TAG=$(echo "${PATCH_JSON}" | jq -r .previousReleaseTag)
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "${GITHUB_OUTPUT}"
echo "RELEASE_TAG=${RELEASE_TAG}" >> "${GITHUB_OUTPUT}"
echo "NPM_TAG=${NPM_TAG}" >> "${GITHUB_OUTPUT}"
echo "PREVIOUS_TAG=${PREVIOUS_TAG}" >> "${GITHUB_OUTPUT}"
- name: 'Verify Version Consistency'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
CHANNEL: '${{ github.event.inputs.type }}'
run: |
echo "🔍 Verifying no concurrent patch releases have occurred..."
# Store original calculation for comparison
ORIGINAL_RELEASE_VERSION="${{ steps.patch_version.outputs.RELEASE_VERSION }}"
ORIGINAL_RELEASE_TAG="${{ steps.patch_version.outputs.RELEASE_TAG }}"
ORIGINAL_PREVIOUS_TAG="${{ steps.patch_version.outputs.PREVIOUS_TAG }}"
echo "Original calculation:"
echo " Release version: ${ORIGINAL_RELEASE_VERSION}"
echo " Release tag: ${ORIGINAL_RELEASE_TAG}"
echo " Previous tag: ${ORIGINAL_PREVIOUS_TAG}"
# Re-run the same version calculation script
echo "Re-calculating version to check for changes..."
CURRENT_PATCH_JSON=$(node scripts/get-release-version.js --type=patch --patch-from="${CHANNEL}")
CURRENT_RELEASE_VERSION=$(echo "${CURRENT_PATCH_JSON}" | jq -r .releaseVersion)
CURRENT_RELEASE_TAG=$(echo "${CURRENT_PATCH_JSON}" | jq -r .releaseTag)
CURRENT_PREVIOUS_TAG=$(echo "${CURRENT_PATCH_JSON}" | jq -r .previousReleaseTag)
echo "Current calculation:"
echo " Release version: ${CURRENT_RELEASE_VERSION}"
echo " Release tag: ${CURRENT_RELEASE_TAG}"
echo " Previous tag: ${CURRENT_PREVIOUS_TAG}"
# Compare calculations
if [[ "${ORIGINAL_RELEASE_VERSION}" != "${CURRENT_RELEASE_VERSION}" ]] || \
[[ "${ORIGINAL_RELEASE_TAG}" != "${CURRENT_RELEASE_TAG}" ]] || \
[[ "${ORIGINAL_PREVIOUS_TAG}" != "${CURRENT_PREVIOUS_TAG}" ]]; then
echo "❌ RACE CONDITION DETECTED: Version calculations have changed!"
echo "This indicates another patch release completed while this one was in progress."
echo ""
echo "Originally planned: ${ORIGINAL_RELEASE_VERSION} (from ${ORIGINAL_PREVIOUS_TAG})"
echo "Should now build: ${CURRENT_RELEASE_VERSION} (from ${CURRENT_PREVIOUS_TAG})"
echo ""
echo "# Setting outputs for failure comment"
echo "CURRENT_RELEASE_VERSION=${CURRENT_RELEASE_VERSION}" >> "${GITHUB_ENV}"
echo "CURRENT_RELEASE_TAG=${CURRENT_RELEASE_TAG}" >> "${GITHUB_ENV}"
echo "CURRENT_PREVIOUS_TAG=${CURRENT_PREVIOUS_TAG}" >> "${GITHUB_ENV}"
echo "The patch release must be restarted to use the correct version numbers."
exit 1
fi
echo "✅ Version calculations unchanged - proceeding with release"
- name: 'Print Calculated Version'
run: |-
echo "Patch Release Summary:"
echo " Release Version: ${{ steps.patch_version.outputs.RELEASE_VERSION }}"
echo " Release Tag: ${{ steps.patch_version.outputs.RELEASE_TAG }}"
echo " NPM Tag: ${{ steps.patch_version.outputs.NPM_TAG }}"
echo " Previous Tag: ${{ steps.patch_version.outputs.PREVIOUS_TAG }}"
- name: 'Run Tests'
uses: './.github/actions/run-tests'
with:
force_skip_tests: '${{ github.event.inputs.force_skip_tests }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
working-directory: './release'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
with:
release-version: '${{ steps.patch_version.outputs.RELEASE_VERSION }}'
release-tag: '${{ steps.patch_version.outputs.RELEASE_TAG }}'
npm-tag: '${{ steps.patch_version.outputs.NPM_TAG }}'
wombat-token-core: '${{ secrets.WOMBAT_TOKEN_CORE }}'
wombat-token-cli: '${{ secrets.WOMBAT_TOKEN_CLI }}'
github-token: '${{ secrets.GITHUB_TOKEN }}'
dry-run: '${{ github.event.inputs.dry_run }}'
previous-tag: '${{ steps.patch_version.outputs.PREVIOUS_TAG }}'
working-directory: './release'
- name: 'Create Issue on Failure'
if: '${{ failure() && github.event.inputs.dry_run == false }}'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
RELEASE_TAG: '${{ steps.patch_version.outputs.RELEASE_TAG }}'
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
run: |
gh issue create \
--title 'Patch Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
--body 'The patch-release workflow failed. See the full run for details: ${DETAILS_URL}' \
--label 'kind/bug,release-failure,priority/p0'
- name: 'Comment Success on Original PR'
if: '${{ success() && github.event.inputs.original_pr }}'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ORIGINAL_PR: '${{ github.event.inputs.original_pr }}'
SUCCESS: 'true'
RELEASE_VERSION: '${{ steps.patch_version.outputs.RELEASE_VERSION }}'
RELEASE_TAG: '${{ steps.patch_version.outputs.RELEASE_TAG }}'
NPM_TAG: '${{ steps.patch_version.outputs.NPM_TAG }}'
CHANNEL: '${{ github.event.inputs.type }}'
DRY_RUN: '${{ github.event.inputs.dry_run }}'
GITHUB_RUN_ID: '${{ github.run_id }}'
GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'
GITHUB_REPOSITORY_NAME: '${{ github.event.repository.name }}'
run: |
node scripts/releasing/patch-comment.js
- name: 'Comment Failure on Original PR'
if: '${{ failure() && github.event.inputs.original_pr }}'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ORIGINAL_PR: '${{ github.event.inputs.original_pr }}'
SUCCESS: 'false'
RELEASE_VERSION: '${{ steps.patch_version.outputs.RELEASE_VERSION }}'
RELEASE_TAG: '${{ steps.patch_version.outputs.RELEASE_TAG }}'
NPM_TAG: '${{ steps.patch_version.outputs.NPM_TAG }}'
CHANNEL: '${{ github.event.inputs.type }}'
DRY_RUN: '${{ github.event.inputs.dry_run }}'
GITHUB_RUN_ID: '${{ github.run_id }}'
GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'
GITHUB_REPOSITORY_NAME: '${{ github.event.repository.name }}'
# Pass current version info for race condition failures
CURRENT_RELEASE_VERSION: '${{ env.CURRENT_RELEASE_VERSION }}'
CURRENT_RELEASE_TAG: '${{ env.CURRENT_RELEASE_TAG }}'
CURRENT_PREVIOUS_TAG: '${{ env.CURRENT_PREVIOUS_TAG }}'
run: |
# Check if this was a version consistency failure
if [[ -n "${CURRENT_RELEASE_VERSION}" ]]; then
echo "Detected version race condition failure - posting specific comment with current version info"
export RACE_CONDITION_FAILURE=true
fi
node scripts/releasing/patch-comment.js

View File

@@ -0,0 +1,187 @@
name: 'Release: Patch from Comment'
on:
issue_comment:
types: ['created']
jobs:
slash-command:
runs-on: 'ubuntu-latest'
# Only run if the comment is from a human user (not automated)
if: "github.event.comment.user.type == 'User' && github.event.comment.user.login != 'github-actions[bot]'"
permissions:
contents: 'write'
pull-requests: 'write'
actions: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
fetch-depth: 1
- name: 'Slash Command Dispatch'
id: 'slash_command'
uses: 'peter-evans/slash-command-dispatch@40877f718dce0101edfc7aea2b3800cc192f9ed5'
with:
token: '${{ secrets.GITHUB_TOKEN }}'
commands: 'patch'
permission: 'write'
issue-type: 'pull-request'
- name: 'Get PR Status'
id: 'pr_status'
if: "startsWith(github.event.comment.body, '/patch')"
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
gh pr view "${{ github.event.issue.number }}" --json mergeCommit,state > pr_status.json
echo "MERGE_COMMIT_SHA=$(jq -r .mergeCommit.oid pr_status.json)" >> "$GITHUB_OUTPUT"
echo "STATE=$(jq -r .state pr_status.json)" >> "$GITHUB_OUTPUT"
- name: 'Dispatch if Merged'
if: "steps.pr_status.outputs.STATE == 'MERGED'"
id: 'dispatch_patch'
uses: 'actions/github-script@00f12e3e20659f42342b1c0226afda7f7c042325'
env:
COMMENT_BODY: '${{ github.event.comment.body }}'
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
script: |
// Parse the comment body directly to extract channel(s)
const commentBody = process.env.COMMENT_BODY;
console.log('Comment body:', commentBody);
let channels = ['stable', 'preview']; // default to both
// Parse different formats:
// /patch (defaults to both)
// /patch both
// /patch stable
// /patch preview
if (commentBody.trim() === '/patch' || commentBody.trim() === '/patch both') {
channels = ['stable', 'preview'];
} else if (commentBody.trim() === '/patch stable') {
channels = ['stable'];
} else if (commentBody.trim() === '/patch preview') {
channels = ['preview'];
} else {
// Fallback parsing for legacy formats
if (commentBody.includes('channel=preview')) {
channels = ['preview'];
} else if (commentBody.includes('--channel preview')) {
channels = ['preview'];
}
}
console.log('Detected channels:', channels);
const dispatchedRuns = [];
// Dispatch workflow for each channel
for (const channel of channels) {
console.log(`Dispatching workflow for channel: ${channel}`);
const response = await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'release-patch-1-create-pr.yml',
ref: 'main',
inputs: {
commit: '${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}',
channel: channel,
original_pr: '${{ github.event.issue.number }}'
}
});
dispatchedRuns.push({ channel, response });
}
// Wait a moment for the workflows to be created
await new Promise(resolve => setTimeout(resolve, 3000));
const runs = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'release-patch-1-create-pr.yml',
per_page: 20 // Increased to handle multiple runs
});
// Find the recent runs that match our trigger
const recentRuns = runs.data.workflow_runs.filter(run =>
run.event === 'workflow_dispatch' &&
new Date(run.created_at) > new Date(Date.now() - 15000) // Within last 15 seconds
).slice(0, channels.length); // Limit to the number of channels we dispatched
// Set outputs
core.setOutput('dispatched_channels', channels.join(','));
core.setOutput('dispatched_run_count', channels.length.toString());
if (recentRuns.length > 0) {
core.setOutput('dispatched_run_urls', recentRuns.map(r => r.html_url).join(','));
core.setOutput('dispatched_run_ids', recentRuns.map(r => r.id).join(','));
}
- name: 'Comment on Failure'
if: "startsWith(github.event.comment.body, '/patch') && steps.pr_status.outputs.STATE != 'MERGED'"
uses: 'peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d'
with:
token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}'
body: |
:x: The `/patch` command failed. This pull request must be merged before a patch can be created.
- name: 'Final Status Comment - Success'
if: "always() && startsWith(github.event.comment.body, '/patch') && steps.dispatch_patch.outcome == 'success' && steps.dispatch_patch.outputs.dispatched_run_urls"
uses: 'peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d'
with:
token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}'
body: |
✅ **Patch workflow(s) dispatched successfully!**
**📋 Details:**
- **Channels**: `${{ steps.dispatch_patch.outputs.dispatched_channels }}`
- **Commit**: `${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}`
- **Workflows Created**: ${{ steps.dispatch_patch.outputs.dispatched_run_count }}
**🔗 Track Progress:**
- [View patch workflows](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml)
- [This workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
- name: 'Final Status Comment - Dispatch Success (No URL)'
if: "always() && startsWith(github.event.comment.body, '/patch') && steps.dispatch_patch.outcome == 'success' && !steps.dispatch_patch.outputs.dispatched_run_urls"
uses: 'peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d'
with:
token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}'
body: |
✅ **Patch workflow(s) dispatched successfully!**
**📋 Details:**
- **Channels**: `${{ steps.dispatch_patch.outputs.dispatched_channels }}`
- **Commit**: `${{ steps.pr_status.outputs.MERGE_COMMIT_SHA }}`
- **Workflows Created**: ${{ steps.dispatch_patch.outputs.dispatched_run_count }}
**🔗 Track Progress:**
- [View patch workflows](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml)
- [This workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
- name: 'Final Status Comment - Failure'
if: "always() && startsWith(github.event.comment.body, '/patch') && (steps.dispatch_patch.outcome == 'failure' || steps.dispatch_patch.outcome == 'cancelled')"
uses: 'peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d'
with:
token: '${{ secrets.GITHUB_TOKEN }}'
issue-number: '${{ github.event.issue.number }}'
body: |
❌ **Patch workflow dispatch failed!**
There was an error dispatching the patch creation workflow.
**🔍 Troubleshooting:**
- Check that the PR is properly merged
- Verify workflow permissions
- Review error logs in the workflow run
**🔗 Debug Links:**
- [This workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
- [Patch workflow history](https://github.com/${{ github.repository }}/actions/workflows/release-patch-1-create-pr.yml)

View File

@@ -1,4 +1,4 @@
name: 'Promote Release'
name: 'Release: Promote'
on:
workflow_dispatch:
@@ -314,20 +314,15 @@ jobs:
echo "Dry run enabled. Skipping push."
fi
- name: 'Create and Approve Pull Request'
if: |-
${{ github.event.inputs.dry_run == 'false' }}
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
run: |
gh pr create \
--title "chore(release): bump version to ${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}" \
--body "Automated version bump to prepare for the next nightly release." \
--base "main" \
--head "${BRANCH_NAME}" \
--fill
gh pr merge --auto --squash
- name: 'Create and Merge Pull Request'
uses: './.github/actions/create-pull-request'
with:
branch-name: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
pr-title: 'chore(release): bump version to ${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}'
pr-body: 'Automated version bump to prepare for the next nightly release.'
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
dry-run: '${{ github.event.inputs.dry_run }}'
- name: 'Create Issue on Failure'
if: '${{ failure() && github.event.inputs.dry_run == false }}'

33
.github/workflows/release-sandbox.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: 'Release Sandbox'
on:
workflow_dispatch:
inputs:
ref:
description: 'The branch, tag, or SHA to release from.'
required: false
type: 'string'
default: 'main'
dry-run:
description: 'Whether this is a dry run.'
required: false
type: 'boolean'
default: true
jobs:
build:
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0
- name: 'Push'
uses: './.github/actions/push-sandbox'
with:
github-actor: '${{ github.actor }}'
github-secret: '${{ secrets.GITHUB_TOKEN }}'
github-sha: '${{ github.event.inputs.ref || github.sha }}'
github-ref-name: '${{github.event.inputs.ref}}'
dry-run: '${{ github.event.inputs.dry-run }}'

View File

@@ -1,202 +0,0 @@
name: 'Release'
on:
workflow_dispatch:
inputs:
version:
description: 'The version to release (e.g., v0.1.11).'
required: true
type: 'string'
ref:
description: 'The branch or ref (full git sha) to release from.'
required: true
type: 'string'
default: 'main'
dry_run:
description: 'Run a dry-run of the release process; no branches, npm packages or GitHub releases will be created.'
required: true
type: 'boolean'
default: true
force_skip_tests:
description: 'Select to skip the "Run Tests" step in testing. Prod releases should run tests'
required: false
type: 'boolean'
default: false
jobs:
release:
runs-on: 'ubuntu-latest'
environment:
name: 'production-release'
url: '${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ steps.version.outputs.RELEASE_TAG }}'
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
permissions:
contents: 'write'
packages: 'write'
id-token: 'write'
issues: 'write' # For creating issues on failure
outputs:
RELEASE_TAG: '${{ steps.version.outputs.RELEASE_TAG }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0
- name: 'Set booleans for simplified logic'
env:
DRY_RUN_INPUT: '${{ github.event.inputs.dry_run }}'
id: 'vars'
run: |-
is_dry_run="false"
if [[ "${DRY_RUN_INPUT}" == "true" ]]; then
is_dry_run="true"
fi
echo "is_dry_run=${is_dry_run}" >> "${GITHUB_OUTPUT}"
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
run: |-
npm ci
- name: 'Get the version'
id: 'version'
run: |-
RELEASE_TAG="${{ inputs.version }}"
# The version for npm should not have the 'v' prefix.
RELEASE_VERSION="${RELEASE_TAG#v}"
NPM_TAG="latest"
if [[ "${RELEASE_TAG}" == *"preview"* ]]; then
NPM_TAG="preview"
fi
PREVIOUS_TAG=$(git describe --tags --abbrev=0)
echo "RELEASE_TAG=${RELEASE_TAG}" >> "${GITHUB_OUTPUT}"
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "${GITHUB_OUTPUT}"
echo "NPM_TAG=${NPM_TAG}" >> "${GITHUB_OUTPUT}"
echo "PREVIOUS_TAG=${PREVIOUS_TAG}" >> "${GITHUB_OUTPUT}"
- name: 'Run Tests'
if: |-
${{ github.event.inputs.force_skip_tests != 'true' }}
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
run: |-
npm run preflight
npm run test:integration:sandbox:none
npm run test:integration:sandbox:docker
- name: 'Configure Git User'
run: |-
git config user.name "gemini-cli-robot"
git config user.email "gemini-cli-robot@google.com"
- name: 'Create and switch to a release branch'
id: 'release_branch'
env:
RELEASE_TAG: '${{ steps.version.outputs.RELEASE_TAG }}'
run: |-
BRANCH_NAME="release/${RELEASE_TAG}"
git switch -c "${BRANCH_NAME}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_OUTPUT}"
- name: 'Update package versions'
env:
RELEASE_VERSION: '${{ steps.version.outputs.RELEASE_VERSION }}'
run: |-
npm run release:version "${RELEASE_VERSION}"
- name: 'Commit and Conditionally Push package versions'
env:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
IS_DRY_RUN: '${{ steps.vars.outputs.is_dry_run }}'
RELEASE_TAG: '${{ steps.version.outputs.RELEASE_TAG }}'
run: |-
git add package.json npm-shrinkwrap.json packages/*/package.json
git commit -m "chore(release): ${RELEASE_TAG}"
if [[ "${IS_DRY_RUN}" == "false" ]]; then
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}" --follow-tags
else
echo "Dry run enabled. Skipping push."
fi
- name: 'Build and Prepare Packages'
run: |-
npm run build:packages
npm run prepare:package
- name: 'Configure npm for publishing'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
registry-url: 'https://wombat-dressing-room.appspot.com'
scope: '@google'
- name: 'Publish @google/gemini-cli-core'
env:
IS_DRY_RUN: '${{ steps.vars.outputs.is_dry_run }}'
NODE_AUTH_TOKEN: '${{ secrets.WOMBAT_TOKEN_CORE }}'
NPM_TAG: '${{ steps.version.outputs.NPM_TAG }}'
run: |-
npm publish \
--dry-run="${IS_DRY_RUN}" \
--workspace="@google/gemini-cli-core" \
--tag="${NPM_TAG}"
- name: 'Install latest core package'
if: |-
${{ steps.vars.outputs.is_dry_run == 'false' }}
env:
RELEASE_VERSION: '${{ steps.version.outputs.RELEASE_VERSION }}'
run: |-
npm install "@google/gemini-cli-core@${RELEASE_VERSION}" \
--workspace="@google/gemini-cli" \
--save-exact
- name: 'Publish @google/gemini-cli'
env:
IS_DRY_RUN: '${{ steps.vars.outputs.is_dry_run }}'
NODE_AUTH_TOKEN: '${{ secrets.WOMBAT_TOKEN_CLI }}'
NPM_TAG: '${{ steps.version.outputs.NPM_TAG }}'
run: |-
npm publish \
--dry-run="${IS_DRY_RUN}" \
--workspace="@google/gemini-cli" \
--tag="${NPM_TAG}"
- name: 'Create GitHub Release and Tag'
if: |-
${{ steps.vars.outputs.is_dry_run == 'false' }}
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
RELEASE_BRANCH: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
RELEASE_TAG: '${{ steps.version.outputs.RELEASE_TAG }}'
PREVIOUS_TAG: '${{ steps.version.outputs.PREVIOUS_TAG }}'
run: |-
gh release create "${RELEASE_TAG}" \
bundle/gemini.js \
--target "$RELEASE_BRANCH" \
--title "Release ${RELEASE_TAG}" \
--notes-start-tag "$PREVIOUS_TAG" \
--generate-notes
- name: 'Create Issue on Failure'
if: |-
${{ failure() }}
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
RELEASE_TAG: '${{ steps.version.outputs.RELEASE_TAG }} || "N/A"'
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
run: |-
gh issue create \
--title "Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')" \
--body "The release workflow failed. See the full run for details: ${DETAILS_URL}" \
--label "kind/bug,release-failure,priority/p0"

View File

@@ -1,30 +0,0 @@
name: 'Trigger Patch Release'
on:
pull_request:
types:
- 'closed'
jobs:
trigger-patch-release:
if: "github.event.pull_request.merged == true && startsWith(github.head_ref, 'hotfix/')"
runs-on: 'ubuntu-latest'
steps:
- name: 'Trigger Patch Release'
uses: 'actions/github-script@00f12e3e20659f42342b1c0226afda7f7c042325'
with:
script: |
const body = context.payload.pull_request.body;
const isDryRun = body.includes('[DRY RUN]');
const ref = context.payload.pull_request.base.ref;
const channel = ref.includes('preview') ? 'preview' : 'stable';
github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'patch-release.yml',
ref: ref,
inputs: {
type: channel,
dry_run: isDryRun.toString()
}
})

31
.github/workflows/verify-release.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: 'Verify NPM release tag'
on:
workflow_dispatch:
inputs:
version:
description: 'The expected Gemini binary version that should be released (e.g., 0.5.0-preview-2).'
required: true
type: 'string'
npm-package:
description: 'NPM package to verify'
required: true
type: 'string'
default: '@google/gemini-cli@latest'
ref:
description: 'The branch, tag, or SHA to release from.'
required: false
type: 'string'
default: 'main'
jobs:
build:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
- name: 'Verify release'
uses: './.github/actions/verify-release'
with:
npm-package: '${github.event.inputs.npm-package}'
expected-version: '${github.event.inputs.version}'
ref: '${github.event.inputs.ref}'