cloud-ide-cide 2.0.34 → 2.0.35
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/deployer/node/upload-api.js +30 -55
- package/package.json +1 -1
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Reads config from: ../.cide/config.json (token, paths)
|
|
6
6
|
* Writes state to: ../.cide/deployments.json
|
|
7
|
-
*
|
|
8
|
-
* Stores
|
|
7
|
+
* Extracts code to: {server_root}/{appCode}/ (live app directory)
|
|
8
|
+
* Stores zips in: ../.cide/releases/{appCode}/{version}.zip (for rollback)
|
|
9
9
|
* Logs to: ../.cide/logs/deploy.log
|
|
10
|
-
* Symlinks: {server_root}/current/{appCode} → active release
|
|
11
10
|
*
|
|
12
11
|
* Endpoints (all except /health require Authorization: Bearer <token>):
|
|
13
12
|
*
|
|
@@ -36,9 +35,7 @@ try { config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')); } catch { /* no
|
|
|
36
35
|
const TOKEN = config.token || process.env.CIDE_UPLOAD_TOKEN || '';
|
|
37
36
|
const PORT = process.env.CIDE_UPLOAD_PORT || process.env.PORT || 4500;
|
|
38
37
|
const RELEASES = config.paths?.releases || path.join(CIDE_DIR, 'releases');
|
|
39
|
-
const BACKUPS = config.paths?.backups || path.join(CIDE_DIR, 'backups');
|
|
40
38
|
const LOGS = config.paths?.logs || path.join(CIDE_DIR, 'logs');
|
|
41
|
-
const CURRENT_DIR = config.paths?.current || path.join(path.dirname(CIDE_DIR), 'current');
|
|
42
39
|
const DEPLOYMENTS = path.join(CIDE_DIR, 'deployments.json');
|
|
43
40
|
|
|
44
41
|
const upload = multer({ dest: path.join(CIDE_DIR, 'tmp') });
|
|
@@ -59,37 +56,6 @@ function appendLog(message) {
|
|
|
59
56
|
try { fs.appendFileSync(logFile, line); } catch { /* logs dir may not exist yet */ }
|
|
60
57
|
}
|
|
61
58
|
|
|
62
|
-
function switchCurrent(currentPath, releasePath) {
|
|
63
|
-
fs.mkdirSync(path.dirname(currentPath), { recursive: true });
|
|
64
|
-
try {
|
|
65
|
-
const stat = fs.lstatSync(currentPath);
|
|
66
|
-
if (stat.isSymbolicLink()) {
|
|
67
|
-
fs.unlinkSync(currentPath);
|
|
68
|
-
} else if (stat.isDirectory()) {
|
|
69
|
-
fs.renameSync(currentPath, `${currentPath}_bak_${Date.now()}`);
|
|
70
|
-
}
|
|
71
|
-
} catch { /* doesn't exist yet */ }
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
fs.symlinkSync(releasePath, currentPath, 'junction');
|
|
75
|
-
} catch {
|
|
76
|
-
copyRecursive(releasePath, currentPath);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function copyRecursive(src, dst) {
|
|
81
|
-
fs.mkdirSync(dst, { recursive: true });
|
|
82
|
-
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
83
|
-
const srcPath = path.join(src, entry.name);
|
|
84
|
-
const dstPath = path.join(dst, entry.name);
|
|
85
|
-
if (entry.isDirectory()) {
|
|
86
|
-
copyRecursive(srcPath, dstPath);
|
|
87
|
-
} else {
|
|
88
|
-
fs.copyFileSync(srcPath, dstPath);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
59
|
// ── Auth middleware ───────────────────────────────────────────────────────────
|
|
94
60
|
function authGuard(req, res, next) {
|
|
95
61
|
if (!TOKEN) {
|
|
@@ -103,6 +69,9 @@ function authGuard(req, res, next) {
|
|
|
103
69
|
next();
|
|
104
70
|
}
|
|
105
71
|
|
|
72
|
+
// ── Server root (parent of .cide/) ───────────────────────────────────────────
|
|
73
|
+
const SERVER_ROOT = config.serverRoot || path.dirname(CIDE_DIR);
|
|
74
|
+
|
|
106
75
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
107
76
|
// ── Upload ────────────────────────────────────────────────────────────────────
|
|
108
77
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -122,31 +91,32 @@ app.post('/upload', authGuard, upload.single('file'), (req, res) => {
|
|
|
122
91
|
}
|
|
123
92
|
|
|
124
93
|
const version = new Date().toISOString().replace(/[:.]/g, '-').replace('T', '_').slice(0, 19);
|
|
125
|
-
const releasePath = path.join(RELEASES, appCode, version);
|
|
126
|
-
const currentPath = path.join(CURRENT_DIR, appCode);
|
|
127
94
|
|
|
128
|
-
// ──
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
95
|
+
// ── Live app directory at server root ────────────────────────────────
|
|
96
|
+
const appDir = path.join(SERVER_ROOT, appCode);
|
|
97
|
+
|
|
98
|
+
// ── Save zip to releases for rollback ────────────────────────────────
|
|
99
|
+
const releaseDir = path.join(RELEASES, appCode);
|
|
100
|
+
fs.mkdirSync(releaseDir, { recursive: true });
|
|
101
|
+
const releaseZipPath = path.join(releaseDir, `${version}.zip`);
|
|
102
|
+
fs.copyFileSync(req.file.path, releaseZipPath);
|
|
132
103
|
|
|
133
|
-
// ── Extract
|
|
104
|
+
// ── Extract directly to {server_root}/{appCode}/ ─────────────────────
|
|
105
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
134
106
|
const zip = new AdmZip(req.file.path);
|
|
135
|
-
|
|
136
|
-
zip.extractAllTo(releasePath, true);
|
|
107
|
+
zip.extractAllTo(appDir, true);
|
|
137
108
|
fs.unlinkSync(req.file.path);
|
|
138
109
|
|
|
139
110
|
// ── Track state ──────────────────────────────────────────────────────
|
|
140
111
|
const deployments = loadDeployments();
|
|
141
112
|
const previousVersion = deployments.apps?.[appCode]?.current?.version || null;
|
|
142
113
|
|
|
143
|
-
switchCurrent(currentPath, releasePath);
|
|
144
|
-
|
|
145
114
|
// ── Record ───────────────────────────────────────────────────────────
|
|
146
115
|
const record = {
|
|
147
116
|
version,
|
|
148
117
|
environment,
|
|
149
|
-
|
|
118
|
+
appDir,
|
|
119
|
+
releaseZip: releaseZipPath,
|
|
150
120
|
deployedAt: new Date().toISOString(),
|
|
151
121
|
action: 'upload',
|
|
152
122
|
message: deployMsg,
|
|
@@ -169,7 +139,8 @@ app.post('/upload', authGuard, upload.single('file'), (req, res) => {
|
|
|
169
139
|
environment,
|
|
170
140
|
releaseVersion: version,
|
|
171
141
|
previousVersion,
|
|
172
|
-
|
|
142
|
+
appDir,
|
|
143
|
+
releaseZip: releaseZipPath,
|
|
173
144
|
completedAt: new Date().toISOString(),
|
|
174
145
|
});
|
|
175
146
|
} catch (err) {
|
|
@@ -211,21 +182,25 @@ app.post('/rollback', authGuard, (req, res) => {
|
|
|
211
182
|
return res.status(422).json({ status: 'FAILED', message: 'Missing required fields: appCode, version' });
|
|
212
183
|
}
|
|
213
184
|
|
|
214
|
-
const
|
|
215
|
-
if (!fs.existsSync(
|
|
216
|
-
return res.status(404).json({ status: 'FAILED', message: `Release not found: ${version}` });
|
|
185
|
+
const releaseZipPath = path.join(RELEASES, appCode, `${version}.zip`);
|
|
186
|
+
if (!fs.existsSync(releaseZipPath)) {
|
|
187
|
+
return res.status(404).json({ status: 'FAILED', message: `Release zip not found: ${version}` });
|
|
217
188
|
}
|
|
218
189
|
|
|
219
|
-
const
|
|
190
|
+
const appDir = path.join(SERVER_ROOT, appCode);
|
|
220
191
|
const deployments = loadDeployments();
|
|
221
192
|
const previousVersion = deployments.apps?.[appCode]?.current?.version || null;
|
|
222
193
|
|
|
223
|
-
|
|
194
|
+
// Re-extract the zip to the app directory
|
|
195
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
196
|
+
const zip = new AdmZip(releaseZipPath);
|
|
197
|
+
zip.extractAllTo(appDir, true);
|
|
224
198
|
|
|
225
199
|
const record = {
|
|
226
200
|
version,
|
|
227
201
|
environment: deployments.apps?.[appCode]?.current?.environment || 'production',
|
|
228
|
-
|
|
202
|
+
appDir,
|
|
203
|
+
releaseZip: releaseZipPath,
|
|
229
204
|
deployedAt: new Date().toISOString(),
|
|
230
205
|
action: 'rollback',
|
|
231
206
|
previousVersion,
|