Skip to content

Commit 908d2b4

Browse files
author
Kinin-Code-Offical
committed
chore(release): v0.5.2
1 parent 4003d85 commit 908d2b4

File tree

10 files changed

+827
-24
lines changed

10 files changed

+827
-24
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
# Changelog
44

5+
## [0.5.2] - 2026-03-02
6+
7+
### Changed
8+
9+
- Implement feature X to enhance user experience and fix bug Y in module Z
10+
511
## [0.5.1] - 2026-03-02
612

713
### Changed

docs/commands.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Cloud SQL Proxy CLI Reference
22

3-
**Version:** 0.5.1
3+
**Version:** 0.5.2
44
**Generated:** 2026-03-02
55

66
## Overview
@@ -16,7 +16,7 @@ Options:
1616
1717
Commands:
1818
install [options] Download and install Cloud SQL Proxy
19-
update Update Cloud SQL Proxy to the latest version
19+
update [options] Update Cloud SQL Proxy to the latest version
2020
select Select a Cloud SQL instance
2121
list [options] List available Cloud SQL instances
2222
connect [options] <instance> Connect to a specific Cloud SQL instance
@@ -41,6 +41,8 @@ Commands:
4141
locations
4242
upgrade [options] Upgrade cloudsqlctl to the latest version
4343
support Support utilities
44+
sync Mock remote sync features (GitHub-like push/pull
45+
for local environments)
4446
help [command] display help for command
4547
```
4648

@@ -66,7 +68,13 @@ Usage: cloudsqlctl update [options]
6668
Update Cloud SQL Proxy to the latest version
6769
6870
Options:
69-
-h, --help display help for command
71+
--check-only Only check latest version, do not download
72+
--version <version> Download a specific version tag (e.g. v2.18.2)
73+
--base-url <url> Custom download base URL for proxy binary/checksum
74+
--timeout <ms> HTTP timeout in milliseconds (default: "60000")
75+
--retries <count> Retry count for network operations (default: "2")
76+
--json Output machine-readable JSON result
77+
-h, --help display help for command
7078
```
7179

7280
### select

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cloudsqlctl",
3-
"version": "0.5.1",
3+
"version": "0.5.2",
44
"description": "Windows-native CLI tool that installs, updates, and manages Google Cloud SQL Auth Proxy via gcloud CLI.",
55
"main": "dist/cli.cjs",
66
"type": "module",

src/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { setupCommand } from './commands/setup.js';
2222
import { pathsCommand } from './commands/paths.js';
2323
import { upgradeCommand } from './commands/upgrade.js';
2424
import { supportCommand } from './commands/support.js';
25+
import { syncCommand } from './commands/sync.js';
2526
import { logger } from './core/logger.js';
2627

2728
const program = new Command();
@@ -53,6 +54,7 @@ program.addCommand(setupCommand);
5354
program.addCommand(pathsCommand);
5455
program.addCommand(upgradeCommand);
5556
program.addCommand(supportCommand);
57+
program.addCommand(syncCommand);
5658

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

src/commands/sync.ts

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { Command } from 'commander';
2+
import path from 'path';
3+
import { logger } from '../core/logger.js';
4+
import {
5+
startSyncServer,
6+
stopSyncServer,
7+
getSyncServerStatus,
8+
pushDirectoryToSyncServer,
9+
pullDirectoryFromSyncServer,
10+
getSyncHistory,
11+
runSyncDaemon,
12+
checkDockerAndOptionallyInstall
13+
} from '../core/sync.js';
14+
15+
const DEFAULT_SERVER_URL = 'http://127.0.0.1:4780';
16+
17+
export const syncCommand = new Command('sync')
18+
.description('Mock remote sync features (GitHub-like push/pull for local environments)');
19+
20+
syncCommand.command('start')
21+
.description('Start local mock sync server')
22+
.option('--host <host>', 'Bind host', '127.0.0.1')
23+
.option('--port <port>', 'Bind port', '4780')
24+
.action(async (options) => {
25+
try {
26+
await startSyncServer(options.host, Number(options.port));
27+
} catch (error) {
28+
logger.error('Failed to start sync server', error);
29+
process.exit(1);
30+
}
31+
});
32+
33+
syncCommand.command('stop')
34+
.description('Stop local mock sync server')
35+
.action(async () => {
36+
try {
37+
await stopSyncServer();
38+
} catch (error) {
39+
logger.error('Failed to stop sync server', error);
40+
process.exit(1);
41+
}
42+
});
43+
44+
syncCommand.command('status')
45+
.description('Show local mock sync server status')
46+
.action(async () => {
47+
try {
48+
const status = await getSyncServerStatus();
49+
if (!status.running) {
50+
logger.info('Sync server: STOPPED');
51+
return;
52+
}
53+
logger.info(`Sync server: RUNNING (pid: ${status.pid}, host: ${status.host}, port: ${status.port})`);
54+
} catch (error) {
55+
logger.error('Failed to read sync server status', error);
56+
process.exit(1);
57+
}
58+
});
59+
60+
syncCommand.command('push')
61+
.description('Push a local directory snapshot to mock sync server')
62+
.requiredOption('--repo <name>', 'Repository name on sync server')
63+
.option('--source <dir>', 'Local source directory', process.cwd())
64+
.option('--server <url>', 'Sync server URL', DEFAULT_SERVER_URL)
65+
.option('--message <message>', 'Snapshot message')
66+
.action(async (options) => {
67+
try {
68+
const sourceDir = path.resolve(options.source);
69+
logger.info(`Preparing snapshot from: ${sourceDir}`);
70+
const result = await pushDirectoryToSyncServer({
71+
sourceDir,
72+
repo: options.repo,
73+
serverUrl: options.server,
74+
message: options.message
75+
});
76+
77+
logger.info(`Push complete. Version: v${result.version}, files: ${result.fileCount}`);
78+
} catch (error) {
79+
logger.error('Sync push failed', error);
80+
process.exit(1);
81+
}
82+
});
83+
84+
syncCommand.command('pull')
85+
.description('Pull a snapshot from mock sync server into local directory')
86+
.requiredOption('--repo <name>', 'Repository name on sync server')
87+
.option('--target <dir>', 'Local target directory', process.cwd())
88+
.option('--server <url>', 'Sync server URL', DEFAULT_SERVER_URL)
89+
.option('--version <version>', 'Snapshot version (default: latest)', 'latest')
90+
.action(async (options) => {
91+
try {
92+
const targetDir = path.resolve(options.target);
93+
logger.info(`Pulling into: ${targetDir}`);
94+
const result = await pullDirectoryFromSyncServer({
95+
targetDir,
96+
repo: options.repo,
97+
serverUrl: options.server,
98+
version: options.version
99+
});
100+
101+
logger.info(`Pull complete. Version: v${result.version}, files: ${result.fileCount}`);
102+
} catch (error) {
103+
logger.error('Sync pull failed', error);
104+
process.exit(1);
105+
}
106+
});
107+
108+
syncCommand.command('history')
109+
.description('Show snapshot history for a repo on mock sync server')
110+
.requiredOption('--repo <name>', 'Repository name on sync server')
111+
.option('--server <url>', 'Sync server URL', DEFAULT_SERVER_URL)
112+
.action(async (options) => {
113+
try {
114+
const history = await getSyncHistory(options.server, options.repo);
115+
logger.info(`Latest: v${history.latestVersion}`);
116+
logger.info(`Versions: ${history.versions.length ? history.versions.map(v => `v${v}`).join(', ') : '(none)'}`);
117+
} catch (error) {
118+
logger.error('Failed to fetch sync history', error);
119+
process.exit(1);
120+
}
121+
});
122+
123+
syncCommand.command('docker')
124+
.description('Check Docker availability (optional auto install via winget)')
125+
.option('--install', 'Install Docker Desktop on Windows if missing')
126+
.action(async (options) => {
127+
try {
128+
const status = await checkDockerAndOptionallyInstall(Boolean(options.install));
129+
if (status.installed) {
130+
logger.info(`Docker: INSTALLED (${status.version})`);
131+
return;
132+
}
133+
134+
logger.warn('Docker: NOT INSTALLED');
135+
if (status.installMessage) {
136+
logger.info(status.installMessage);
137+
}
138+
} catch (error) {
139+
logger.error('Docker check/install failed', error);
140+
process.exit(1);
141+
}
142+
});
143+
144+
syncCommand.command('daemon', { hidden: true })
145+
.option('--host <host>', 'Bind host', '127.0.0.1')
146+
.option('--port <port>', 'Bind port', '4780')
147+
.action(async (options) => {
148+
try {
149+
await runSyncDaemon(options.host, Number(options.port));
150+
} catch (error) {
151+
logger.error('Sync daemon failed', error);
152+
process.exit(1);
153+
}
154+
});

src/commands/update.ts

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,68 @@ import { getLatestVersion, downloadProxy } from '../core/updater.js';
33
import { logger } from '../core/logger.js';
44
import { isRunning, stopProxy } from '../core/proxy.js';
55
import { isServiceInstalled, isServiceRunning, startService, stopService } from '../system/service.js';
6+
import { isAdmin } from '../system/powershell.js';
67

78
export const updateCommand = new Command('update')
89
.description('Update Cloud SQL Proxy to the latest version')
9-
.action(async () => {
10+
.option('--check-only', 'Only check latest version, do not download')
11+
.option('--version <version>', 'Download a specific version tag (e.g. v2.18.2)')
12+
.option('--base-url <url>', 'Custom download base URL for proxy binary/checksum')
13+
.option('--timeout <ms>', 'HTTP timeout in milliseconds', '60000')
14+
.option('--retries <count>', 'Retry count for network operations', '2')
15+
.option('--json', 'Output machine-readable JSON result')
16+
.action(async (options) => {
1017
const serviceInstalled = await isServiceInstalled();
1118
const serviceWasRunning = serviceInstalled && await isServiceRunning();
1219
let serviceStopped = false;
1320

1421
try {
1522
if (serviceWasRunning) {
23+
const admin = await isAdmin();
24+
if (!admin) {
25+
throw new Error('Windows Service is running but this shell is not elevated. Re-run as Administrator or stop the service manually before update.');
26+
}
1627
logger.info('Stopping Windows Service before update...');
1728
await stopService();
1829
serviceStopped = true;
1930
}
2031

21-
if (await isRunning()) {
32+
const processRunning = await isRunning();
33+
if (processRunning) {
2234
logger.info('Stopping running proxy before update...');
2335
await stopProxy();
2436
}
2537

2638
logger.info('Checking for updates...');
27-
const version = await getLatestVersion();
28-
logger.info(`Latest version is ${version}. Updating...`);
29-
await downloadProxy(version);
30-
logger.info('Update successful.');
39+
const version = options.version || await getLatestVersion(Number(options.timeout));
40+
41+
if (options.checkOnly) {
42+
if (options.json) {
43+
console.log(JSON.stringify({ ok: true, latestVersion: version, checkOnly: true }));
44+
} else {
45+
logger.info(`Latest version is ${version}.`);
46+
}
47+
return;
48+
}
49+
50+
logger.info(`Target version is ${version}. Updating...`);
51+
await downloadProxy(version, {
52+
baseUrl: options.baseUrl,
53+
timeoutMs: Number(options.timeout),
54+
retries: Number(options.retries)
55+
});
56+
57+
if (options.json) {
58+
console.log(JSON.stringify({ ok: true, version, updated: true }));
59+
} else {
60+
logger.info('Update successful.');
61+
}
3162
} catch (error) {
32-
logger.error('Update failed', error);
63+
if (options.json) {
64+
console.log(JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) }));
65+
} else {
66+
logger.error('Update failed', error);
67+
}
3368
process.exit(1);
3469
} finally {
3570
if (serviceStopped) {

0 commit comments

Comments
 (0)