@geekmidas/cli 1.0.2 → 1.2.0
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/CHANGELOG.md +12 -0
- package/dist/{SSMStateProvider-C4wp4AZe.mjs → SSMStateProvider-BjCi_58g.mjs} +16 -7
- package/dist/SSMStateProvider-BjCi_58g.mjs.map +1 -0
- package/dist/{SSMStateProvider-BxAPU99a.cjs → SSMStateProvider-D79o_JjM.cjs} +16 -7
- package/dist/SSMStateProvider-D79o_JjM.cjs.map +1 -0
- package/dist/{config-C6awcFBx.mjs → config-BQ4a36Rq.mjs} +2 -2
- package/dist/{config-C6awcFBx.mjs.map → config-BQ4a36Rq.mjs.map} +1 -1
- package/dist/{config-BGeJsW1r.cjs → config-Bayob8pB.cjs} +2 -2
- package/dist/{config-BGeJsW1r.cjs.map → config-Bayob8pB.cjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +2 -2
- package/dist/{index-KFEbMIRa.d.mts → index-Bi9vGQJy.d.mts} +61 -13
- package/dist/index-Bi9vGQJy.d.mts.map +1 -0
- package/dist/{index-B5rGIc4g.d.cts → index-CufAAnge.d.cts} +61 -13
- package/dist/index-CufAAnge.d.cts.map +1 -0
- package/dist/index.cjs +14 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +14 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-D1KXv2Ml.cjs → openapi-BZP8jkI4.cjs} +2 -2
- package/dist/{openapi-D1KXv2Ml.cjs.map → openapi-BZP8jkI4.cjs.map} +1 -1
- package/dist/{openapi-BMFmLnX6.mjs → openapi-DrbBWq0s.mjs} +2 -2
- package/dist/{openapi-BMFmLnX6.mjs.map → openapi-DrbBWq0s.mjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.mjs +3 -3
- package/dist/workspace/index.cjs +2 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +2 -2
- package/dist/{workspace-BFRUOOrh.cjs → workspace-BMJE18LV.cjs} +46 -6
- package/dist/workspace-BMJE18LV.cjs.map +1 -0
- package/dist/{workspace-DAxG3_H2.mjs → workspace-CASoZOjs.mjs} +41 -7
- package/dist/workspace-CASoZOjs.mjs.map +1 -0
- package/package.json +4 -4
- package/src/deploy/SSMStateProvider.ts +20 -7
- package/src/deploy/StateProvider.ts +1 -1
- package/src/deploy/__tests__/CachedStateProvider.spec.ts +7 -0
- package/src/deploy/__tests__/LocalStateProvider.spec.ts +4 -0
- package/src/deploy/__tests__/SSMStateProvider.spec.ts +20 -8
- package/src/deploy/__tests__/dns-verification.spec.ts +1 -1
- package/src/deploy/__tests__/env-resolver.spec.ts +9 -9
- package/src/deploy/__tests__/state-e2e.spec.ts +387 -0
- package/src/deploy/__tests__/state.spec.ts +53 -29
- package/src/deploy/index.ts +6 -1
- package/src/deploy/state.ts +4 -0
- package/src/init/__tests__/init.spec.ts +10 -1
- package/src/init/versions.ts +1 -1
- package/src/secrets/__tests__/storage.spec.ts +6 -2
- package/src/workspace/__tests__/index.spec.ts +129 -0
- package/src/workspace/index.ts +44 -0
- package/src/workspace/schema.ts +17 -6
- package/src/workspace/types.ts +26 -9
- package/dist/SSMStateProvider-BxAPU99a.cjs.map +0 -1
- package/dist/SSMStateProvider-C4wp4AZe.mjs.map +0 -1
- package/dist/index-B5rGIc4g.d.cts.map +0 -1
- package/dist/index-KFEbMIRa.d.mts.map +0 -1
- package/dist/workspace-BFRUOOrh.cjs.map +0 -1
- package/dist/workspace-DAxG3_H2.mjs.map +0 -1
|
@@ -39,11 +39,12 @@ describe('state management', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
describe('createEmptyState', () => {
|
|
42
|
-
it('should create a valid empty state', () => {
|
|
43
|
-
const state = createEmptyState('production', 'env_123');
|
|
42
|
+
it('should create a valid empty state with projectId', () => {
|
|
43
|
+
const state = createEmptyState('production', 'proj_123', 'env_123');
|
|
44
44
|
|
|
45
45
|
expect(state.provider).toBe('dokploy');
|
|
46
46
|
expect(state.stage).toBe('production');
|
|
47
|
+
expect(state.projectId).toBe('proj_123');
|
|
47
48
|
expect(state.environmentId).toBe('env_123');
|
|
48
49
|
expect(state.applications).toEqual({});
|
|
49
50
|
expect(state.services).toEqual({});
|
|
@@ -51,7 +52,7 @@ describe('state management', () => {
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
it('should generate valid ISO timestamp', () => {
|
|
54
|
-
const state = createEmptyState('staging', 'env_456');
|
|
55
|
+
const state = createEmptyState('staging', 'proj_test', 'env_456');
|
|
55
56
|
|
|
56
57
|
expect(() => new Date(state.lastDeployedAt)).not.toThrow();
|
|
57
58
|
});
|
|
@@ -68,6 +69,7 @@ describe('state management', () => {
|
|
|
68
69
|
const stateData: DokployStageState = {
|
|
69
70
|
provider: 'dokploy',
|
|
70
71
|
stage: 'production',
|
|
72
|
+
projectId: 'proj_test',
|
|
71
73
|
environmentId: 'env_123',
|
|
72
74
|
applications: { api: 'app_123' },
|
|
73
75
|
services: { postgresId: 'pg_123' },
|
|
@@ -100,7 +102,7 @@ describe('state management', () => {
|
|
|
100
102
|
|
|
101
103
|
describe('writeStageState', () => {
|
|
102
104
|
it('should create .gkm directory if not exists', async () => {
|
|
103
|
-
const state = createEmptyState('staging', 'env_456');
|
|
105
|
+
const state = createEmptyState('staging', 'proj_test', 'env_456');
|
|
104
106
|
|
|
105
107
|
await writeStageState(testDir, 'staging', state);
|
|
106
108
|
|
|
@@ -112,7 +114,7 @@ describe('state management', () => {
|
|
|
112
114
|
});
|
|
113
115
|
|
|
114
116
|
it('should update lastDeployedAt timestamp', async () => {
|
|
115
|
-
const state = createEmptyState('staging', 'env_456');
|
|
117
|
+
const state = createEmptyState('staging', 'proj_test', 'env_456');
|
|
116
118
|
const originalTimestamp = state.lastDeployedAt;
|
|
117
119
|
|
|
118
120
|
// Wait a bit to ensure different timestamp
|
|
@@ -127,6 +129,7 @@ describe('state management', () => {
|
|
|
127
129
|
const state: DokployStageState = {
|
|
128
130
|
provider: 'dokploy',
|
|
129
131
|
stage: 'production',
|
|
132
|
+
projectId: 'proj_test',
|
|
130
133
|
environmentId: 'env_123',
|
|
131
134
|
applications: { api: 'app_123', web: 'app_456' },
|
|
132
135
|
services: { postgresId: 'pg_123', redisId: 'redis_123' },
|
|
@@ -158,6 +161,7 @@ describe('state management', () => {
|
|
|
158
161
|
const state: DokployStageState = {
|
|
159
162
|
provider: 'dokploy',
|
|
160
163
|
stage: 'production',
|
|
164
|
+
projectId: 'proj_test',
|
|
161
165
|
environmentId: 'env_123',
|
|
162
166
|
applications: { api: 'app_123' },
|
|
163
167
|
services: {},
|
|
@@ -171,6 +175,7 @@ describe('state management', () => {
|
|
|
171
175
|
const state: DokployStageState = {
|
|
172
176
|
provider: 'dokploy',
|
|
173
177
|
stage: 'production',
|
|
178
|
+
projectId: 'proj_test',
|
|
174
179
|
environmentId: 'env_123',
|
|
175
180
|
applications: {},
|
|
176
181
|
services: {},
|
|
@@ -187,7 +192,7 @@ describe('state management', () => {
|
|
|
187
192
|
|
|
188
193
|
describe('setApplicationId', () => {
|
|
189
194
|
it('should set application ID', () => {
|
|
190
|
-
const state = createEmptyState('production', 'env_123');
|
|
195
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
191
196
|
|
|
192
197
|
setApplicationId(state, 'api', 'app_123');
|
|
193
198
|
|
|
@@ -195,7 +200,7 @@ describe('state management', () => {
|
|
|
195
200
|
});
|
|
196
201
|
|
|
197
202
|
it('should update existing application ID', () => {
|
|
198
|
-
const state = createEmptyState('production', 'env_123');
|
|
203
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
199
204
|
state.applications.api = 'app_old';
|
|
200
205
|
|
|
201
206
|
setApplicationId(state, 'api', 'app_new');
|
|
@@ -209,6 +214,7 @@ describe('state management', () => {
|
|
|
209
214
|
const state: DokployStageState = {
|
|
210
215
|
provider: 'dokploy',
|
|
211
216
|
stage: 'production',
|
|
217
|
+
projectId: 'proj_test',
|
|
212
218
|
environmentId: 'env_123',
|
|
213
219
|
applications: {},
|
|
214
220
|
services: { postgresId: 'pg_123' },
|
|
@@ -219,7 +225,7 @@ describe('state management', () => {
|
|
|
219
225
|
});
|
|
220
226
|
|
|
221
227
|
it('should return undefined when postgres not configured', () => {
|
|
222
|
-
const state = createEmptyState('production', 'env_123');
|
|
228
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
223
229
|
|
|
224
230
|
expect(getPostgresId(state)).toBeUndefined();
|
|
225
231
|
});
|
|
@@ -231,7 +237,7 @@ describe('state management', () => {
|
|
|
231
237
|
|
|
232
238
|
describe('setPostgresId', () => {
|
|
233
239
|
it('should set postgres ID', () => {
|
|
234
|
-
const state = createEmptyState('production', 'env_123');
|
|
240
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
235
241
|
|
|
236
242
|
setPostgresId(state, 'pg_123');
|
|
237
243
|
|
|
@@ -244,6 +250,7 @@ describe('state management', () => {
|
|
|
244
250
|
const state: DokployStageState = {
|
|
245
251
|
provider: 'dokploy',
|
|
246
252
|
stage: 'production',
|
|
253
|
+
projectId: 'proj_test',
|
|
247
254
|
environmentId: 'env_123',
|
|
248
255
|
applications: {},
|
|
249
256
|
services: { redisId: 'redis_123' },
|
|
@@ -254,7 +261,7 @@ describe('state management', () => {
|
|
|
254
261
|
});
|
|
255
262
|
|
|
256
263
|
it('should return undefined when redis not configured', () => {
|
|
257
|
-
const state = createEmptyState('production', 'env_123');
|
|
264
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
258
265
|
|
|
259
266
|
expect(getRedisId(state)).toBeUndefined();
|
|
260
267
|
});
|
|
@@ -266,7 +273,7 @@ describe('state management', () => {
|
|
|
266
273
|
|
|
267
274
|
describe('setRedisId', () => {
|
|
268
275
|
it('should set redis ID', () => {
|
|
269
|
-
const state = createEmptyState('production', 'env_123');
|
|
276
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
270
277
|
|
|
271
278
|
setRedisId(state, 'redis_123');
|
|
272
279
|
|
|
@@ -279,6 +286,7 @@ describe('state management', () => {
|
|
|
279
286
|
const state: DokployStageState = {
|
|
280
287
|
provider: 'dokploy',
|
|
281
288
|
stage: 'production',
|
|
289
|
+
projectId: 'proj_test',
|
|
282
290
|
environmentId: 'env_123',
|
|
283
291
|
applications: {},
|
|
284
292
|
services: {},
|
|
@@ -298,6 +306,7 @@ describe('state management', () => {
|
|
|
298
306
|
const state: DokployStageState = {
|
|
299
307
|
provider: 'dokploy',
|
|
300
308
|
stage: 'production',
|
|
309
|
+
projectId: 'proj_test',
|
|
301
310
|
environmentId: 'env_123',
|
|
302
311
|
applications: {},
|
|
303
312
|
services: {},
|
|
@@ -309,7 +318,7 @@ describe('state management', () => {
|
|
|
309
318
|
});
|
|
310
319
|
|
|
311
320
|
it('should return undefined when no appCredentials', () => {
|
|
312
|
-
const state = createEmptyState('production', 'env_123');
|
|
321
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
313
322
|
|
|
314
323
|
expect(getAppCredentials(state, 'api')).toBeUndefined();
|
|
315
324
|
});
|
|
@@ -321,7 +330,7 @@ describe('state management', () => {
|
|
|
321
330
|
|
|
322
331
|
describe('setAppCredentials', () => {
|
|
323
332
|
it('should set credentials', () => {
|
|
324
|
-
const state = createEmptyState('production', 'env_123');
|
|
333
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
325
334
|
|
|
326
335
|
setAppCredentials(state, 'api', { dbUser: 'api', dbPassword: 'secret' });
|
|
327
336
|
|
|
@@ -332,7 +341,7 @@ describe('state management', () => {
|
|
|
332
341
|
});
|
|
333
342
|
|
|
334
343
|
it('should initialize appCredentials if not exists', () => {
|
|
335
|
-
const state = createEmptyState('production', 'env_123');
|
|
344
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
336
345
|
expect(state.appCredentials).toBeUndefined();
|
|
337
346
|
|
|
338
347
|
setAppCredentials(state, 'api', { dbUser: 'api', dbPassword: 'secret' });
|
|
@@ -341,7 +350,7 @@ describe('state management', () => {
|
|
|
341
350
|
});
|
|
342
351
|
|
|
343
352
|
it('should update existing credentials', () => {
|
|
344
|
-
const state = createEmptyState('production', 'env_123');
|
|
353
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
345
354
|
state.appCredentials = {
|
|
346
355
|
api: { dbUser: 'api', dbPassword: 'old_password' },
|
|
347
356
|
};
|
|
@@ -360,6 +369,7 @@ describe('state management', () => {
|
|
|
360
369
|
const state: DokployStageState = {
|
|
361
370
|
provider: 'dokploy',
|
|
362
371
|
stage: 'production',
|
|
372
|
+
projectId: 'proj_test',
|
|
363
373
|
environmentId: 'env_123',
|
|
364
374
|
applications: {},
|
|
365
375
|
services: {},
|
|
@@ -377,7 +387,7 @@ describe('state management', () => {
|
|
|
377
387
|
});
|
|
378
388
|
|
|
379
389
|
it('should return empty object when no credentials', () => {
|
|
380
|
-
const state = createEmptyState('production', 'env_123');
|
|
390
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
381
391
|
|
|
382
392
|
expect(getAllAppCredentials(state)).toEqual({});
|
|
383
393
|
});
|
|
@@ -396,6 +406,7 @@ describe('state management', () => {
|
|
|
396
406
|
const state: DokployStageState = {
|
|
397
407
|
provider: 'dokploy',
|
|
398
408
|
stage: 'production',
|
|
409
|
+
projectId: 'proj_test',
|
|
399
410
|
environmentId: 'env_123',
|
|
400
411
|
applications: {},
|
|
401
412
|
services: {},
|
|
@@ -414,6 +425,7 @@ describe('state management', () => {
|
|
|
414
425
|
const state: DokployStageState = {
|
|
415
426
|
provider: 'dokploy',
|
|
416
427
|
stage: 'production',
|
|
428
|
+
projectId: 'proj_test',
|
|
417
429
|
environmentId: 'env_123',
|
|
418
430
|
applications: {},
|
|
419
431
|
services: {},
|
|
@@ -432,6 +444,7 @@ describe('state management', () => {
|
|
|
432
444
|
const state: DokployStageState = {
|
|
433
445
|
provider: 'dokploy',
|
|
434
446
|
stage: 'production',
|
|
447
|
+
projectId: 'proj_test',
|
|
435
448
|
environmentId: 'env_123',
|
|
436
449
|
applications: {},
|
|
437
450
|
services: {},
|
|
@@ -445,7 +458,7 @@ describe('state management', () => {
|
|
|
445
458
|
});
|
|
446
459
|
|
|
447
460
|
it('should return undefined when no generatedSecrets', () => {
|
|
448
|
-
const state = createEmptyState('production', 'env_123');
|
|
461
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
449
462
|
|
|
450
463
|
expect(
|
|
451
464
|
getGeneratedSecret(state, 'auth', 'BETTER_AUTH_SECRET'),
|
|
@@ -461,7 +474,7 @@ describe('state management', () => {
|
|
|
461
474
|
|
|
462
475
|
describe('setGeneratedSecret', () => {
|
|
463
476
|
it('should set secret', () => {
|
|
464
|
-
const state = createEmptyState('production', 'env_123');
|
|
477
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
465
478
|
|
|
466
479
|
setGeneratedSecret(state, 'auth', 'BETTER_AUTH_SECRET', 'secret123');
|
|
467
480
|
|
|
@@ -471,7 +484,7 @@ describe('state management', () => {
|
|
|
471
484
|
});
|
|
472
485
|
|
|
473
486
|
it('should initialize generatedSecrets if not exists', () => {
|
|
474
|
-
const state = createEmptyState('production', 'env_123');
|
|
487
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
475
488
|
expect(state.generatedSecrets).toBeUndefined();
|
|
476
489
|
|
|
477
490
|
setGeneratedSecret(state, 'auth', 'BETTER_AUTH_SECRET', 'secret123');
|
|
@@ -480,7 +493,7 @@ describe('state management', () => {
|
|
|
480
493
|
});
|
|
481
494
|
|
|
482
495
|
it('should initialize app secrets if not exists', () => {
|
|
483
|
-
const state = createEmptyState('production', 'env_123');
|
|
496
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
484
497
|
state.generatedSecrets = {};
|
|
485
498
|
|
|
486
499
|
setGeneratedSecret(state, 'auth', 'BETTER_AUTH_SECRET', 'secret123');
|
|
@@ -489,7 +502,7 @@ describe('state management', () => {
|
|
|
489
502
|
});
|
|
490
503
|
|
|
491
504
|
it('should update existing secret', () => {
|
|
492
|
-
const state = createEmptyState('production', 'env_123');
|
|
505
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
493
506
|
state.generatedSecrets = {
|
|
494
507
|
auth: { BETTER_AUTH_SECRET: 'old_secret' },
|
|
495
508
|
};
|
|
@@ -500,7 +513,7 @@ describe('state management', () => {
|
|
|
500
513
|
});
|
|
501
514
|
|
|
502
515
|
it('should add multiple secrets for same app', () => {
|
|
503
|
-
const state = createEmptyState('production', 'env_123');
|
|
516
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
504
517
|
|
|
505
518
|
setGeneratedSecret(state, 'auth', 'BETTER_AUTH_SECRET', 'secret1');
|
|
506
519
|
setGeneratedSecret(state, 'auth', 'OTHER_SECRET', 'secret2');
|
|
@@ -517,6 +530,7 @@ describe('state management', () => {
|
|
|
517
530
|
const state: DokployStageState = {
|
|
518
531
|
provider: 'dokploy',
|
|
519
532
|
stage: 'production',
|
|
533
|
+
projectId: 'proj_test',
|
|
520
534
|
environmentId: 'env_123',
|
|
521
535
|
applications: {},
|
|
522
536
|
services: {},
|
|
@@ -539,6 +553,7 @@ describe('state management', () => {
|
|
|
539
553
|
const state: DokployStageState = {
|
|
540
554
|
provider: 'dokploy',
|
|
541
555
|
stage: 'production',
|
|
556
|
+
projectId: 'proj_test',
|
|
542
557
|
environmentId: 'env_123',
|
|
543
558
|
applications: {},
|
|
544
559
|
services: {},
|
|
@@ -561,6 +576,7 @@ describe('state management', () => {
|
|
|
561
576
|
const state: DokployStageState = {
|
|
562
577
|
provider: 'dokploy',
|
|
563
578
|
stage: 'production',
|
|
579
|
+
projectId: 'proj_test',
|
|
564
580
|
environmentId: 'env_123',
|
|
565
581
|
applications: {},
|
|
566
582
|
services: {},
|
|
@@ -578,7 +594,7 @@ describe('state management', () => {
|
|
|
578
594
|
});
|
|
579
595
|
|
|
580
596
|
it('should return empty object when no secrets', () => {
|
|
581
|
-
const state = createEmptyState('production', 'env_123');
|
|
597
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
582
598
|
|
|
583
599
|
expect(getAllGeneratedSecrets(state)).toEqual({});
|
|
584
600
|
});
|
|
@@ -597,6 +613,7 @@ describe('state management', () => {
|
|
|
597
613
|
const state: DokployStageState = {
|
|
598
614
|
provider: 'dokploy',
|
|
599
615
|
stage: 'production',
|
|
616
|
+
projectId: 'proj_test',
|
|
600
617
|
environmentId: 'env_123',
|
|
601
618
|
applications: {},
|
|
602
619
|
services: {},
|
|
@@ -619,6 +636,7 @@ describe('state management', () => {
|
|
|
619
636
|
const state: DokployStageState = {
|
|
620
637
|
provider: 'dokploy',
|
|
621
638
|
stage: 'production',
|
|
639
|
+
projectId: 'proj_test',
|
|
622
640
|
environmentId: 'env_123',
|
|
623
641
|
applications: {},
|
|
624
642
|
services: {},
|
|
@@ -635,7 +653,7 @@ describe('state management', () => {
|
|
|
635
653
|
});
|
|
636
654
|
|
|
637
655
|
it('should return undefined when no dnsVerified', () => {
|
|
638
|
-
const state = createEmptyState('production', 'env_123');
|
|
656
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
639
657
|
|
|
640
658
|
expect(getDnsVerification(state, 'api.example.com')).toBeUndefined();
|
|
641
659
|
});
|
|
@@ -647,7 +665,7 @@ describe('state management', () => {
|
|
|
647
665
|
|
|
648
666
|
describe('setDnsVerification', () => {
|
|
649
667
|
it('should set verification record', () => {
|
|
650
|
-
const state = createEmptyState('production', 'env_123');
|
|
668
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
651
669
|
|
|
652
670
|
setDnsVerification(state, 'api.example.com', '1.2.3.4');
|
|
653
671
|
|
|
@@ -656,7 +674,7 @@ describe('state management', () => {
|
|
|
656
674
|
});
|
|
657
675
|
|
|
658
676
|
it('should initialize dnsVerified if not exists', () => {
|
|
659
|
-
const state = createEmptyState('production', 'env_123');
|
|
677
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
660
678
|
expect(state.dnsVerified).toBeUndefined();
|
|
661
679
|
|
|
662
680
|
setDnsVerification(state, 'api.example.com', '1.2.3.4');
|
|
@@ -665,7 +683,7 @@ describe('state management', () => {
|
|
|
665
683
|
});
|
|
666
684
|
|
|
667
685
|
it('should update existing verification', () => {
|
|
668
|
-
const state = createEmptyState('production', 'env_123');
|
|
686
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
669
687
|
state.dnsVerified = {
|
|
670
688
|
'api.example.com': {
|
|
671
689
|
serverIp: '1.1.1.1',
|
|
@@ -679,7 +697,7 @@ describe('state management', () => {
|
|
|
679
697
|
});
|
|
680
698
|
|
|
681
699
|
it('should generate valid ISO timestamp', () => {
|
|
682
|
-
const state = createEmptyState('production', 'env_123');
|
|
700
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
683
701
|
|
|
684
702
|
setDnsVerification(state, 'api.example.com', '1.2.3.4');
|
|
685
703
|
|
|
@@ -693,6 +711,7 @@ describe('state management', () => {
|
|
|
693
711
|
const state: DokployStageState = {
|
|
694
712
|
provider: 'dokploy',
|
|
695
713
|
stage: 'production',
|
|
714
|
+
projectId: 'proj_test',
|
|
696
715
|
environmentId: 'env_123',
|
|
697
716
|
applications: {},
|
|
698
717
|
services: {},
|
|
@@ -712,6 +731,7 @@ describe('state management', () => {
|
|
|
712
731
|
const state: DokployStageState = {
|
|
713
732
|
provider: 'dokploy',
|
|
714
733
|
stage: 'production',
|
|
734
|
+
projectId: 'proj_test',
|
|
715
735
|
environmentId: 'env_123',
|
|
716
736
|
applications: {},
|
|
717
737
|
services: {},
|
|
@@ -731,6 +751,7 @@ describe('state management', () => {
|
|
|
731
751
|
const state: DokployStageState = {
|
|
732
752
|
provider: 'dokploy',
|
|
733
753
|
stage: 'production',
|
|
754
|
+
projectId: 'proj_test',
|
|
734
755
|
environmentId: 'env_123',
|
|
735
756
|
applications: {},
|
|
736
757
|
services: {},
|
|
@@ -751,6 +772,7 @@ describe('state management', () => {
|
|
|
751
772
|
const state: DokployStageState = {
|
|
752
773
|
provider: 'dokploy',
|
|
753
774
|
stage: 'production',
|
|
775
|
+
projectId: 'proj_test',
|
|
754
776
|
environmentId: 'env_123',
|
|
755
777
|
applications: {},
|
|
756
778
|
services: {},
|
|
@@ -780,7 +802,7 @@ describe('state management', () => {
|
|
|
780
802
|
});
|
|
781
803
|
|
|
782
804
|
it('should return empty object when no verifications', () => {
|
|
783
|
-
const state = createEmptyState('production', 'env_123');
|
|
805
|
+
const state = createEmptyState('production', 'proj_test', 'env_123');
|
|
784
806
|
|
|
785
807
|
expect(getAllDnsVerifications(state)).toEqual({});
|
|
786
808
|
});
|
|
@@ -795,6 +817,7 @@ describe('state management', () => {
|
|
|
795
817
|
const state: DokployStageState = {
|
|
796
818
|
provider: 'dokploy',
|
|
797
819
|
stage: 'production',
|
|
820
|
+
projectId: 'proj_test',
|
|
798
821
|
environmentId: 'env_123',
|
|
799
822
|
applications: {},
|
|
800
823
|
services: {},
|
|
@@ -821,6 +844,7 @@ describe('state management', () => {
|
|
|
821
844
|
const state: DokployStageState = {
|
|
822
845
|
provider: 'dokploy',
|
|
823
846
|
stage: 'production',
|
|
847
|
+
projectId: 'proj_test',
|
|
824
848
|
environmentId: 'env_123',
|
|
825
849
|
applications: {},
|
|
826
850
|
services: {},
|
package/src/deploy/index.ts
CHANGED
|
@@ -1083,6 +1083,11 @@ export async function workspaceDeployCommand(
|
|
|
1083
1083
|
|
|
1084
1084
|
if (state) {
|
|
1085
1085
|
logger.log(` Found existing state for stage "${stage}"`);
|
|
1086
|
+
// Verify project ID matches (in case of recreation)
|
|
1087
|
+
if (state.projectId !== project.projectId) {
|
|
1088
|
+
logger.log(` ⚠ Project ID changed, updating state`);
|
|
1089
|
+
state.projectId = project.projectId;
|
|
1090
|
+
}
|
|
1086
1091
|
// Verify environment ID matches (in case of recreation)
|
|
1087
1092
|
if (state.environmentId !== environmentId) {
|
|
1088
1093
|
logger.log(` ⚠ Environment ID changed, updating state`);
|
|
@@ -1090,7 +1095,7 @@ export async function workspaceDeployCommand(
|
|
|
1090
1095
|
}
|
|
1091
1096
|
} else {
|
|
1092
1097
|
logger.log(` Creating new state for stage "${stage}"`);
|
|
1093
|
-
state = createEmptyState(stage, environmentId);
|
|
1098
|
+
state = createEmptyState(stage, project.projectId, environmentId);
|
|
1094
1099
|
}
|
|
1095
1100
|
|
|
1096
1101
|
// Get or set up registry
|
package/src/deploy/state.ts
CHANGED
|
@@ -30,6 +30,8 @@ export interface DnsVerificationRecord {
|
|
|
30
30
|
export interface DokployStageState {
|
|
31
31
|
provider: 'dokploy';
|
|
32
32
|
stage: string;
|
|
33
|
+
/** Dokploy project ID - created on first deploy */
|
|
34
|
+
projectId: string;
|
|
33
35
|
environmentId: string;
|
|
34
36
|
applications: Record<string, string>; // appName -> applicationId
|
|
35
37
|
services: {
|
|
@@ -101,11 +103,13 @@ export async function writeStageState(
|
|
|
101
103
|
*/
|
|
102
104
|
export function createEmptyState(
|
|
103
105
|
stage: string,
|
|
106
|
+
projectId: string,
|
|
104
107
|
environmentId: string,
|
|
105
108
|
): DokployStageState {
|
|
106
109
|
return {
|
|
107
110
|
provider: 'dokploy',
|
|
108
111
|
stage,
|
|
112
|
+
projectId,
|
|
109
113
|
environmentId,
|
|
110
114
|
applications: {},
|
|
111
115
|
services: {},
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { mkdir, readFile, rm } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
3
|
+
import { homedir, tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
6
|
import { initCommand } from '../index.js';
|
|
7
7
|
|
|
8
|
+
// Project names used in tests - keystore directories are created at ~/.gkm/{name}
|
|
9
|
+
const TEST_PROJECT_NAMES = ['my-api', 'my-monorepo', 'my-fullstack'];
|
|
10
|
+
|
|
8
11
|
describe('initCommand', () => {
|
|
9
12
|
let tempDir: string;
|
|
10
13
|
let originalCwd: string;
|
|
@@ -19,6 +22,12 @@ describe('initCommand', () => {
|
|
|
19
22
|
afterEach(async () => {
|
|
20
23
|
process.chdir(originalCwd);
|
|
21
24
|
await rm(tempDir, { recursive: true, force: true });
|
|
25
|
+
|
|
26
|
+
// Clean up keystore directories created at ~/.gkm/{project-name}
|
|
27
|
+
const gkmDir = join(homedir(), '.gkm');
|
|
28
|
+
for (const name of TEST_PROJECT_NAMES) {
|
|
29
|
+
await rm(join(gkmDir, name), { recursive: true, force: true });
|
|
30
|
+
}
|
|
22
31
|
});
|
|
23
32
|
|
|
24
33
|
describe('non-monorepo', () => {
|
package/src/init/versions.ts
CHANGED
|
@@ -45,7 +45,7 @@ export const GEEKMIDAS_VERSIONS = {
|
|
|
45
45
|
'@geekmidas/storage': '~1.0.0',
|
|
46
46
|
'@geekmidas/studio': '~1.0.0',
|
|
47
47
|
'@geekmidas/telescope': '~1.0.0',
|
|
48
|
-
'@geekmidas/testkit': '~1.0.
|
|
48
|
+
'@geekmidas/testkit': '~1.0.1',
|
|
49
49
|
'@geekmidas/cli': CLI_VERSION,
|
|
50
50
|
} as const;
|
|
51
51
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { mkdir, rm } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
3
|
+
import { homedir, tmpdir } from 'node:os';
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
5
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
6
|
import {
|
|
7
7
|
getSecretsDir,
|
|
@@ -56,6 +56,10 @@ describe('file operations', () => {
|
|
|
56
56
|
if (existsSync(tempDir)) {
|
|
57
57
|
await rm(tempDir, { recursive: true });
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
// Clean up keystore directory created at ~/.gkm/{tempDir-basename}
|
|
61
|
+
const keystoreDir = join(homedir(), '.gkm', basename(tempDir));
|
|
62
|
+
await rm(keystoreDir, { recursive: true, force: true });
|
|
59
63
|
});
|
|
60
64
|
|
|
61
65
|
describe('writeStageSecrets / readStageSecrets', () => {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
getAppBuildOrder,
|
|
6
6
|
getAppGkmConfig,
|
|
7
7
|
getDependencyEnvVars,
|
|
8
|
+
getEndpointForStage,
|
|
8
9
|
isWorkspaceConfig,
|
|
9
10
|
normalizeWorkspace,
|
|
10
11
|
processConfig,
|
|
@@ -211,6 +212,67 @@ describe('normalizeWorkspace', () => {
|
|
|
211
212
|
|
|
212
213
|
expect(result.apps.api.resolvedDeployTarget).toBe('dokploy');
|
|
213
214
|
});
|
|
215
|
+
|
|
216
|
+
it('should pass through state config when specified', () => {
|
|
217
|
+
const config: WorkspaceConfig = {
|
|
218
|
+
apps: {
|
|
219
|
+
api: {
|
|
220
|
+
type: 'backend',
|
|
221
|
+
path: 'apps/api',
|
|
222
|
+
port: 3000,
|
|
223
|
+
routes: './src/**/*.ts',
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
state: {
|
|
227
|
+
provider: 'ssm',
|
|
228
|
+
region: 'us-east-1',
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const result = normalizeWorkspace(config, '/project');
|
|
233
|
+
|
|
234
|
+
expect(result.state).toEqual({
|
|
235
|
+
provider: 'ssm',
|
|
236
|
+
region: 'us-east-1',
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should leave state undefined when not specified', () => {
|
|
241
|
+
const config: WorkspaceConfig = {
|
|
242
|
+
apps: {
|
|
243
|
+
api: {
|
|
244
|
+
type: 'backend',
|
|
245
|
+
path: 'apps/api',
|
|
246
|
+
port: 3000,
|
|
247
|
+
routes: './src/**/*.ts',
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const result = normalizeWorkspace(config, '/project');
|
|
253
|
+
|
|
254
|
+
expect(result.state).toBeUndefined();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should pass through local state config', () => {
|
|
258
|
+
const config: WorkspaceConfig = {
|
|
259
|
+
apps: {
|
|
260
|
+
api: {
|
|
261
|
+
type: 'backend',
|
|
262
|
+
path: 'apps/api',
|
|
263
|
+
port: 3000,
|
|
264
|
+
routes: './src/**/*.ts',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
state: {
|
|
268
|
+
provider: 'local',
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const result = normalizeWorkspace(config, '/project');
|
|
273
|
+
|
|
274
|
+
expect(result.state).toEqual({ provider: 'local' });
|
|
275
|
+
});
|
|
214
276
|
});
|
|
215
277
|
|
|
216
278
|
describe('wrapSingleAppAsWorkspace', () => {
|
|
@@ -540,3 +602,70 @@ describe('getDependencyEnvVars', () => {
|
|
|
540
602
|
expect(envVars).toEqual({});
|
|
541
603
|
});
|
|
542
604
|
});
|
|
605
|
+
|
|
606
|
+
describe('getEndpointForStage', () => {
|
|
607
|
+
it('should return per-stage endpoint when available', () => {
|
|
608
|
+
const config = {
|
|
609
|
+
endpoints: {
|
|
610
|
+
development: 'https://dev.dokploy.example.com:3000',
|
|
611
|
+
production: 'https://prod.dokploy.example.com:3000',
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
expect(getEndpointForStage(config, 'production')).toBe(
|
|
616
|
+
'https://prod.dokploy.example.com:3000',
|
|
617
|
+
);
|
|
618
|
+
expect(getEndpointForStage(config, 'development')).toBe(
|
|
619
|
+
'https://dev.dokploy.example.com:3000',
|
|
620
|
+
);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it('should fall back to global endpoint when per-stage not found', () => {
|
|
624
|
+
const config = {
|
|
625
|
+
endpoint: 'https://dokploy.example.com:3000',
|
|
626
|
+
endpoints: {
|
|
627
|
+
development: 'https://dev.dokploy.example.com:3000',
|
|
628
|
+
},
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
expect(getEndpointForStage(config, 'production')).toBe(
|
|
632
|
+
'https://dokploy.example.com:3000',
|
|
633
|
+
);
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
it('should return global endpoint when only endpoint is configured', () => {
|
|
637
|
+
const config = {
|
|
638
|
+
endpoint: 'https://dokploy.example.com:3000',
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
expect(getEndpointForStage(config, 'production')).toBe(
|
|
642
|
+
'https://dokploy.example.com:3000',
|
|
643
|
+
);
|
|
644
|
+
expect(getEndpointForStage(config, 'development')).toBe(
|
|
645
|
+
'https://dokploy.example.com:3000',
|
|
646
|
+
);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
it('should return undefined when config is undefined', () => {
|
|
650
|
+
expect(getEndpointForStage(undefined, 'production')).toBeUndefined();
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
it('should return undefined when neither endpoint nor endpoints is configured', () => {
|
|
654
|
+
const config = {};
|
|
655
|
+
|
|
656
|
+
expect(getEndpointForStage(config, 'production')).toBeUndefined();
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
it('should prefer per-stage endpoint over global endpoint', () => {
|
|
660
|
+
const config = {
|
|
661
|
+
endpoint: 'https://global.example.com:3000',
|
|
662
|
+
endpoints: {
|
|
663
|
+
production: 'https://prod.example.com:3000',
|
|
664
|
+
},
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
expect(getEndpointForStage(config, 'production')).toBe(
|
|
668
|
+
'https://prod.example.com:3000',
|
|
669
|
+
);
|
|
670
|
+
});
|
|
671
|
+
});
|