Skip to content

Commit c4651d6

Browse files
Refactor CLI commands and enhance environment management; update Node.js version and improve logging paths
1 parent 3307a37 commit c4651d6

File tree

23 files changed

+273
-114
lines changed

23 files changed

+273
-114
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
node-version: [22.x]
18+
node-version: [20.x]
1919

2020
steps:
2121
- uses: actions/checkout@v4

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ jobs:
1414
steps:
1515
- uses: actions/checkout@v4
1616

17-
- name: Use Node.js 22.x
17+
- name: Use Node.js 20.x
1818
uses: actions/setup-node@v4
1919
with:
20-
node-version: 22.x
20+
node-version: 20.x
2121
cache: 'npm'
2222

2323
- name: Install dependencies

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ coverage/
88
bin/
99

1010
*.exe
11-
*.zip
11+
*.zip

README.md

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,23 @@ cloudsqlctl [command] [options]
2323

2424
### Commands
2525

26-
| Command | Description |
27-
| :-------- | :------------------------------------------------------- |
28-
| `install` | Download and install the Cloud SQL Proxy binary. |
29-
| `update` | Update the Cloud SQL Proxy binary to the latest version. |
30-
| `list` | List available Cloud SQL instances. |
31-
| `select` | Interactively select a Cloud SQL instance to proxy. |
32-
| `connect` | Connect to a specific instance directly. |
33-
| `start` | Start the proxy for the selected instance. |
34-
| `stop` | Stop the running proxy process. |
35-
| `restart` | Restart the proxy process. |
36-
| `status` | Check if the proxy is running and view details. |
37-
| `logs` | View the tail of the proxy logs. |
38-
| `doctor` | Run diagnostics to verify environment setup. |
39-
| `reset` | Reset configuration and remove local files. |
26+
| Command | Description |
27+
| :-------- | :------------------------------------------------------------ |
28+
| `install` | Download and install the Cloud SQL Proxy binary (User scope). |
29+
| `update` | Update the Cloud SQL Proxy binary to the latest version. |
30+
| `list` | List available Cloud SQL instances. |
31+
| `select` | Interactively select a Cloud SQL instance to proxy. |
32+
| `connect` | Connect to a specific instance directly. |
33+
| `start` | Start the proxy for the selected instance. |
34+
| `stop` | Stop the running proxy process. |
35+
| `service` | Manage Windows Service (Admin required). |
36+
| `env` | Manage environment variables (User/Machine scope). |
37+
| `gcloud` | Manage Google Cloud CLI (install portable version). |
38+
| `restart` | Restart the proxy process. |
39+
| `status` | Check if the proxy is running and view details. |
40+
| `logs` | View the tail of the proxy logs. |
41+
| `doctor` | Run diagnostics to verify environment setup. |
42+
| `reset` | Reset configuration and remove local files. |
4043

4144
### Example
4245

bin/cloudsqlctl.exe

20.5 KB
Binary file not shown.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
"name": "cloudsqlctl",
33
"version": "0.2.0",
44
"description": "Windows-native CLI tool that installs, updates, and manages Google Cloud SQL Auth Proxy via gcloud CLI.",
5-
"main": "dist/cli.js",
5+
"main": "dist/cli.cjs",
66
"type": "module",
77
"bin": {
8-
"cloudsqlctl": "./dist/cli.js"
8+
"cloudsqlctl": "./dist/cli.cjs"
99
},
1010
"scripts": {
1111
"build": "tsup src/cli.ts --format cjs --minify --out-dir dist --no-splitting",
12-
"package": "pkg dist/cli.js --targets node20-win-x64 --output bin/cloudsqlctl.exe",
12+
"package": "npm run build && powershell -ExecutionPolicy Bypass -File tools/build-sea.ps1",
1313
"zip": "powershell -Command \"Get-ChildItem -Path . -Force | Where-Object { $_.Name -notin 'node_modules', 'dist', 'bin', 'coverage', '.git', '.vs', '.DS_Store' -and $_.Extension -notin '.zip', '.exe', '.log' } | Compress-Archive -DestinationPath cloudsqlctl.zip -Force\"",
1414
"lint": "eslint src",
1515
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --passWithNoTests",

src/cli.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import { statusCommand } from './commands/status.js';
1111
import { logsCommand } from './commands/logs.js';
1212
import { doctorCommand } from './commands/doctor.js';
1313
import { resetCommand } from './commands/reset.js';
14-
import { setenvCommand } from './commands/setenv.js';
14+
import { envCommand } from './commands/env.js';
15+
import { serviceCommand } from './commands/service.js';
1516
import { ps1Command } from './commands/ps1.js';
1617
import { repairCommand } from './commands/repair.js';
1718
import { checkCommand } from './commands/check.js';
19+
import { gcloudCommand } from './commands/gcloud.js';
1820
import { logger } from './core/logger.js';
1921

2022
const program = new Command();
@@ -35,10 +37,12 @@ program.addCommand(statusCommand);
3537
program.addCommand(logsCommand);
3638
program.addCommand(doctorCommand);
3739
program.addCommand(resetCommand);
38-
program.addCommand(setenvCommand);
40+
program.addCommand(envCommand);
41+
program.addCommand(serviceCommand);
3942
program.addCommand(ps1Command);
4043
program.addCommand(repairCommand);
4144
program.addCommand(checkCommand);
45+
program.addCommand(gcloudCommand);
4246

4347
program.parseAsync(process.argv).catch(err => {
4448
logger.error('Unhandled error', err);

src/commands/env.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Command } from 'commander';
2+
import { setupEnvironment } from '../system/env.js';
3+
import { logger } from '../core/logger.js';
4+
5+
export const envCommand = new Command('env')
6+
.description('Manage environment variables');
7+
8+
envCommand.command('set')
9+
.description('Set environment variables')
10+
.option('--scope <scope>', 'Scope of environment variables (User|Machine)', 'User')
11+
.action(async (options) => {
12+
try {
13+
const scope = options.scope === 'Machine' ? 'Machine' : 'User';
14+
await setupEnvironment(scope);
15+
logger.info('Environment variables set successfully.');
16+
} catch (error) {
17+
logger.error('Failed to set environment variables', error);
18+
process.exit(1);
19+
}
20+
});

src/commands/gcloud.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Command } from 'commander';
2+
import { checkGcloudInstalled, getActiveAccount } from '../core/gcloud.js';
3+
import { logger } from '../core/logger.js';
4+
import { readConfig, writeConfig } from '../core/config.js';
5+
import { PATHS } from '../system/paths.js';
6+
import fs from 'fs-extra';
7+
import path from 'path';
8+
import axios from 'axios';
9+
import { execa } from 'execa';
10+
11+
// Official Google Cloud SDK download URL pattern
12+
const GCLOUD_DOWNLOAD_URL = 'https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-windows-x86_64.zip';
13+
14+
export const gcloudCommand = new Command('gcloud')
15+
.description('Manage Google Cloud CLI');
16+
17+
gcloudCommand.command('status')
18+
.description('Check gcloud CLI status')
19+
.action(async () => {
20+
const config = await readConfig();
21+
logger.info(`Configured gcloud path: ${config.gcloudPath || '(default)'}`);
22+
23+
const installed = await checkGcloudInstalled();
24+
if (installed) {
25+
logger.info('✅ gcloud CLI is installed and reachable.');
26+
const account = await getActiveAccount();
27+
logger.info(`Active account: ${account || 'None'}`);
28+
} else {
29+
logger.warn('❌ gcloud CLI is NOT installed or not found.');
30+
}
31+
});
32+
33+
gcloudCommand.command('install')
34+
.description('Install portable Google Cloud CLI')
35+
.action(async () => {
36+
try {
37+
logger.info('Installing portable Google Cloud CLI...');
38+
await fs.ensureDir(PATHS.GCLOUD_DIR);
39+
40+
const zipPath = path.join(PATHS.TEMP, 'google-cloud-sdk.zip');
41+
await fs.ensureDir(PATHS.TEMP);
42+
43+
logger.info(`Downloading from ${GCLOUD_DOWNLOAD_URL}...`);
44+
const response = await axios({
45+
url: GCLOUD_DOWNLOAD_URL,
46+
method: 'GET',
47+
responseType: 'stream'
48+
});
49+
50+
const writer = fs.createWriteStream(zipPath);
51+
response.data.pipe(writer);
52+
53+
await new Promise<void>((resolve, reject) => {
54+
writer.on('finish', () => resolve());
55+
writer.on('error', reject);
56+
});
57+
58+
logger.info('Extracting...');
59+
// Use PowerShell to extract
60+
await execa('powershell', ['-Command', `Expand-Archive -Path "${zipPath}" -DestinationPath "${PATHS.GCLOUD_DIR}" -Force`]);
61+
62+
const gcloudExe = path.join(PATHS.GCLOUD_DIR, 'google-cloud-sdk', 'bin', 'gcloud.cmd');
63+
64+
if (await fs.pathExists(gcloudExe)) {
65+
logger.info(`gcloud installed to ${gcloudExe}`);
66+
await writeConfig({ gcloudPath: gcloudExe });
67+
logger.info('Configuration updated.');
68+
} else {
69+
throw new Error('gcloud.cmd not found after extraction');
70+
}
71+
72+
// Cleanup
73+
await fs.remove(zipPath);
74+
75+
} catch (error) {
76+
logger.error('Failed to install gcloud', error);
77+
process.exit(1);
78+
}
79+
});

src/commands/install.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@ import { Command } from 'commander';
22
import { getLatestVersion, downloadProxy } from '../core/updater.js';
33
import { logger } from '../core/logger.js';
44
import { isRunning, stopProxy } from '../core/proxy.js';
5-
import { setupEnvironment } from '../system/env.js';
6-
import { generateScripts } from '../system/ps1.js';
7-
import { installService } from '../system/service.js';
85

96
export const installCommand = new Command('install')
10-
.description('Download and install Cloud SQL Proxy, setup environment and service')
7+
.description('Download and install Cloud SQL Proxy')
118
.option('-v, --version <version>', 'Specific version to install')
129
.action(async (options) => {
1310
try {
@@ -24,16 +21,7 @@ export const installCommand = new Command('install')
2421
logger.info(`Installing Cloud SQL Proxy version ${version}...`);
2522
await downloadProxy(version);
2623

27-
logger.info('Setting up environment variables...');
28-
await setupEnvironment();
29-
30-
logger.info('Generating PowerShell scripts...');
31-
await generateScripts();
32-
33-
logger.info('Installing Windows Service...');
34-
await installService();
35-
36-
logger.info('Installation and setup successful.');
24+
logger.info('Installation successful.');
3725
} catch (error) {
3826
logger.error('Installation failed', error);
3927
process.exit(1);

0 commit comments

Comments
 (0)