@ongtrieuhau861457/runner-tailscale-sync 1.260202.11948 → 1.260202.12010
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -30
- package/bin/runner-sync.js +10 -42
- package/package.json +1 -1
- package/src/cli/parser.js +19 -35
- package/src/core/sync-orchestrator.js +33 -22
- package/src/index.js +0 -3
package/README.md
CHANGED
|
@@ -26,61 +26,55 @@ npm install -g runner-tailscale-sync
|
|
|
26
26
|
### CLI
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
#
|
|
29
|
+
# Run full workflow (init → detect → pull → stop → push)
|
|
30
30
|
TAILSCALE_ENABLE=1 runner-sync
|
|
31
31
|
|
|
32
|
-
# Chỉ khởi tạo Tailscale
|
|
33
|
-
runner-sync init
|
|
34
|
-
|
|
35
|
-
# Chỉ push git
|
|
36
|
-
runner-sync push
|
|
37
|
-
|
|
38
|
-
# Xem status
|
|
39
|
-
runner-sync status
|
|
40
|
-
|
|
41
32
|
# Custom working directory
|
|
42
33
|
runner-sync --cwd /path/to/project
|
|
43
34
|
|
|
44
35
|
# Verbose mode
|
|
45
|
-
runner-sync
|
|
36
|
+
runner-sync --verbose
|
|
37
|
+
|
|
38
|
+
# Quiet mode
|
|
39
|
+
runner-sync --quiet
|
|
46
40
|
```
|
|
47
41
|
|
|
42
|
+
**Workflow tự động**:
|
|
43
|
+
|
|
44
|
+
1. **Init**: Cài đặt Tailscale và kết nối mạng
|
|
45
|
+
2. **Detect**: Tìm runner trước đó (cùng tag)
|
|
46
|
+
3. **Pull**: Đồng bộ `.runner-data` từ runner cũ (nếu có)
|
|
47
|
+
4. **Stop**: Dừng services trên runner cũ (nếu có)
|
|
48
|
+
5. **Push**: Đẩy `.runner-data` lên git (nếu có runner cũ)
|
|
49
|
+
|
|
48
50
|
### Library
|
|
49
51
|
|
|
50
52
|
```javascript
|
|
51
|
-
const runnerSync = require(
|
|
53
|
+
const runnerSync = require("runner-tailscale-sync");
|
|
52
54
|
|
|
53
|
-
//
|
|
55
|
+
// Run full workflow
|
|
54
56
|
await runnerSync.sync({
|
|
55
|
-
cwd:
|
|
57
|
+
cwd: "/path/to/project",
|
|
56
58
|
verbose: true,
|
|
57
59
|
});
|
|
58
60
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
+
// Access individual modules (advanced)
|
|
62
|
+
const { Config, Logger, syncOrchestrator } = require("runner-tailscale-sync");
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
const config = new Config({ cwd: process.cwd() });
|
|
65
|
+
const logger = new Logger({ packageName: "my-tool", version: "1.0.0" });
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
await runnerSync.status();
|
|
67
|
+
await syncOrchestrator.orchestrate(config, logger);
|
|
67
68
|
```
|
|
68
69
|
|
|
69
70
|
### Advanced Usage - Sử dụng modules riêng lẻ
|
|
70
71
|
|
|
71
72
|
```javascript
|
|
72
|
-
const {
|
|
73
|
-
Config,
|
|
74
|
-
Logger,
|
|
75
|
-
syncOrchestrator,
|
|
76
|
-
runnerDetector,
|
|
77
|
-
dataSync,
|
|
78
|
-
tailscale
|
|
79
|
-
} = require('runner-tailscale-sync');
|
|
73
|
+
const { Config, Logger, syncOrchestrator, runnerDetector, dataSync, tailscale } = require("runner-tailscale-sync");
|
|
80
74
|
|
|
81
75
|
// Tạo config
|
|
82
76
|
const config = new Config({ cwd: process.cwd() });
|
|
83
|
-
const logger = new Logger({ packageName:
|
|
77
|
+
const logger = new Logger({ packageName: "my-tool", version: "1.0.0" });
|
|
84
78
|
|
|
85
79
|
// Detect previous runner
|
|
86
80
|
const detection = await runnerDetector.detectPreviousRunner(config, logger);
|
|
@@ -177,7 +171,7 @@ Tất cả dữ liệu được lưu trong `.runner-data/`:
|
|
|
177
171
|
TAILSCALE_CLIENT_ID: $(TAILSCALE_CLIENT_ID)
|
|
178
172
|
TAILSCALE_CLIENT_SECRET: $(TAILSCALE_CLIENT_SECRET)
|
|
179
173
|
TAILSCALE_ENABLE: 1
|
|
180
|
-
displayName:
|
|
174
|
+
displayName: "Sync Runner Data"
|
|
181
175
|
```
|
|
182
176
|
|
|
183
177
|
### Self-hosted Runner
|
|
@@ -231,6 +225,7 @@ node -e "require('./src/index.js').status().then(console.log)"
|
|
|
231
225
|
Version theo giờ Việt Nam (UTC+7): `1.yyMMdd.1HHmm`
|
|
232
226
|
|
|
233
227
|
Ví dụ:
|
|
228
|
+
|
|
234
229
|
- Build lúc 15:30 ngày 02/02/2025 → `1.250202.11530`
|
|
235
230
|
- Build lúc 09:45 ngày 15/03/2025 → `1.250315.10945`
|
|
236
231
|
|
|
@@ -246,11 +241,13 @@ Ví dụ:
|
|
|
246
241
|
### Windows
|
|
247
242
|
|
|
248
243
|
Trên Windows, cần cài thêm:
|
|
244
|
+
|
|
249
245
|
- [Tailscale for Windows](https://tailscale.com/download/windows)
|
|
250
246
|
- Git for Windows (có sẵn ssh/scp)
|
|
251
247
|
- Hoặc cài rsync qua: `choco install rsync` hoặc WSL
|
|
252
248
|
|
|
253
249
|
Cấu hình đường dẫn trong `.env`:
|
|
250
|
+
|
|
254
251
|
```env
|
|
255
252
|
SSH_PATH=C:\Program Files\Git\usr\bin\ssh.exe
|
|
256
253
|
RSYNC_PATH=C:\Program Files\rsync\rsync.exe
|
package/bin/runner-sync.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* bin/runner-sync.js
|
|
4
|
-
* CLI entry point
|
|
4
|
+
* CLI entry point - Always run full workflow
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const path = require("path");
|
|
8
7
|
const Config = require("../src/utils/config");
|
|
9
8
|
const Logger = require("../src/utils/logger");
|
|
10
9
|
const { parseArgs, printHelp } = require("../src/cli/parser");
|
|
10
|
+
const syncOrchestrator = require("../src/core/sync-orchestrator");
|
|
11
11
|
const pkg = require("../package.json");
|
|
12
12
|
|
|
13
13
|
// Parse arguments
|
|
14
|
-
const {
|
|
14
|
+
const { options } = parseArgs(process.argv);
|
|
15
15
|
|
|
16
16
|
// Handle help
|
|
17
17
|
if (options.help) {
|
|
@@ -20,19 +20,17 @@ if (options.help) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// Handle version
|
|
23
|
-
if (
|
|
23
|
+
if (options.version) {
|
|
24
24
|
console.log(`${pkg.name} v${pkg.version}`);
|
|
25
25
|
process.exit(0);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
// Create config
|
|
28
|
+
// Create config & logger
|
|
29
29
|
const config = new Config(options);
|
|
30
|
-
|
|
31
|
-
// Create logger
|
|
32
30
|
const logger = new Logger({
|
|
33
31
|
packageName: pkg.name,
|
|
34
32
|
version: pkg.version,
|
|
35
|
-
command,
|
|
33
|
+
command: "sync",
|
|
36
34
|
verbose: options.verbose,
|
|
37
35
|
quiet: options.quiet,
|
|
38
36
|
});
|
|
@@ -40,46 +38,16 @@ const logger = new Logger({
|
|
|
40
38
|
// Print banner
|
|
41
39
|
logger.printBanner();
|
|
42
40
|
|
|
43
|
-
// Run
|
|
41
|
+
// Run full workflow
|
|
44
42
|
(async () => {
|
|
45
43
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
switch (command) {
|
|
49
|
-
case "init":
|
|
50
|
-
commandModule = require("../src/cli/commands/init");
|
|
51
|
-
break;
|
|
52
|
-
case "sync":
|
|
53
|
-
commandModule = require("../src/cli/commands/sync");
|
|
54
|
-
break;
|
|
55
|
-
case "push":
|
|
56
|
-
commandModule = require("../src/cli/commands/push");
|
|
57
|
-
break;
|
|
58
|
-
case "status":
|
|
59
|
-
commandModule = require("../src/cli/commands/status");
|
|
60
|
-
break;
|
|
61
|
-
default:
|
|
62
|
-
logger.error(`Unknown command: ${command}`);
|
|
63
|
-
printHelp();
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const result = await commandModule.run(config, logger);
|
|
68
|
-
|
|
69
|
-
if (result.success) {
|
|
70
|
-
process.exit(0);
|
|
71
|
-
} else {
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
44
|
+
const result = await syncOrchestrator.orchestrate(config, logger);
|
|
45
|
+
process.exit(result.success ? 0 : 1);
|
|
74
46
|
} catch (err) {
|
|
75
47
|
logger.error(err.message);
|
|
76
|
-
|
|
77
48
|
if (options.verbose && err.stack) {
|
|
78
49
|
logger.debug(err.stack);
|
|
79
50
|
}
|
|
80
|
-
|
|
81
|
-
// Exit with appropriate code
|
|
82
|
-
const exitCode = err.exitCode || 1;
|
|
83
|
-
process.exit(exitCode);
|
|
51
|
+
process.exit(err.exitCode || 1);
|
|
84
52
|
}
|
|
85
53
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ongtrieuhau861457/runner-tailscale-sync",
|
|
3
|
-
"version": "1.260202.
|
|
3
|
+
"version": "1.260202.12010",
|
|
4
4
|
"description": "Đồng bộ runner-data giữa các runner trên GitHub Actions, Azure Pipeline qua Tailscale network",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/cli/parser.js
CHANGED
|
@@ -3,32 +3,20 @@
|
|
|
3
3
|
* Parse command-line arguments
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Parse command line arguments
|
|
8
|
-
* Returns: { command, options }
|
|
9
|
-
*/
|
|
10
6
|
function parseArgs(argv) {
|
|
11
|
-
const args = argv.slice(2);
|
|
7
|
+
const args = argv.slice(2);
|
|
12
8
|
|
|
13
9
|
const options = {
|
|
14
10
|
cwd: null,
|
|
15
11
|
verbose: false,
|
|
16
12
|
quiet: false,
|
|
17
13
|
help: false,
|
|
14
|
+
version: false,
|
|
18
15
|
};
|
|
19
16
|
|
|
20
|
-
let command = "sync"; // Default command
|
|
21
|
-
|
|
22
17
|
for (let i = 0; i < args.length; i++) {
|
|
23
18
|
const arg = args[i];
|
|
24
19
|
|
|
25
|
-
// Commands
|
|
26
|
-
if (arg === "init" || arg === "sync" || arg === "push" || arg === "status") {
|
|
27
|
-
command = arg;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Options
|
|
32
20
|
if (arg === "--cwd" && i + 1 < args.length) {
|
|
33
21
|
options.cwd = args[++i];
|
|
34
22
|
continue;
|
|
@@ -50,60 +38,56 @@ function parseArgs(argv) {
|
|
|
50
38
|
}
|
|
51
39
|
|
|
52
40
|
if (arg === "--version") {
|
|
53
|
-
|
|
41
|
+
options.version = true;
|
|
54
42
|
continue;
|
|
55
43
|
}
|
|
56
44
|
}
|
|
57
45
|
|
|
58
|
-
return {
|
|
46
|
+
return { options };
|
|
59
47
|
}
|
|
60
48
|
|
|
61
|
-
/**
|
|
62
|
-
* Print help
|
|
63
|
-
*/
|
|
64
49
|
function printHelp() {
|
|
65
50
|
console.log(`
|
|
66
51
|
runner-tailscale-sync - Đồng bộ runner data qua Tailscale network
|
|
67
52
|
|
|
68
53
|
USAGE:
|
|
69
|
-
runner-sync [
|
|
54
|
+
runner-sync [options]
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
DESCRIPTION:
|
|
57
|
+
Tự động chạy workflow: init → detect → pull → stop → push
|
|
58
|
+
- Init: Cài đặt và kết nối Tailscale
|
|
59
|
+
- Detect: Tìm runner trước đó trên mạng
|
|
60
|
+
- Pull: Đồng bộ .runner-data (nếu có runner cũ)
|
|
61
|
+
- Stop: Dừng services trên runner cũ (nếu có)
|
|
62
|
+
- Push: Đẩy code lên git
|
|
77
63
|
|
|
78
64
|
OPTIONS:
|
|
79
65
|
--cwd <path> Set working directory (default: current dir)
|
|
80
|
-
--verbose
|
|
81
|
-
--quiet
|
|
66
|
+
--verbose Enable verbose logging
|
|
67
|
+
--quiet Suppress non-error output
|
|
82
68
|
--help, -h Show this help
|
|
69
|
+
--version Show version
|
|
83
70
|
|
|
84
71
|
ENVIRONMENT VARIABLES:
|
|
85
72
|
TAILSCALE_CLIENT_ID OAuth client ID (required if TAILSCALE_ENABLE=1)
|
|
86
73
|
TAILSCALE_CLIENT_SECRET OAuth client secret (required if TAILSCALE_ENABLE=1)
|
|
87
74
|
TAILSCALE_TAGS Tailscale tags (default: tag:ci)
|
|
88
75
|
TAILSCALE_ENABLE Enable Tailscale (0 or 1, default: 0)
|
|
89
|
-
SERVICES_TO_STOP
|
|
76
|
+
SERVICES_TO_STOP Services to stop on old runner (default: cloudflared,pocketbase)
|
|
90
77
|
GIT_PUSH_ENABLED Enable git push (0 or 1, default: 1)
|
|
91
78
|
GIT_BRANCH Git branch (default: main)
|
|
92
79
|
TOOL_CWD Working directory (can be overridden by --cwd)
|
|
93
80
|
|
|
94
81
|
EXAMPLES:
|
|
95
|
-
#
|
|
82
|
+
# Run full workflow
|
|
96
83
|
TAILSCALE_ENABLE=1 runner-sync
|
|
97
84
|
|
|
98
|
-
#
|
|
99
|
-
runner-sync
|
|
85
|
+
# Verbose mode
|
|
86
|
+
runner-sync --verbose
|
|
100
87
|
|
|
101
88
|
# Custom working directory
|
|
102
89
|
runner-sync --cwd /path/to/project
|
|
103
90
|
|
|
104
|
-
# Verbose mode
|
|
105
|
-
runner-sync -v
|
|
106
|
-
|
|
107
91
|
For more info: https://github.com/yourname/runner-tailscale-sync
|
|
108
92
|
`);
|
|
109
93
|
}
|
|
@@ -50,9 +50,6 @@ function plan(input) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/**
|
|
54
|
-
* Execute - chạy từng bước
|
|
55
|
-
*/
|
|
56
53
|
async function execute(planResult, input) {
|
|
57
54
|
const { config, logger } = input;
|
|
58
55
|
const results = {};
|
|
@@ -77,25 +74,45 @@ async function execute(planResult, input) {
|
|
|
77
74
|
|
|
78
75
|
case "detect_previous_runner":
|
|
79
76
|
results.detection = await runnerDetector.detectPreviousRunner(config, logger);
|
|
77
|
+
|
|
78
|
+
// Set flag for later steps
|
|
79
|
+
const hasPreviousRunner = results.detection?.previousRunner != null;
|
|
80
|
+
|
|
81
|
+
if (!hasPreviousRunner) {
|
|
82
|
+
logger.info("No previous runner detected - skipping pull/stop/push");
|
|
83
|
+
}
|
|
80
84
|
break;
|
|
81
85
|
|
|
82
86
|
case "pull_data":
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
// Check if we have previous runner
|
|
88
|
+
if (!results.detection?.previousRunner) {
|
|
89
|
+
logger.info("Skipping pull - no previous runner");
|
|
90
|
+
results.pullData = { success: true, skipped: true };
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
results.pullData = await dataSync.pullData(config, results.detection.previousRunner, logger);
|
|
88
95
|
break;
|
|
89
96
|
|
|
90
97
|
case "stop_remote_services":
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
// Check if we have previous runner
|
|
99
|
+
if (!results.detection?.previousRunner) {
|
|
100
|
+
logger.info("Skipping service stop - no previous runner");
|
|
101
|
+
results.stopServices = { success: true, skipped: true };
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
results.stopServices = await serviceController.stopRemoteServices(config, results.detection.previousRunner, logger);
|
|
96
106
|
break;
|
|
97
107
|
|
|
98
108
|
case "push_to_git":
|
|
109
|
+
// Check if we have previous runner
|
|
110
|
+
if (!results.detection?.previousRunner) {
|
|
111
|
+
logger.info("Skipping git push - no previous runner");
|
|
112
|
+
results.pushGit = { success: true, skipped: true };
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
|
|
99
116
|
results.pushGit = await pushToGit(config, logger);
|
|
100
117
|
break;
|
|
101
118
|
|
|
@@ -150,7 +167,7 @@ function report(results, input) {
|
|
|
150
167
|
*/
|
|
151
168
|
async function setupDirectories(config, logger) {
|
|
152
169
|
logger.info("Setting up directories...");
|
|
153
|
-
|
|
170
|
+
|
|
154
171
|
const dirs = config.getDirectoriesToEnsure();
|
|
155
172
|
fs_adapter.ensureDirs(dirs);
|
|
156
173
|
|
|
@@ -175,13 +192,7 @@ async function connectTailscale(config, logger) {
|
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
// Login
|
|
178
|
-
await tailscale.login(
|
|
179
|
-
config.tailscaleClientId,
|
|
180
|
-
config.tailscaleClientSecret,
|
|
181
|
-
config.tailscaleTags,
|
|
182
|
-
logger,
|
|
183
|
-
config
|
|
184
|
-
);
|
|
195
|
+
await tailscale.login(config.tailscaleClientId, config.tailscaleClientSecret, config.tailscaleTags, logger, config);
|
|
185
196
|
|
|
186
197
|
// Get connection info
|
|
187
198
|
const ip = tailscale.getIP(logger);
|
|
@@ -241,7 +252,7 @@ async function orchestrate(config, logger) {
|
|
|
241
252
|
|
|
242
253
|
// Step 3: Plan
|
|
243
254
|
const planResult = plan(input);
|
|
244
|
-
logger.debug(`Planned ${planResult.steps.filter(s => s.enabled).length} steps`);
|
|
255
|
+
logger.debug(`Planned ${planResult.steps.filter((s) => s.enabled).length} steps`);
|
|
245
256
|
|
|
246
257
|
// Step 4: Execute
|
|
247
258
|
const execResult = await execute(planResult, input);
|