From 7ad65566236dd0eb81e49f0611ecafde2ebcd63d Mon Sep 17 00:00:00 2001 From: Brandon Keiji Date: Mon, 28 Apr 2025 20:25:19 +0000 Subject: [PATCH] feat: publish docker image alongside npm package (#197) --- .gcp/Dockerfile.gemini-code-builder | 90 +++++++++++++++++++ .gcp/dogfood.yaml | 29 ++---- .gcp/publish-dry-run.yaml | 29 ++---- package-lock.json | 6 +- packages/cli/.npmrc | 2 + .../cli/{Dockerfile => Dockerfile.sandbox} | 9 +- packages/cli/package.json | 14 +-- packages/server/package.json | 2 +- 8 files changed, 127 insertions(+), 54 deletions(-) create mode 100644 .gcp/Dockerfile.gemini-code-builder create mode 100644 packages/cli/.npmrc rename packages/cli/{Dockerfile => Dockerfile.sandbox} (78%) diff --git a/.gcp/Dockerfile.gemini-code-builder b/.gcp/Dockerfile.gemini-code-builder new file mode 100644 index 00000000..f8ef6dfa --- /dev/null +++ b/.gcp/Dockerfile.gemini-code-builder @@ -0,0 +1,90 @@ +# Use a common base image like Debian. +# Using 'bookworm-slim' for a balance of size and compatibility. +FROM debian:bookworm-slim + +# Set environment variables to prevent interactive prompts during installation +ENV DEBIAN_FRONTEND=noninteractive +ENV NODE_VERSION=20.12.2 +ENV NODE_VERSION_MAJOR=20 +ENV DOCKER_CLI_VERSION=26.1.3 +ENV BUILDX_VERSION=v0.14.0 + + +# Install dependencies for adding NodeSource repository, gcloud, and other tools +# - curl: for downloading files +# - gnupg: for managing GPG keys (used by NodeSource & Google Cloud SDK) +# - apt-transport-https: for HTTPS apt repositories +# - ca-certificates: for HTTPS apt repositories +# - rsync: the rsync utility itself +# - git: often useful in build environments +# - python3, python3-pip, python3-venv, python3-crcmod: for gcloud SDK and some of its components +# - lsb-release: for gcloud install script to identify distribution +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + gnupg \ + apt-transport-https \ + ca-certificates \ + rsync \ + git \ + python3 \ + python3-pip \ + python3-venv \ + python3-crcmod \ + lsb-release \ + && rm -rf /var/lib/apt/lists/* + +# Install Node.js and npm +# We'll use the official NodeSource repository for a specific version +RUN set -eux; \ + curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ + # For Node.js 20.x, it's node_20.x + # Let's explicitly define the major version for clarity + echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends nodejs && \ + npm install -g npm@latest && \ + # Verify installations + node -v && \ + npm -v && \ + rm -rf /var/lib/apt/lists/* + +# Install Docker CLI +# Download the static binary from Docker's official source +RUN set -eux; \ + DOCKER_CLI_ARCH=$(dpkg --print-architecture); \ + case "${DOCKER_CLI_ARCH}" in \ + amd64) DOCKER_CLI_ARCH_SUFFIX="x86_64" ;; \ + arm64) DOCKER_CLI_ARCH_SUFFIX="aarch64" ;; \ + *) echo "Unsupported architecture: ${DOCKER_CLI_ARCH}"; exit 1 ;; \ + esac; \ + curl -fsSL "https://download.docker.com/linux/static/stable/${DOCKER_CLI_ARCH_SUFFIX}/docker-${DOCKER_CLI_VERSION}.tgz" -o docker.tgz && \ + tar -xzf docker.tgz --strip-components=1 -C /usr/local/bin docker/docker && \ + rm docker.tgz && \ + # Verify installation + docker --version + +# Install Docker Buildx plugin +RUN set -eux; \ + BUILDX_ARCH_DEB=$(dpkg --print-architecture); \ + case "${BUILDX_ARCH_DEB}" in \ + amd64) BUILDX_ARCH_SUFFIX="amd64" ;; \ + arm64) BUILDX_ARCH_SUFFIX="arm64" ;; \ + *) echo "Unsupported architecture for Buildx: ${BUILDX_ARCH_DEB}"; exit 1 ;; \ + esac; \ + mkdir -p /usr/local/lib/docker/cli-plugins && \ + curl -fsSL "https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-${BUILDX_ARCH_SUFFIX}" -o /usr/local/lib/docker/cli-plugins/docker-buildx && \ + chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx && \ + # verify installation + docker buildx version + +# Install Google Cloud SDK (gcloud CLI) +RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg && apt-get update -y && apt-get install google-cloud-cli -y + +# Set a working directory (optional, but good practice) +WORKDIR /workspace + +# You can add a CMD or ENTRYPOINT if you intend to run this image directly, +# but for Cloud Build, it's usually not necessary as Cloud Build steps override it. +# For example: +ENTRYPOINT '/bin/bash' \ No newline at end of file diff --git a/.gcp/dogfood.yaml b/.gcp/dogfood.yaml index 5fd3fbdd..7d8842eb 100644 --- a/.gcp/dogfood.yaml +++ b/.gcp/dogfood.yaml @@ -1,11 +1,13 @@ steps: - # Install dependencies - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' args: ['install'] - # Run prerelease versioning script across workspaces with dynamic version - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' + entrypoint: 'npm' + args: ['run', 'auth'] + + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' args: [ @@ -16,26 +18,13 @@ steps: '--suffix="$SHORT_SHA.$_REVISION"', ] - # Run prerelease dependency script across workspaces - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' args: ['run', 'prerelease:deps', '--workspaces'] - # Authenticate with our registry - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' - args: ['run', 'auth:npm'] - - # Publish packages from workspaces with 'dogfood' tag - # we awkwardly need to install rsync beforehand. TODO: use a dedicated dev container - - name: 'node:bookworm' - entrypoint: 'bash' - args: - - '-c' - - | - apt-get update -y - apt-get install -y rsync - npm publish --tag=head --workspaces + args: ['publish', '--tag=head', '--workspace=@gemini-code/cli'] options: defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET diff --git a/.gcp/publish-dry-run.yaml b/.gcp/publish-dry-run.yaml index 7149c4de..1de80952 100644 --- a/.gcp/publish-dry-run.yaml +++ b/.gcp/publish-dry-run.yaml @@ -1,11 +1,13 @@ steps: - # Install dependencies - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' args: ['install'] - # Run prerelease versioning script across workspaces with dynamic version - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' + entrypoint: 'npm' + args: ['run', 'auth'] + + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' args: [ @@ -16,26 +18,13 @@ steps: '--suffix="$SHORT_SHA.$_REVISION"', ] - # Run prerelease dependency script across workspaces - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' args: ['run', 'prerelease:deps', '--workspaces'] - # Authenticate with our registry - - name: 'node:bookworm' + - name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder' entrypoint: 'npm' - args: ['run', 'auth:npm'] - - # Dry run publish to make sure that's not broken - # we awkwardly need to install rsync beforehand. TODO: use a dedicated dev container - - name: 'node:bookworm' - entrypoint: 'bash' - args: - - '-c' - - | - apt-get update -y - apt-get install -y rsync - npm publish --dry-run --tag=head --workspaces + args: ['publish', '--tag=head', '--dry-run', '--workspace=@gemini-code/cli'] options: defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET diff --git a/package-lock.json b/package-lock.json index a5b0c8ae..ae698b10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6836,9 +6836,9 @@ }, "packages/cli": { "name": "@gemini-code/cli", - "version": "0.1.0-dev-62cc889.0", + "version": "0.1.0", "dependencies": { - "@gemini-code/server": "0.1.0-dev-62cc889.0", + "@gemini-code/server": "0.1.0", "diff": "^7.0.0", "dotenv": "^16.4.7", "highlight.js": "^11.11.1", @@ -6871,7 +6871,7 @@ }, "packages/server": { "name": "@gemini-code/server", - "version": "0.1.0-dev-62cc889.0", + "version": "0.1.0", "dependencies": { "@google/genai": "^0.10.0", "diff": "^7.0.0", diff --git a/packages/cli/.npmrc b/packages/cli/.npmrc new file mode 100644 index 00000000..e17bb8be --- /dev/null +++ b/packages/cli/.npmrc @@ -0,0 +1,2 @@ +@gemini-code:registry=https://us-west1-npm.pkg.dev/gemini-code-dev/gemini-code/ +//us-west1-npm.pkg.dev/gemini-code-dev/gemini-code/:always-auth=true \ No newline at end of file diff --git a/packages/cli/Dockerfile b/packages/cli/Dockerfile.sandbox similarity index 78% rename from packages/cli/Dockerfile rename to packages/cli/Dockerfile.sandbox index 9cf4b1b9..1d4c4048 100644 --- a/packages/cli/Dockerfile +++ b/packages/cli/Dockerfile.sandbox @@ -1,7 +1,7 @@ FROM docker.io/library/node:20-slim -ENV GEMINI_CODE_SANDBOX=docker -ENV SANDBOX=sandbox +ARG CLI_VERSION +ENV SANDBOX=${CLI_VERSION} # install minimal set of packages, then clean up RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -22,6 +22,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -RUN --mount=type=secret,id=npmrc,dst=/root/.npmrc npm install -g @gemini-code/cli@head --verbose - -ENTRYPOINT 'gemini-code' \ No newline at end of file +RUN --mount=type=secret,id=npmrc,dst=/root/.npmrc npm install -g @gemini-code/cli@${CLI_VERSION} --verbose +ENTRYPOINT 'gemini-code' diff --git a/packages/cli/package.json b/packages/cli/package.json index 13403ccf..d178e5ef 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@gemini-code/cli", - "version": "0.1.0-dev-62cc889.0", + "version": "0.1.0", "description": "Gemini Code CLI", "type": "module", "main": "dist/index.js", @@ -8,8 +8,12 @@ "gemini-code": "dist/index.js", "gemini-code-sandbox": "bin/sandbox.sh" }, + "image": "us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-cli", "scripts": { + "build:package": "tsc --build", + "build:sandbox": "DOCKER_BUILDKIT=1 docker build --build-arg CLI_VERSION=$npm_package_version --no-cache --secret id=npmrc,src=$HOME/.npmrc -t us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-cli:$npm_package_version -f Dockerfile.sandbox .", "build": "../../scripts/build_package.sh", + "publish:sandbox": "docker push us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-cli:$npm_package_version", "clean": "rm -rf dist", "start": "node dist/index.js", "debug": "node --inspect-brk dist/index.js", @@ -18,15 +22,15 @@ "test": "vitest run", "prerelease:version": "node ../../scripts/bind_package_version.js", "prerelease:deps": "node ../../scripts/bind_package_dependencies.js", - "prerelease:sandbox": "DOCKER_BUILDKIT=1 docker build --no-cache --secret id=npmrc,src=$HOME/.npmrc -t 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code:0.1.0-fakeversion' .", - "prepack": "npm run build", - "xpostpublish": "docker push 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code:0.1.0-fakeversion'" + "prepublishOnly": "npm publish --dry-run --workspace=@gemini-code/server", + "prepack": "npm run build:package", + "postpublish": "npm run build:sandbox && npm run publish:sandbox" }, "files": [ "dist" ], "dependencies": { - "@gemini-code/server": "0.1.0-dev-62cc889.0", + "@gemini-code/server": "0.1.0", "diff": "^7.0.0", "dotenv": "^16.4.7", "highlight.js": "^11.11.1", diff --git a/packages/server/package.json b/packages/server/package.json index df48d612..a4ec126d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@gemini-code/server", - "version": "0.1.0-dev-62cc889.0", + "version": "0.1.0", "description": "Gemini Code Server", "type": "module", "main": "dist/index.js",