Compare commits

...

109 Commits

Author SHA1 Message Date
mkorwel 0fecabc368 fix(ci): correct yaml indentation in ci.yml 2025-10-29 10:20:52 -07:00
mkorwel 7a42aa11d4 chore(ci): temporarily switch to standard runners 2025-10-29 09:57:06 -07:00
mkorwel 8826432034 fix(ci): update package scope for cli package 2025-10-29 08:54:58 -07:00
mkorwel 6701f061a3 fixing ci 2025-10-29 08:24:49 -07:00
matt korwel ab84509eed Merge branch 'main' into mk-bundling-no-npmrc 2025-10-29 08:19:51 -07:00
mkorwel e98178ebcf fix(ci): resolve remaining linting issues in release workflows 2025-10-28 13:07:15 -07:00
mkorwel bd549fabd6 fix(ci): resolve linting issues in release workflows 2025-10-28 13:05:03 -07:00
mkorwel d2e96b6c0a fix(ci): remove duplicative steps from bundled release workflow 2025-10-28 13:02:10 -07:00
mkorwel b89f64341e feat(ci): refactor release workflows for bundled and deprecated releases 2025-10-28 12:57:46 -07:00
mkorwel 3fa8a7e9fd feat(ci): generalize publish-bundle action and script 2025-10-28 12:43:10 -07:00
mkorwel 1666218952 refactor(ci): restore original manual release workflow and remove deprecated version 2025-10-27 11:35:47 -07:00
mkorwel 8c3f6ad220 refactor(ci): split manual release workflow 2025-10-27 10:09:23 -07:00
mkorwel 69cb84d43e fix(ci): add unique cache key for npmrc generation 2025-10-27 10:04:26 -07:00
mkorwel 555105ddcb fix(ci): reorder npm configuration step 2025-10-27 09:54:04 -07:00
mkorwel 884d5a4aa2 fix(ci): correct inputs for Get core Token step 2025-10-27 09:48:33 -07:00
mkorwel 4432c188e0 fix(ci): update package-lock.json 2025-10-27 09:38:24 -07:00
mkorwel 03cfcfca0b fix(ci): restore non-bundle release path 2025-10-24 11:30:40 -07:00
mkorwel 48a04d2d2d chore: run preflight checks 2025-10-24 09:45:50 -07:00
mkorwel 6b7a1150b5 Merge remote-tracking branch 'origin/main' into mk-bundling-no-npmrc 2025-10-24 09:03:40 -07:00
mkorwel 7c81b1837e pr clean up 2025-10-24 09:02:32 -07:00
mkorwel 6502f99619 docker pull 2025-10-24 08:23:42 -07:00
mkorwel aecfa04862 permissions 2025-10-24 08:10:30 -07:00
mkorwel 5d1d0d569f fix(e2e): grant package read permissions to e2e job
This ensures the reusable e2e workflow has the necessary permissions to pull the sandbox image from GHCR.
2025-10-23 22:40:27 -07:00
mkorwel 0c21f374f3 fix(orchestrator): remove ci dependency from e2e workflow
The e2e workflow in orchestrator.yml was incorrectly depending on the ci workflow. These are separate concerns and e2e should not depend on ci. This commit removes the ci dependency from the e2e workflow.
2025-10-23 22:27:38 -07:00
matt korwel 3e3d71297a Merge branch 'main' into mk-bundling-no-npmrc 2025-10-23 22:16:38 -07:00
mkorwel 82f2bd9b44 feat: add npm-run-all to dev dependencies
fix(e2e): add docker login to e2e workflow

The e2e tests were failing due to an authentication error when pulling the sandbox docker image. This was because the docker login step was missing from the e2e workflow.

This change adds the docker login step to the e2e workflow and also adds "npm-run-all" to the dev dependencies, which was missing and caused the linting to fail.
2025-10-23 22:10:38 -07:00
mkorwel cac05a838d fix(ci): Remove sandbox build from E2E test script
Removes the `npm run build:sandbox` command from the `test:integration:sandbox:docker` script. This prevents the E2E tests from attempting to rebuild the Docker image, which is now handled by a separate workflow. The tests will instead use the pre-built image specified by the `GEMINI_SANDBOX_IMAGE` environment variable.
2025-10-23 16:04:40 -07:00
mkorwel 4ee0820117 fix(ci): expand get-vars job and update dependencies in orchestrator
Expanded the `get-vars` job in `orchestrator.yml` to output `npm-registry-scope` and `npm-registry-url` in addition to `cli-package-name`. The `build-and-publish` and `e2e` jobs now correctly depend on `get-vars` and consume all three outputs, ensuring proper plumbing of environment variables for the Docker build.
2025-10-23 15:20:36 -07:00
mkorwel 070b74bb83 fix(ci): restore get-vars job to orchestrator workflow
Restores the `get-vars` job to the `orchestrator` workflow. This job was accidentally removed and is necessary for passing the `CLI_PACKAGE_NAME` to the `e2e` tests, which is required for the Docker build.
2025-10-23 15:14:08 -07:00
mkorwel 973573ef49 fix(ci): restore ci job to orchestrator workflow
Re-adds the `ci` job to the `orchestrator` workflow, which was
accidentally removed. The `e2e` job is also updated to correctly
depend on the `ci` job.
2025-10-23 14:42:29 -07:00
mkorwel 6f4c9a5317 fix(ci): correct workflow variable passing
- Adds explicit inputs for variables required by the reusable
  `build-and-publish` workflow.
- Updates the `orchestrator` workflow to pass these variables correctly.
- Removes a duplicated job from the `orchestrator` workflow.
2025-10-23 14:36:29 -07:00
mkorwel 247ac33265 fix(docker): grant write permissions for npm-global directory
Adds a `chown` command to the Dockerfile to grant the `node` user
write permissions to the `/usr/local/share/npm-global` directory.
This resolves an `EACCES` permission denied error during the `npm install -g`
step in the Docker build process.
2025-10-23 13:51:45 -07:00
mkorwel c9a3d28d99 refactor(ci): simplify sandbox build process
- Replaces the `build_sandbox.js` script with a direct `docker build`
  command in the `build-and-publish` workflow.
- Deletes the now-redundant `build_sandbox.js` and
  `sandbox_command.js` scripts.
- This makes the sandbox build process more transparent and removes
  unnecessary complexity.
2025-10-23 10:14:32 -07:00
mkorwel 6831c79c0a fix(ci): remove redundant npm install in sandbox build
Removes the unnecessary `npm install` step from the
`build-and-publish-sandbox` job. The Dockerfile is responsible
for installing the correct version of the package, so this step
was redundant.
2025-10-23 10:11:58 -07:00
mkorwel 14707b6d5e refactor(ci): consolidate sandbox build into publish workflow
- Moves the sandbox build and publish logic into the main
  `build-and-publish` workflow.
- The sandbox image is now built *after* the NPM package is published,
  and uses the published package.
- Removes the redundant `build-sandbox` and `release-sandbox` workflows.
- Updates the `orchestrator` workflow to reflect these changes.
2025-10-23 09:52:11 -07:00
mkorwel a4b05d8346 fix(ci): remove sandbox build from e2e workflow
Removes the sandbox image build step from the e2e workflow.
The e2e workflow will now consume a pre-built sandbox image,
separating the concerns of building and testing.
2025-10-23 09:48:19 -07:00
matt korwel 256ccd8d23 Merge branch 'main' into mk-bundling-no-npmrc 2025-10-23 09:38:54 -07:00
mkorwel dea79901a5 fix(release): update docker push action to use ghcr.io
Updates the release-sandbox workflow to use the push-docker action,
which is configured to push to ghcr.io.

Also updates the push-docker action to use `github.repository_owner`
as the username for ghcr.io login, which is the recommended practice.
2025-10-23 09:30:32 -07:00
mkorwel 0d55843c4a incorporating docker into new orchestrator 2025-10-23 08:40:10 -07:00
mkorwel 7b83236ab2 fix(e2e): mock ClearcutLogger to fix test runner dependency 2025-10-22 16:17:23 -07:00
mkorwel 30770bf362 refactor(ci): remove debug npmrc step from build-and-publish 2025-10-22 14:26:28 -07:00
mkorwel d83ecc4585 fix(ci): correct npm publish authentication in build-and-publish workflow 2025-10-22 14:20:36 -07:00
mkorwel 1da17999c7 linting 2025-10-22 14:01:32 -07:00
mkorwel 2797039239 fix: correct invalid workflow syntax in e2e 2025-10-22 13:39:29 -07:00
mkorwel e03dc0d603 fix: correct invalid workflow syntax in orchestrator 2025-10-22 13:36:32 -07:00
matt korwel 642adf350f Merge branch 'main' into mk-bundling-no-npmrc 2025-10-22 13:32:24 -07:00
mkorwel 6058c1be45 feat: address PR feedback
- Use reusable npmrc action in workflows
- Make package name dynamic in e2e tests
- Add rationale for configure-registry script
- Force orchestrator to run in dev environment
2025-10-22 13:31:07 -07:00
mkorwel f0541c35ac feat(ci): Parallelize linting and move to larger runner
This change parallelizes the linting tasks in package.json and moves the lint job to a larger runner for a significant performance improvement. It also fixes an infinite loop that was introduced during the refactoring.
2025-10-22 12:48:55 -07:00
mkorwel b255e904fd chore(ci): Optimize runner usage for lightweight jobs 2025-10-22 12:40:05 -07:00
mkorwel be08763cfa fix(ci): Pass GEMINI_API_KEY secret to E2E workflow 2025-10-22 12:34:19 -07:00
mkorwel dc2aa1ead7 fix: Centralize workflow concurrency in orchestrator 2025-10-22 12:27:39 -07:00
matt korwel ce0bed07c6 Merge branch 'main' into mk-bundling-no-npmrc 2025-10-22 12:19:52 -07:00
mkorwel b6887db096 fix: Safely restore .npmrc from backup 2025-10-22 12:19:23 -07:00
mkorwel a9834cc6c3 fixing url parsing 2025-10-22 12:16:45 -07:00
mkorwel 8a1d905fd6 feat: Refactor release process for bundling
This change refactors the release process to support a new bundle-based publishing method while maintaining backward compatibility for existing release and patch workflows.

Key changes:
- The `publish-release` composite action now includes a `use-bundle-release` input (string, default 'false') to conditionally switch between the old source-based publishing and the new bundle-based method.
- The `release-nightly.yml` workflow is updated to use the new bundle-based process (`use-bundle-release: 'true'`).
- The `release-manual.yml` workflow includes a new `use_bundle_release` input (defaulting to false) to allow for manual testing of either release method.
- Existing `release-promote.yml` and patch workflows remain unchanged, ensuring they continue to use the old, non-bundled process for backward compatibility.
2025-10-22 11:54:18 -07:00
mkorwel a35e4436a0 feat: Refactor release process for bundling
This change refactors the release process to support a new bundle-based publishing method while
maintaining backward compatibility for existing release and patch workflows.

Key changes:
- The  composite action now includes a  input (string, default 'false') to conditionally switch between the old source-based publishing
the new bundle-based method.
- The  workflow is updated to use the new bundle-based process ().
- The  workflow includes a new  input (defaulting to false) to allow for manual testing of either release method.
- Existing  and patch workflows remain unchanged, ensuring they continue to use the old, non-bundled process for backward compatibility.
2025-10-22 11:24:50 -07:00
mkorwel f09e38ee0e linting 2025-10-22 01:26:54 -07:00
mkorwel 8c9494eb70 fix(ci): Add npm config step to e2e_linux job
Adds the 'Configure npm for GitHub Packages' step to the 'e2e_linux' job in 'e2e.yml'.

This was missing, causing the job to fail when trying to install the test package from the GitHub Packages registry.
2025-10-22 01:09:09 -07:00
mkorwel ec7f503d13 fix(ci): Add 'packages: read' permission to bundle-size workflow
Adds the 'packages: read' permission to the 'bundle-size.yml' workflow.

This is necessary to allow the job to download the package from the GitHub Packages registry to perform the size check.
2025-10-22 01:06:44 -07:00
mkorwel b21a5a0c3c debug(ci): Add .npmrc debug step after prepare-github-release
Adds a debug step to the 'build-and-publish.yml' workflow to print the contents of the .npmrc file immediately after the 'prepare-github-release.js' script runs.

This will help determine if the 'prepare-github-release.js' script is inadvertently modifying or overwriting the .npmrc file, which could be causing the 'ENEEDAUTH' error during the publish step.
2025-10-22 01:00:39 -07:00
mkorwel 2f179d1886 debug(ci): Add .npmrc debug step to build workflow
Adds a debug step to the 'build-and-publish.yml' workflow to print the contents of the .npmrc file immediately before the 'npm publish' step.

This will help diagnose the 'ENEEDAUTH' error by showing the exact state of the npm configuration at the time of failure.
2025-10-22 00:57:17 -07:00
mkorwel 430e9c68d7 refactor(ci): Move bundle size check to a parallel job
Creates a new reusable workflow, 'bundle-size.yml', to handle the bundle size check.

This check is now run in a separate job in the main 'orchestrator.yml' workflow, parallel to the 'e2e' job. This optimizes the CI pipeline by allowing the E2E tests to start as soon as the bundle is published, without waiting for the size check to complete.
2025-10-22 00:54:20 -07:00
mkorwel 2513dd929d revert(ci): Remove incorrect .npmrc creation from prepare-github-release.js
Reverts the change that added .npmrc creation logic to 'scripts/prepare-github-release.js'.

This logic was incorrectly overwriting the .npmrc file that is correctly configured by the 'Configure npm for GitHub Packages' step in the 'build-and-publish.yml' workflow, leading to authentication failures during npm publish.

The workflow itself already handles the .npmrc creation correctly, and this revert ensures that the correct authentication token is preserved.
2025-10-22 00:46:39 -07:00
mkorwel 9856a67b4c fix(ci): Create .npmrc file for GitHub Packages publishing
Updates the 'prepare-github-release.js' script to create an '.npmrc' file in the root directory.

This ensures that the 'npm publish' command is properly authenticated with the GitHub Packages registry, preventing the 'ENEEDAUTH' error during the publish step.
2025-10-22 00:34:01 -07:00
mkorwel 706a48629f ci(lint): Optimize dependency installation
Updates the 'lint.yml' workflow to use 'npm ci --only=dev'.

This ensures that only 'devDependencies' are installed, making the linting job faster and more efficient as it doesn't need to download and install the main application dependencies.
2025-10-22 00:30:33 -07:00
mkorwel 17b3b264e6 refactor(ci): Remove redundant smoke test bundle steps
Removes the 'smoke test bundle' steps from the 'test_linux', 'test_mac', and 'test_windows' jobs in 'ci.yml'.

This step is redundant as the e2e workflow is responsible for testing the final bundled artifact.
2025-10-22 00:24:22 -07:00
mkorwel 20a2430d89 fix(ci): Reorder build steps to prevent lockfile inconsistency
Reorders the steps in the 'publish-bundle' job to run the bundle creation and size check *before* modifying the package.json files for release.

This prevents the 'package-lock.json' from becoming out-of-sync, which was causing the 'npm ci' command in the bundle size action to fail.
2025-10-22 00:15:36 -07:00
mkorwel a7395df23a refactor(cli): Remove redundant generate from workspace test:ci script
Removes the 'npm run generate' command from the 'test:ci' script in 'packages/cli/package.json'.

This step was redundant because the root 'test:ci' script now runs 'npm run build' (which includes 'generate') before executing the workspace tests.
2025-10-21 23:43:10 -07:00
mkorwel b4f6191704 ci: Set fail-fast to false for all matrix jobs
Updates the 'test_linux', 'test_mac', and 'test_windows' jobs in 'ci.yml' to explicitly set 'strategy.fail-fast' to 'false'.

This ensures that all matrix variations for each job will run to completion, even if one of the variations fails. This provides a more complete picture of test status across all supported Node.js versions.
2025-10-21 23:36:07 -07:00
mkorwel 2dde05deb0 refactor(ci): Move bundle size check to build workflow
Moves the bundle size check from a separate job in 'ci.yml' to a step within the 'publish-bundle' job in 'build-and-publish.yml'.

This is a more logical location for the check and completely resolves the race condition where the '.npmrc' file created by the bundle size job could interfere with parallel unit test jobs.
2025-10-21 23:28:22 -07:00
mkorwel 6a6c344f49 refactor(ci): Remove redundant generate step from test:ci script
Removes the 'npm run generate' command from the 'test:ci' script in the root package.json.

This step was redundant because the 'npm run build' command, which is run first, already includes the 'generate' step.
2025-10-21 22:59:56 -07:00
mkorwel 4faa59fb72 fix(ci): Build packages before running unit tests
Updates the root 'test:ci' script to run 'npm run build' before the test execution steps.

This ensures that all workspace packages are compiled before Vitest runs, preventing 'Failed to resolve entry for package' errors when tests in one package import from another.
2025-10-21 22:55:08 -07:00
mkorwel 208e9e24bf fix(ci): Generate git-commit.js before running workspace tests
Updates the root 'test:ci' script to run 'npm run generate' before executing the workspace tests.

This ensures that the 'generated/git-commit.js' file is created before any unit tests are run, preventing the 'Cannot find module' error that was occurring in the CI environment.
2025-10-21 22:49:55 -07:00
mkorwel 5b2ad83372 refactor(build): Remove redundant lint job and dependency
Removes the redundant 'lint' job from 'build-and-publish.yml'.

This job was duplicating the linting efforts now handled by the dedicated 'lint.yml' workflow. The 'publish-bundle' job no longer declares an internal dependency on 'lint', as the orchestrator workflow ensures linting is completed before calling 'build-and-publish'.
2025-10-21 22:44:53 -07:00
mkorwel 5e2d2ecf76 fix(lint): Set fetch-depth to 0 to ensure full git history
Updates the checkout step in the 'lint.yml' workflow to use 'fetch-depth: 0'.

This is necessary to prevent intermittent failures in the sensitive keyword linter, which requires a full git history to reliably compare the current branch against 'origin/main'.
2025-10-21 22:41:06 -07:00
mkorwel 5fa0e5520f fix(lint): Explicitly set fetch-depth to 1
Explicitly sets 'fetch-depth: 1' in the checkout step of the 'lint.yml' workflow.

This makes the default behavior of fetching only the most recent commit explicit for clarity and consistency with other jobs that perform shallow clones.
2025-10-21 22:37:35 -07:00
mkorwel 1a5742efec refactor(ci): Create reusable lint workflow and define dependencies
Creates a new reusable workflow, 'lint.yml', to handle all linting operations.

The main 'orchestrator.yml' is updated to use this new workflow. The dependency chain is now explicitly defined: 'lint' runs first, followed by 'build-and-publish' and 'ci' in parallel. The 'e2e' job remains dependent on 'build-and-publish'.

This change also removes the now-unused 'version' input from 'ci.yml' and corrects the 'bundle_size' job to use 'npm ci'.
2025-10-21 22:29:22 -07:00
mkorwel 56f1ffe14f refactor(ci): Use npm ci and remove published package install
Replaces the explicit GitHub Packages configuration and published package installation with 'npm ci' in the 'test_linux', 'test_mac', and 'test_windows' jobs within 'ci.yml'.

This streamlines the unit testing process by focusing on the source code dependencies and avoids misleadingly installing the published package in the unit test phase. The 'bundle_size' job retains its specific install as it requires the published artifact.
2025-10-21 22:23:36 -07:00
mkorwel 118e3176e8 fix(cli): Ensure git-commit.js is generated before unit tests
Updates the 'test:ci' script in 'packages/cli/package.json' to run 'npm run generate' before 'vitest run'.

This ensures that the '../../generated/git-commit.js' file, which is required by some telemetry modules, is created before unit tests attempt to import it, resolving the 'Cannot find module' error during CI runs.
2025-10-21 22:19:08 -07:00
mkorwel e03570f99e fix(workflows): namespace concurrency groups
Prefixes the concurrency group names in 'ci.yml' and 'e2e.yml' with 'ci-' and 'e2e-' respectively.

This prevents the workflows from canceling each other out when they are triggered by the same orchestrator workflow, as the 'github.workflow' context variable was resolving to the same value for both.
2025-10-21 22:00:49 -07:00
mkorwel 33fc71b22e refactor(ci): centralize workflow permissions
Consolidates all job-level permissions into a single workflow-level block in 'ci.yml'.

This simplifies the workflow configuration and makes it easier to manage permissions. The workflow-level permissions now include all necessary permissions for the 'test_linux', 'test_mac', 'codeql', and 'bundle_size' jobs.
2025-10-21 21:54:38 -07:00
mkorwel f6727cc14f fix(workflows): Add packages:read permission and rename orchestrator
Adds 'packages: read' permission to the 'ci.yml' and 'e2e.yml' workflows. This is necessary to allow the jobs to download packages from the GitHub Packages registry, fixing the 403 Forbidden error during 'npm install'.

Also renames the 'orchestrator.yml' workflow from 'PR Checks' to 'Checks' for brevity.
2025-10-21 21:48:31 -07:00
mkorwel 2e0bf57e63 linting 2025-10-21 21:40:43 -07:00
mkorwel 27fceb9679 remove merge check 2025-10-21 21:29:37 -07:00
mkorwel a6c9eaabf6 Feat: Implement dynamic versioning and PR-based tagging for CI builds 2025-10-21 21:08:37 -07:00
mkorwel dc3072c597 Fix: Remove concurrency from orchestrator.yml to resolve deadlock 2025-10-21 20:54:49 -07:00
mkorwel 4a0b341575 Remove 'private' field from root package.json to enable publishing 2025-10-21 20:50:59 -07:00
mkorwel f0ccf3e52d include githuboutput 2025-10-21 20:45:43 -07:00
mkorwel cc5ce59dca waht hwat 2025-10-21 20:40:27 -07:00
mkorwel 1eba9123de what 2025-10-21 20:38:19 -07:00
mkorwel 7226817a6b fix(ci): correct syntax in orchestrator permissions 2025-10-21 20:37:07 -07:00
mkorwel 111c598ed9 fix(ci): correct syntax in orchestrator permissions 2025-10-21 20:26:51 -07:00
mkorwel d66884a38b fix(ci): restore full explicit permissions to orchestrator 2025-10-21 20:25:47 -07:00
mkorwel 4155f7404b fix(ci): simplify orchestrator permissions to read-all 2025-10-21 20:23:56 -07:00
mkorwel 6038f48241 fix(ci): add all required read permissions to orchestrator 2025-10-21 20:20:02 -07:00
mkorwel af5b5d5ccc fix(ci): add actions:read permission to orchestrator 2025-10-21 20:18:51 -07:00
mkorwel 2530610a59 fix(ci): grant check and status write permissions to orchestrator 2025-10-21 20:17:20 -07:00
mkorwel 69f9bfb67b fix(ci): add permissions to orchestrator workflow 2025-10-21 20:13:05 -07:00
mkorwel 4955b470db orchestrator 2025-10-21 20:07:37 -07:00
mkorwel ff3398f297 feat(ci): Implement orchestrator workflow for unified build and test 2025-10-21 19:21:59 -07:00
matt korwel 8383974276 Merge branch 'main' into mk-bundling-no-npmrc 2025-10-21 18:50:25 -07:00
mkorwel 7bfa1de1b3 pushing changes to publish first 2025-10-21 18:47:32 -07:00
mkorwel a28ff41a75 fix(ci): Add npmrc configuration to E2E workflow
This commit adds a step to the E2E workflow to create an .npmrc file and configure it with the necessary credentials for the GitHub Packages registry. This resolves the '401 Unauthorized' error that was occurring during the 'npm ci' step.
2025-10-21 18:46:31 -07:00
mkorwel 46b1c59a47 feat(dev-experience): Automate npmrc configuration for dev vs prod
This PR introduces a new, automated workflow for developers to switch between the development (GitHub Packages) and production (npmjs.org) npm registries.

- A new script, , now automatically backs up and modifies the user's global  file.
-  has been updated with  and  scripts to run this new script.
-  has been updated to reflect this new, simplified, and automated process, removing all manual steps for the user.
2025-10-21 18:46:20 -07:00
Tommaso Sciortino beed1515c2 Add aria labels to Todo list display (#11621) 2025-10-21 18:46:20 -07:00
mkorwel 5e58f5ea3c feat: Unify CLI bundling and publishing process
This commit unifies the bundling and publishing process for the CLI package across both npmjs.org and GitHub Packages.

- The  script has been updated to only rename packages for the GitHub registry, removing the bundle copying and package.json modification logic.
- The  has been modified to remove the  flag from the CLI publish step, ensuring the root package (which includes the bundled executable) is published.

This ensures a consistent, bundled artifact is published to both registries.
2025-10-21 18:46:20 -07:00
James 9fadff531a feat(cli): Adds the ability to run MCP prompt commands in non-interactive mode (#10194)
Co-authored-by: Allen Hutchison <adh@google.com>
2025-10-21 18:46:20 -07:00
Silvio Junior 57789e2e34 fix(config): Disable CI for stable release (#11615) 2025-10-21 18:46:20 -07:00
mkorwel 989352f557 feat: Add NOTICES.txt validation to CI workflow
fix: Update NOTICES.txt to reflect current dependencies
2025-10-21 16:35:56 -07:00
27 changed files with 1189 additions and 543 deletions
+47
View File
@@ -0,0 +1,47 @@
# .github/actions/publish-bundle/action.yml
name: 'Publish Bundle'
description: 'Builds, versions, and publishes the bundled CLI package.'
inputs:
version:
description: 'The version to publish the package with.'
required: true
tag:
description: 'The npm dist-tag to publish the package with.'
required: true
github-token:
description: 'GitHub token for authentication.'
required: true
package-scope:
description: 'The npm scope to publish the package to.'
required: false
runs:
using: 'composite'
steps:
- name: 'Setup NPMRC'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ inputs.github-token }}'
- name: 'Bundle'
shell: 'bash'
run: 'npm run bundle'
- name: 'Prepare Package for Publishing'
if: "${{ inputs.package-scope != '' }}"
shell: 'bash'
env:
PACKAGE_SCOPE: '${{ inputs.package-scope }}'
run: 'node scripts/prepare-package.js --scope=${{ env.PACKAGE_SCOPE }}'
- name: 'Set Version'
shell: 'bash'
env:
PACKAGE_VERSION: '${{ inputs.version }}'
run: 'npm version --no-git-tag-version "${{ env.PACKAGE_VERSION }}"'
- name: 'Publish to GitHub Packages'
env:
NODE_AUTH_TOKEN: '${{ inputs.github-token }}'
NPM_TAG: '${{ inputs.tag }}'
shell: 'bash'
run: 'npm publish --tag="${{ env.NPM_TAG }}"'
@@ -0,0 +1,274 @@
name: 'Publish Release (DEPRECATED)'
description: 'Builds, prepares, and publishes the gemini-cli packages to npm and creates a GitHub release.'
inputs:
release-version:
description: 'The version to release (e.g., 0.1.11).'
required: true
npm-tag:
description: 'The npm tag to publish with (e.g., latest, preview, nightly).'
required: true
wombat-token-core:
description: 'The npm token for the cli-core package.'
required: true
wombat-token-cli:
description: 'The npm token for the cli package.'
required: true
wombat-token-a2a-server:
description: 'The npm token for the a2a package.'
required: true
github-token:
description: 'The GitHub token for creating the release.'
required: true
dry-run:
description: 'Whether to run in dry-run mode.'
type: 'string'
required: true
release-tag:
description: 'The release tag for the release (e.g., v0.1.11).'
required: true
previous-tag:
description: 'The previous tag to use for generating release notes.'
required: true
skip-github-release:
description: 'Whether to skip creating a GitHub release.'
type: 'boolean'
required: false
default: false
working-directory:
description: 'The working directory to run the steps in.'
required: false
default: '.'
force-skip-tests:
description: 'Skip tests and validation'
required: false
default: false
skip-branch-cleanup:
description: 'Whether to skip cleaning up the release branch.'
type: 'boolean'
required: false
default: false
gemini_api_key:
description: 'The API key for running integration tests.'
required: true
npm-registry-publish-url:
description: 'npm registry publish url'
required: true
npm-registry-url:
description: 'npm registry url'
required: true
npm-registry-scope:
description: 'npm registry scope'
required: true
cli-package-name:
description: 'The name of the cli package.'
required: true
core-package-name:
description: 'The name of the core package.'
required: true
a2a-package-name:
description: 'The name of the a2a package.'
required: true
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: '👤 Configure Git User'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
git config user.name "gemini-cli-robot"
git config user.email "gemini-cli-robot@google.com"
- name: '🌿 Create and switch to a release branch'
working-directory: '${{ inputs.working-directory }}'
id: 'release_branch'
shell: 'bash'
run: |
BRANCH_NAME="release/${{ inputs.release-tag }}"
git switch -c "${BRANCH_NAME}"
echo "BRANCH_NAME=${BRANCH_NAME}" >> "${GITHUB_OUTPUT}"
- name: '⬆️ Update package versions'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
npm run release:version "${{ inputs.release-version }}"
- name: '💾 Commit and Conditionally Push package versions'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
env:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
DRY_RUN: '${{ inputs.dry-run }}'
RELEASE_TAG: '${{ inputs.release-tag }}'
run: |-
set -e
git add package.json package-lock.json packages/*/package.json
git commit -m "chore(release): ${RELEASE_TAG}"
if [[ "${DRY_RUN}" == "false" ]]; then
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}" --follow-tags
else
echo "Dry run enabled. Skipping push."
fi
- name: '🛠️ Build and Prepare Packages'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
npm run build:packages
npm run prepare:package
- name: '🎁 Bundle'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
npm run bundle
# TODO: Refactor this github specific publishing script to be generalized based upon inputs.
- name: '📦 Prepare for GitHub release'
if: "inputs.npm-registry-url == 'https://npm.pkg.github.com/'"
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
run: |
node ${{ github.workspace }}/scripts/prepare-github-release.js
- name: 'Configure npm for publishing to npm'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: '${{ inputs.working-directory }}/.nvmrc'
registry-url: '${{inputs.npm-registry-publish-url}}'
scope: '${{inputs.npm-registry-scope}}'
- name: 'Get core Token'
uses: './.github/actions/npm-auth-token'
id: 'core-token'
with:
package-name: '${{ inputs.core-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: '📦 Publish CORE to NPM'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ steps.core-token.outputs.auth-token }}'
shell: 'bash'
run: |
npm publish \
--dry-run="${{ inputs.dry-run }}" \
--workspace="${{ inputs.core-package-name }}" \
--no-tag
npm dist-tag rm ${{ inputs.core-package-name }} false --silent
- name: '🔗 Install latest core package'
working-directory: '${{ inputs.working-directory }}'
if: "${{ inputs.dry-run != 'true' }}"
shell: 'bash'
run: |
npm install "${{ inputs.core-package-name }}@${{ inputs.release-version }}" \
--workspace="${{ inputs.cli-package-name }}" \
--workspace="${{ inputs.a2a-package-name }}" \
--save-exact
- name: 'Get CLI Token'
uses: './.github/actions/npm-auth-token'
id: 'cli-token'
with:
package-name: '${{ inputs.cli-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: '📦 Publish CLI'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ steps.cli-token.outputs.auth-token }}'
shell: 'bash'
run: |
npm publish \
--dry-run="${{ inputs.dry-run }}" \
--workspace="${{ inputs.cli-package-name }}" \
--no-tag
npm dist-tag rm ${{ inputs.cli-package-name }} false --silent
- name: 'Get a2a-server Token'
uses: './.github/actions/npm-auth-token'
id: 'a2a-token'
with:
package-name: '${{ inputs.a2a-package-name }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
- name: '📦 Publish a2a'
working-directory: '${{ inputs.working-directory }}'
env:
NODE_AUTH_TOKEN: '${{ steps.a2a-token.outputs.auth-token }}'
shell: 'bash'
# Tag staging for initial release
run: |
npm publish \
--dry-run="${{ inputs.dry-run }}" \
--workspace="${{ inputs.a2a-package-name }}" \
--no-tag
npm dist-tag rm ${{ inputs.a2a-package-name }} false --silent
- name: '🔬 Verify NPM release by version'
uses: './.github/actions/verify-release'
if: "${{ inputs.dry-run != 'true' && inputs.force-skip-tests != 'true' }}"
with:
npm-package: '${{ inputs.cli-package-name }}@${{ inputs.release-version }}'
expected-version: '${{ inputs.release-version }}'
working-directory: '${{ inputs.working-directory }}'
gemini_api_key: '${{ inputs.gemini_api_key }}'
github-token: '${{ inputs.github-token }}'
npm-registry-url: '${{ inputs.npm-registry-url }}'
npm-registry-scope: '${{ inputs.npm-registry-scope }}'
- name: '🏷️ Tag release'
uses: './.github/actions/tag-npm-release'
with:
channel: '${{ inputs.npm-tag }}'
version: '${{ inputs.release-version }}'
dry-run: '${{ inputs.dry-run }}'
github-token: '${{ inputs.github-token }}'
wombat-token-core: '${{ inputs.wombat-token-core }}'
wombat-token-cli: '${{ inputs.wombat-token-cli }}'
wombat-token-a2a-server: '${{ inputs.wombat-token-a2a-server }}'
cli-package-name: '${{ inputs.cli-package-name }}'
core-package-name: '${{ inputs.core-package-name }}'
a2a-package-name: '${{ inputs.a2a-package-name }}'
working-directory: '${{ inputs.working-directory }}'
- name: '🎉 Create GitHub Release'
working-directory: '${{ inputs.working-directory }}'
if: "${{ inputs.dry-run != 'true' && inputs.skip-github-release != 'true' && inputs.npm-tag != 'dev' && inputs.npm-registry-url != 'https://npm.pkg.github.com/' }}"
env:
GITHUB_TOKEN: '${{ inputs.github-token }}'
shell: 'bash'
run: |
gh release create "${{ inputs.release-tag }}" \
bundle/gemini.js \
--target "${{ steps.release_branch.outputs.BRANCH_NAME }}" \
--title "Release ${{ inputs.release-tag }}" \
--notes-start-tag "${{ inputs.previous-tag }}" \
--generate-notes
- name: '🧹 Clean up release branch'
working-directory: '${{ inputs.working-directory }}'
if: "${{ inputs.dry-run != 'true' && inputs.skip-branch-cleanup != 'true' }}"
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 }}"
+1 -1
View File
@@ -46,7 +46,7 @@ runs:
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
with:
registry: 'ghcr.io'
username: '${{ inputs.github-actor }}'
username: '${{ github.repository_owner }}'
password: '${{ inputs.github-secret }}'
- name: 'Get branch name'
id: 'branch_name'
-96
View File
@@ -1,96 +0,0 @@
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
dockerhub-username:
description: 'Dockerhub username'
required: true
dockerhub-token:
description: 'Dockerhub PAT w/ R+W'
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: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- 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: 'docker.io'
username: '${{ inputs.dockerhub-username }}'
password: '${{ inputs.dockerhub-token }}'
- 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 google/gemini-cli-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 != 'true' }}"
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"
+124
View File
@@ -0,0 +1,124 @@
# .github/workflows/build-and-publish.yml
name: 'Build and Publish Bundle'
on:
workflow_call:
inputs:
cli-package-name:
description: 'The name of the CLI package.'
required: true
type: 'string'
npm-registry-scope:
description: 'NPM registry scope'
required: true
type: 'string'
npm-registry-url:
description: 'NPM registry URL'
required: true
type: 'string'
outputs:
version:
description: 'The version of the published package'
value: '${{ jobs.publish-bundle.outputs.version }}'
image-uri:
description: 'The URI of the built sandbox image.'
value: '${{ jobs.build-and-publish-sandbox.outputs.image-uri }}'
jobs:
publish-bundle:
name: 'Publish Bundle'
runs-on: 'ubuntu-latest'
outputs:
version: '${{ steps.vars.outputs.version }}'
permissions:
contents: 'read'
packages: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 0
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
run: 'npm ci'
- name: 'Calculate Version and Tag'
id: 'vars'
run: |
CURRENT_VERSION=$(node -p "require('./package.json').version")
NEW_VERSION="${CURRENT_VERSION}-ci.${{ github.run_number }}.${{ github.sha }}"
echo "version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "tag=pr-${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
else
echo "tag=ci" >> "$GITHUB_OUTPUT"
fi
- name: 'Publish Bundle'
uses: './.github/actions/publish-bundle'
with:
version: '${{ steps.vars.outputs.version }}'
tag: '${{ steps.vars.outputs.tag }}'
github-token: '${{ secrets.GITHUB_TOKEN }}'
package-scope: '${{ inputs.npm-registry-scope }}'
build-and-publish-sandbox:
name: 'Build and Publish Sandbox'
runs-on: 'ubuntu-latest'
needs: 'publish-bundle'
outputs:
image-uri: '${{ steps.docker_build.outputs.uri }}'
permissions:
contents: 'read'
packages: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 0
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Setup NPMRC'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@v3'
with:
registry: 'ghcr.io'
username: '${{ github.repository_owner }}'
password: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Set up Docker Buildx'
uses: 'docker/setup-buildx-action@v3'
- name: 'Build and Push Sandbox Image'
id: 'docker_build'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
shell: 'bash'
run: |
IMAGE_TAG="ghcr.io/${{ github.repository }}/sandbox:${{ needs.publish-bundle.outputs.version }}"
docker build . \
--file Dockerfile \
--tag "${IMAGE_TAG}" \
--build-arg CLI_VERSION=${{ needs.publish-bundle.outputs.version }} \
--build-arg NPM_REGISTRY_SCOPE=${{ inputs.npm-registry-scope }} \
--build-arg NPM_REGISTRY_URL=${{ inputs.npm-registry-url }} \
--build-arg CLI_PACKAGE_NAME=${{ inputs.cli-package-name }} \
--secret id=GITHUB_TOKEN
docker push "${IMAGE_TAG}"
echo "uri=${IMAGE_TAG}" >> "$GITHUB_OUTPUT"
+50
View File
@@ -0,0 +1,50 @@
# .github/workflows/bundle-size.yml
name: 'Bundle Size Check'
on:
workflow_call:
inputs:
version:
description: 'The version of the published package'
required: true
type: 'string'
permissions:
contents: 'read'
pull-requests: 'write'
packages: 'read'
jobs:
bundle-size:
name: 'Check Bundle Size'
runs-on: 'ubuntu-latest'
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/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Setup NPMRC'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Install dependencies'
env:
VERSION: '${{ inputs.version }}'
run: 'npm install @google-gemini/gemini-cli@${{ env.VERSION }}'
- name: 'Check Bundle Size'
uses: 'preactjs/compressed-size-action@946a292cd35bd1088e0d7eb92b69d1a8d5b5d76a'
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
pattern: './bundle/**/*.{js,sb}'
minimum-change-threshold: '1000'
compression: 'none'
clean-script: 'clean'
+17 -189
View File
@@ -1,121 +1,27 @@
name: 'Testing: CI'
on:
push:
branches:
- 'main'
- 'release/**'
pull_request:
branches:
- 'main'
- 'release/**'
merge_group:
workflow_dispatch:
inputs:
branch_ref:
description: 'Branch to run on'
required: true
default: 'main'
type: 'string'
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: |-
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
workflow_call:
permissions:
checks: 'write'
contents: 'read'
statuses: 'write'
packages: 'read'
pull-requests: 'write'
actions: 'read'
security-events: 'write'
defaults:
run:
shell: 'bash'
jobs:
merge_queue_skipper:
permissions: 'read-all'
name: 'Merge Queue Skipper'
runs-on: 'gemini-cli-ubuntu-16-core'
outputs:
skip: '${{ steps.merge-queue-ci-skipper.outputs.skip-check }}'
steps:
- id: 'merge-queue-ci-skipper'
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
with:
secret: '${{ secrets.GITHUB_TOKEN }}'
lint:
name: 'Lint'
runs-on: 'gemini-cli-ubuntu-16-core'
needs: 'merge_queue_skipper'
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 0
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Validate NOTICES.txt'
run: 'git diff --exit-code packages/vscode-ide-companion/NOTICES.txt'
- name: 'Check lockfile'
run: 'npm run check:lockfile'
- name: 'Install linters'
run: 'node scripts/lint.js --setup'
- name: 'Run ESLint'
run: 'node scripts/lint.js --eslint'
- name: 'Run actionlint'
run: 'node scripts/lint.js --actionlint'
- name: 'Run shellcheck'
run: 'node scripts/lint.js --shellcheck'
- name: 'Run yamllint'
run: 'node scripts/lint.js --yamllint'
- name: 'Run Prettier'
run: 'node scripts/lint.js --prettier'
- name: 'Run sensitive keyword linter'
run: 'node scripts/lint.js --sensitive-keywords'
link_checker:
name: 'Link Checker'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
- name: 'Link Checker'
uses: 'lycheeverse/lychee-action@885c65f3dc543b57c898c8099f4e08c8afd178a2' # ratchet: lycheeverse/lychee-action@v2.6.1
with:
args: '--verbose ./**/*.md'
fail: true
test_linux:
name: 'Test (Linux)'
runs-on: 'gemini-cli-ubuntu-16-core'
needs:
- 'lint'
- 'merge_queue_skipper'
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
permissions:
contents: 'read'
checks: 'write'
pull-requests: 'write'
runs-on: 'ubuntu-latest'
strategy:
fail-fast: false
matrix:
node-version:
- '20.x'
@@ -131,10 +37,7 @@ jobs:
node-version: '${{ matrix.node-version }}'
cache: 'npm'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies for testing'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Run tests and generate reports'
@@ -142,12 +45,6 @@ jobs:
NO_COLOR: true
run: 'npm run test:ci'
- name: 'Bundle'
run: 'npm run bundle'
- name: 'Smoke test bundle'
run: 'node ./bundle/gemini.js --version'
- name: 'Wait for file system sync'
run: 'sleep 2'
@@ -172,16 +69,9 @@ jobs:
test_mac:
name: 'Test (Mac)'
runs-on: '${{ matrix.os }}'
needs:
- 'lint'
- 'merge_queue_skipper'
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
permissions:
contents: 'read'
checks: 'write'
pull-requests: 'write'
continue-on-error: true
strategy:
fail-fast: false
matrix:
os:
- 'macos-latest'
@@ -199,10 +89,7 @@ jobs:
node-version: '${{ matrix.node-version }}'
cache: 'npm'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies for testing'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Run tests and generate reports'
@@ -210,12 +97,6 @@ jobs:
NO_COLOR: true
run: 'npm run test:ci -- --coverage.enabled=false'
- name: 'Bundle'
run: 'npm run bundle'
- name: 'Smoke test bundle'
run: 'node ./bundle/gemini.js --version'
- name: 'Wait for file system sync'
run: 'sleep 2'
@@ -247,13 +128,7 @@ jobs:
codeql:
name: 'CodeQL'
runs-on: 'gemini-cli-ubuntu-16-core'
needs: 'merge_queue_skipper'
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
permissions:
actions: 'read'
contents: 'read'
security-events: 'write'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
@@ -268,37 +143,12 @@ jobs:
- name: 'Perform CodeQL Analysis'
uses: 'github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2' # ratchet:github/codeql-action/analyze@v3
# Check for changes in bundle size.
bundle_size:
name: 'Check Bundle Size'
needs: 'merge_queue_skipper'
if: "${{github.event_name == 'pull_request' && needs.merge_queue_skipper.outputs.skip == 'false'}}"
runs-on: 'gemini-cli-ubuntu-16-core'
permissions:
contents: 'read' # For checkout
pull-requests: 'write' # For commenting
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 1
- uses: 'preactjs/compressed-size-action@946a292cd35bd1088e0d7eb92b69d1a8d5b5d76a'
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
pattern: './bundle/**/*.{js,sb}'
minimum-change-threshold: '1000'
compression: 'none'
clean-script: 'clean'
test_windows:
name: 'Slow Test - Win'
runs-on: 'gemini-cli-windows-16-core'
needs: 'merge_queue_skipper'
if: "${{needs.merge_queue_skipper.outputs.skip == 'false'}}"
runs-on: 'windows-latest'
continue-on-error: true
strategy:
fail-fast: false
steps:
- name: 'Checkout'
@@ -334,14 +184,6 @@ jobs:
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 }}'
@@ -352,34 +194,20 @@ jobs:
run: 'npm run test:ci -- --coverage.enabled=false'
shell: 'pwsh'
- name: 'Bundle'
run: 'npm run bundle'
shell: 'pwsh'
- name: 'Smoke test bundle'
run: 'node ./bundle/gemini.js --version'
shell: 'pwsh'
ci:
name: 'CI'
if: 'always()'
needs:
- 'lint'
- 'link_checker'
- 'test_linux'
- 'test_mac'
- 'codeql'
- 'bundle_size'
runs-on: 'gemini-cli-ubuntu-16-core'
runs-on: 'ubuntu-latest'
steps:
- name: 'Check all job results'
run: |
if [[ (${{ needs.lint.result }} != 'success' && ${{ needs.lint.result }} != 'skipped') || \
(${{ needs.link_checker.result }} != 'success' && ${{ needs.link_checker.result }} != 'skipped') || \
(${{ needs.test_linux.result }} != 'success' && ${{ needs.test_linux.result }} != 'skipped') || \
if [[ (${{ needs.test_linux.result }} != 'success' && ${{ needs.test_linux.result }} != 'skipped') || \
(${{ needs.test_mac.result }} != 'success' && ${{ needs.test_mac.result }} != 'skipped') || \
(${{ needs.codeql.result }} != 'success' && ${{ needs.codeql.result }} != 'skipped') || \
(${{ needs.bundle_size.result }} != 'success' && ${{ needs.bundle_size.result }} != 'skipped') ]]; then
(${{ needs.codeql.result }} != 'success' && ${{ needs.codeql.result }} != 'skipped') ]]; then
echo "One or more CI jobs failed."
exit 1
fi
+67 -77
View File
@@ -1,56 +1,32 @@
name: 'Testing: E2E'
on:
push:
branches:
- 'main'
# This will run for PRs from the base repository, providing secrets.
pull_request:
branches:
- 'main'
- 'release/**'
# This will run for PRs from forks when a label is added.
pull_request_target:
types: ['labeled']
merge_group:
workflow_dispatch:
workflow_call:
inputs:
branch_ref:
description: 'Branch to run on'
version:
description: 'The version of the published package'
required: true
default: 'main'
type: 'string'
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: |-
${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/') }}
cli-package-name:
description: 'The name of the CLI package to install'
required: true
type: 'string'
image-uri:
description: 'The URI of the built sandbox image.'
required: true
type: 'string'
secrets:
GEMINI_API_KEY:
required: true
jobs:
merge_queue_skipper:
name: 'Merge Queue Skipper'
runs-on: 'gemini-cli-ubuntu-16-core'
permissions: 'read-all'
outputs:
skip: '${{ steps.merge-queue-e2e-skipper.outputs.skip-check }}'
steps:
- id: 'merge-queue-e2e-skipper'
uses: 'cariad-tech/merge-queue-ci-skipper@1032489e59437862c90a08a2c92809c903883772' # ratchet:cariad-tech/merge-queue-ci-skipper@main
with:
secret: '${{ secrets.GITHUB_TOKEN }}'
continue-on-error: true
e2e_linux:
name: 'E2E Test (Linux) - ${{ matrix.sandbox }}'
needs: 'merge_queue_skipper'
if: |
(needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip == 'false') &&
(github.event_name == 'push' ||
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'
github.event.pull_request.head.repo.full_name == github.repository ||
github.event.label.name == 'maintainer:e2e:ok'
runs-on: 'ubuntu-latest'
strategy:
fail-fast: false
matrix:
@@ -59,7 +35,6 @@ jobs:
- 'sandbox:docker'
node-version:
- '20.x'
steps:
- name: 'Checkout (fork)'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v5
@@ -74,26 +49,34 @@ jobs:
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
- name: 'Setup NPMRC'
uses: './.github/actions/setup-npmrc'
with:
node-version: '${{ matrix.node-version }}'
github-token: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
with:
registry: 'ghcr.io'
username: '${{ github.repository_owner }}'
password: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Pull sandbox image'
run: 'docker pull ${{ inputs.image-uri }}'
- 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
env:
CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
VERSION: '${{ inputs.version }}'
run: 'npm install ${{ env.CLI_PACKAGE_NAME }}@${{ env.VERSION }}'
- name: 'Run E2E tests'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
KEEP_OUTPUT: 'true'
VERBOSE: 'true'
INTEGRATION_TEST_USE_INSTALLED_GEMINI: 'true'
GEMINI_SANDBOX_IMAGE: '${{ inputs.image-uri }}'
shell: 'bash'
run: |
if [[ "${{ matrix.sandbox }}" == "sandbox:docker" ]]; then
@@ -104,14 +87,12 @@ jobs:
e2e_mac:
name: 'E2E Test (macOS)'
needs: 'merge_queue_skipper'
if: |
(needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip == 'false') &&
(github.event_name == 'push' ||
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'))
github.event.pull_request.head.repo.full_name == github.repository ||
github.event.label.name == 'maintainer:e2e:ok'
runs-on: 'macos-latest'
steps:
- name: 'Checkout (fork)'
@@ -132,11 +113,16 @@ jobs:
with:
node-version: '20.x'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Setup NPMRC'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies'
env:
CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
VERSION: '${{ inputs.version }}'
run: 'npm install ${{ env.CLI_PACKAGE_NAME }}@${{ env.VERSION }}'
- name: 'Fix rollup optional dependencies on macOS'
if: "runner.os == 'macOS'"
@@ -149,19 +135,18 @@ jobs:
KEEP_OUTPUT: 'true'
SANDBOX: 'sandbox:none'
VERBOSE: 'true'
INTEGRATION_TEST_USE_INSTALLED_GEMINI: 'true'
run: 'npm run test:integration:sandbox:none'
e2e_windows:
name: 'Slow E2E - Win'
needs: 'merge_queue_skipper'
if: |
(needs.merge_queue_skipper.result !='success' || needs.merge_queue_skipper.outputs.skip == 'false') &&
(github.event_name == 'push' ||
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'
github.event.pull_request.head.repo.full_name == github.repository ||
github.event.label.name == 'maintainer:e2e:ok'
runs-on: 'windows-latest'
continue-on-error: true
steps:
@@ -202,12 +187,16 @@ jobs:
npm config set registry https://registry.npmjs.org/
shell: 'pwsh'
- name: 'Install dependencies'
run: 'npm ci'
shell: 'pwsh'
- name: 'Setup NPMRC'
uses: './.github/actions/setup-npmrc'
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
- name: 'Build project'
run: 'npm run build'
- name: 'Install dependencies'
env:
CLI_PACKAGE_NAME: '${{ inputs.cli-package-name }}'
VERSION: '${{ inputs.version }}'
run: 'npm install ${{ env.CLI_PACKAGE_NAME }}@${{ env.VERSION }}'
shell: 'pwsh'
- name: 'Run E2E tests'
@@ -219,6 +208,7 @@ jobs:
NODE_OPTIONS: '--max-old-space-size=32768 --max-semi-space-size=256'
UV_THREADPOOL_SIZE: '32'
NODE_ENV: 'test'
INTEGRATION_TEST_USE_INSTALLED_GEMINI: 'true'
shell: 'pwsh'
run: 'npm run test:integration:sandbox:none'
@@ -229,13 +219,13 @@ jobs:
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')
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'
runs-on: 'ubuntu-latest'
steps:
- name: 'Check E2E test results'
run: |
+30
View File
@@ -0,0 +1,30 @@
# .github/workflows/lint.yml
name: 'Linting'
on:
workflow_call:
permissions:
contents: 'read'
jobs:
lint:
name: 'Lint All'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
fetch-depth: 0
- name: 'Set up 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 --only=dev'
- name: 'Run linting'
run: 'npm run lint:all'
+91
View File
@@ -0,0 +1,91 @@
# .github/workflows/pr-checks.yml
name: 'Checks'
on:
pull_request:
branches:
- 'main'
- 'release/**'
merge_group:
concurrency:
group: '${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}'
cancel-in-progress: true
env:
CLI_PACKAGE_NAME: '@google/gemini-cli'
permissions:
contents: 'read'
packages: 'write'
pull-requests: 'write'
security-events: 'write'
checks: 'write'
statuses: 'write'
actions: 'read'
attestations: 'read'
deployments: 'read'
discussions: 'read'
issues: 'read'
pages: 'read'
repository-projects: 'read'
id-token: 'write'
jobs:
lint:
name: 'Lint'
uses: './.github/workflows/lint.yml'
get-vars:
name: 'Get Environment Variables'
runs-on: 'ubuntu-latest'
environment: 'dev'
outputs:
cli-package-name: '${{ steps.get-vars.outputs.cli-package-name }}'
npm-registry-scope: '${{ steps.get-vars.outputs.npm-registry-scope }}'
npm-registry-url: '${{ steps.get-vars.outputs.npm-registry-url }}'
steps:
- id: 'get-vars'
env:
CLI_PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
NPM_REGISTRY_SCOPE: '${{ vars.NPM_REGISTRY_SCOPE }}'
NPM_REGISTRY_URL: '${{ vars.NPM_REGISTRY_URL }}'
run: |
echo "cli-package-name=${CLI_PACKAGE_NAME}" >> "$GITHUB_OUTPUT"
echo "npm-registry-scope=${NPM_REGISTRY_SCOPE}" >> "$GITHUB_OUTPUT"
echo "npm-registry-url=${NPM_REGISTRY_URL}" >> "$GITHUB_OUTPUT"
build-and-publish:
name: 'Build and Publish CI Bundle'
needs: ['lint', 'get-vars']
uses: './.github/workflows/build-and-publish.yml'
with:
cli-package-name: '${{ needs.get-vars.outputs.cli-package-name }}'
npm-registry-scope: '${{ needs.get-vars.outputs.npm-registry-scope }}'
npm-registry-url: '${{ needs.get-vars.outputs.npm-registry-url }}'
ci:
name: 'CI Checks'
needs: 'lint'
uses: './.github/workflows/ci.yml'
e2e:
name: 'E2E Checks'
needs: ['build-and-publish', 'get-vars']
uses: './.github/workflows/e2e.yml'
permissions:
contents: 'read'
packages: 'read'
with:
version: '${{ needs.build-and-publish.outputs.version }}'
cli-package-name: '${{ needs.get-vars.outputs.cli-package-name }}'
image-uri: '${{ needs.build-and-publish.outputs.image-uri }}'
secrets:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
bundle-size:
name: 'Bundle Size Check'
needs: 'build-and-publish'
uses: './.github/workflows/bundle-size.yml'
with:
version: '${{ needs.build-and-publish.outputs.version }}'
@@ -0,0 +1,144 @@
name: 'Release: Manual (Bundled)'
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:
- 'dev'
- 'preview'
- 'nightly'
- 'latest'
default: 'latest'
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 (only used when environment is PROD)'
required: false
type: 'boolean'
default: false
environment:
description: 'Environment'
required: false
type: 'choice'
options:
- 'prod'
- 'dev'
default: 'prod'
jobs:
release:
runs-on: 'ubuntu-latest'
environment: "${{ github.event.inputs.environment || 'prod' }}"
permissions:
contents: 'write'
packages: 'write'
issues: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
fetch-depth: 0
- name: 'Checkout Release Code'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
ref: '${{ github.event.inputs.ref }}'
path: 'release'
fetch-depth: 0
- name: 'Debug Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
node-version-file: './release/.nvmrc'
cache: 'npm'
- name: 'Install Dependencies'
working-directory: './release'
run: 'npm ci'
- name: 'Prepare Release Info'
id: 'release_info'
working-directory: './release'
env:
INPUT_VERSION: '${{ github.event.inputs.version }}'
run: |
RELEASE_VERSION="${INPUT_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 }}'
working-directory: './release'
- name: 'Publish Bundle'
uses: './.github/actions/publish-bundle'
with:
version: '${{ steps.release_info.outputs.RELEASE_VERSION }}'
tag: '${{ github.event.inputs.npm_channel }}'
github-token: '${{ secrets.GITHUB_TOKEN }}'
package-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
- name: '🔬 Verify Bundled NPM release by version'
if: '${{ github.event.inputs.dry_run == false && github.event.inputs.force_skip_tests == false }}'
working-directory: './release'
shell: 'bash'
env:
CLI_PACKAGE_NAME: '${{ vars.CLI_PACKAGE_NAME }}'
RELEASE_VERSION: '${{ steps.release_info.outputs.RELEASE_VERSION }}'
run: |
npx -y "${CLI_PACKAGE_NAME}"@"${RELEASE_VERSION}" --version
- name: '🎉 Create GitHub Release'
working-directory: './release'
if: "${{ github.event.inputs.dry_run == false && github.event.inputs.skip_github_release == false && github.event.inputs.npm_channel != 'dev' && vars.NPM_REGISTRY_URL != 'https://npm.pkg.github.com/' }}"
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
RELEASE_TAG: '${{ github.event.inputs.version }}'
PREVIOUS_TAG: '${{ steps.release_info.outputs.PREVIOUS_TAG }}'
run: |
gh release create "${RELEASE_TAG}" \
bundle/gemini.js \
--title "Release ${RELEASE_TAG}" \
--notes-start-tag "${PREVIOUS_TAG}" \
--generate-notes
- name: 'Create Issue on Failure'
if: '${{ failure() && github.event.inputs.dry_run == false }}'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
RELEASE_TAG: '${{ github.event.inputs.version }}'
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
run: |
gh issue create \
--title 'Manual Release Failed for ${RELEASE_TAG} on $(date +'%Y-%m-%d')' \
--body 'The manual release workflow failed. See the full run for details: ${DETAILS_URL}' \
--label 'kind/bug,release-failure,priority/p0'
+2 -2
View File
@@ -1,4 +1,4 @@
name: 'Release: Manual'
name: 'Release: Manual (Depreciated)'
on:
workflow_dispatch:
@@ -100,7 +100,7 @@ jobs:
working-directory: './release'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
uses: './.github/actions/publish-release-deprecated'
with:
force-skip-tests: '${{ github.event.inputs.force_skip_tests }}'
release-version: '${{ steps.release_info.outputs.RELEASE_VERSION }}'
+2 -2
View File
@@ -227,7 +227,7 @@ jobs:
run: 'npm ci'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
uses: './.github/actions/publish-release-deprecated'
with:
release-version: '${{ needs.calculate-versions.outputs.PREVIEW_VERSION }}'
release-tag: 'v${{ needs.calculate-versions.outputs.PREVIEW_VERSION }}'
@@ -293,7 +293,7 @@ jobs:
run: 'npm ci'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
uses: './.github/actions/publish-release-deprecated'
with:
release-version: '${{ needs.calculate-versions.outputs.STABLE_VERSION }}'
release-tag: 'v${{ needs.calculate-versions.outputs.STABLE_VERSION }}'
-49
View File
@@ -1,49 +0,0 @@
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'
permissions:
contents: 'read'
packages: 'write'
issues: 'write'
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:
dockerhub-username: '${{ secrets.DOCKER_SERVICE_ACCOUNT_NAME }}'
dockerhub-token: '${{ secrets.DOCKER_SERVICE_ACCOUNT_KEY }}'
github-actor: '${{ github.actor }}'
github-secret: '${{ secrets.GITHUB_TOKEN }}'
github-sha: '${{ github.sha }}'
github-ref-name: '${{github.event.inputs.ref}}'
dry-run: '${{ github.event.inputs.dry-run }}'
- name: 'Create Issue on Failure'
if: '${{ failure() && github.event.inputs.dry-run == false }}'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
DETAILS_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
run: |
gh issue create \
--title 'Sandbox Release Failed on $(date +'%Y-%m-%d')' \
--body 'The sandbox-release workflow failed. See the full run for details: ${DETAILS_URL}' \
--label 'kind/bug,release-failure,priority/p0'
+2
View File
@@ -55,4 +55,6 @@ gha-creds-*.json
# Log files
patch_output.log
# Local npm configuration
.npmrc
.genkit
-1
View File
@@ -1 +0,0 @@
@google:registry=https://wombat-dressing-room.appspot.com
+39 -1
View File
@@ -304,7 +304,45 @@ npm run lint
- **Imports:** Pay special attention to import paths. The project uses ESLint to
enforce restrictions on relative imports between packages.
### Project structure
### Setting Up Your NPM Environment
**Note:** The following instructions are intended for contributors who need to
work with pre-release versions hosted on the private GitHub Packages registry.
General contributors who only use the public `npmjs.org` registry may not need
to perform this setup.
This project uses a hybrid registry model:
- Production packages (e.g., `@google/gemini-cli`) are published to `npmjs.org`.
- Pre-release and development packages (e.g., `@google-gemini/gemini-cli`) are
published to **GitHub Packages**.
To work with both registries, you need to configure your user-level `~/.npmrc`
file to authenticate with GitHub Packages. We have a script to automate this.
#### Configure Your `~/.npmrc` File
Run the following command to automatically configure your `~/.npmrc` file:
```bash
npm run setup-npmrc
```
This command will:
1. Check that you have the [GitHub CLI (`gh`)](https://cli.github.com/)
installed and that you are logged in.
2. **Back up** your existing `~/.npmrc` to `~/.npmrc.bak` if a backup doesn't
already exist.
3. **Overwrite** your `~/.npmrc` with the correct configuration to pull
packages from both `npmjs.org` and `npm.pkg.github.com` based on their
scope.
After running this, you can install packages from both registries without any
further configuration. If your GitHub token expires, you can simply run the
command again to update it.
### Project Structure
- `packages/`: Contains the individual sub-packages of the project.
- `a2a-server`: A2A server implementation for the Gemini CLI. (Experimental)
+34 -14
View File
@@ -1,11 +1,38 @@
# --- Builder Stage ---
FROM docker.io/library/node:20-slim AS builder
ARG CLI_VERSION
ARG NPM_REGISTRY_SCOPE
ARG NPM_REGISTRY_URL
ARG CLI_PACKAGE_NAME
# Set up npm global package folder
ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global
ENV PATH=$PATH:/usr/local/share/npm-global/bin
# Ensure the node user has permissions to write to the global npm directory
RUN mkdir -p /usr/local/share/npm-global && chown -R node:node /usr/local/share/npm-global
# Configure npm to use GitHub Packages
RUN --mount=type=secret,id=GITHUB_TOKEN \
echo "${NPM_REGISTRY_SCOPE}:registry=${NPM_REGISTRY_URL}" > /home/node/.npmrc && \
echo "//npm.pkg.github.com/:_authToken=$(cat /run/secrets/GITHUB_TOKEN)" >> /home/node/.npmrc && \
chown -R node:node /home/node/.npmrc
# Switch to non-root user
USER node
# Install the Gemini CLI package
RUN npm install -g ${CLI_PACKAGE_NAME}@${CLI_VERSION} && \
npm cache clean --force
# --- Final Stage ---
FROM docker.io/library/node:20-slim
ARG SANDBOX_NAME="gemini-cli-sandbox"
ARG CLI_VERSION_ARG
ENV SANDBOX="$SANDBOX_NAME"
ENV CLI_VERSION=$CLI_VERSION_ARG
# install minimal set of packages, then clean up
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
make \
@@ -29,22 +56,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# set up npm global package folder under /usr/local/share
# give it to non-root user node, already set up in base image
# Set up npm global package folder and user
RUN mkdir -p /usr/local/share/npm-global \
&& chown -R node:node /usr/local/share/npm-global
ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global
ENV PATH=$PATH:/usr/local/share/npm-global/bin
# switch to non-root user node
USER node
# install gemini-cli and clean up
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 /tmp/gemini-{cli,core}.tgz
# Copy installed package from the builder stage
COPY --from=builder /usr/local/share/npm-global /usr/local/share/npm-global
# default entrypoint when none specified
# Default entrypoint
CMD ["gemini"]
+1
View File
@@ -8,6 +8,7 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
setupFiles: ['./vitest.setup.ts'],
testTimeout: 300000, // 5 minutes
globalSetup: './globalSetup.ts',
reporters: ['default'],
+58
View File
@@ -0,0 +1,58 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { vi } from 'vitest';
// Mock the ClearcutLogger module to prevent E2E tests from failing due to a missing generated file.
// The ClearcutLogger (which imports git-commit.js) is not needed for E2E test validation,
// as tests rely on the OpenTelemetry logger which writes to telemetry.log.
vi.mock(
(await import('node:path')).resolve(
process.cwd(),
'packages/core/src/telemetry/clearcut-logger/clearcut-logger.js',
),
() => ({
ClearcutLogger: {
getInstance: vi.fn(() => ({
logStartSessionEvent: vi.fn(),
logNewPromptEvent: vi.fn(),
logToolCallEvent: vi.fn(),
logToolOutputTruncatedEvent: vi.fn(),
logFileOperationEvent: vi.fn(),
logApiRequestEvent: vi.fn(),
logApiResponseEvent: vi.fn(),
logApiErrorEvent: vi.fn(),
logChatCompressionEvent: vi.fn(),
logFlashFallbackEvent: vi.fn(),
logRipgrepFallbackEvent: vi.fn(),
logLoopDetectedEvent: vi.fn(),
logLoopDetectionDisabledEvent: vi.fn(),
logNextSpeakerCheck: vi.fn(),
logSlashCommandEvent: vi.fn(),
logMalformedJsonResponseEvent: vi.fn(),
logIdeConnectionEvent: vi.fn(),
logConversationFinishedEvent: vi.fn(),
logKittySequenceOverflowEvent: vi.fn(),
logInvalidChunkEvent: vi.fn(),
logContentRetryEvent: vi.fn(),
logContentRetryFailureEvent: vi.fn(),
logModelRoutingEvent: vi.fn(),
logExtensionInstallEvent: vi.fn(),
logExtensionUninstallEvent: vi.fn(),
logExtensionUpdateEvent: vi.fn(),
logExtensionEnableEvent: vi.fn(),
logExtensionDisableEvent: vi.fn(),
logSmartEditStrategyEvent: vi.fn(),
logSmartEditCorrectionEvent: vi.fn(),
logAgentStartEvent: vi.fn(),
logAgentFinishEvent: vi.fn(),
logWebFetchFallbackAttemptEvent: vi.fn(),
logEndSessionEvent: vi.fn(),
})),
clearInstance: vi.fn(),
},
}),
);
+25
View File
@@ -5376,6 +5376,15 @@
"node": ">= 0.6"
}
},
"node_modules/accepts/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/accepts/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
@@ -8655,6 +8664,13 @@
"ms": "2.0.0"
}
},
"node_modules/express/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT",
"peer": true
},
"node_modules/express/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -16214,6 +16230,15 @@
"node": ">= 0.6"
}
},
"node_modules/type-is/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/type-is/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+15 -7
View File
@@ -8,7 +8,6 @@
"workspaces": [
"packages/*"
],
"private": "true",
"repository": {
"type": "git",
"url": "git+https://github.com/google-gemini/gemini-cli.git"
@@ -34,18 +33,26 @@
"build:packages": "npm run build --workspaces",
"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",
"test:ci": "npm run test:ci --workspaces --if-present && npm run test:scripts",
"test": "npm run test --workspaces --if-present --parallel",
"test:ci": "npm run build && npm run test:ci --workspaces --if-present --parallel && npm run test:scripts",
"test:scripts": "vitest run --config ./scripts/tests/vitest.config.ts",
"test:e2e": "cross-env VERBOSE=true KEEP_OUTPUT=true npm run test:integration:sandbox:none",
"test:integration:all": "npm run test:integration:sandbox:none && npm run test:integration:sandbox:docker && npm run test:integration:sandbox:podman",
"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:docker": "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": "node scripts/lint.js --eslint",
"lint:eslint": "node scripts/lint.js --eslint",
"lint:actionlint": "node scripts/lint.js --actionlint",
"lint:shellcheck": "node scripts/lint.js --shellcheck",
"lint:yamllint": "node scripts/lint.js --yamllint",
"lint:prettier": "node scripts/lint.js --prettier",
"lint:sensitive-keywords": "node scripts/lint.js --sensitive-keywords",
"lint:tsconfig": "node scripts/lint.js --tsconfig",
"lint:setup": "node scripts/lint.js --setup",
"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",
"lint:all": "npm run lint:setup && npm-run-all --parallel lint:eslint lint:actionlint lint:shellcheck lint:yamllint lint:prettier lint:sensitive-keywords lint:tsconfig",
"format": "prettier --experimental-cli --write .",
"typecheck": "npm run typecheck --workspaces --if-present",
"preflight": "npm run clean && npm ci && npm run format && npm run lint:ci && npm run build && npm run typecheck && npm run test:ci",
@@ -55,7 +62,8 @@
"telemetry": "node scripts/telemetry.js",
"check:lockfile": "node scripts/check-lockfile.js",
"clean": "node scripts/clean.js",
"pre-commit": "node scripts/pre-commit.js"
"pre-commit": "node scripts/pre-commit.js",
"setup-npmrc": "node scripts/configure-registry.js"
},
"overrides": {
"wrap-ansi": "9.0.2",
+1 -1
View File
@@ -17,7 +17,7 @@
"debug": "node --inspect-brk dist/index.js",
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write .",
"test": "vitest run",
"test": "vitest run -- ",
"test:ci": "vitest run",
"typecheck": "tsc --noEmit"
},
+115
View File
@@ -0,0 +1,115 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview This script automates the configuration of the user's
* global .npmrc file to work with this repository's development workflow.
*
* Rationale:
* This project uses a hybrid registry setup:
* - Production packages (`@google/gemini-cli`) are on the public npmjs.org registry.
* - Pre-release packages (`@google-gemini/gemini-cli`) are on the GitHub Packages registry.
*
* This script provides a consistent, automated, and less error-prone way to
* configure the necessary scopes and authentication for both registries. It
* backs up the user's existing .npmrc, making it a safe, one-time setup.
*/
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { execSync } from 'node:child_process';
const homedir = os.homedir();
const npmrcPath = path.join(homedir, '.npmrc');
const backupPath = path.join(homedir, '.npmrc.bak');
const GITHUB_REGISTRY_URL = 'https://npm.pkg.github.com/';
const GITHUB_SCOPE = '@google-gemini';
const PROD_SCOPE = '@google';
const PROD_REGISTRY_URL = 'https://registry.npmjs.org/';
function checkGhCli() {
try {
execSync('gh --version', { stdio: 'ignore' });
return true;
} catch (_e) {
console.error(
'Error: The GitHub CLI (`gh`) is not installed or not in your PATH.',
);
console.error('Please install it to continue: https://cli.github.com/');
return false;
}
}
function getGhAuthStatus() {
try {
execSync('gh auth status', { stdio: 'ignore' });
return true;
} catch (_e) {
console.error('Error: You are not logged in to the GitHub CLI (`gh`).');
console.error(
"Please run `gh auth login` and ensure you grant the 'read:packages' and 'write:packages' scopes.",
);
return false;
}
}
function getGhAuthToken() {
try {
const token = execSync('gh auth token', {
encoding: 'utf8',
}).trim();
if (!token) {
throw new Error('No token returned from `gh auth token`');
}
return token;
} catch (_e) {
console.error('Error: Failed to retrieve GitHub auth token.');
console.error(
'Please ensure you are logged in (`gh auth status`) and have the correct permissions.',
);
return null;
}
}
function setupNpmrc() {
console.log('Configuring your global ~/.npmrc for development...');
if (!checkGhCli() || !getGhAuthStatus()) {
process.exit(1);
}
const token = getGhAuthToken();
if (!token) {
process.exit(1);
}
// Back up the original .npmrc if it exists and a backup doesn't already.
if (fs.existsSync(npmrcPath) && !fs.existsSync(backupPath)) {
fs.copyFileSync(npmrcPath, backupPath);
console.log(`Backed up your existing configuration to ${backupPath}`);
}
const newContent = [
`# Added by gemini-cli setup`,
`# Configures scopes for both production and development registries`,
``,
`# Production packages from npmjs.org`,
`${PROD_SCOPE}:registry=${PROD_REGISTRY_URL}`,
``,
`# Pre-release packages from GitHub Packages`,
`${GITHUB_SCOPE}:registry=${GITHUB_REGISTRY_URL}`,
`//${new URL(GITHUB_REGISTRY_URL).hostname}/:_authToken=${token}`,
``,
].join('\n');
fs.writeFileSync(npmrcPath, newContent);
console.log(`✅ Successfully configured your ~/.npmrc file.`);
console.log('You can now install both production and pre-release packages.');
}
setupNpmrc();
+5 -1
View File
@@ -147,7 +147,11 @@ export function setupLinters() {
export function runESLint() {
console.log('\nRunning ESLint...');
if (!runCommand('npm run lint')) {
if (
!runCommand(
'eslint . --ext .ts,.tsx && eslint integration-tests && eslint scripts',
)
) {
process.exit(1);
}
}
-68
View File
@@ -1,68 +0,0 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import fs from 'node:fs';
import path from 'node:path';
const rootDir = process.cwd();
function updatePackageJson(packagePath, updateFn) {
const packageJsonPath = path.resolve(rootDir, packagePath);
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
updateFn(packageJson);
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
}
// Copy bundle directory into packages/cli
const sourceBundleDir = path.resolve(rootDir, 'bundle');
const destBundleDir = path.resolve(rootDir, 'packages/cli/bundle');
if (fs.existsSync(sourceBundleDir)) {
fs.rmSync(destBundleDir, { recursive: true, force: true });
fs.cpSync(sourceBundleDir, destBundleDir, { recursive: true });
console.log('Copied bundle/ directory to packages/cli/');
} else {
console.error(
'Error: bundle/ directory not found at project root. Please run `npm run bundle` first.',
);
process.exit(1);
}
// Overwrite the .npmrc in the core package to point to the GitHub registry.
const coreNpmrcPath = path.resolve(rootDir, 'packages/core/.npmrc');
fs.writeFileSync(
coreNpmrcPath,
'@google-gemini:registry=https://npm.pkg.github.com/',
);
console.log('Wrote .npmrc for @google-gemini scope to packages/core/');
// Update @google/gemini-cli
updatePackageJson('packages/cli/package.json', (pkg) => {
pkg.name = '@google-gemini/gemini-cli';
pkg.files = ['bundle/'];
pkg.bin = {
gemini: 'bundle/gemini.js',
};
// Remove fields that are not relevant to the bundled package.
delete pkg.dependencies;
delete pkg.devDependencies;
delete pkg.scripts;
delete pkg.main;
delete pkg.config; // Deletes the sandboxImageUri
});
// Update @google/gemini-cli-a2a-server
updatePackageJson('packages/a2a-server/package.json', (pkg) => {
pkg.name = '@google-gemini/gemini-cli-a2a-server';
});
// Update @google/gemini-cli-core
updatePackageJson('packages/core/package.json', (pkg) => {
pkg.name = '@google-gemini/gemini-cli-core';
});
console.log('Successfully prepared packages for GitHub release.');
+45 -34
View File
@@ -6,46 +6,57 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
// ES module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootDir = process.cwd();
const rootDir = path.resolve(__dirname, '..');
function copyFiles(packageName, filesToCopy) {
const packageDir = path.resolve(rootDir, 'packages', packageName);
if (!fs.existsSync(packageDir)) {
console.error(`Error: Package directory not found at ${packageDir}`);
process.exit(1);
}
console.log(`Preparing package: ${packageName}`);
for (const [source, dest] of Object.entries(filesToCopy)) {
const sourcePath = path.resolve(rootDir, source);
const destPath = path.resolve(packageDir, dest);
try {
fs.copyFileSync(sourcePath, destPath);
console.log(`Copied ${source} to packages/${packageName}/`);
} catch (err) {
console.error(`Error copying ${source}:`, err);
process.exit(1);
}
function getArg(name) {
const arg = process.argv.find((arg) => arg.startsWith(name));
if (!arg) {
return null;
}
return arg.split('=')[1];
}
// Prepare 'core' package
copyFiles('core', {
'README.md': 'README.md',
LICENSE: 'LICENSE',
'.npmrc': '.npmrc',
function updatePackageJson(packagePath, updateFn) {
const packageJsonPath = path.resolve(rootDir, packagePath);
if (!fs.existsSync(packageJsonPath)) {
console.error(`Error: package.json not found at ${packageJsonPath}`);
process.exit(1);
}
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
updateFn(packageJson);
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
console.log(`Updated ${packagePath}`);
}
const scope = getArg('--scope');
if (!scope) {
console.error('Error: --scope argument is required.');
process.exit(1);
}
console.log(`Preparing packages with scope: ${scope}...`);
// Update root package.json
updatePackageJson('package.json', (pkg) => {
pkg.name = `${scope}/gemini-cli`;
});
// Prepare 'cli' package
copyFiles('cli', {
'README.md': 'README.md',
LICENSE: 'LICENSE',
// Update @google/gemini-cli-a2a-server
updatePackageJson('packages/a2a-server/package.json', (pkg) => {
pkg.name = `${scope}/gemini-cli-a2a-server`;
});
console.log('Successfully prepared all packages.');
// Update @google/gemini-cli-core
updatePackageJson('packages/core/package.json', (pkg) => {
pkg.name = `${scope}/gemini-cli-core`;
});
// Update @google/gemini-cli
updatePackageJson('packages/cli/package.json', (pkg) => {
pkg.name = `${scope}/gemini-cli`;
pkg.dependencies['@google/gemini-cli-core'] =
`npm:${scope}/gemini-cli-core@^0.0.0`;
});
console.log('Successfully prepared packages.');