From 5f080aa52a4b5731d081c01adb54cdbef62360ad Mon Sep 17 00:00:00 2001 From: matt korwel Date: Thu, 25 Sep 2025 11:26:07 -0700 Subject: [PATCH] fix(ci): e2e workflow aligned with release (#9296) --- .github/workflows/e2e.yml | 114 +++++++++--------------------- Dockerfile | 8 +-- package.json | 2 +- packages/cli/src/utils/sandbox.ts | 32 ++++++--- 4 files changed, 62 insertions(+), 94 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index bba4869fc0..b595147735 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -27,48 +27,12 @@ concurrency: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }} jobs: - build: - name: 'Build Project' - runs-on: 'gemini-cli-ubuntu-16-core' - 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') - steps: - - name: 'Checkout' - uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 - with: - ref: '${{ github.event.inputs.branch_ref || github.ref }}' - - - name: 'Set up Node.js' - uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'npm' - - - name: 'Install dependencies' - run: 'npm ci' - - - name: 'Build project' - run: 'npm run build' - - - name: 'Archive build artifacts' - run: 'tar -cvf build-artifacts.tar bundle/ node_modules/ packages/ package.json' - - - name: 'Upload build artifacts' - uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' - with: - name: 'build-artifacts-${{ github.run_id }}' - path: 'build-artifacts.tar' - e2e_linux: name: 'E2E Test (Linux) - ${{ matrix.sandbox }}' - needs: - - 'build' if: | github.event_name == 'push' || github.event_name == 'merge_group' || + github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository) || (github.event.label.name == 'maintainer:e2e:ok') runs-on: 'gemini-cli-ubuntu-16-core' @@ -83,32 +47,29 @@ jobs: steps: - name: 'Checkout (fork)' - uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 + uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # 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 + uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5 if: "github.event_name != 'pull_request_target'" with: ref: '${{ github.event.inputs.branch_ref || github.ref }}' - - name: 'Download build artifacts' - uses: 'actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093' - with: - name: 'build-artifacts-${{ github.run_id }}' - path: '.' - - - name: 'Extract build artifacts' - run: 'tar -xvf build-artifacts.tar' - - name: 'Set up Node.js ${{ matrix.node-version }}' uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4 with: node-version: '${{ matrix.node-version }}' + - name: 'Install dependencies' + run: 'npm ci' + + - name: 'Build project' + run: 'npm run build' + - name: 'Set up Docker' if: "matrix.sandbox == 'sandbox:docker'" uses: 'docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435' # ratchet:docker/setup-buildx-action@v3 @@ -117,61 +78,49 @@ jobs: env: GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}' KEEP_OUTPUT: 'true' - SANDBOX: '${{ matrix.sandbox }}' VERBOSE: 'true' - GEMINI_SANDBOX: 'docker' shell: 'bash' run: | if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then - npm run build:sandbox + npm run test:integration:sandbox:docker + else + npm run test:integration:sandbox:none fi - npx vitest run --root ./integration-tests - e2e_slow_platforms: - name: 'Slow E2E - Mac' - needs: - - 'build' + e2e_mac: + name: 'E2E Test (macOS)' if: | github.event_name == 'push' || github.event_name == 'merge_group' || + github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository) || (github.event.label.name == 'maintainer:e2e:ok') - runs-on: '${{ matrix.os }}' + runs-on: 'macos-latest' continue-on-error: true - strategy: - fail-fast: false - matrix: - os: - - 'macos-12' - node-version: - - '20.x' steps: - name: 'Checkout (fork)' - uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 + uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # 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 + uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5 if: "github.event_name != 'pull_request_target'" with: ref: '${{ github.event.inputs.branch_ref || github.ref }}' - - 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 20.x' uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4 with: - node-version: '${{ matrix.node-version }}' + node-version: '20.x' + + - name: 'Install dependencies' + run: 'npm ci' + + - name: 'Build project' + run: 'npm run build' - name: 'Fix rollup optional dependencies on macOS' if: "runner.os == 'macOS'" @@ -193,6 +142,7 @@ jobs: if: | github.event_name == 'push' || github.event_name == 'merge_group' || + github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository) || (github.event.label.name == 'maintainer:e2e:ok') runs-on: 'gemini-cli-windows-16-core' @@ -200,14 +150,14 @@ jobs: steps: - name: 'Checkout (fork)' - uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 + uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # 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 + uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5 if: "github.event_name != 'pull_request_target'" with: ref: '${{ github.event.inputs.branch_ref || github.ref }}' @@ -240,6 +190,10 @@ jobs: run: 'npm ci' shell: 'pwsh' + - name: 'Build project' + run: 'npm run build' + shell: 'pwsh' + - name: 'Run E2E tests' env: GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}' @@ -258,11 +212,13 @@ jobs: always() && ( github.event_name == 'push' || github.event_name == 'merge_group' || + github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository) || (github.event.label.name == 'maintainer:e2e:ok') ) needs: - 'e2e_linux' + - 'e2e_mac' runs-on: 'gemini-cli-ubuntu-16-core' steps: - name: 'Check E2E test results' diff --git a/Dockerfile b/Dockerfile index d4f22305a5..b41ea00368 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,11 +40,11 @@ ENV PATH=$PATH:/usr/local/share/npm-global/bin USER node # install gemini-cli and clean up -COPY packages/cli/dist/google-gemini-cli-*.tgz /usr/local/share/npm-global/gemini-cli.tgz -COPY packages/core/dist/google-gemini-cli-core-*.tgz /usr/local/share/npm-global/gemini-core.tgz -RUN npm install -g /usr/local/share/npm-global/gemini-cli.tgz /usr/local/share/npm-global/gemini-core.tgz \ +COPY packages/cli/dist/google-gemini-cli-*.tgz /tmp/gemini-cli.tgz +COPY packages/core/dist/google-gemini-cli-core-*.tgz /tmp/gemini-core.tgz +RUN npm install -g /tmp/gemini-cli.tgz /tmp/gemini-core.tgz \ && npm cache clean --force \ - && rm -f /usr/local/share/npm-global/gemini-{cli,core}.tgz + && rm -f /tmp/gemini-{cli,core}.tgz # default entrypoint when none specified CMD ["gemini"] diff --git a/package.json b/package.json index 82912de06c..db76d3e673 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "build:vscode": "node scripts/build_vscode_companion.js", "build:all": "npm run build && npm run build:sandbox && npm run build:vscode", "build:packages": "npm run build --workspaces", - "build:sandbox": "node scripts/build_sandbox.js --skip-npm-install-build", + "build:sandbox": "node scripts/build_sandbox.js", "bundle": "npm run generate && node esbuild.config.js && node scripts/copy_bundle_assets.js", "test": "npm run test --workspaces --if-present --parallel", "test:ci": "npm run test:ci --workspaces --if-present --parallel && npm run test:scripts", diff --git a/packages/cli/src/utils/sandbox.ts b/packages/cli/src/utils/sandbox.ts index f7005c3bf7..a8ad57d7ca 100644 --- a/packages/cli/src/utils/sandbox.ts +++ b/packages/cli/src/utils/sandbox.ts @@ -19,6 +19,7 @@ import { promisify } from 'node:util'; import type { Config, SandboxConfig } from '@google/gemini-cli-core'; import { FatalSandboxError } from '@google/gemini-cli-core'; import { ConsolePatcher } from '../ui/utils/ConsolePatcher.js'; +import { randomBytes } from 'node:crypto'; const execAsync = promisify(exec); @@ -558,18 +559,29 @@ export async function start_sandbox( } } - // name container after image, plus numeric suffix to avoid conflicts + // name container after image, plus random suffix to avoid conflicts const imageName = parseImageName(image); - let index = 0; - const containerNameCheck = execSync( - `${config.command} ps -a --format "{{.Names}}"`, - ) - .toString() - .trim(); - while (containerNameCheck.includes(`${imageName}-${index}`)) { - index++; + const isIntegrationTest = + process.env['GEMINI_CLI_INTEGRATION_TEST'] === 'true'; + let containerName; + if (isIntegrationTest) { + containerName = `gemini-cli-integration-test-${randomBytes(4).toString( + 'hex', + )}`; + console.log(`ContainerName: ${containerName}`); + } else { + let index = 0; + const containerNameCheck = execSync( + `${config.command} ps -a --format "{{.Names}}"`, + ) + .toString() + .trim(); + while (containerNameCheck.includes(`${imageName}-${index}`)) { + index++; + } + containerName = `${imageName}-${index}`; + console.log(`ContainerName (regular): ${containerName}`); } - const containerName = `${imageName}-${index}`; args.push('--name', containerName, '--hostname', containerName); // copy GEMINI_API_KEY(s)