diff --git a/.github/workflows/chained_e2e.yml b/.github/workflows/chained_e2e.yml index 722559ec17..494163966e 100644 --- a/.github/workflows/chained_e2e.yml +++ b/.github/workflows/chained_e2e.yml @@ -168,6 +168,7 @@ jobs: GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}' KEEP_OUTPUT: 'true' VERBOSE: 'true' + BUILD_SANDBOX_FLAGS: '--cache-from type=gha --cache-to type=gha,mode=max' shell: 'bash' run: | if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa8ce717f1..3fb1867db7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,6 +50,8 @@ jobs: runs-on: 'gemini-cli-ubuntu-16-core' needs: 'merge_queue_skipper' if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}" + env: + GEMINI_LINT_TEMP_DIR: '${{ github.workspace }}/.gemini-linters' steps: - name: 'Checkout' uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 @@ -63,9 +65,21 @@ jobs: node-version-file: '.nvmrc' cache: 'npm' + - name: 'Cache Linters' + uses: 'actions/cache@v4' + with: + path: '${{ env.GEMINI_LINT_TEMP_DIR }}' + key: "${{ runner.os }}-${{ runner.arch }}-linters-${{ hashFiles('scripts/lint.js') }}" + - name: 'Install dependencies' run: 'npm ci' + - name: 'Cache ESLint' + uses: 'actions/cache@v4' + with: + path: '.eslintcache' + key: "${{ runner.os }}-eslint-${{ hashFiles('package-lock.json', 'eslint.config.js') }}" + - name: 'Validate NOTICES.txt' run: 'git diff --exit-code packages/vscode-ide-companion/NOTICES.txt' @@ -111,10 +125,9 @@ jobs: args: '--verbose --accept 200,503 ./**/*.md' fail: true test_linux: - name: 'Test (Linux)' + name: 'Test (Linux) - ${{ matrix.shard }}' runs-on: 'gemini-cli-ubuntu-16-core' needs: - - 'lint' - 'merge_queue_skipper' if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}" permissions: @@ -127,6 +140,9 @@ jobs: - '20.x' - '22.x' - '24.x' + shard: + - 'cli' + - 'others' steps: - name: 'Checkout' uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 @@ -146,7 +162,14 @@ jobs: - name: 'Run tests and generate reports' env: NO_COLOR: true - run: 'npm run test:ci' + run: | + if [[ "${{ matrix.shard }}" == "cli" ]]; then + npm run test:ci --workspace @google/gemini-cli + else + # Explicitly list non-cli packages to ensure they are sharded correctly + npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present + npm run test:scripts + fi - name: 'Bundle' run: 'npm run bundle' @@ -162,7 +185,7 @@ jobs: ${{ 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 }})' + name: 'Test Results (Node ${{ matrix.node-version }}, ${{ matrix.shard }})' path: 'packages/*/junit.xml' reporter: 'java-junit' fail-on-error: 'false' @@ -176,10 +199,9 @@ jobs: path: 'packages/*/junit.xml' test_mac: - name: 'Test (Mac)' + name: 'Test (Mac) - ${{ matrix.shard }}' runs-on: '${{ matrix.os }}' needs: - - 'lint' - 'merge_queue_skipper' if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}" permissions: @@ -195,6 +217,9 @@ jobs: - '20.x' - '22.x' - '24.x' + shard: + - 'cli' + - 'others' steps: - name: 'Checkout' uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 @@ -214,7 +239,14 @@ jobs: - name: 'Run tests and generate reports' env: NO_COLOR: true - run: 'npm run test:ci -- --coverage.enabled=false' + run: | + if [[ "${{ matrix.shard }}" == "cli" ]]; then + npm run test:ci --workspace @google/gemini-cli -- --coverage.enabled=false + else + # Explicitly list non-cli packages to ensure they are sharded correctly + npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false + npm run test:scripts + fi - name: 'Bundle' run: 'npm run bundle' @@ -230,7 +262,7 @@ jobs: ${{ 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 }})' + name: 'Test Results (Node ${{ matrix.node-version }}, ${{ matrix.shard }})' path: 'packages/*/junit.xml' reporter: 'java-junit' fail-on-error: 'false' diff --git a/.prettierignore b/.prettierignore index 7b8a75a110..120f04c358 100644 --- a/.prettierignore +++ b/.prettierignore @@ -17,5 +17,6 @@ eslint.config.js **/generated gha-creds-*.json junit.xml +.gemini-linters/ Thumbs.db .pytest_cache diff --git a/package.json b/package.json index 04c7077437..4328d4e637 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "test:integration:sandbox:none": "cross-env GEMINI_SANDBOX=false vitest run --root ./integration-tests", "test:integration:sandbox:docker": "cross-env GEMINI_SANDBOX=docker npm run build:sandbox && cross-env GEMINI_SANDBOX=docker vitest run --root ./integration-tests", "test:integration:sandbox:podman": "cross-env GEMINI_SANDBOX=podman vitest run --root ./integration-tests", - "lint": "eslint . --ext .ts,.tsx && eslint integration-tests && eslint scripts", + "lint": "eslint . --cache", "lint:fix": "eslint . --fix --ext .ts,.tsx && eslint integration-tests --fix && eslint scripts --fix && npm run format", "lint:ci": "npm run lint:all", "lint:all": "node scripts/lint.js", diff --git a/scripts/lint.js b/scripts/lint.js index 255c572551..c0c5689a01 100644 --- a/scripts/lint.js +++ b/scripts/lint.js @@ -21,7 +21,8 @@ const ACTIONLINT_VERSION = '1.7.7'; const SHELLCHECK_VERSION = '0.11.0'; const YAMLLINT_VERSION = '1.35.1'; -const TEMP_DIR = join(tmpdir(), 'gemini-cli-linters'); +const TEMP_DIR = + process.env.GEMINI_LINT_TEMP_DIR || join(tmpdir(), 'gemini-cli-linters'); function getPlatformArch() { const platform = process.platform; @@ -134,7 +135,9 @@ function runCommand(command, stdio = 'inherit') { export function setupLinters() { console.log('Setting up linters...'); - rmSync(TEMP_DIR, { recursive: true, force: true }); + if (!process.env.GEMINI_LINT_TEMP_DIR) { + rmSync(TEMP_DIR, { recursive: true, force: true }); + } mkdirSync(TEMP_DIR, { recursive: true }); for (const linter in LINTERS) { @@ -183,6 +186,9 @@ export function runYamllint() { export function runPrettier() { console.log('\nRunning Prettier...'); if (!runCommand('prettier --check .')) { + console.log( + 'Prettier check failed. Please run "npm run format" to fix formatting issues.', + ); process.exit(1); } }