mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-24 21:10:43 -07:00
feat(offload): finalize high-performance architecture with fast-path SSH and worktrees
This commit is contained in:
@@ -11,12 +11,10 @@
|
||||
"deepReview": {
|
||||
"projectId": "gemini-cli-team-quota",
|
||||
"zone": "us-west1-a",
|
||||
"machineType": "n2-standard-8",
|
||||
"terminalType": "iterm2",
|
||||
"syncAuth": true,
|
||||
"setupType": "isolated",
|
||||
"geminiSetup": "isolated",
|
||||
"ghSetup": "isolated"
|
||||
"remoteHost": "gcli-worker",
|
||||
"remoteHome": "/home/mattkorwel_google_com",
|
||||
"remoteWorkDir": "/home/mattkorwel_google_com/dev/main",
|
||||
"terminalType": "iterm2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Universal Deep Review Cleanup (Local)
|
||||
* Universal Offload Cleanup (Local)
|
||||
*
|
||||
* Cleans up tmux sessions and workspace on the GCE worker.
|
||||
*/
|
||||
import { spawnSync } from 'child_process';
|
||||
import path from 'path';
|
||||
@@ -23,7 +25,7 @@ async function confirm(question: string): Promise<boolean> {
|
||||
export async function runCleanup() {
|
||||
const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json');
|
||||
if (!fs.existsSync(settingsPath)) {
|
||||
console.error('❌ Settings not found. Run "npm run review:setup" first.');
|
||||
console.error('❌ Settings not found. Run "npm run offload:setup" first.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -31,33 +33,32 @@ export async function runCleanup() {
|
||||
const config = settings.maintainer?.deepReview;
|
||||
|
||||
if (!config) {
|
||||
console.error('❌ Deep Review configuration not found.');
|
||||
console.error('❌ Offload configuration not found.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
const { remoteHost, remoteWorkDir } = config;
|
||||
const { projectId, zone } = config;
|
||||
const targetVM = `gcli-offload-${process.env.USER || 'mattkorwel'}`;
|
||||
|
||||
console.log(`🧹 Starting cleanup for ${remoteHost}:${remoteWorkDir}...`);
|
||||
console.log(`🧹 Starting cleanup for ${targetVM}...`);
|
||||
|
||||
// 1. Standard Cleanup
|
||||
console.log(' - Killing remote tmux sessions...');
|
||||
spawnSync('ssh', [remoteHost, 'tmux kill-server'], { shell: true });
|
||||
spawnSync(`ssh ${remoteHost} "tmux kill-server"`, { shell: true });
|
||||
|
||||
console.log(' - Removing PR directories...');
|
||||
// Find all directories in the work dir that aren't .gemini and delete them
|
||||
const dirCleanup = `find ${remoteWorkDir} -mindepth 1 -maxdepth 1 -type d ! -name ".gemini" -exec rm -rf {} +`;
|
||||
spawnSync('ssh', [remoteHost, dirCleanup], { shell: true });
|
||||
console.log(' - Cleaning up Git Worktrees...');
|
||||
spawnSync(`ssh ${remoteHost} "cd ~/dev/main && git worktree prune"`, { shell: true });
|
||||
spawnSync(`ssh ${remoteHost} "rm -rf ~/dev/worktrees/*"`, { shell: true });
|
||||
|
||||
console.log('✅ Standard cleanup complete.');
|
||||
console.log('✅ Remote environment cleared.');
|
||||
|
||||
// 2. Full Wipe Option
|
||||
const shouldWipe = await confirm('\nWould you like to COMPLETELY remove the work directory from the remote machine?');
|
||||
const shouldWipe = await confirm('\nWould you like to COMPLETELY wipe the remote workspace directory?');
|
||||
|
||||
if (shouldWipe) {
|
||||
console.log(`🔥 Wiping ${remoteWorkDir}...`);
|
||||
const wipeCmd = `rm -rf ${remoteWorkDir}`;
|
||||
spawnSync('ssh', [remoteHost, wipeCmd], { stdio: 'inherit', shell: true });
|
||||
console.log('✅ Remote directory wiped.');
|
||||
console.log(`🔥 Wiping ~/.offload/workspace...`);
|
||||
spawnSync(`gcloud compute ssh ${targetVM} --project ${projectId} --zone ${zone} --command "rm -rf ~/.offload/workspace && mkdir -p ~/.offload/workspace"`, { stdio: 'inherit', shell: true });
|
||||
console.log('✅ Remote workspace wiped.');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Universal Offload Orchestrator (Local)
|
||||
*
|
||||
* Automatically detects and connects to your dynamic GCE fleet.
|
||||
* Automatically connects to your dedicated worker and launches the task.
|
||||
*/
|
||||
import { spawnSync } from 'child_process';
|
||||
import path from 'path';
|
||||
@@ -22,93 +22,54 @@ export async function runOrchestrator(args: string[], env: NodeJS.ProcessEnv = p
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1. Load GCP Settings
|
||||
// 1. Load Settings
|
||||
const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json');
|
||||
if (!fs.existsSync(settingsPath)) {
|
||||
console.error('❌ Settings not found. Run "npm run offload:setup" first.');
|
||||
return 1;
|
||||
}
|
||||
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
||||
const config = settings.maintainer?.deepReview;
|
||||
if (!config) {
|
||||
console.error('❌ Fleet settings not found. Run "npm run offload:setup" first.');
|
||||
console.error('❌ Settings not found. Run "npm run offload:setup" first.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
const { projectId, zone, terminalType, syncAuth } = config;
|
||||
const { projectId, zone, remoteHost, remoteHome, remoteWorkDir } = config;
|
||||
const targetVM = `gcli-offload-${env.USER || 'mattkorwel'}`;
|
||||
|
||||
console.log(`🔍 Connecting to offload worker: ${targetVM}...`);
|
||||
|
||||
// 1. Get remote HOME and Status
|
||||
const infoCheck = spawnSync(`gcloud compute ssh ${targetVM} --project ${projectId} --zone ${zone} --command "echo \$HOME && gcloud compute instances describe ${targetVM} --project ${projectId} --zone ${zone} --format='get(status)'"`, { shell: true });
|
||||
const infoOutput = infoCheck.stdout.toString().trim().split('\n');
|
||||
const remoteHome = infoOutput[0] || '/home/ubuntu';
|
||||
const status = infoOutput[infoOutput.length - 1] || 'RUNNING';
|
||||
|
||||
console.log(`DEBUG: Remote Home: ${remoteHome}, Status: ${status}`);
|
||||
// 2. Wake Worker
|
||||
const statusCheck = spawnSync(`gcloud compute instances describe ${targetVM} --project ${projectId} --zone ${zone} --format="get(status)"`, { shell: true });
|
||||
const status = statusCheck.stdout.toString().trim();
|
||||
|
||||
if (status !== 'RUNNING' && status !== 'PROVISIONING' && status !== 'STAGING') {
|
||||
console.log(`⚠️ Worker ${targetVM} is ${status}. Starting it now...`);
|
||||
console.log(`⚠️ Worker ${targetVM} is ${status}. Waking it up...`);
|
||||
spawnSync(`gcloud compute instances start ${targetVM} --project ${projectId} --zone ${zone}`, { shell: true, stdio: 'inherit' });
|
||||
}
|
||||
|
||||
const remoteWorkDir = `${remoteHome}/.offload/workspace`;
|
||||
const ISOLATED_GEMINI = `${remoteHome}/.offload/gemini-cli-config`;
|
||||
const ISOLATED_GH = `${remoteHome}/.offload/gh-cli-config`;
|
||||
const remotePolicyPath = `${ISOLATED_GEMINI}/policies/offload-policy.toml`;
|
||||
|
||||
const remotePolicyPath = `${remoteHome}/.gemini/policies/offload-policy.toml`;
|
||||
const persistentScripts = `${remoteHome}/.offload/scripts`;
|
||||
const sessionName = `offload-${prNumber}-${action}`;
|
||||
|
||||
// Fetch Metadata (local)
|
||||
console.log(`🔍 Fetching metadata for ${action === 'implement' ? 'Issue' : 'PR'} #${prNumber}...`);
|
||||
const ghCmd = action === 'implement'
|
||||
? `gh issue view ${prNumber} --json title -q .title`
|
||||
: `gh pr view ${prNumber} --json headRefName -q .headRefName`;
|
||||
// 3. Remote Context Setup (Parallel Worktree, NO symlinking)
|
||||
console.log(`🚀 Provisioning clean worktree for ${action} on PR #${prNumber}...`);
|
||||
const remoteWorktreeDir = `${remoteHome}/dev/worktrees/offload-${prNumber}-${action}`;
|
||||
|
||||
const ghView = spawnSync(ghCmd, { shell: true });
|
||||
const metaName = ghView.stdout.toString().trim() || `task-${prNumber}`;
|
||||
const branchName = action === 'implement' ? `impl-${prNumber}` : metaName;
|
||||
console.log(`DEBUG: Branch name for session: ${branchName}`);
|
||||
const setupCmd = `
|
||||
mkdir -p ${remoteHome}/dev/worktrees && \
|
||||
cd ${remoteWorkDir} && \
|
||||
git fetch origin pull/${prNumber}/head && \
|
||||
git worktree add -f ${remoteWorktreeDir} FETCH_HEAD
|
||||
`;
|
||||
|
||||
console.log(`📦 Synchronizing with ${targetVM}...`);
|
||||
spawnSync(`gcloud compute ssh ${targetVM} --project ${projectId} --zone ${zone} --command "mkdir -p ${remoteWorkDir} ${ISOLATED_GEMINI}/policies/"`, { shell: true });
|
||||
spawnSync(`ssh ${remoteHost} ${q(setupCmd)}`, { shell: true, stdio: 'inherit' });
|
||||
|
||||
// Sync manifests and scripts
|
||||
const rsyncBase = `rsync -avz -e "gcloud compute ssh --project ${projectId} --zone ${zone}"`;
|
||||
spawnSync(`${rsyncBase} package.json package-lock.json .gemini/skills/offload/policy.toml ${targetVM}:${remoteWorkDir}/`, { shell: true });
|
||||
spawnSync(`${rsyncBase} .gemini/skills/offload/policy.toml ${targetVM}:${remotePolicyPath}`, { shell: true });
|
||||
spawnSync(`${rsyncBase} --delete .gemini/skills/offload/scripts/ ${targetVM}:${remoteWorkDir}/.gemini/skills/offload/scripts/`, { shell: true });
|
||||
|
||||
if (syncAuth) {
|
||||
const homeDir = env.HOME || '';
|
||||
const localGeminiDir = path.join(homeDir, '.gemini');
|
||||
const syncFiles = ['google_accounts.json', 'settings.json'];
|
||||
for (const f of syncFiles) {
|
||||
const lp = path.join(localGeminiDir, f);
|
||||
if (fs.existsSync(lp)) {
|
||||
spawnSync(`rsync -avz -e "gcloud compute ssh --project ${projectId} --zone ${zone}" ${lp} ${targetVM}:${ISOLATED_GEMINI}/${f}`, { shell: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Construct Command
|
||||
const remoteWorker = `export GEMINI_CLI_HOME=${ISOLATED_GEMINI} && export GH_CONFIG_DIR=${ISOLATED_GH} && [ -d node_modules ] || npm install --no-audit --no-fund && node_modules/.bin/tsx .gemini/skills/offload/scripts/entrypoint.ts ${prNumber} ${branchName} ${remotePolicyPath} ${action}`;
|
||||
const tmuxCmd = `cd ${remoteWorkDir} && ${remoteWorker}; exec $SHELL`;
|
||||
|
||||
const gcloudPath = spawnSync('which', ['gcloud'], { stdio: 'pipe' }).stdout.toString().trim() || 'gcloud';
|
||||
// Use global tsx for the runner
|
||||
const remoteWorker = `tsx ${persistentScripts}/entrypoint.ts ${prNumber} remote-branch ${remotePolicyPath} ${action}`;
|
||||
const tmuxCmd = `cd ${remoteWorktreeDir} && ${remoteWorker}; exec $SHELL`;
|
||||
|
||||
const sshInternal = `tmux attach-session -t ${sessionName} 2>/dev/null || tmux new-session -s ${sessionName} -n 'offload' ${q(tmuxCmd)}`;
|
||||
const finalSSH = `${gcloudPath} compute ssh ${targetVM} --project ${projectId} --zone ${zone} -- -t ${q(sshInternal)}`;
|
||||
const finalSSH = `ssh -t ${remoteHost} ${q(sshInternal)}`;
|
||||
|
||||
console.log(`DEBUG: Final SSH command: ${finalSSH}`);
|
||||
|
||||
// 5. Terminal Automation
|
||||
// 4. Open in iTerm2
|
||||
const isWithinGemini = !!env.GEMINI_CLI || !!env.GEMINI_SESSION_ID || !!env.GCLI_SESSION_ID;
|
||||
console.log(`DEBUG: isWithinGemini: ${isWithinGemini}`);
|
||||
|
||||
if (isWithinGemini && terminalType === 'iterm2') {
|
||||
// Write the command to a temp file to avoid AppleScript/Shell mangling
|
||||
if (isWithinGemini) {
|
||||
const tempCmdPath = path.join(process.env.TMPDIR || '/tmp', `offload-ssh-${prNumber}.sh`);
|
||||
fs.writeFileSync(tempCmdPath, `#!/bin/bash\n${finalSSH}\nrm "$0"`, { mode: 0o755 });
|
||||
|
||||
@@ -124,12 +85,10 @@ export async function runOrchestrator(args: string[], env: NodeJS.ProcessEnv = p
|
||||
end run
|
||||
`;
|
||||
spawnSync('osascript', ['-', tempCmdPath], { input: appleScript });
|
||||
console.log(`✅ iTerm2 window opened on ${targetVM}.`);
|
||||
console.log(`✅ iTerm2 window opened on ${remoteHost}.`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
console.log('🚀 Launching interactive session...');
|
||||
spawnSync(finalSSH, { stdio: 'inherit', shell: true });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* Universal Offload Onboarding (Local)
|
||||
*
|
||||
* Configures the GCP Project and Fleet defaults.
|
||||
* Configures the GCP Project and performs one-time initialization of the worker.
|
||||
*/
|
||||
import { spawnSync } from 'child_process';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import { fileURLToPath } from 'url';
|
||||
import readline from 'readline';
|
||||
|
||||
@@ -33,32 +34,115 @@ async function confirm(question: string): Promise<boolean> {
|
||||
}
|
||||
|
||||
export async function runSetup(env: NodeJS.ProcessEnv = process.env) {
|
||||
console.log('\n🌟 Initializing GCE Offload Fleet Settings...');
|
||||
console.log('\n🌟 Initializing Dedicated Offload Worker...');
|
||||
|
||||
const projectId = await prompt('GCP Project ID', 'gemini-cli-team-quota');
|
||||
const zone = await prompt('Compute Zone', 'us-west1-a');
|
||||
const machineType = await prompt('Machine Type', 'n2-standard-8');
|
||||
const targetVM = `gcli-offload-${env.USER || 'mattkorwel'}`;
|
||||
|
||||
console.log(`🔍 Verifying project access for ${projectId}...`);
|
||||
const projectCheck = spawnSync('gcloud', ['projects', 'describe', projectId], { stdio: 'pipe' });
|
||||
if (projectCheck.status !== 0) {
|
||||
console.error(`❌ Access denied to project: ${projectId}. Ensure you are logged in via gcloud.`);
|
||||
console.log(`🔍 Verifying access and finding worker ${targetVM}...`);
|
||||
const statusCheck = spawnSync(`gcloud compute instances describe ${targetVM} --project ${projectId} --zone ${zone} --format="json(status,networkInterfaces[0].accessConfigs[0].natIP)"`, { shell: true });
|
||||
|
||||
let instanceData: any;
|
||||
try {
|
||||
instanceData = JSON.parse(statusCheck.stdout.toString());
|
||||
} catch (e) {
|
||||
console.error(`❌ Worker ${targetVM} not found. Run "npm run offload:fleet provision" first.`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Identity Synchronization Onboarding
|
||||
console.log('\n🔐 Identity & Authentication:');
|
||||
const homeDir = env.HOME || '';
|
||||
const localAuth = path.join(homeDir, '.gemini/google_accounts.json');
|
||||
const hasAuth = fs.existsSync(localAuth);
|
||||
const status = instanceData.status;
|
||||
const publicIp = instanceData.networkInterfaces[0].accessConfigs[0].natIP;
|
||||
|
||||
let syncAuth = false;
|
||||
if (hasAuth) {
|
||||
console.log(` 🔍 Found local Gemini CLI credentials.`);
|
||||
syncAuth = await confirm(' Would you like to automatically sync your local credentials to new fleet workers for seamless authentication?');
|
||||
if (status !== 'RUNNING') {
|
||||
console.log(`⚠️ Worker is ${status}. Starting it for initialization...`);
|
||||
spawnSync(`gcloud compute instances start ${targetVM} --project ${projectId} --zone ${zone}`, { shell: true, stdio: 'inherit' });
|
||||
}
|
||||
|
||||
const terminalType = await prompt('\nTerminal Automation (iterm2 / terminal / none)', 'iterm2');
|
||||
// 1. Configure Fast-Path SSH Alias
|
||||
console.log(`\n🚀 Configuring Fast-Path SSH Alias...`);
|
||||
const sshAlias = 'gcli-worker';
|
||||
const sshConfigPath = path.join(os.homedir(), '.ssh/config');
|
||||
const sshEntry = `
|
||||
Host ${sshAlias}
|
||||
HostName ${publicIp}
|
||||
IdentityFile ~/.ssh/google_compute_engine
|
||||
User ${env.USER || 'mattkorwel'}_google_com
|
||||
CheckHostIP no
|
||||
StrictHostKeyChecking no
|
||||
`;
|
||||
|
||||
let currentConfig = '';
|
||||
if (fs.existsSync(sshConfigPath)) currentConfig = fs.readFileSync(sshConfigPath, 'utf8');
|
||||
|
||||
if (!currentConfig.includes(`Host ${sshAlias}`)) {
|
||||
fs.appendFileSync(sshConfigPath, sshEntry);
|
||||
console.log(` ✅ Added '${sshAlias}' alias to ~/.ssh/config`);
|
||||
} else {
|
||||
console.log(` ℹ️ '${sshAlias}' alias already exists in ~/.ssh/config`);
|
||||
}
|
||||
|
||||
// 1. Configure Fast-Path SSH Alias
|
||||
// ... (unchanged)
|
||||
|
||||
// Use the alias for remaining setup steps
|
||||
const remoteHost = sshAlias;
|
||||
const remoteHome = spawnSync(`ssh ${remoteHost} "pwd"`, { shell: true }).stdout.toString().trim();
|
||||
const remoteWorkDir = `${remoteHome}/dev/main`;
|
||||
const persistentScripts = `${remoteHome}/.offload/scripts`;
|
||||
|
||||
console.log(`\n📦 Performing One-Time Synchronization...`);
|
||||
spawnSync(`ssh ${remoteHost} "mkdir -p ${remoteWorkDir} ${remoteHome}/.gemini/policies ${persistentScripts}"`, { shell: true });
|
||||
|
||||
// Sync offload scripts to persistent location
|
||||
console.log(' - Pushing offload logic to persistent worker directory...');
|
||||
spawnSync(`rsync -avz --delete .gemini/skills/offload/scripts/ ${remoteHost}:${persistentScripts}/`, { shell: true });
|
||||
spawnSync(`rsync -avz .gemini/skills/offload/policy.toml ${remoteHost}:${remoteHome}/.gemini/policies/offload-policy.toml`, { shell: true });
|
||||
|
||||
// 3. Sync Auth (Gemini)
|
||||
if (await confirm('Sync Gemini accounts credentials?')) {
|
||||
const homeDir = env.HOME || '';
|
||||
const lp = path.join(homeDir, '.gemini/google_accounts.json');
|
||||
if (fs.existsSync(lp)) {
|
||||
console.log(` - Syncing .gemini/google_accounts.json...`);
|
||||
spawnSync(`rsync -avz ${lp} ${remoteHost}:${remoteHome}/.gemini/google_accounts.json`, { shell: true });
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Remote GitHub Login
|
||||
if (await confirm('Authenticate GitHub CLI on the worker?')) {
|
||||
console.log('\n🔐 Performing non-interactive GitHub CLI authentication on worker...');
|
||||
const localToken = spawnSync('gh', ['auth', 'token'], { stdio: 'pipe' }).stdout.toString().trim();
|
||||
if (!localToken) {
|
||||
console.error('❌ Could not find local GitHub token. Please log in locally first with "gh auth login".');
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Pipe the local token to the remote worker's gh auth login
|
||||
const loginCmd = `gh auth login --with-token --insecure-storage`;
|
||||
const result = spawnSync(`echo ${localToken} | ssh ${remoteHost} ${JSON.stringify(loginCmd)}`, { shell: true, stdio: 'inherit' });
|
||||
|
||||
if (result.status === 0) {
|
||||
console.log('✅ GitHub CLI authenticated successfully on worker.');
|
||||
// Set git protocol to https by default for simplicity
|
||||
spawnSync(`ssh ${remoteHost} "gh config set git_protocol https"`, { shell: true });
|
||||
} else {
|
||||
console.error('❌ GitHub CLI authentication failed on worker.');
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Global Tooling & Clone
|
||||
if (await confirm('Configure global tools (tsx, vitest) and clone repository?')) {
|
||||
console.log('🚀 Installing global developer tools...');
|
||||
spawnSync(`ssh ${remoteHost} "sudo npm install -g tsx vitest"`, { shell: true, stdio: 'inherit' });
|
||||
|
||||
console.log('🚀 Cloning repository (blob-less) on worker...');
|
||||
const repoUrl = 'https://github.com/google-gemini/gemini-cli.git';
|
||||
const cloneCmd = `[ -d ${remoteWorkDir}/.git ] || git clone --filter=blob:none ${repoUrl} ${remoteWorkDir}`;
|
||||
spawnSync(`ssh ${remoteHost} ${JSON.stringify(cloneCmd)}`, { shell: true, stdio: 'inherit' });
|
||||
|
||||
// We skip the full npm install here as requested; per-worktree builds will handle it if needed.
|
||||
}
|
||||
|
||||
// Save Settings
|
||||
const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json');
|
||||
@@ -70,18 +154,14 @@ export async function runSetup(env: NodeJS.ProcessEnv = process.env) {
|
||||
settings.maintainer.deepReview = {
|
||||
projectId,
|
||||
zone,
|
||||
machineType,
|
||||
terminalType,
|
||||
syncAuth,
|
||||
setupType: 'isolated',
|
||||
geminiSetup: 'isolated',
|
||||
ghSetup: 'isolated'
|
||||
remoteHost,
|
||||
remoteHome,
|
||||
remoteWorkDir,
|
||||
terminalType: 'iterm2'
|
||||
};
|
||||
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
||||
|
||||
console.log('\n✅ GCE Fleet Onboarding complete! Settings saved to .gemini/settings.json');
|
||||
console.log(`👉 Use 'npm run offload:fleet provision' to spin up your first worker.`);
|
||||
console.log('\n✅ Initialization complete! Your dedicated worker is ready via fast-path SSH.');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,11 @@ describe('Offload Orchestration (GCE)', () => {
|
||||
// Default mock for gcloud instance info and describe
|
||||
vi.mocked(spawnSync).mockImplementation((cmd: any, args: any) => {
|
||||
const callInfo = JSON.stringify({ cmd, args });
|
||||
if (callInfo.includes('gcloud') && callInfo.includes('ssh') && callInfo.includes('echo $HOME')) {
|
||||
return { status: 0, stdout: Buffer.from('/home/testuser\nRUNNING\n'), stderr: Buffer.from('') } as any;
|
||||
if (callInfo.includes('compute') && callInfo.includes('describe')) {
|
||||
return { status: 0, stdout: Buffer.from('RUNNING\n'), stderr: Buffer.from('') } as any;
|
||||
}
|
||||
if (callInfo.includes('gcloud') && callInfo.includes('ssh') && callInfo.includes('pwd')) {
|
||||
return { status: 0, stdout: Buffer.from('/home/testuser\n'), stderr: Buffer.from('') } as any;
|
||||
}
|
||||
if (callInfo.includes('gh') && callInfo.includes('view')) {
|
||||
return { status: 0, stdout: Buffer.from('test-meta\n'), stderr: Buffer.from('') } as any;
|
||||
|
||||
Reference in New Issue
Block a user