Release Process vNext (#8152)

Co-authored-by: gemini-cli-robot <gemini-cli-robot@google.com>
This commit is contained in:
matt korwel
2025-09-10 01:28:58 -07:00
committed by GitHub
parent a31830a3cb
commit 0d03f4ea9d
15 changed files with 658 additions and 604 deletions

View File

@@ -0,0 +1,99 @@
name: 'Publish Release'
description: 'Builds, prepares, and publishes the gemini-cli packages to npm and creates a GitHub release.'
inputs:
release-version:
description: 'The version to release (e.g., 0.1.11).'
required: true
npm-tag:
description: 'The npm tag to publish with (e.g., latest, preview, nightly).'
required: true
wombat-token-core:
description: 'The npm token for the @google/gemini-cli-core package.'
required: true
wombat-token-cli:
description: 'The npm token for the @google/gemini-cli package.'
required: true
github-token:
description: 'The GitHub token for creating the release.'
required: true
dry-run:
description: 'Whether to run in dry-run mode.'
required: true
release-branch:
description: 'The branch to target for the release.'
required: true
previous-tag:
description: 'The previous tag to use for generating release notes.'
required: true
working-directory:
description: 'The working directory to run the steps in.'
required: false
default: '.'
runs:
using: 'composite'
steps:
- name: 'Build and Prepare Packages'
working-directory: '${{ inputs.working-directory }}'
run: |-
npm run build:packages
npm run prepare:package
shell: 'bash'
- name: 'Configure npm for publishing'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
registry-url: 'https://wombat-dressing-room.appspot.com'
scope: '@google'
- name: 'Publish @google/gemini-cli-core'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-core }}'
run: |-
npm publish \
--dry-run="${{ inputs.dry-run }}" \
--workspace="@google/gemini-cli-core" \
--tag="${{ inputs.npm-tag }}"
shell: 'bash'
- name: 'Install latest core package'
working-directory: '${{ inputs.working-directory }}'
if: '${{ inputs.dry-run == "false" }}'
run: |-
npm install "@google/gemini-cli-core@${{ inputs.release-version }}" \
--workspace="@google/gemini-cli" \
--save-exact
shell: 'bash'
- name: 'Publish @google/gemini-cli'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-cli }}'
run: |-
npm publish \
--dry-run="${{ inputs.dry-run }}" \
--workspace="@google/gemini-cli" \
--tag="${{ inputs.npm-tag }}"
shell: 'bash'
- name: 'Bundle'
working-directory: '${{ inputs.working-directory }}'
run: 'npm run bundle'
shell: 'bash'
- name: 'Create GitHub Release'
working-directory: '${{ inputs.working-directory }}'
if: '${{ inputs.dry-run == "false" }}'
env:
GITHUB_TOKEN: '${{ inputs.github-token }}'
run: |-
gh release create "v${{ inputs.release-version }}" \
bundle/gemini.js \
--target "${{ inputs.release-branch }}" \
--title "Release v${{ inputs.release-version }}" \
--notes-start-tag "${{ inputs.previous-tag }}" \
--generate-notes
shell: 'bash'

53
.github/workflows/nightly-release.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: 'Nightly Release'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
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
jobs:
release:
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
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: 'Get Nightly Version'
id: 'nightly_version'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
VERSION_JSON=$(node scripts/get-release-version.js --type=nightly)
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: 'Publish Release'
uses: './.github/actions/publish-release'
with:
release-version: '${{ steps.nightly_version.outputs.RELEASE_VERSION }}'
npm-tag: '${{ steps.nightly_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 }}'
release-branch: 'main'
previous-tag: '${{ steps.nightly_version.outputs.PREVIOUS_TAG }}'

213
.github/workflows/promote-release.yml vendored Normal file
View File

@@ -0,0 +1,213 @@
name: 'Promote Release'
on:
workflow_dispatch:
inputs:
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
jobs:
calculate-versions:
name: 'Calculate Versions and Plan'
runs-on: 'ubuntu-latest'
outputs:
STABLE_VERSION: '${{ steps.versions.outputs.STABLE_VERSION }}'
STABLE_SHA: '${{ steps.versions.outputs.STABLE_SHA }}'
PREVIOUS_STABLE_TAG: '${{ steps.versions.outputs.PREVIOUS_STABLE_TAG }}'
PREVIEW_VERSION: '${{ steps.versions.outputs.PREVIEW_VERSION }}'
PREVIEW_SHA: '${{ steps.versions.outputs.PREVIEW_SHA }}'
PREVIOUS_PREVIEW_TAG: '${{ steps.versions.outputs.PREVIOUS_PREVIEW_TAG }}'
NEXT_NIGHTLY_VERSION: '${{ steps.versions.outputs.NEXT_NIGHTLY_VERSION }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
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: 'Calculate Versions and SHAs'
id: 'versions'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
set -e
STABLE_JSON=$(node scripts/get-release-version.js --type=stable)
PREVIEW_JSON=$(node scripts/get-release-version.js --type=preview)
NIGHTLY_JSON=$(node scripts/get-release-version.js --type=nightly)
echo "STABLE_VERSION=$(echo "${STABLE_JSON}" | jq -r .releaseVersion)" >> "${GITHUB_OUTPUT}"
# shellcheck disable=SC1083
echo "STABLE_SHA=$(git rev-parse "$(echo "${STABLE_JSON}" | jq -r .previousReleaseTag)"^{commit})" >> "${GITHUB_OUTPUT}"
echo "PREVIOUS_STABLE_TAG=$(echo "${STABLE_JSON}" | jq -r .previousReleaseTag)" >> "${GITHUB_OUTPUT}"
echo "PREVIEW_VERSION=$(echo "${PREVIEW_JSON}" | jq -r .releaseVersion)" >> "${GITHUB_OUTPUT}"
# shellcheck disable=SC1083
echo "PREVIEW_SHA=$(git rev-parse "$(echo "${PREVIEW_JSON}" | jq -r .previousReleaseTag)"^{commit})" >> "${GITHUB_OUTPUT}"
echo "PREVIOUS_PREVIEW_TAG=$(echo "${PREVIEW_JSON}" | jq -r .previousReleaseTag)" >> "${GITHUB_OUTPUT}"
echo "NEXT_NIGHTLY_VERSION=$(echo "${NIGHTLY_JSON}" | jq -r .releaseVersion)" >> "${GITHUB_OUTPUT}"
promote:
name: 'Promote to ${{ matrix.channel }}'
needs: 'calculate-versions'
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
packages: 'write'
strategy:
matrix:
include:
- channel: 'stable'
version: '${{ needs.calculate-versions.outputs.STABLE_VERSION }}'
sha: '${{ needs.calculate-versions.outputs.STABLE_SHA }}'
npm-tag: 'latest'
previous-tag: '${{ needs.calculate-versions.outputs.PREVIOUS_STABLE_TAG }}'
- channel: 'preview'
version: '${{ needs.calculate-versions.outputs.PREVIEW_VERSION }}'
sha: '${{ needs.calculate-versions.outputs.PREVIEW_SHA }}'
npm-tag: 'preview'
previous-tag: '${{ needs.calculate-versions.outputs.PREVIOUS_PREVIEW_TAG }}'
steps:
- name: 'Checkout main'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: 'main'
- name: 'Checkout correct SHA'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: '${{ matrix.sha }}'
path: 'release'
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
working-directory: './release'
run: 'npm ci'
- name: 'Configure Git User'
working-directory: './release'
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'
working-directory: './release'
id: 'release_branch'
run: |
BRANCH_NAME="release/v${{ matrix.version }}"
git switch -c "${BRANCH_NAME}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_OUTPUT}"
- name: 'Update package versions'
working-directory: './release'
run: 'npm run release:version "${{ matrix.version }}"'
- name: 'Commit and Conditionally Push package versions'
working-directory: './release'
env:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
DRY_RUN: '${{ github.event.inputs.dry_run }}'
RELEASE_TAG: 'v${{ matrix.version }}'
run: |-
git add package.json package-lock.json packages/*/package.json
git commit -m "chore(release): ${RELEASE_TAG}"
if [[ "${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: 'Publish Release'
uses: './.github/actions/publish-release'
with:
release-version: '${{ matrix.version }}'
npm-tag: '${{ matrix.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 }}'
release-branch: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
previous-tag: '${{ matrix.previous-tag }}'
working-directory: './release'
nightly-pr:
name: 'Create Nightly PR'
needs: 'calculate-versions'
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
pull-requests: 'write'
steps:
- name: 'Checkout main'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: 'main'
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
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 and switch to a new branch'
id: 'release_branch'
run: |
BRANCH_NAME="chore/nightly-version-bump-${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}"
git switch -c "${BRANCH_NAME}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_OUTPUT}"
- name: 'Update package versions'
run: 'npm run release:version "${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}"'
- name: 'Commit and Push package versions'
env:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
DRY_RUN: '${{ github.event.inputs.dry_run }}'
run: |-
git add package.json package-lock.json packages/*/package.json
git commit -m "chore(release): bump version to ${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}"
if [[ "${DRY_RUN}" == "false" ]]; then
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}"
else
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

View File

@@ -1,231 +0,0 @@
name: 'Release'
on:
schedule:
# Runs every day at midnight UTC for the nightly release.
- cron: '0 0 * * *'
# Runs every Tuesday at 23:59 UTC for the preview release.
- cron: '59 23 * * 2'
workflow_dispatch:
inputs:
version:
description: 'The version to release (e.g., v0.1.11). Required for manual patch releases.'
required: false # Not required for scheduled runs
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
create_nightly_release:
description: 'Auto apply the nightly release tag, input version is ignored.'
required: false
type: 'boolean'
default: false
create_preview_release:
description: 'Auto apply the preview release tag, input version is ignored.'
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:
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:
CREATE_NIGHTLY_RELEASE: '${{ github.event.inputs.create_nightly_release }}'
CREATE_PREVIEW_RELEASE: '${{ github.event.inputs.create_preview_release }}'
EVENT_NAME: '${{ github.event_name }}'
CRON: '${{ github.event.schedule }}'
DRY_RUN_INPUT: '${{ github.event.inputs.dry_run }}'
id: 'vars'
run: |-
is_nightly="false"
if [[ "${CRON}" == "0 0 * * *" || "${CREATE_NIGHTLY_RELEASE}" == "true" ]]; then
is_nightly="true"
fi
echo "is_nightly=${is_nightly}" >> "${GITHUB_OUTPUT}"
is_preview="false"
if [[ "${CRON}" == "59 23 * * 2" || "${CREATE_PREVIEW_RELEASE}" == "true" ]]; then
is_preview="true"
fi
echo "is_preview=${is_preview}" >> "${GITHUB_OUTPUT}"
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'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
IS_NIGHTLY: '${{ steps.vars.outputs.is_nightly }}'
IS_PREVIEW: '${{ steps.vars.outputs.is_preview }}'
MANUAL_VERSION: '${{ inputs.version }}'
run: |-
VERSION_JSON="$(node scripts/get-release-version.js)"
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: '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 package-lock.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"