mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-27 05:24:34 -07:00
Update .github directory from main branch (#9155)
This commit is contained in:
committed by
GitHub
parent
4fb8dfe258
commit
0ca8669a80
@@ -0,0 +1,55 @@
|
|||||||
|
name: 'Create and Merge Pull Request'
|
||||||
|
description: 'Creates a pull request and merges it automatically.'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
branch-name:
|
||||||
|
description: 'The name of the branch to create the PR from.'
|
||||||
|
required: true
|
||||||
|
pr-title:
|
||||||
|
description: 'The title of the pull request.'
|
||||||
|
required: true
|
||||||
|
pr-body:
|
||||||
|
description: 'The body of the pull request.'
|
||||||
|
required: true
|
||||||
|
base-branch:
|
||||||
|
description: 'The branch to merge into.'
|
||||||
|
required: true
|
||||||
|
default: 'main'
|
||||||
|
app-id:
|
||||||
|
description: 'The ID of the GitHub App.'
|
||||||
|
required: true
|
||||||
|
private-key:
|
||||||
|
description: 'The private key of the GitHub App.'
|
||||||
|
required: true
|
||||||
|
dry-run:
|
||||||
|
description: 'Whether to run in dry-run mode.'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: 'Generate GitHub App Token'
|
||||||
|
id: 'generate_token'
|
||||||
|
if: "inputs.dry-run == 'false'"
|
||||||
|
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b'
|
||||||
|
with:
|
||||||
|
app-id: '${{ inputs.app-id }}'
|
||||||
|
private-key: '${{ inputs.private-key }}'
|
||||||
|
permission-pull-requests: 'write'
|
||||||
|
permission-contents: 'write'
|
||||||
|
|
||||||
|
- name: 'Create and Approve Pull Request'
|
||||||
|
if: "inputs.dry-run == 'false'"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: '${{ steps.generate_token.outputs.token }}'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
PR_URL=$(gh pr create \
|
||||||
|
--title "${{ inputs.pr-title }}" \
|
||||||
|
--body "${{ inputs.pr-body }}" \
|
||||||
|
--base "${{ inputs.base-branch }}" \
|
||||||
|
--head "${{ inputs.branch-name }}" \
|
||||||
|
--fill)
|
||||||
|
gh pr merge "$PR_URL" --auto --squash
|
||||||
@@ -27,10 +27,19 @@ inputs:
|
|||||||
previous-tag:
|
previous-tag:
|
||||||
description: 'The previous tag to use for generating release notes.'
|
description: 'The previous tag to use for generating release notes.'
|
||||||
required: true
|
required: true
|
||||||
|
skip-github-release:
|
||||||
|
description: 'Whether to skip creating a GitHub release.'
|
||||||
|
type: 'boolean'
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
working-directory:
|
working-directory:
|
||||||
description: 'The working directory to run the steps in.'
|
description: 'The working directory to run the steps in.'
|
||||||
required: false
|
required: false
|
||||||
default: '.'
|
default: '.'
|
||||||
|
force-skip-tests:
|
||||||
|
description: 'Skip tests and validation'
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'composite'
|
using: 'composite'
|
||||||
@@ -102,7 +111,7 @@ runs:
|
|||||||
npm publish \
|
npm publish \
|
||||||
--dry-run="${{ inputs.dry-run }}" \
|
--dry-run="${{ inputs.dry-run }}" \
|
||||||
--workspace="@google/gemini-cli-core" \
|
--workspace="@google/gemini-cli-core" \
|
||||||
--tag="${{ inputs.npm-tag }}"
|
--no-tag
|
||||||
|
|
||||||
- name: '🔗 Install latest core package'
|
- name: '🔗 Install latest core package'
|
||||||
working-directory: '${{ inputs.working-directory }}'
|
working-directory: '${{ inputs.working-directory }}'
|
||||||
@@ -122,7 +131,31 @@ runs:
|
|||||||
npm publish \
|
npm publish \
|
||||||
--dry-run="${{ inputs.dry-run }}" \
|
--dry-run="${{ inputs.dry-run }}" \
|
||||||
--workspace="@google/gemini-cli" \
|
--workspace="@google/gemini-cli" \
|
||||||
--tag="${{ inputs.npm-tag }}"
|
--no-tag
|
||||||
|
|
||||||
|
- name: '🔬 Verify NPM release by version'
|
||||||
|
uses: './.github/actions/verify-release'
|
||||||
|
if: "${{ inputs.dry-run == 'false' && inputs.force-skip-tests == 'false' }}"
|
||||||
|
with:
|
||||||
|
npm-package: '@google/gemini-cli@${{ inputs.release-version }}'
|
||||||
|
expected-version: '${{ inputs.release-version }}'
|
||||||
|
ref: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
|
||||||
|
|
||||||
|
- name: '🏷️ Tag release'
|
||||||
|
uses: './.github/actions/tag-npm-release'
|
||||||
|
if: "${{ inputs.dry-run == 'false' }}"
|
||||||
|
with:
|
||||||
|
channel: '${{ inputs.npm-tag }}'
|
||||||
|
version: '${{ inputs.release-version }}'
|
||||||
|
dry-run: '${{ inputs.dry-run }}'
|
||||||
|
wombat-token-core: '${{ inputs.wombat-token-core }}'
|
||||||
|
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
|
||||||
|
|
||||||
|
- name: 'Install deps'
|
||||||
|
working-directory: '${{ inputs.working-directory }}'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
|
||||||
- name: '🎁 Bundle'
|
- name: '🎁 Bundle'
|
||||||
working-directory: '${{ inputs.working-directory }}'
|
working-directory: '${{ inputs.working-directory }}'
|
||||||
@@ -132,7 +165,7 @@ runs:
|
|||||||
|
|
||||||
- name: '🎉 Create GitHub Release'
|
- name: '🎉 Create GitHub Release'
|
||||||
working-directory: '${{ inputs.working-directory }}'
|
working-directory: '${{ inputs.working-directory }}'
|
||||||
if: "${{ inputs.dry-run == 'false' }}"
|
if: "${{ inputs.dry-run == 'false' && inputs.skip-github-release == 'false' && inputs.npm-tag != 'dev' }}"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: '${{ inputs.github-token }}'
|
GITHUB_TOKEN: '${{ inputs.github-token }}'
|
||||||
shell: 'bash'
|
shell: 'bash'
|
||||||
@@ -143,3 +176,12 @@ runs:
|
|||||||
--title "Release ${{ inputs.release-tag }}" \
|
--title "Release ${{ inputs.release-tag }}" \
|
||||||
--notes-start-tag "${{ inputs.previous-tag }}" \
|
--notes-start-tag "${{ inputs.previous-tag }}" \
|
||||||
--generate-notes
|
--generate-notes
|
||||||
|
|
||||||
|
- name: '🧹 Clean up release branch'
|
||||||
|
working-directory: '${{ inputs.working-directory }}'
|
||||||
|
if: "${{ inputs.dry-run == 'false' }}"
|
||||||
|
continue-on-error: true
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
echo "Cleaning up release branch ${{ steps.release_branch.outputs.BRANCH_NAME }}..."
|
||||||
|
git push origin --delete "${{ steps.release_branch.outputs.BRANCH_NAME }}"
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
name: 'Push to docker'
|
||||||
|
description: 'Builds packages and pushes a docker image to GHCR'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
github-actor:
|
||||||
|
description: 'Github actor'
|
||||||
|
required: true
|
||||||
|
github-secret:
|
||||||
|
description: 'Github secret'
|
||||||
|
required: true
|
||||||
|
ref-name:
|
||||||
|
description: 'Github ref name'
|
||||||
|
required: true
|
||||||
|
github-sha:
|
||||||
|
description: 'Github Commit SHA Hash'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: 'Checkout'
|
||||||
|
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: '${{ inputs.github-sha }}'
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: 'Install Dependencies'
|
||||||
|
shell: 'bash'
|
||||||
|
run: 'npm install'
|
||||||
|
- name: 'Set up Docker Buildx'
|
||||||
|
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
|
||||||
|
- name: 'build'
|
||||||
|
shell: 'bash'
|
||||||
|
run: 'npm run build'
|
||||||
|
- name: 'pack @google/gemini-cli'
|
||||||
|
shell: 'bash'
|
||||||
|
run: 'npm pack -w @google/gemini-cli --pack-destination ./packages/cli/dist'
|
||||||
|
- name: 'pack @google/gemini-cli-core'
|
||||||
|
shell: 'bash'
|
||||||
|
run: 'npm pack -w @google/gemini-cli-core --pack-destination ./packages/core/dist'
|
||||||
|
- name: 'Log in to GitHub Container Registry'
|
||||||
|
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: 'ghcr.io'
|
||||||
|
username: '${{ inputs.github-actor }}'
|
||||||
|
password: '${{ inputs.github-secret }}'
|
||||||
|
- name: 'Get branch name'
|
||||||
|
id: 'branch_name'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
REF_NAME="${{ inputs.ref-name }}"
|
||||||
|
echo "name=${REF_NAME%/merge}" >> $GITHUB_OUTPUT
|
||||||
|
- name: 'Build and Push the Docker Image'
|
||||||
|
uses: 'docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83' # ratchet:docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: '.'
|
||||||
|
file: './Dockerfile'
|
||||||
|
push: true
|
||||||
|
provenance: false # avoid pushing 3 images to Aritfact Registry
|
||||||
|
tags: |
|
||||||
|
ghcr.io/${{ github.repository }}/cli:${{ steps.branch_name.outputs.name }}
|
||||||
|
ghcr.io/${{ github.repository }}/cli:${{ inputs.github-sha }}
|
||||||
|
- name: 'Create issue on failure'
|
||||||
|
if: |-
|
||||||
|
${{ failure() }}
|
||||||
|
shell: 'bash'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: '${{ inputs.github-secret }}'
|
||||||
|
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
run: |-
|
||||||
|
gh issue create \
|
||||||
|
--title "Docker build failed" \
|
||||||
|
--body "The docker build failed. See the full run for details: ${DETAILS_URL}" \
|
||||||
|
--label "kind/bug,release-failure"
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
name: 'Build and push sandbox docker'
|
||||||
|
description: 'Pushes sandbox docker image to container registry'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
github-actor:
|
||||||
|
description: 'Github actor'
|
||||||
|
required: true
|
||||||
|
github-secret:
|
||||||
|
description: 'Github secret'
|
||||||
|
required: true
|
||||||
|
github-sha:
|
||||||
|
description: 'Github Commit SHA Hash'
|
||||||
|
required: true
|
||||||
|
github-ref-name:
|
||||||
|
description: 'Github ref name'
|
||||||
|
required: true
|
||||||
|
dry-run:
|
||||||
|
description: 'Whether this is a dry run.'
|
||||||
|
required: true
|
||||||
|
type: 'boolean'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: 'Checkout'
|
||||||
|
uses: 'actions/checkout@v4'
|
||||||
|
with:
|
||||||
|
ref: '${{ inputs.github-sha }}'
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: 'Install Dependencies'
|
||||||
|
shell: 'bash'
|
||||||
|
run: 'npm install'
|
||||||
|
- name: 'npm build'
|
||||||
|
shell: 'bash'
|
||||||
|
run: 'npm run build'
|
||||||
|
- name: 'Set up Docker Buildx'
|
||||||
|
uses: 'docker/setup-buildx-action@v3'
|
||||||
|
- name: 'Log in to GitHub Container Registry'
|
||||||
|
uses: 'docker/login-action@v3'
|
||||||
|
with:
|
||||||
|
registry: 'ghcr.io'
|
||||||
|
username: '${{ inputs.github-actor }}'
|
||||||
|
password: '${{ inputs.github-secret }}'
|
||||||
|
- name: 'determine image tag'
|
||||||
|
id: 'image_tag'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |-
|
||||||
|
SHELL_TAG_NAME="${{ inputs.github-ref-name }}"
|
||||||
|
FINAL_TAG="${{ inputs.github-sha }}"
|
||||||
|
if [[ "$SHELL_TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
|
||||||
|
echo "Release detected."
|
||||||
|
FINAL_TAG="${SHELL_TAG_NAME#v}"
|
||||||
|
else
|
||||||
|
echo "Development release detected. Using commit SHA as tag."
|
||||||
|
fi
|
||||||
|
echo "Determined image tag: $FINAL_TAG"
|
||||||
|
echo "FINAL_TAG=$FINAL_TAG" >> $GITHUB_OUTPUT
|
||||||
|
- name: 'build'
|
||||||
|
id: 'docker_build'
|
||||||
|
shell: 'bash'
|
||||||
|
env:
|
||||||
|
GEMINI_SANDBOX_IMAGE_TAG: '${{ steps.image_tag.outputs.FINAL_TAG }}'
|
||||||
|
GEMINI_SANDBOX: 'docker'
|
||||||
|
run: |-
|
||||||
|
npm run build:sandbox -- \
|
||||||
|
--image ghcr.io/${{ github.repository}}/sandbox:${{ steps.image_tag.outputs.FINAL_TAG }} \
|
||||||
|
--output-file final_image_uri.txt
|
||||||
|
echo "uri=$(cat final_image_uri.txt)" >> $GITHUB_OUTPUT
|
||||||
|
- name: 'publish'
|
||||||
|
shell: 'bash'
|
||||||
|
if: "${{ inputs.dry-run == 'false' }}"
|
||||||
|
run: |-
|
||||||
|
docker push "${{ steps.docker_build.outputs.uri }}"
|
||||||
|
- name: 'Create issue on failure'
|
||||||
|
if: |-
|
||||||
|
${{ failure() }}
|
||||||
|
shell: 'bash'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: '${{ inputs.github-secret }}'
|
||||||
|
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
run: |-
|
||||||
|
gh issue create \
|
||||||
|
--title "Docker build failed" \
|
||||||
|
--body "The docker build failed. See the full run for details: ${DETAILS_URL}" \
|
||||||
|
--label "kind/bug,release-failure"
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
name: 'Tag an NPM release'
|
||||||
|
description: 'Tags a specific npm version to a specific channel.'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
channel:
|
||||||
|
description: 'NPM Channel tag'
|
||||||
|
required: true
|
||||||
|
version:
|
||||||
|
description: 'version'
|
||||||
|
required: true
|
||||||
|
dry-run:
|
||||||
|
description: 'Whether to run in dry-run mode.'
|
||||||
|
required: true
|
||||||
|
wombat-token-core:
|
||||||
|
description: 'The npm token for the wombat @google/gemini-cli-core'
|
||||||
|
required: true
|
||||||
|
wombat-token-cli:
|
||||||
|
description: 'The npm token for wombat @google/gemini-cli'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- 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 for @google/gemini-cli-core'
|
||||||
|
if: |-
|
||||||
|
${{ inputs.dry-run == 'false' }}
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-core }}'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
npm dist-tag add @google/gemini-cli-core@${{ inputs.version }} ${{ inputs.channel }}
|
||||||
|
|
||||||
|
- name: 'Change tag for @google/gemini-cli'
|
||||||
|
if: |-
|
||||||
|
${{ inputs.dry-run == 'false' }}
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: '${{ inputs.wombat-token-cli }}'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
npm dist-tag add @google/gemini-cli@${{ inputs.version }} ${{ inputs.channel }}
|
||||||
|
|
||||||
|
- name: 'Log dry run'
|
||||||
|
if: |-
|
||||||
|
${{ inputs.dry-run == 'true' }}
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
echo "Dry run: Would have added tag '${{ inputs.channel }}' to version '${{ inputs.version }}' for @google/gemini-cli and @google/gemini-cli-core."
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
name: 'Verify an NPM release'
|
||||||
|
description: 'Fetches a package from NPM and does some basic smoke tests'
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
npm-package:
|
||||||
|
description: 'NPM Package'
|
||||||
|
required: true
|
||||||
|
default: '@google/gemini-cli@latest'
|
||||||
|
expected-version:
|
||||||
|
description: 'Expected version'
|
||||||
|
required: true
|
||||||
|
ref:
|
||||||
|
description: 'The branch, tag, or SHA to release from.'
|
||||||
|
required: false
|
||||||
|
type: 'string'
|
||||||
|
default: 'main'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: '📝 Print Inputs'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |
|
||||||
|
echo "${{ toJSON(inputs) }}"
|
||||||
|
- name: 'Checkout'
|
||||||
|
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: '${{ github.event.inputs.ref }}'
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: 'Install from NPM'
|
||||||
|
uses: 'nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08' # ratchet:nick-fields/retry@v3
|
||||||
|
with:
|
||||||
|
timeout_seconds: 900
|
||||||
|
retry_wait_seconds: 30
|
||||||
|
max_attempts: 10
|
||||||
|
command: |-
|
||||||
|
npm install --prefer-online --no-cache -g ${{ inputs.npm-package }}
|
||||||
|
|
||||||
|
# This provides a very basic smoke test for Gemini CLI
|
||||||
|
- name: 'Run Gemini CLI'
|
||||||
|
id: 'gemini_cli'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |-
|
||||||
|
echo "gemini_version=$(gemini --version)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Force a failure if it doesn't match
|
||||||
|
- name: 'Fail workflow if version does not match'
|
||||||
|
if: '${{ steps.gemini_cli.outputs.gemini_version != inputs.expected-version }}'
|
||||||
|
shell: 'bash'
|
||||||
|
run: |-
|
||||||
|
echo '❌ Got ${{ steps.gemini_cli.outputs.gemini_version }} from ${{ inputs.npm-package }}'
|
||||||
|
echo '❌ Expected Version ${{ inputs.expected-version }}'
|
||||||
|
|
||||||
|
exit 1
|
||||||
+166
-253
@@ -1,4 +1,4 @@
|
|||||||
name: 'Gemini CLI CI'
|
name: 'Testing: CI'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -10,6 +10,7 @@ on:
|
|||||||
- 'main'
|
- 'main'
|
||||||
- 'release/**'
|
- 'release/**'
|
||||||
merge_group:
|
merge_group:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
|
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
|
||||||
@@ -25,63 +26,10 @@ defaults:
|
|||||||
run:
|
run:
|
||||||
shell: 'bash'
|
shell: 'bash'
|
||||||
|
|
||||||
env:
|
|
||||||
ACTIONLINT_VERSION: '1.7.7'
|
|
||||||
SHELLCHECK_VERSION: '0.11.0'
|
|
||||||
YAMLLINT_VERSION: '1.35.1'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
#
|
lint:
|
||||||
# Lint: GitHub Actions
|
name: 'Lint'
|
||||||
#
|
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||||
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'
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout'
|
- name: 'Checkout'
|
||||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||||
@@ -94,161 +42,33 @@ jobs:
|
|||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Run lockfile check'
|
|
||||||
run: |-
|
|
||||||
npm run check:lockfile
|
|
||||||
|
|
||||||
- name: 'Install dependencies'
|
- name: 'Install dependencies'
|
||||||
run: |-
|
run: 'npm ci'
|
||||||
npm ci
|
|
||||||
|
|
||||||
- name: 'Run formatter check'
|
- name: 'Check lockfile'
|
||||||
run: |-
|
run: 'npm run check:lockfile'
|
||||||
npm run format
|
|
||||||
git diff --exit-code
|
|
||||||
|
|
||||||
- name: 'Run linter'
|
- name: 'Install linters'
|
||||||
run: |-
|
run: 'node scripts/lint.js --setup'
|
||||||
npm run lint:ci
|
|
||||||
|
|
||||||
- name: 'Run linter on integration tests'
|
- name: 'Run ESLint'
|
||||||
run: |-
|
run: 'node scripts/lint.js --eslint'
|
||||||
npx eslint integration-tests --max-warnings 0
|
|
||||||
|
|
||||||
- name: 'Run formatter on integration tests'
|
- name: 'Run actionlint'
|
||||||
run: |-
|
run: 'node scripts/lint.js --actionlint'
|
||||||
npx prettier --check integration-tests
|
|
||||||
git diff --exit-code
|
|
||||||
|
|
||||||
- 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'
|
- name: 'Run shellcheck'
|
||||||
run: |-
|
run: 'node scripts/lint.js --shellcheck'
|
||||||
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}"
|
|
||||||
|
|
||||||
- name: 'Run yamllint'
|
- name: 'Run yamllint'
|
||||||
run: |-
|
run: 'node scripts/lint.js --yamllint'
|
||||||
git ls-files | grep -E '\.(yaml|yml)' | xargs yamllint --format github
|
|
||||||
|
|
||||||
#
|
- name: 'Run Prettier'
|
||||||
# Lint: All
|
run: 'node scripts/lint.js --prettier'
|
||||||
#
|
|
||||||
# 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!'
|
|
||||||
|
|
||||||
#
|
test_linux:
|
||||||
# Test: Node
|
name: 'Test (Linux)'
|
||||||
#
|
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||||
test:
|
|
||||||
name: 'Test'
|
|
||||||
runs-on: '${{ matrix.os }}'
|
|
||||||
needs:
|
needs:
|
||||||
- 'lint'
|
- 'lint'
|
||||||
permissions:
|
permissions:
|
||||||
@@ -256,12 +76,7 @@ jobs:
|
|||||||
checks: 'write'
|
checks: 'write'
|
||||||
pull-requests: 'write'
|
pull-requests: 'write'
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false # So we can see all test failures
|
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
|
||||||
- 'macos-latest'
|
|
||||||
- 'ubuntu-latest'
|
|
||||||
- 'windows-latest'
|
|
||||||
node-version:
|
node-version:
|
||||||
- '20.x'
|
- '20.x'
|
||||||
- '22.x'
|
- '22.x'
|
||||||
@@ -277,18 +92,19 @@ jobs:
|
|||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |-
|
run: 'npm run build'
|
||||||
npm run build
|
|
||||||
|
|
||||||
- name: 'Install dependencies for testing'
|
- name: 'Install dependencies for testing'
|
||||||
run: |-
|
run: 'npm ci'
|
||||||
npm ci
|
|
||||||
|
|
||||||
- name: 'Run tests and generate reports'
|
- name: 'Run tests and generate reports'
|
||||||
env:
|
env:
|
||||||
NO_COLOR: true
|
NO_COLOR: true
|
||||||
run: 'npm run test:ci'
|
run: 'npm run test:ci'
|
||||||
|
|
||||||
|
- name: 'Wait for file system sync'
|
||||||
|
run: 'sleep 2'
|
||||||
|
|
||||||
- name: 'Publish Test Report (for non-forks)'
|
- name: 'Publish Test Report (for non-forks)'
|
||||||
if: |-
|
if: |-
|
||||||
${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }}
|
${{ 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) }}
|
${{ 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
|
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
|
||||||
with:
|
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'
|
path: 'packages/*/junit.xml'
|
||||||
|
|
||||||
- name: 'Upload coverage reports'
|
- name: 'Upload coverage reports'
|
||||||
@@ -315,47 +191,9 @@ jobs:
|
|||||||
name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}'
|
name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}'
|
||||||
path: 'packages/*/coverage'
|
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:
|
codeql:
|
||||||
name: 'CodeQL'
|
name: 'CodeQL'
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||||
permissions:
|
permissions:
|
||||||
actions: 'read'
|
actions: 'read'
|
||||||
contents: 'read'
|
contents: 'read'
|
||||||
@@ -375,9 +213,8 @@ jobs:
|
|||||||
# Check for changes in bundle size.
|
# Check for changes in bundle size.
|
||||||
bundle_size:
|
bundle_size:
|
||||||
name: 'Check Bundle Size'
|
name: 'Check Bundle Size'
|
||||||
if: |-
|
if: "github.event_name == 'pull_request'"
|
||||||
${{ github.event_name != 'merge_group' }}
|
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: 'read' # For checkout
|
contents: 'read' # For checkout
|
||||||
pull-requests: 'write' # For commenting
|
pull-requests: 'write' # For commenting
|
||||||
@@ -395,3 +232,79 @@ jobs:
|
|||||||
minimum-change-threshold: '1000'
|
minimum-change-threshold: '1000'
|
||||||
compression: 'none'
|
compression: 'none'
|
||||||
clean-script: 'clean'
|
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!"
|
||||||
|
|||||||
@@ -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 }}'
|
|
||||||
+168
-27
@@ -1,4 +1,4 @@
|
|||||||
name: 'E2E Tests'
|
name: 'Testing: E2E'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -14,11 +14,15 @@ on:
|
|||||||
types: ['labeled']
|
types: ['labeled']
|
||||||
merge_group:
|
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:
|
jobs:
|
||||||
e2e-test:
|
build:
|
||||||
name: 'E2E Test (${{ matrix.os }}) - ${{ matrix.sandbox }}'
|
name: 'Build Project'
|
||||||
# This condition ensures the job runs for pushes to main, merge groups,
|
runs-on: 'gemini-cli-ubuntu-16-core'
|
||||||
# PRs from the base repo, OR PRs from forks with the correct label.
|
|
||||||
if: |
|
if: |
|
||||||
github.event_name == 'push' ||
|
github.event_name == 'push' ||
|
||||||
github.event_name == 'merge_group' ||
|
github.event_name == 'merge_group' ||
|
||||||
@@ -62,21 +66,11 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
|
||||||
- 'ubuntu-latest'
|
|
||||||
- 'macos-latest'
|
|
||||||
- 'gemini-cli-windows-16-core'
|
|
||||||
sandbox:
|
sandbox:
|
||||||
- 'sandbox:none'
|
- 'sandbox:none'
|
||||||
- 'sandbox:docker'
|
- 'sandbox:docker'
|
||||||
node-version:
|
node-version:
|
||||||
- '20.x'
|
- '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:
|
steps:
|
||||||
- name: 'Checkout (fork)'
|
- name: 'Checkout (fork)'
|
||||||
@@ -90,22 +84,22 @@ jobs:
|
|||||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
|
||||||
if: "github.event_name != 'pull_request_target'"
|
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 }}'
|
- name: 'Set up Node.js ${{ matrix.node-version }}'
|
||||||
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '${{ matrix.node-version }}'
|
node-version: '${{ matrix.node-version }}'
|
||||||
|
|
||||||
- name: 'Install dependencies'
|
|
||||||
run: |-
|
|
||||||
npm ci
|
|
||||||
|
|
||||||
- name: 'Build project'
|
|
||||||
run: |-
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
- name: 'Set up Docker'
|
- name: 'Set up Docker'
|
||||||
if: |-
|
if: "matrix.sandbox == 'sandbox:docker'"
|
||||||
matrix.os == 'ubuntu-latest' && matrix.sandbox == 'sandbox:docker'
|
|
||||||
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
|
uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: 'Run E2E tests'
|
- name: 'Run E2E tests'
|
||||||
@@ -114,6 +108,153 @@ jobs:
|
|||||||
KEEP_OUTPUT: 'true'
|
KEEP_OUTPUT: 'true'
|
||||||
SANDBOX: '${{ matrix.sandbox }}'
|
SANDBOX: '${{ matrix.sandbox }}'
|
||||||
VERBOSE: 'true'
|
VERBOSE: 'true'
|
||||||
|
GEMINI_SANDBOX: 'docker'
|
||||||
shell: 'bash'
|
shell: 'bash'
|
||||||
run: |-
|
run: |
|
||||||
npm run "test:integration:${SANDBOX}"
|
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!"
|
||||||
|
|||||||
@@ -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.
|
|
||||||
@@ -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 }}'
|
|
||||||
@@ -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 }}'
|
||||||
@@ -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 }}'
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: 'Nightly Release'
|
name: 'Release: Nightly'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@@ -25,7 +25,10 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
permissions:
|
permissions:
|
||||||
|
contents: 'write'
|
||||||
|
packages: 'write'
|
||||||
issues: 'write'
|
issues: 'write'
|
||||||
|
pull-requests: 'write'
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout'
|
- name: 'Checkout'
|
||||||
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
|
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
|
||||||
@@ -71,6 +74,16 @@ jobs:
|
|||||||
dry-run: '${{ github.event.inputs.dry_run }}'
|
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||||
previous-tag: '${{ steps.nightly_version.outputs.PREVIOUS_TAG }}'
|
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'
|
- name: 'Create Issue on Failure'
|
||||||
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
||||||
env:
|
env:
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: 'Promote Release'
|
name: 'Release: Promote'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -314,20 +314,15 @@ jobs:
|
|||||||
echo "Dry run enabled. Skipping push."
|
echo "Dry run enabled. Skipping push."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: 'Create and Approve Pull Request'
|
- name: 'Create and Merge Pull Request'
|
||||||
if: |-
|
uses: './.github/actions/create-pull-request'
|
||||||
${{ github.event.inputs.dry_run == 'false' }}
|
with:
|
||||||
env:
|
branch-name: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
|
||||||
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
pr-title: 'chore(release): bump version to ${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}'
|
||||||
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
|
pr-body: 'Automated version bump to prepare for the next nightly release.'
|
||||||
run: |
|
app-id: '${{ secrets.APP_ID }}'
|
||||||
gh pr create \
|
private-key: '${{ secrets.PRIVATE_KEY }}'
|
||||||
--title "chore(release): bump version to ${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}" \
|
dry-run: '${{ github.event.inputs.dry_run }}'
|
||||||
--body "Automated version bump to prepare for the next nightly release." \
|
|
||||||
--base "main" \
|
|
||||||
--head "${BRANCH_NAME}" \
|
|
||||||
--fill
|
|
||||||
gh pr merge --auto --squash
|
|
||||||
|
|
||||||
- name: 'Create Issue on Failure'
|
- name: 'Create Issue on Failure'
|
||||||
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
if: '${{ failure() && github.event.inputs.dry_run == false }}'
|
||||||
@@ -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 }}'
|
||||||
@@ -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"
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -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}'
|
||||||
Reference in New Issue
Block a user