feat: publish root Dockerfile to our image registry (#599)
This commit is contained in:
parent
6a1b94529b
commit
dc94a03f39
|
@ -1,8 +1,10 @@
|
||||||
steps:
|
steps:
|
||||||
|
# Step 1: Install root dependencies (includes workspaces)
|
||||||
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
||||||
entrypoint: 'npm'
|
entrypoint: 'npm'
|
||||||
args: ['install']
|
args: ['install']
|
||||||
|
|
||||||
|
# Step 2: Update version with build suffix
|
||||||
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
||||||
entrypoint: 'npm'
|
entrypoint: 'npm'
|
||||||
args:
|
args:
|
||||||
|
@ -14,22 +16,33 @@ steps:
|
||||||
'--suffix="$SHORT_SHA.$_REVISION"',
|
'--suffix="$SHORT_SHA.$_REVISION"',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Step 3: Bind dependencies to the new versions
|
||||||
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
||||||
entrypoint: 'npm'
|
entrypoint: 'npm'
|
||||||
args: ['run', 'prerelease:deps', '--workspaces']
|
args: ['run', 'prerelease:deps', '--workspaces']
|
||||||
|
|
||||||
# A bit of a hack to get the .npmrc into the Dockerfile.sandbox. Should probably streamline this.
|
# Step 4: Authenticate for Docker and NPM
|
||||||
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
|
||||||
entrypoint: 'cp'
|
|
||||||
args: ['/workspace/.npmrc', '/builder/home/.npmrc']
|
|
||||||
|
|
||||||
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
||||||
entrypoint: 'npm'
|
entrypoint: 'npm'
|
||||||
args: ['run', 'auth']
|
args: ['run', 'auth']
|
||||||
|
|
||||||
|
# Step 5: Run the master release script
|
||||||
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
- name: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-builder'
|
||||||
entrypoint: 'npm'
|
entrypoint: 'npm'
|
||||||
args: ['publish', '--tag=head', '--workspace=@gemini-code/cli']
|
args: ['run', 'publish:release']
|
||||||
|
env:
|
||||||
|
- 'GEMINI_SANDBOX=$_CONTAINER_TOOL'
|
||||||
|
- 'SANDBOX_IMAGE_REGISTRY=$_SANDBOX_IMAGE_REGISTRY'
|
||||||
|
- 'SANDBOX_IMAGE_NAME=$_SANDBOX_IMAGE_NAME'
|
||||||
|
- 'NPM_PUBLISH_TAG=$_NPM_PUBLISH_TAG'
|
||||||
|
|
||||||
options:
|
options:
|
||||||
defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET
|
defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET
|
||||||
|
dynamicSubstitutions: true
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
_REVISION: '0'
|
||||||
|
_SANDBOX_IMAGE_REGISTRY: 'us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers'
|
||||||
|
_SANDBOX_IMAGE_NAME: 'gemini-cli-sandbox'
|
||||||
|
_NPM_PUBLISH_TAG: 'head'
|
||||||
|
_CONTAINER_TOOL: 'docker'
|
||||||
|
|
|
@ -36,3 +36,5 @@ COPY packages/server/dist/gemini-code-server-*.tgz /usr/local/share/npm-global/g
|
||||||
RUN npm install -g /usr/local/share/npm-global/gemini-code-cli.tgz /usr/local/share/npm-global/gemini-code-server.tgz \
|
RUN npm install -g /usr/local/share/npm-global/gemini-code-cli.tgz /usr/local/share/npm-global/gemini-code-server.tgz \
|
||||||
&& npm cache clean --force \
|
&& npm cache clean --force \
|
||||||
&& rm -f /usr/local/share/npm-global/gemini-code-{cli,server}.tgz
|
&& rm -f /usr/local/share/npm-global/gemini-code-{cli,server}.tgz
|
||||||
|
|
||||||
|
ENTRYPOINT ["gemini"]
|
||||||
|
|
11
package.json
11
package.json
|
@ -25,7 +25,16 @@
|
||||||
"auth:docker": "gcloud auth configure-docker us-west1-docker.pkg.dev",
|
"auth:docker": "gcloud auth configure-docker us-west1-docker.pkg.dev",
|
||||||
"auth": "npm run auth:npm && npm run auth:docker",
|
"auth": "npm run auth:npm && npm run auth:docker",
|
||||||
"prerelease:dev": "npm run prerelease:version --workspaces && npm run prerelease:deps --workspaces",
|
"prerelease:dev": "npm run prerelease:version --workspaces && npm run prerelease:deps --workspaces",
|
||||||
"bundle": "npm run generate && node_modules/.bin/esbuild packages/cli/index.ts --bundle --outfile=bundle/gemini.js --platform=node --format=esm --banner:js=\"import { createRequire } from 'module'; const require = createRequire(import.meta.url); globalThis.__filename = require('url').fileURLToPath(import.meta.url); globalThis.__dirname = require('path').dirname(globalThis.__filename);\" && bash scripts/copy_bundle_assets.sh"
|
"bundle": "npm run generate && node_modules/.bin/esbuild packages/cli/index.ts --bundle --outfile=bundle/gemini.js --platform=node --format=esm --banner:js=\"import { createRequire } from 'module'; const require = createRequire(import.meta.url); globalThis.__filename = require('url').fileURLToPath(import.meta.url); globalThis.__dirname = require('path').dirname(globalThis.__filename);\" && bash scripts/copy_bundle_assets.sh",
|
||||||
|
"build:cli": "npm run build --workspace packages/cli",
|
||||||
|
"build:server": "npm run build --workspace packages/server",
|
||||||
|
"build:packages": "npm run build:server && npm run build:cli",
|
||||||
|
"build:docker": "scripts/build_sandbox.sh -s",
|
||||||
|
"tag:docker": "docker tag gemini-code-sandbox:latest ${SANDBOX_IMAGE_REGISTRY:?SANDBOX_IMAGE_REGISTRY not set}/${SANDBOX_IMAGE_NAME:?SANDBOX_IMAGE_NAME not set}:$npm_package_version",
|
||||||
|
"prepare:cli-packagejson": "node scripts/prepare-cli-packagejson.js",
|
||||||
|
"publish:sandbox": "scripts/publish-sandbox.sh",
|
||||||
|
"publish:npm": "npm publish --workspace @gemini-code/cli ${NPM_PUBLISH_TAG:+--tag=$NPM_PUBLISH_TAG} ${NPM_DRY_RUN:+--dry-run}",
|
||||||
|
"publish:release": "npm run build:packages && npm run build:docker && npm run tag:docker && npm run prepare:cli-packagejson && npm run publish:sandbox && npm run publish:npm"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"gemini": "bundle/gemini.js"
|
"gemini": "bundle/gemini.js"
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
FROM docker.io/library/node:20-slim
|
|
||||||
|
|
||||||
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 \
|
|
||||||
man-db \
|
|
||||||
curl \
|
|
||||||
dnsutils \
|
|
||||||
less \
|
|
||||||
jq \
|
|
||||||
bc \
|
|
||||||
gh \
|
|
||||||
git \
|
|
||||||
unzip \
|
|
||||||
rsync \
|
|
||||||
ripgrep \
|
|
||||||
procps \
|
|
||||||
psmisc \
|
|
||||||
lsof \
|
|
||||||
socat \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN --mount=type=secret,id=npmrc,dst=/root/.npmrc npm install -g @gemini-code/cli@${CLI_VERSION} --verbose
|
|
||||||
|
|
||||||
ENTRYPOINT 'gemini'
|
|
|
@ -7,11 +7,8 @@
|
||||||
"bin": {
|
"bin": {
|
||||||
"gemini": "dist/index.js"
|
"gemini": "dist/index.js"
|
||||||
},
|
},
|
||||||
"image": "us-west1-docker.pkg.dev/gemini-code-dev/gemini-code-containers/gemini-code-cli",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"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",
|
"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",
|
"clean": "rm -rf dist",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"debug": "node --inspect-brk dist/index.js",
|
"debug": "node --inspect-brk dist/index.js",
|
||||||
|
@ -23,8 +20,7 @@
|
||||||
"prerelease:version": "node ../../scripts/bind_package_version.js",
|
"prerelease:version": "node ../../scripts/bind_package_version.js",
|
||||||
"prerelease:deps": "node ../../scripts/bind_package_dependencies.js",
|
"prerelease:deps": "node ../../scripts/bind_package_dependencies.js",
|
||||||
"prepublishOnly": "npm publish --workspace=@gemini-code/server",
|
"prepublishOnly": "npm publish --workspace=@gemini-code/server",
|
||||||
"prepack": "npm run build",
|
"prepack": "npm run build"
|
||||||
"postpublish": "npm run build:sandbox && npm run publish:sandbox"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|
|
@ -26,7 +26,7 @@ fi
|
||||||
CMD=$(scripts/sandbox_command.sh)
|
CMD=$(scripts/sandbox_command.sh)
|
||||||
echo "using $CMD for sandboxing"
|
echo "using $CMD for sandboxing"
|
||||||
|
|
||||||
IMAGE=gemini-code-sandbox
|
IMAGE=gemini-code-sandbox:latest
|
||||||
DOCKERFILE=Dockerfile
|
DOCKERFILE=Dockerfile
|
||||||
|
|
||||||
SKIP_NPM_INSTALL_BUILD=false
|
SKIP_NPM_INSTALL_BUILD=false
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
// ES module equivalent of __dirname
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
const cliPackageJsonPath = path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'../packages/cli/package.json',
|
||||||
|
);
|
||||||
|
const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, 'utf8'));
|
||||||
|
|
||||||
|
// Get version from root package.json (accessible via env var in npm scripts)
|
||||||
|
const version = process.env.npm_package_version;
|
||||||
|
|
||||||
|
// Get Docker registry and image name directly from PUBLISH_ environment variables.
|
||||||
|
// These are expected to be set by the CI/build environment.
|
||||||
|
const dockerRegistry = process.env.SANDBOX_IMAGE_REGISTRY;
|
||||||
|
const dockerImageName = process.env.SANDBOX_IMAGE_NAME;
|
||||||
|
|
||||||
|
if (!version || !dockerRegistry || !dockerImageName) {
|
||||||
|
console.error(
|
||||||
|
'Error: Missing required environment variables. Need: ' +
|
||||||
|
'npm_package_version, SANDBOX_IMAGE_REGISTRY, and SANDBOX_IMAGE_NAME.',
|
||||||
|
);
|
||||||
|
console.error(
|
||||||
|
'These should be passed from the CI environment (e.g., Cloud Build substitutions) ' +
|
||||||
|
'to the npm publish:release script.',
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dockerImageUri = `${dockerRegistry}/${dockerImageName}:${version}`;
|
||||||
|
|
||||||
|
// Add or update fields in cliPackageJson.config to store this information
|
||||||
|
if (!cliPackageJson.config) {
|
||||||
|
cliPackageJson.config = {};
|
||||||
|
}
|
||||||
|
cliPackageJson.config.dockerImageUri = dockerImageUri;
|
||||||
|
cliPackageJson.config.dockerRegistry = dockerRegistry;
|
||||||
|
cliPackageJson.config.dockerImageName = dockerImageName;
|
||||||
|
|
||||||
|
// Remove 'prepublishOnly' from scripts if it exists
|
||||||
|
if (cliPackageJson.scripts && cliPackageJson.scripts.prepublishOnly) {
|
||||||
|
delete cliPackageJson.scripts.prepublishOnly;
|
||||||
|
console.log('Removed prepublishOnly script from packages/cli/package.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
cliPackageJsonPath,
|
||||||
|
JSON.stringify(cliPackageJson, null, 2) + '\n',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`Updated ${path.relative(process.cwd(), cliPackageJsonPath)} with Docker image details:`,
|
||||||
|
);
|
||||||
|
console.log(` URI: ${dockerImageUri}`);
|
||||||
|
console.log(` Registry: ${dockerRegistry}`);
|
||||||
|
console.log(` Image Name: ${dockerImageName}`);
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2025 Google LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Ensure required environment variables are set
|
||||||
|
if [ -z "${SANDBOX_IMAGE_REGISTRY}" ]; then
|
||||||
|
echo "Error: SANDBOX_IMAGE_REGISTRY environment variable is not set." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${SANDBOX_IMAGE_NAME}" ]; then
|
||||||
|
echo "Error: SANDBOX_IMAGE_NAME environment variable is not set." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${npm_package_version}" ]; then
|
||||||
|
echo "Error: npm_package_version environment variable is not set (should be run via npm)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE_URI="${SANDBOX_IMAGE_REGISTRY}/${SANDBOX_IMAGE_NAME}:${npm_package_version}"
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_DRY_RUN:-}" ]; then
|
||||||
|
echo "DRY RUN: Would execute: docker push \"${IMAGE_URI}\""
|
||||||
|
else
|
||||||
|
echo "Executing: docker push \"${IMAGE_URI}\""
|
||||||
|
docker push "${IMAGE_URI}"
|
||||||
|
fi
|
Loading…
Reference in New Issue