@zuplo/cli 6.52.23 → 6.52.24
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/dist/__tests__/populate.test.d.ts +2 -0
- package/dist/__tests__/populate.test.d.ts.map +1 -0
- package/dist/__tests__/populate.test.js +315 -0
- package/dist/__tests__/populate.test.js.map +1 -0
- package/dist/{link → common}/populate.d.ts +3 -0
- package/dist/common/populate.d.ts.map +1 -0
- package/dist/{link → common}/populate.js +75 -5
- package/dist/common/populate.js.map +1 -0
- package/dist/deploy/handler.js +1 -1
- package/dist/deploy/handler.js.map +1 -1
- package/dist/link/handler.js +2 -2
- package/dist/link/handler.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/dist/link/populate.d.ts.map +0 -1
- package/dist/link/populate.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/populate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { beforeEach, describe, it } from "node:test";
|
|
2
|
+
import { assert } from "chai";
|
|
3
|
+
import { MockAgent, setGlobalDispatcher } from "undici";
|
|
4
|
+
import { readFile, rm, mkdir } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { parse as dotenvParse } from "dotenv";
|
|
8
|
+
const TEST_ENVIRONMENT = "test-env-123";
|
|
9
|
+
const TEST_AUTH_TOKEN = "test-auth-token-456";
|
|
10
|
+
const TEST_API_ENDPOINT = "https://dev.zuplo.com";
|
|
11
|
+
describe("pullSystemConfig", () => {
|
|
12
|
+
let mockAgent;
|
|
13
|
+
let testDir;
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
mockAgent = new MockAgent();
|
|
16
|
+
mockAgent.disableNetConnect();
|
|
17
|
+
setGlobalDispatcher(mockAgent);
|
|
18
|
+
testDir = join(tmpdir(), `zuplo-test-${Date.now()}`);
|
|
19
|
+
await mkdir(testDir, { recursive: true });
|
|
20
|
+
});
|
|
21
|
+
it("should generate correct .env.zuplo file with system variables", async () => {
|
|
22
|
+
const mockPayload = {
|
|
23
|
+
accountName: "test-account",
|
|
24
|
+
projectName: "test-project",
|
|
25
|
+
environmentType: "development",
|
|
26
|
+
systemConfigurations: "config-123",
|
|
27
|
+
};
|
|
28
|
+
mockAgent
|
|
29
|
+
.get(TEST_API_ENDPOINT)
|
|
30
|
+
.intercept({
|
|
31
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
32
|
+
method: "GET",
|
|
33
|
+
headers: {
|
|
34
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
.reply(200, mockPayload);
|
|
38
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
39
|
+
await pullSystemConfig({
|
|
40
|
+
dir: testDir,
|
|
41
|
+
environment: TEST_ENVIRONMENT,
|
|
42
|
+
authToken: TEST_AUTH_TOKEN,
|
|
43
|
+
});
|
|
44
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
45
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
46
|
+
assert.include(content, "# This file is auto-generated from zuplo link. Please do not edit it manually.");
|
|
47
|
+
assert.include(content, "# It will be auto-generated afresh the next time you run zuplo link.");
|
|
48
|
+
assert.include(content, "# If you wish to add your own environment variables, create a separate .env file.");
|
|
49
|
+
assert.include(content, "ZUPLO_ACCOUNT_NAME=test-account");
|
|
50
|
+
assert.include(content, "ZUPLO_PROJECT_NAME=test-project");
|
|
51
|
+
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=development");
|
|
52
|
+
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=config-123");
|
|
53
|
+
assert.notInclude(content, "# Public Zuplo environment variables");
|
|
54
|
+
assert.notInclude(content, "# Environment variables defined in the Zuplo UI for the environment");
|
|
55
|
+
await rm(testDir, { recursive: true, force: true });
|
|
56
|
+
});
|
|
57
|
+
it("should handle payload with public and user environment variables", async () => {
|
|
58
|
+
const mockPayload = {
|
|
59
|
+
accountName: "my-account",
|
|
60
|
+
projectName: "my-project",
|
|
61
|
+
environmentType: "production",
|
|
62
|
+
systemConfigurations: "prod-config-456",
|
|
63
|
+
ZUPLO_PUBLIC_API_URL: "https://api.example.com",
|
|
64
|
+
ZUPLO_PUBLIC_DOCS_URL: "https://docs.example.com",
|
|
65
|
+
DATABASE_URL: "postgres://localhost:5432/db",
|
|
66
|
+
API_KEY: "secret-key-123",
|
|
67
|
+
REDIS_URL: "redis://localhost:6379",
|
|
68
|
+
};
|
|
69
|
+
mockAgent
|
|
70
|
+
.get(TEST_API_ENDPOINT)
|
|
71
|
+
.intercept({
|
|
72
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
73
|
+
method: "GET",
|
|
74
|
+
headers: {
|
|
75
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
.reply(200, mockPayload);
|
|
79
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
80
|
+
await pullSystemConfig({
|
|
81
|
+
dir: testDir,
|
|
82
|
+
environment: TEST_ENVIRONMENT,
|
|
83
|
+
authToken: TEST_AUTH_TOKEN,
|
|
84
|
+
});
|
|
85
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
86
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
87
|
+
assert.include(content, "ZUPLO_ACCOUNT_NAME=my-account");
|
|
88
|
+
assert.include(content, "ZUPLO_PROJECT_NAME=my-project");
|
|
89
|
+
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=production");
|
|
90
|
+
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=prod-config-456");
|
|
91
|
+
const publicSectionRegex = /# Public Zuplo environment variables[\s\S]*?(?=# Environment variables defined in the Zuplo UI|$)/;
|
|
92
|
+
const publicSection = content.match(publicSectionRegex)?.[0] || "";
|
|
93
|
+
assert.include(publicSection, 'ZUPLO_PUBLIC_API_URL="https://api.example.com"');
|
|
94
|
+
assert.include(publicSection, 'ZUPLO_PUBLIC_DOCS_URL="https://docs.example.com"');
|
|
95
|
+
const userSectionRegex = /# Environment variables defined in the Zuplo UI[\s\S]*$/;
|
|
96
|
+
const userSection = content.match(userSectionRegex)?.[0] || "";
|
|
97
|
+
assert.include(userSection, 'DATABASE_URL="postgres://localhost:5432/db"');
|
|
98
|
+
assert.include(userSection, 'API_KEY="secret-key-123"');
|
|
99
|
+
assert.include(userSection, 'REDIS_URL="redis://localhost:6379"');
|
|
100
|
+
assert.notInclude(userSection, "accountName=");
|
|
101
|
+
assert.notInclude(userSection, "projectName=");
|
|
102
|
+
assert.notInclude(userSection, "environmentType=");
|
|
103
|
+
assert.notInclude(userSection, "systemConfigurations=");
|
|
104
|
+
await rm(testDir, { recursive: true, force: true });
|
|
105
|
+
});
|
|
106
|
+
it("should handle empty environment variables gracefully", async () => {
|
|
107
|
+
const mockPayload = {
|
|
108
|
+
accountName: "test-account",
|
|
109
|
+
projectName: "test-project",
|
|
110
|
+
environmentType: "development",
|
|
111
|
+
systemConfigurations: "config-789",
|
|
112
|
+
};
|
|
113
|
+
mockAgent
|
|
114
|
+
.get(TEST_API_ENDPOINT)
|
|
115
|
+
.intercept({
|
|
116
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
117
|
+
method: "GET",
|
|
118
|
+
headers: {
|
|
119
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
.reply(200, mockPayload);
|
|
123
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
124
|
+
await pullSystemConfig({
|
|
125
|
+
dir: testDir,
|
|
126
|
+
environment: TEST_ENVIRONMENT,
|
|
127
|
+
authToken: TEST_AUTH_TOKEN,
|
|
128
|
+
});
|
|
129
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
130
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
131
|
+
assert.include(content, "ZUPLO_ACCOUNT_NAME=test-account");
|
|
132
|
+
assert.include(content, "ZUPLO_PROJECT_NAME=test-project");
|
|
133
|
+
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=development");
|
|
134
|
+
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=config-789");
|
|
135
|
+
assert.notInclude(content, "# Public Zuplo environment variables");
|
|
136
|
+
assert.notInclude(content, "# Environment variables defined in the Zuplo UI for the environment");
|
|
137
|
+
await rm(testDir, { recursive: true, force: true });
|
|
138
|
+
});
|
|
139
|
+
it("should handle special characters in environment variable values", async () => {
|
|
140
|
+
const mockPayload = {
|
|
141
|
+
accountName: "test-account",
|
|
142
|
+
projectName: "test-project",
|
|
143
|
+
environmentType: "development",
|
|
144
|
+
systemConfigurations: "config-123",
|
|
145
|
+
DATABASE_URL: "postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true",
|
|
146
|
+
API_SECRET: "secret-with-special-chars!@#$%^&*()",
|
|
147
|
+
JSON_CONFIG: '{"key": "value", "nested": {"array": [1, 2, 3]}}',
|
|
148
|
+
};
|
|
149
|
+
mockAgent
|
|
150
|
+
.get(TEST_API_ENDPOINT)
|
|
151
|
+
.intercept({
|
|
152
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
153
|
+
method: "GET",
|
|
154
|
+
headers: {
|
|
155
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
156
|
+
},
|
|
157
|
+
})
|
|
158
|
+
.reply(200, mockPayload);
|
|
159
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
160
|
+
await pullSystemConfig({
|
|
161
|
+
dir: testDir,
|
|
162
|
+
environment: TEST_ENVIRONMENT,
|
|
163
|
+
authToken: TEST_AUTH_TOKEN,
|
|
164
|
+
});
|
|
165
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
166
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
167
|
+
assert.include(content, 'DATABASE_URL="postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true"');
|
|
168
|
+
assert.include(content, 'API_SECRET="secret-with-special-chars!@#$%^&*()"');
|
|
169
|
+
assert.include(content, 'JSON_CONFIG="{\\"key\\": \\"value\\", \\"nested\\": {\\"array\\": [1, 2, 3]}}"');
|
|
170
|
+
const userSectionRegex = /# Environment variables defined in the Zuplo UI[\s\S]*$/;
|
|
171
|
+
const userSection = content.match(userSectionRegex)?.[0] || "";
|
|
172
|
+
assert.include(userSection, 'DATABASE_URL="postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true"');
|
|
173
|
+
assert.include(userSection, 'API_SECRET="secret-with-special-chars!@#$%^&*()"');
|
|
174
|
+
assert.include(userSection, 'JSON_CONFIG="{\\"key\\": \\"value\\", \\"nested\\": {\\"array\\": [1, 2, 3]}}"');
|
|
175
|
+
await rm(testDir, { recursive: true, force: true });
|
|
176
|
+
});
|
|
177
|
+
it("should only include public variables section when public variables exist", async () => {
|
|
178
|
+
const mockPayload = {
|
|
179
|
+
accountName: "test-account",
|
|
180
|
+
projectName: "test-project",
|
|
181
|
+
environmentType: "development",
|
|
182
|
+
systemConfigurations: "config-123",
|
|
183
|
+
ZUPLO_PUBLIC_API_URL: "https://api.example.com",
|
|
184
|
+
ZUPLO_PUBLIC_DOCS_URL: "https://docs.example.com",
|
|
185
|
+
};
|
|
186
|
+
mockAgent
|
|
187
|
+
.get(TEST_API_ENDPOINT)
|
|
188
|
+
.intercept({
|
|
189
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
190
|
+
method: "GET",
|
|
191
|
+
headers: {
|
|
192
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
193
|
+
},
|
|
194
|
+
})
|
|
195
|
+
.reply(200, mockPayload);
|
|
196
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
197
|
+
await pullSystemConfig({
|
|
198
|
+
dir: testDir,
|
|
199
|
+
environment: TEST_ENVIRONMENT,
|
|
200
|
+
authToken: TEST_AUTH_TOKEN,
|
|
201
|
+
});
|
|
202
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
203
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
204
|
+
assert.include(content, "ZUPLO_ACCOUNT_NAME=test-account");
|
|
205
|
+
assert.include(content, "ZUPLO_PROJECT_NAME=test-project");
|
|
206
|
+
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=development");
|
|
207
|
+
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=config-123");
|
|
208
|
+
assert.include(content, "# Public Zuplo environment variables");
|
|
209
|
+
assert.include(content, 'ZUPLO_PUBLIC_API_URL="https://api.example.com"');
|
|
210
|
+
assert.include(content, 'ZUPLO_PUBLIC_DOCS_URL="https://docs.example.com"');
|
|
211
|
+
assert.notInclude(content, "# Environment variables defined in the Zuplo UI for the environment");
|
|
212
|
+
await rm(testDir, { recursive: true, force: true });
|
|
213
|
+
});
|
|
214
|
+
it("should only include user variables section when user variables exist", async () => {
|
|
215
|
+
const mockPayload = {
|
|
216
|
+
accountName: "test-account",
|
|
217
|
+
projectName: "test-project",
|
|
218
|
+
environmentType: "development",
|
|
219
|
+
systemConfigurations: "config-123",
|
|
220
|
+
DATABASE_URL: "postgres://localhost:5432/db",
|
|
221
|
+
API_KEY: "secret-key-123",
|
|
222
|
+
};
|
|
223
|
+
mockAgent
|
|
224
|
+
.get(TEST_API_ENDPOINT)
|
|
225
|
+
.intercept({
|
|
226
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
227
|
+
method: "GET",
|
|
228
|
+
headers: {
|
|
229
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
230
|
+
},
|
|
231
|
+
})
|
|
232
|
+
.reply(200, mockPayload);
|
|
233
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
234
|
+
await pullSystemConfig({
|
|
235
|
+
dir: testDir,
|
|
236
|
+
environment: TEST_ENVIRONMENT,
|
|
237
|
+
authToken: TEST_AUTH_TOKEN,
|
|
238
|
+
});
|
|
239
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
240
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
241
|
+
assert.include(content, "ZUPLO_ACCOUNT_NAME=test-account");
|
|
242
|
+
assert.include(content, "ZUPLO_PROJECT_NAME=test-project");
|
|
243
|
+
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=development");
|
|
244
|
+
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=config-123");
|
|
245
|
+
assert.notInclude(content, "# Public Zuplo environment variables");
|
|
246
|
+
assert.include(content, "# Environment variables defined in the Zuplo UI for the environment");
|
|
247
|
+
assert.include(content, 'DATABASE_URL="postgres://localhost:5432/db"');
|
|
248
|
+
assert.include(content, 'API_KEY="secret-key-123"');
|
|
249
|
+
await rm(testDir, { recursive: true, force: true });
|
|
250
|
+
});
|
|
251
|
+
it("should properly escape double quotes in environment variable values for dotenv parsing", async () => {
|
|
252
|
+
const mockPayload = {
|
|
253
|
+
accountName: "test-account",
|
|
254
|
+
projectName: "test-project",
|
|
255
|
+
environmentType: "development",
|
|
256
|
+
systemConfigurations: "config-123",
|
|
257
|
+
DATABASE_URL: "postgres://user:p'assw'ord@localhost:5432/db",
|
|
258
|
+
API_KEY: "secret'with'quotes",
|
|
259
|
+
JSON_CONFIG: '{"message": "Hello \'world\'", "nested": {"value": "test\'s"}}',
|
|
260
|
+
ZUPLO_PUBLIC_MESSAGE: "Welcome to Zuplo's platform!",
|
|
261
|
+
COMPLEX_VALUE: "?\\\"!##==A_special_chars'''",
|
|
262
|
+
EDGE_CASE_1: "value with 'single' and \"double\" quotes",
|
|
263
|
+
EDGE_CASE_2: "path\\to\\file's location",
|
|
264
|
+
EDGE_CASE_3: "it's a $pecial @#$%^&*() value!",
|
|
265
|
+
EDGE_CASE_4: "multi\nline\nwith'quotes",
|
|
266
|
+
EDGE_CASE_5: "tabs\tand\tspaces and 'quotes'",
|
|
267
|
+
};
|
|
268
|
+
mockAgent
|
|
269
|
+
.get(TEST_API_ENDPOINT)
|
|
270
|
+
.intercept({
|
|
271
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
272
|
+
method: "GET",
|
|
273
|
+
headers: {
|
|
274
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
275
|
+
},
|
|
276
|
+
})
|
|
277
|
+
.reply(200, mockPayload);
|
|
278
|
+
const { pullLocalConfig: pullSystemConfig } = await import("../common/populate.js");
|
|
279
|
+
await pullSystemConfig({
|
|
280
|
+
dir: testDir,
|
|
281
|
+
environment: TEST_ENVIRONMENT,
|
|
282
|
+
authToken: TEST_AUTH_TOKEN,
|
|
283
|
+
});
|
|
284
|
+
const envFilePath = join(testDir, ".env.zuplo");
|
|
285
|
+
const content = await readFile(envFilePath, "utf-8");
|
|
286
|
+
assert.include(content, "DATABASE_URL=\"postgres://user:p'assw'ord@localhost:5432/db\"");
|
|
287
|
+
assert.include(content, "API_KEY=\"secret'with'quotes\"");
|
|
288
|
+
assert.include(content, 'JSON_CONFIG="{\\"message\\": \\"Hello \'world\'\\", \\"nested\\": {\\"value\\": \\"test\'s\\"}}"');
|
|
289
|
+
assert.include(content, 'ZUPLO_PUBLIC_MESSAGE="Welcome to Zuplo\'s platform!"');
|
|
290
|
+
assert.include(content, `COMPLEX_VALUE="?\\\\"!##==A_special_chars'''"`);
|
|
291
|
+
assert.include(content, 'EDGE_CASE_1="value with \'single\' and \\"double\\" quotes"');
|
|
292
|
+
assert.include(content, 'EDGE_CASE_2="path\\to\\file\'s location"');
|
|
293
|
+
assert.include(content, 'EDGE_CASE_3="it\'s a $pecial @#$%^&*() value!"');
|
|
294
|
+
assert.include(content, 'EDGE_CASE_4="multi\nline\nwith\'quotes"');
|
|
295
|
+
assert.include(content, "EDGE_CASE_5=\"tabs\tand\tspaces and 'quotes'\"");
|
|
296
|
+
const fileContent = await readFile(envFilePath, "utf-8");
|
|
297
|
+
const parsedEnv = dotenvParse(fileContent);
|
|
298
|
+
assert.isUndefined(parsedEnv.error, "dotenv should parse the file without errors");
|
|
299
|
+
assert.equal(parsedEnv.DATABASE_URL, mockPayload.DATABASE_URL);
|
|
300
|
+
assert.equal(parsedEnv.API_KEY, mockPayload.API_KEY);
|
|
301
|
+
assert.isString(parsedEnv.JSON_CONFIG);
|
|
302
|
+
assert.include(parsedEnv.JSON_CONFIG, '\\"message\\"');
|
|
303
|
+
assert.equal(parsedEnv.ZUPLO_PUBLIC_MESSAGE, mockPayload.ZUPLO_PUBLIC_MESSAGE);
|
|
304
|
+
assert.isString(parsedEnv.COMPLEX_VALUE);
|
|
305
|
+
assert.include(parsedEnv.COMPLEX_VALUE, "special_chars");
|
|
306
|
+
assert.isString(parsedEnv.EDGE_CASE_1);
|
|
307
|
+
assert.include(parsedEnv.EDGE_CASE_1, "single");
|
|
308
|
+
assert.equal(parsedEnv.EDGE_CASE_2, mockPayload.EDGE_CASE_2);
|
|
309
|
+
assert.equal(parsedEnv.EDGE_CASE_3, mockPayload.EDGE_CASE_3);
|
|
310
|
+
assert.equal(parsedEnv.EDGE_CASE_4, mockPayload.EDGE_CASE_4);
|
|
311
|
+
assert.equal(parsedEnv.EDGE_CASE_5, mockPayload.EDGE_CASE_5);
|
|
312
|
+
await rm(testDir, { recursive: true, force: true });
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
//# sourceMappingURL=populate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate.test.js","sourceRoot":"","sources":["../../src/__tests__/populate.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unit tests for the pullSystemConfig function\n * Focuses on testing the parsing logic and environment file generation\n */\n\nimport { beforeEach, describe, it } from \"node:test\";\nimport { assert } from \"chai\";\nimport { MockAgent, setGlobalDispatcher } from \"undici\";\nimport { readFile, rm, mkdir } from \"node:fs/promises\";\nimport { join, parse } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { parse as dotenvParse } from \"dotenv\";\n\n// Test constants\nconst TEST_ENVIRONMENT = \"test-env-123\";\nconst TEST_AUTH_TOKEN = \"test-auth-token-456\";\nconst TEST_API_ENDPOINT = \"https://dev.zuplo.com\";\n\ndescribe(\"pullSystemConfig\", () => {\n let mockAgent: MockAgent;\n let testDir: string;\n\n beforeEach(async () => {\n // Setup HTTP mocking\n mockAgent = new MockAgent();\n mockAgent.disableNetConnect();\n setGlobalDispatcher(mockAgent);\n\n // Create a temporary directory for testing\n testDir = join(tmpdir(), `zuplo-test-${Date.now()}`);\n await mkdir(testDir, { recursive: true });\n });\n\n it(\"should generate correct .env.zuplo file with system variables\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Verify the .env.zuplo file was created\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify file header\n assert.include(\n content,\n \"# This file is auto-generated from zuplo link. Please do not edit it manually.\"\n );\n assert.include(\n content,\n \"# It will be auto-generated afresh the next time you run zuplo link.\"\n );\n assert.include(\n content,\n \"# If you wish to add your own environment variables, create a separate .env file.\"\n );\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify sections are NOT present when there are no variables for them\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle payload with public and user environment variables\", async () => {\n const mockPayload = {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: \"production\",\n systemConfigurations: \"prod-config-456\",\n // Public variables (should be in public section)\n ZUPLO_PUBLIC_API_URL: \"https://api.example.com\",\n ZUPLO_PUBLIC_DOCS_URL: \"https://docs.example.com\",\n // User variables (should be in user section)\n DATABASE_URL: \"postgres://localhost:5432/db\",\n API_KEY: \"secret-key-123\",\n REDIS_URL: \"redis://localhost:6379\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=my-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=my-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=production\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=prod-config-456\");\n\n // Verify public variables are in the public section\n const publicSectionRegex =\n /# Public Zuplo environment variables[\\s\\S]*?(?=# Environment variables defined in the Zuplo UI|$)/;\n const publicSection = content.match(publicSectionRegex)?.[0] || \"\";\n assert.include(\n publicSection,\n 'ZUPLO_PUBLIC_API_URL=\"https://api.example.com\"'\n );\n assert.include(\n publicSection,\n 'ZUPLO_PUBLIC_DOCS_URL=\"https://docs.example.com\"'\n );\n\n // Verify user variables are in the user section\n const userSectionRegex =\n /# Environment variables defined in the Zuplo UI[\\s\\S]*$/;\n const userSection = content.match(userSectionRegex)?.[0] || \"\";\n assert.include(userSection, 'DATABASE_URL=\"postgres://localhost:5432/db\"');\n assert.include(userSection, 'API_KEY=\"secret-key-123\"');\n assert.include(userSection, 'REDIS_URL=\"redis://localhost:6379\"');\n\n // Verify system variables are NOT in user section\n assert.notInclude(userSection, \"accountName=\");\n assert.notInclude(userSection, \"projectName=\");\n assert.notInclude(userSection, \"environmentType=\");\n assert.notInclude(userSection, \"systemConfigurations=\");\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle empty environment variables gracefully\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-789\",\n // No additional environment variables\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are still present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-789\");\n\n // Verify sections are NOT present when there are no variables for them\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle special characters in environment variable values\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n DATABASE_URL: \"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\",\n API_SECRET: \"secret-with-special-chars!@#$%^&*()\",\n JSON_CONFIG: '{\"key\": \"value\", \"nested\": {\"array\": [1, 2, 3]}}',\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify special characters are preserved in environment variable values\n assert.include(\n content,\n 'DATABASE_URL=\"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\"'\n );\n assert.include(content, 'API_SECRET=\"secret-with-special-chars!@#$%^&*()\"');\n assert.include(\n content,\n 'JSON_CONFIG=\"{\\\\\"key\\\\\": \\\\\"value\\\\\", \\\\\"nested\\\\\": {\\\\\"array\\\\\": [1, 2, 3]}}\"'\n );\n\n // Verify these are in the user section (not public section)\n const userSectionRegex =\n /# Environment variables defined in the Zuplo UI[\\s\\S]*$/;\n const userSection = content.match(userSectionRegex)?.[0] || \"\";\n assert.include(\n userSection,\n 'DATABASE_URL=\"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\"'\n );\n assert.include(\n userSection,\n 'API_SECRET=\"secret-with-special-chars!@#$%^&*()\"'\n );\n assert.include(\n userSection,\n 'JSON_CONFIG=\"{\\\\\"key\\\\\": \\\\\"value\\\\\", \\\\\"nested\\\\\": {\\\\\"array\\\\\": [1, 2, 3]}}\"'\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should only include public variables section when public variables exist\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Only public variables, no user variables\n ZUPLO_PUBLIC_API_URL: \"https://api.example.com\",\n ZUPLO_PUBLIC_DOCS_URL: \"https://docs.example.com\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify public section is present with variables\n assert.include(content, \"# Public Zuplo environment variables\");\n assert.include(content, 'ZUPLO_PUBLIC_API_URL=\"https://api.example.com\"');\n assert.include(content, 'ZUPLO_PUBLIC_DOCS_URL=\"https://docs.example.com\"');\n\n // Verify user section is NOT present since there are no user variables\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should only include user variables section when user variables exist\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Only user variables, no public variables\n DATABASE_URL: \"postgres://localhost:5432/db\",\n API_KEY: \"secret-key-123\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify public section is NOT present since there are no public variables\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n\n // Verify user section is present with variables\n assert.include(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n assert.include(content, 'DATABASE_URL=\"postgres://localhost:5432/db\"');\n assert.include(content, 'API_KEY=\"secret-key-123\"');\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should properly escape double quotes in environment variable values for dotenv parsing\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Environment variables with double quotes that need escaping\n DATABASE_URL: \"postgres://user:p'assw'ord@localhost:5432/db\",\n API_KEY: \"secret'with'quotes\",\n JSON_CONFIG:\n '{\"message\": \"Hello \\'world\\'\", \"nested\": {\"value\": \"test\\'s\"}}',\n ZUPLO_PUBLIC_MESSAGE: \"Welcome to Zuplo's platform!\",\n COMPLEX_VALUE: \"?\\\\\\\"!##==A_special_chars'''\",\n // Additional special character test cases\n EDGE_CASE_1: \"value with 'single' and \\\"double\\\" quotes\",\n EDGE_CASE_2: \"path\\\\to\\\\file's location\",\n EDGE_CASE_3: \"it's a $pecial @#$%^&*() value!\",\n EDGE_CASE_4: \"multi\\nline\\nwith'quotes\",\n EDGE_CASE_5: \"tabs\\tand\\tspaces and 'quotes'\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig: pullSystemConfig } = await import(\n \"../common/populate.js\"\n );\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify that all values use double quotes with escaped double quotes\n assert.include(\n content,\n \"DATABASE_URL=\\\"postgres://user:p'assw'ord@localhost:5432/db\\\"\"\n );\n assert.include(content, \"API_KEY=\\\"secret'with'quotes\\\"\");\n assert.include(\n content,\n 'JSON_CONFIG=\"{\\\\\"message\\\\\": \\\\\"Hello \\'world\\'\\\\\", \\\\\"nested\\\\\": {\\\\\"value\\\\\": \\\\\"test\\'s\\\\\"}}\"'\n );\n assert.include(\n content,\n 'ZUPLO_PUBLIC_MESSAGE=\"Welcome to Zuplo\\'s platform!\"'\n );\n assert.include(content, `COMPLEX_VALUE=\"?\\\\\\\\\"!##==A_special_chars'''\"`);\n\n // Verify additional edge cases use double quotes with escaped double quotes\n assert.include(\n content,\n 'EDGE_CASE_1=\"value with \\'single\\' and \\\\\"double\\\\\" quotes\"'\n );\n assert.include(content, 'EDGE_CASE_2=\"path\\\\to\\\\file\\'s location\"');\n assert.include(content, 'EDGE_CASE_3=\"it\\'s a $pecial @#$%^&*() value!\"');\n assert.include(content, 'EDGE_CASE_4=\"multi\\nline\\nwith\\'quotes\"');\n assert.include(content, \"EDGE_CASE_5=\\\"tabs\\tand\\tspaces and 'quotes'\\\"\");\n\n // Test that dotenv can properly parse the generated file\n const fileContent = await readFile(envFilePath, \"utf-8\");\n const parsedEnv = dotenvParse(fileContent);\n\n // Verify that dotenv successfully parsed the file without errors\n assert.isUndefined(\n parsedEnv.error,\n \"dotenv should parse the file without errors\"\n );\n\n // Verify that the parsed values match the original values from the mock payload\n // Note: dotenv may not perfectly unescape all values, but should parse without errors\n assert.equal(parsedEnv.DATABASE_URL, mockPayload.DATABASE_URL);\n assert.equal(parsedEnv.API_KEY, mockPayload.API_KEY);\n // For JSON_CONFIG, dotenv doesn't unescape the quotes, so we check that it contains the escaped version\n assert.isString(parsedEnv.JSON_CONFIG);\n assert.include(parsedEnv.JSON_CONFIG, '\\\\\"message\\\\\"');\n assert.equal(\n parsedEnv.ZUPLO_PUBLIC_MESSAGE,\n mockPayload.ZUPLO_PUBLIC_MESSAGE\n );\n // For COMPLEX_VALUE, dotenv doesn't unescape the backslash-escaped quotes properly\n assert.isString(parsedEnv.COMPLEX_VALUE);\n assert.include(parsedEnv.COMPLEX_VALUE, \"special_chars\");\n\n // Verify additional edge cases are parsed correctly\n // For values with double quotes, dotenv may not unescape them perfectly\n assert.isString(parsedEnv.EDGE_CASE_1);\n assert.include(parsedEnv.EDGE_CASE_1, \"single\");\n assert.equal(parsedEnv.EDGE_CASE_2, mockPayload.EDGE_CASE_2);\n assert.equal(parsedEnv.EDGE_CASE_3, mockPayload.EDGE_CASE_3);\n assert.equal(parsedEnv.EDGE_CASE_4, mockPayload.EDGE_CASE_4);\n assert.equal(parsedEnv.EDGE_CASE_5, mockPayload.EDGE_CASE_5);\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n});\n"]}
|
|
@@ -6,4 +6,7 @@ export declare function safeMergeConfig(
|
|
|
6
6
|
export declare function pullSystemConfig(
|
|
7
7
|
argv: Pick<Arguments, "dir" | "environment" | "authToken">
|
|
8
8
|
): Promise<void>;
|
|
9
|
+
export declare function pullLocalConfig(
|
|
10
|
+
argv: Pick<Arguments, "dir" | "environment" | "authToken">
|
|
11
|
+
): Promise<void>;
|
|
9
12
|
//# sourceMappingURL=populate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate.d.ts","sourceRoot":"","sources":["../../src/common/populate.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAwB/C,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAkDjE;AASD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,CAAC,iBAiD3D;AAUD,wBAAsB,eAAe,CACnC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,CAAC,iBAwF3D"}
|
|
@@ -3,10 +3,20 @@ import { readFile, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { join, relative } from "node:path";
|
|
4
4
|
import { applyEdits, modify } from "jsonc-parser";
|
|
5
5
|
import { format } from "prettier";
|
|
6
|
-
import { ZUPLO_FALLBACK_JSON_FILE, ZUPLO_PREFERRED_JSON_FILE, ZUPLO_SYSTEM_ENV_VAR, } from "
|
|
7
|
-
import { logger } from "
|
|
8
|
-
import { printCriticalFailureToConsoleAndExit } from "
|
|
9
|
-
import settings from "
|
|
6
|
+
import { ZUPLO_FALLBACK_JSON_FILE, ZUPLO_PREFERRED_JSON_FILE, ZUPLO_SYSTEM_ENV_VAR, } from "./constants.js";
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
|
+
import { printCriticalFailureToConsoleAndExit } from "./output.js";
|
|
9
|
+
import settings from "./settings.js";
|
|
10
|
+
const SYSTEM_KEYS = [
|
|
11
|
+
"accountName",
|
|
12
|
+
"projectName",
|
|
13
|
+
"environmentType",
|
|
14
|
+
"systemConfigurations",
|
|
15
|
+
];
|
|
16
|
+
function wrapEnvValue(value) {
|
|
17
|
+
const escapedValue = value.replace(/"/g, '\\"');
|
|
18
|
+
return `"${escapedValue}"`;
|
|
19
|
+
}
|
|
10
20
|
export async function safeMergeConfig(dir, project) {
|
|
11
21
|
const normalizedDir = join(relative(process.cwd(), dir));
|
|
12
22
|
const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_PREFERRED_JSON_FILE);
|
|
@@ -73,7 +83,6 @@ export async function pullSystemConfig(argv) {
|
|
|
73
83
|
# This file is auto-generated from zuplo link. Please do not edit it manually.
|
|
74
84
|
# It will be auto-generated afresh the next time you run zuplo link.
|
|
75
85
|
# If you wish to add your own environment variables, create a separate .env file.
|
|
76
|
-
|
|
77
86
|
ZUPLO_ACCOUNT_NAME=${payload.accountName}
|
|
78
87
|
ZUPLO_PROJECT_NAME=${payload.projectName}
|
|
79
88
|
ZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}
|
|
@@ -81,4 +90,65 @@ ZUPLO_SYSTEM_CONFIGURATIONS=${payload["systemConfigurations"]}
|
|
|
81
90
|
`;
|
|
82
91
|
await writeFile(zuploPreferredConfigFile, content);
|
|
83
92
|
}
|
|
93
|
+
export async function pullLocalConfig(argv) {
|
|
94
|
+
const normalizedDir = join(relative(process.cwd(), argv.dir));
|
|
95
|
+
const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);
|
|
96
|
+
const environmentResponseFromDeveloperAPI = await fetch(`${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/local-configurations`, {
|
|
97
|
+
headers: {
|
|
98
|
+
authorization: `Bearer ${argv.authToken}`,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
if (!environmentResponseFromDeveloperAPI.ok) {
|
|
102
|
+
if (environmentResponseFromDeveloperAPI.status === 404 ||
|
|
103
|
+
environmentResponseFromDeveloperAPI.status === 401) {
|
|
104
|
+
await printCriticalFailureToConsoleAndExit("Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.");
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
logger.error({
|
|
108
|
+
status: environmentResponseFromDeveloperAPI.status,
|
|
109
|
+
statusText: environmentResponseFromDeveloperAPI.statusText,
|
|
110
|
+
}, `Failed to link data from ${argv.environment}`);
|
|
111
|
+
await printCriticalFailureToConsoleAndExit("Error: Failed to link data from the environment. Please try again later.");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const payload = await environmentResponseFromDeveloperAPI.json();
|
|
115
|
+
const userEnvVars = Object.keys(payload)
|
|
116
|
+
.filter((key) => {
|
|
117
|
+
return !key.startsWith("ZUPLO_PUBLIC_") && !SYSTEM_KEYS.includes(key);
|
|
118
|
+
})
|
|
119
|
+
.map((key) => {
|
|
120
|
+
return `${key}=${wrapEnvValue(payload[key])}`;
|
|
121
|
+
});
|
|
122
|
+
const zuploPublicEnvVars = Object.keys(payload)
|
|
123
|
+
.filter((key) => {
|
|
124
|
+
return key.startsWith("ZUPLO_PUBLIC_");
|
|
125
|
+
})
|
|
126
|
+
.map((key) => {
|
|
127
|
+
return `${key}=${wrapEnvValue(payload[key])}`;
|
|
128
|
+
});
|
|
129
|
+
let content = `# This file is auto-generated from zuplo link. Please do not edit it manually.
|
|
130
|
+
# It will be auto-generated afresh the next time you run zuplo link.
|
|
131
|
+
# If you wish to add your own environment variables, create a separate .env file.
|
|
132
|
+
|
|
133
|
+
ZUPLO_ACCOUNT_NAME=${payload.accountName}
|
|
134
|
+
ZUPLO_PROJECT_NAME=${payload.projectName}
|
|
135
|
+
ZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}
|
|
136
|
+
ZUPLO_SYSTEM_CONFIGURATIONS=${payload["systemConfigurations"]}`;
|
|
137
|
+
if (zuploPublicEnvVars.length > 0) {
|
|
138
|
+
content += `
|
|
139
|
+
|
|
140
|
+
# Public Zuplo environment variables
|
|
141
|
+
${zuploPublicEnvVars.join("\n")}`;
|
|
142
|
+
}
|
|
143
|
+
if (userEnvVars.length > 0) {
|
|
144
|
+
content += `
|
|
145
|
+
|
|
146
|
+
# Environment variables defined in the Zuplo UI for the environment
|
|
147
|
+
# Note that " characters are escaped with a backslash and escaped double quotes
|
|
148
|
+
# will show up as \\" in the value.
|
|
149
|
+
${userEnvVars.join("\n")}`;
|
|
150
|
+
}
|
|
151
|
+
content += "\n";
|
|
152
|
+
await writeFile(zuploPreferredConfigFile, content);
|
|
153
|
+
}
|
|
84
154
|
//# sourceMappingURL=populate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate.js","sourceRoot":"","sources":["../../src/common/populate.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport { applyEdits, modify } from \"jsonc-parser\";\nimport { format } from \"prettier\";\nimport {\n ZUPLO_FALLBACK_JSON_FILE,\n ZUPLO_PREFERRED_JSON_FILE,\n ZUPLO_SYSTEM_ENV_VAR,\n} from \"./constants.js\";\nimport { logger } from \"./logger.js\";\nimport { printCriticalFailureToConsoleAndExit } from \"./output.js\";\nimport settings from \"./settings.js\";\nimport { Arguments } from \"../link/handler.js\";\n\nconst SYSTEM_KEYS = [\n \"accountName\",\n \"projectName\",\n \"environmentType\",\n \"systemConfigurations\",\n];\n\n/**\n * Wraps environment variable values in single quotes for dotenv compatibility.\n * Escapes any single quotes within the value by replacing them with \\'.\n * This ensures proper parsing while preserving special characters.\n *\n * @param value The environment variable value to wrap\n * @returns The value wrapped in single quotes with escaped single quotes\n */\nfunction wrapEnvValue(value: string): string {\n // Escape single quotes by replacing them with \\'\n const escapedValue = value.replace(/\"/g, '\\\\\"');\n // Always use single quotes\n return `\"${escapedValue}\"`;\n}\n\nexport async function safeMergeConfig(dir: string, project: string) {\n const normalizedDir = join(relative(process.cwd(), dir));\n const zuploPreferredConfigFile = join(\n normalizedDir,\n ZUPLO_PREFERRED_JSON_FILE\n );\n const zuploFallbackConfigFile = join(normalizedDir, ZUPLO_FALLBACK_JSON_FILE);\n if (existsSync(zuploPreferredConfigFile)) {\n // Process the file, while respecting comments\n // Apply the edits sequentially\n const originalContents = await readFile(zuploPreferredConfigFile, \"utf-8\");\n const modifyProjectEdit = modify(originalContents, [\"project\"], project, {\n getInsertionIndex: () => 2,\n });\n const contentsPostProject = applyEdits(originalContents, modifyProjectEdit);\n const formatted = await format(contentsPostProject, {\n parser: \"json\",\n quoteProps: \"as-needed\",\n });\n await writeFile(zuploPreferredConfigFile, formatted);\n } else if (existsSync(zuploFallbackConfigFile)) {\n // Copy the file over\n const config = JSON.parse(await readFile(zuploFallbackConfigFile, \"utf-8\"));\n const formatted = await format(\n JSON.stringify({\n version: 1,\n project: project,\n compatibilityDate: config.compatibilityDate,\n }),\n {\n parser: \"json\",\n quoteProps: \"as-needed\",\n }\n );\n await writeFile(zuploPreferredConfigFile, formatted);\n } else {\n // Create new file\n const formatted = await format(\n JSON.stringify({\n version: 1,\n project: project,\n compatibilityDate: \"2023-03-14\",\n }),\n {\n parser: \"json\",\n quoteProps: \"as-needed\",\n }\n );\n await writeFile(zuploPreferredConfigFile, formatted);\n }\n}\n\n/**\n * Pulls the system configuration from the API and writes it to the .env.zuplo file.\n * All the system environment variables are encoded in base58. Use this wherever\n * we need to *make sure* that the system environment variables are preserved correctly,\n * e.g in deployments.\n * @param argv\n */\nexport async function pullSystemConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = join(relative(process.cwd(), argv.dir));\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n\n const content = `\n# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}\n`;\n\n await writeFile(zuploPreferredConfigFile, content);\n}\n\n/**\n * Pulls the local configuration from dev-api and writes it to the .env.zuplo file.\n * This method differs from pullSystemConfig in that it writes the user defined\n * environment variables, as well as the public variables explicitly to the\n * file instead of getting all variable in the base58 encoded ZUPLO_SYSTEM_CONFIGURATIONS\n * variable.\n * @param argv\n */\nexport async function pullLocalConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = join(relative(process.cwd(), argv.dir));\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/local-configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n\n // We wrap the env vars in appropriate quotes to preserve special characters\n // and handle single quotes properly for dotenv parsing.\n const userEnvVars = Object.keys(payload)\n .filter((key) => {\n return !key.startsWith(\"ZUPLO_PUBLIC_\") && !SYSTEM_KEYS.includes(key);\n })\n .map((key) => {\n return `${key}=${wrapEnvValue(payload[key])}`;\n });\n\n const zuploPublicEnvVars = Object.keys(payload)\n .filter((key) => {\n // These start with ZUPLO_PUBLIC_ and are not system variables\n return key.startsWith(\"ZUPLO_PUBLIC_\");\n })\n .map((key) => {\n return `${key}=${wrapEnvValue(payload[key])}`;\n });\n\n let content = `# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\n\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}`;\n\n // Only add public environment variables section if there are any\n if (zuploPublicEnvVars.length > 0) {\n content += `\n\n# Public Zuplo environment variables\n${zuploPublicEnvVars.join(\"\\n\")}`;\n }\n\n // Only add user environment variables section if there are any\n if (userEnvVars.length > 0) {\n content += `\n\n# Environment variables defined in the Zuplo UI for the environment\n# Note that \" characters are escaped with a backslash and escaped double quotes\n# will show up as \\\\\" in the value.\n${userEnvVars.join(\"\\n\")}`;\n }\n\n // Add final newline\n content += \"\\n\";\n\n await writeFile(zuploPreferredConfigFile, content);\n}\n"]}
|
package/dist/deploy/handler.js
CHANGED
|
@@ -5,7 +5,7 @@ import { logger } from "../common/logger.js";
|
|
|
5
5
|
import { printCriticalFailureToConsoleAndExit, printDiagnosticsToConsole, printResultToConsoleAndExitGracefully, printSpinnerToConsole, printWarningToConsole, } from "../common/output.js";
|
|
6
6
|
import settings from "../common/settings.js";
|
|
7
7
|
import { normalizeUrl } from "../common/utils/urls.js";
|
|
8
|
-
import { pullSystemConfig } from "../
|
|
8
|
+
import { pullSystemConfig } from "../common/populate.js";
|
|
9
9
|
import { archive, generateMetadata } from "./archive.js";
|
|
10
10
|
import { UnableToAutoLinkToExistingProject, retrieveOrCreateEnvironment, } from "./environments.js";
|
|
11
11
|
import { upload } from "./file-upload.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/deploy/handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport {\n MAX_PRETTY_BRANCH_NAME as MAX_PRETTY_BRANCH_LENGTH,\n ZUPLO_SYSTEM_ENV_VAR,\n} from \"../common/constants.js\";\nimport { logger } from \"../common/logger.js\";\nimport {\n printCriticalFailureToConsoleAndExit,\n printDiagnosticsToConsole,\n printResultToConsoleAndExitGracefully,\n printSpinnerToConsole,\n printWarningToConsole,\n} from \"../common/output.js\";\nimport settings from \"../common/settings.js\";\nimport { RequiredProperties } from \"../common/utils/types.js\";\nimport { normalizeUrl } from \"../common/utils/urls.js\";\nimport { pullSystemConfig } from \"../link/populate.js\";\nimport { archive, generateMetadata } from \"./archive.js\";\nimport {\n UnableToAutoLinkToExistingProject,\n retrieveOrCreateEnvironment,\n} from \"./environments.js\";\nimport { upload } from \"./file-upload.js\";\nimport { pollBuild, pollDeployment } from \"./poll-deployment.js\";\n\nexport interface Arguments {\n account: string;\n project: string;\n dir: string;\n environment?: string;\n authToken: string;\n \"verify-remote\"?: boolean;\n \"self-hosted-endpoint\"?: string;\n \"override-repo-url\"?: string;\n}\n\nexport type SelfHostedArgs = RequiredProperties<\n Arguments,\n \"self-hosted-endpoint\"\n>;\n\nexport async function deploy(argv: Arguments) {\n if (argv[\"self-hosted-endpoint\"]) {\n const args = argv as SelfHostedArgs;\n await deployToSelfHosted(args);\n } else {\n await deployToSaas(argv);\n }\n}\n\nasync function deployToSaas(argv: Arguments) {\n // 1. Create the tarball locally\n const archiveMetadata = await archive(argv);\n logger.debug(`Tarball created locally at ${archiveMetadata.tarball}`);\n\n // 2. Build uploadUrl request\n const { account, project } = argv;\n\n const payload = {\n accountName: account,\n projectName: project,\n environment: archiveMetadata.metadata.branch,\n repositoryUrl: archiveMetadata.metadata.repoUrl,\n sha: archiveMetadata.metadata.sha,\n };\n\n const uploadUrlResponse = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/deployments/source-url`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${argv.authToken}`,\n },\n body: JSON.stringify(payload),\n }\n );\n\n logger.debug(`Upload URL response: ${uploadUrlResponse.status}`);\n\n if (uploadUrlResponse.ok) {\n // 3. Upload to request URL\n const { uploadUrl, deploymentId } = await uploadUrlResponse.json();\n\n printDiagnosticsToConsole(\n `Uploading source for deployment (${deploymentId})...`\n );\n\n const uploadResponse = await upload({\n tarballPath: archiveMetadata.tarball,\n uploadUrl,\n deploymentId,\n ...payload,\n });\n\n logger.debug(`Upload response: ${uploadResponse.status}`);\n\n if (uploadResponse.ok) {\n const spinner = printSpinnerToConsole(\n `Deploying the '${payload.environment}' environment to '${project}' on account '${account}'...`\n );\n\n const { url, logUrl } = await pollDeployment(\n argv,\n deploymentId,\n account,\n project,\n spinner\n );\n if (url) {\n await printResultToConsoleAndExitGracefully(\n `Deployed to ${url}`,\n spinner\n );\n } else {\n await printCriticalFailureToConsoleAndExit(\n `Failed to deploy the environment ${\n archiveMetadata.metadata.branch\n } to project ${project} on account ${account}.\\nFor more information, check the deployment logs in the Zuplo dashboard.\\n\n ${logUrl}`,\n spinner\n );\n }\n } else {\n logger.error(\n {\n status: uploadResponse.status,\n statusText: uploadResponse.statusText,\n },\n \"Failed to upload source to cloud storage\"\n );\n printDiagnosticsToConsole(\n \"Error: Failed to upload deployment source. Please try again.\"\n );\n }\n } else {\n logger.error(\n {\n status: uploadUrlResponse.status,\n statusText: uploadUrlResponse.statusText,\n },\n \"Failed to retrieve uploadUrl\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to upload deployment source. Please try again.\"\n );\n }\n}\n\nasync function deployToSelfHosted(argv: SelfHostedArgs) {\n const { account, project } = argv;\n\n let existingZuploEnv: string | undefined;\n\n try {\n // 0. Finagle the URL first\n const endpoint = normalizeUrl(argv[\"self-hosted-endpoint\"]);\n\n // 1. Perform the link on-behalf-of-the-user\n // Store the current .env.zuplo if there is one and restore it later\n existingZuploEnv = retrieveExistingZuploEnv(argv);\n const branch = (await generateMetadata(argv)).branch;\n try {\n const environmentToAutoLink = await retrieveOrCreateEnvironment(\n branch,\n argv\n );\n await pullSystemConfig({\n dir: argv.dir,\n environment: environmentToAutoLink.name,\n authToken: argv.authToken,\n });\n } catch (error) {\n if (\n error instanceof UnableToAutoLinkToExistingProject &&\n // eslint-disable-next-line node/no-process-env\n process.env.ZUPLO_ALLOW_DEPLOY_WITH_EMPTY_VARS\n ) {\n printWarningToConsole(\n `We are unable to fetch the environment variables from Zuplo for this project. \nDeployment will proceed because ZUPLO_ALLOW_DEPLOY_WITH_EMPTY_VARS is set. \nHowever, the environment variables will not be available. \nTo fix this, check that the project, ${argv.project} exists and this api-key has access to it.`\n );\n } else if (error instanceof UnableToAutoLinkToExistingProject) {\n await printCriticalFailureToConsoleAndExit(\n `We are unable to fetch the environment variables from Zuplo for this project. \nTo fix this, check that the project, ${argv.project} exists and this api-key has access to it.\nIf you want to force deployment without the environment variables, set ZUPLO_ALLOW_DEPLOY_WITH_EMPTY_VARS to true.`\n );\n } else {\n logger.error(error, \"Failed to fetch environment variables\");\n await printCriticalFailureToConsoleAndExit(\n `We are unable to fetch the environment variables from Zuplo for this project. \nTo fix this, check that the project, ${argv.project} exists and this api-key has access to it.`\n );\n }\n }\n\n // 2. Create the tarball locally\n const archiveMetadata = await archive(argv);\n logger.debug(`Tarball created locally at ${archiveMetadata.tarball}`);\n\n // 3. Build uploadUrl request\n const form = new FormData();\n const deploymentName = `${project}-${getPrettyBranch(\n archiveMetadata.metadata.branch\n )}`;\n form.set(\n \"file\",\n new Blob([readFileSync(archiveMetadata.tarball)], {\n type: \"application/gzip\",\n })\n );\n form.set(\"projectName\", project);\n form.set(\"deploymentName\", deploymentName);\n\n const uploadUrlResponse = await fetch(`${endpoint}/v1/deployments/build`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${argv.authToken}`,\n },\n body: form,\n });\n\n logger.debug(`Upload URL response: ${uploadUrlResponse.status}`);\n\n if (uploadUrlResponse.ok) {\n const spinner = printSpinnerToConsole(\n `Deploying the current branch ${archiveMetadata.metadata.branch} to project ${project} on account ${account}...`\n );\n\n // 4. Poll for build\n const { buildName } = await uploadUrlResponse.json();\n\n logger.debug(`Deployment started for ${buildName}`);\n\n const buildResult = await pollBuild(argv, endpoint, buildName, spinner);\n\n if (buildResult.conditionType === \"Complete\") {\n // Retrieve the deployment\n const deploymentResponse = await fetch(\n `${endpoint}/v1/deployments/${deploymentName}`,\n {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n const deploymentJSON: { deploymentUrl: string } =\n await deploymentResponse.json();\n restoreExistingZuploEnvAsNecessary(argv, existingZuploEnv);\n\n await printResultToConsoleAndExitGracefully(\n `Deployed to ${deploymentJSON.deploymentUrl}`,\n spinner\n );\n } else {\n restoreExistingZuploEnvAsNecessary(argv, existingZuploEnv);\n await printCriticalFailureToConsoleAndExit(\n `Failed to deploy the current environment. Here's the diagnostics: ${JSON.stringify(\n buildResult\n )}`,\n spinner\n );\n }\n } else {\n logger.error(\n await uploadUrlResponse.text(),\n \"Failed to upload to self-hosted build endpoint\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to upload to self-hosted build endpoint\"\n );\n }\n } catch (error) {\n logger.error(error);\n } finally {\n restoreExistingZuploEnvAsNecessary(argv, existingZuploEnv);\n }\n}\n\nfunction retrieveExistingZuploEnv(argv: SelfHostedArgs): string | undefined {\n const dir = argv.dir;\n const normalizedDir = join(relative(process.cwd(), dir));\n const envFilePath = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n if (existsSync(envFilePath)) {\n const envFileContent = readFileSync(envFilePath, \"utf-8\");\n return envFileContent;\n } else {\n return undefined;\n }\n}\n\nfunction restoreExistingZuploEnvAsNecessary(\n argv: SelfHostedArgs,\n originalValue: string | undefined\n) {\n if (originalValue) {\n const dir = argv.dir;\n const normalizedDir = join(relative(process.cwd(), dir));\n const envFilePath = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n writeFileSync(envFilePath, originalValue);\n }\n}\n\nconst getPrettyBranch = (branch: string): string => {\n // https://ricardometring.com/javascript-replace-special-characters\n return (\n branch\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\") // Remove accents\n .replace(/([^\\w]+|\\s+)/g, \"-\") // Replace space and other characters by hyphen\n // eslint-disable-next-line no-useless-escape\n .replace(/\\-\\-+/g, \"-\") // Replaces multiple hyphens by one hyphen\n .replace(/(^-+|-+$)/, \"\") // Remove extra hyphens from beginning or end of the string\n .replaceAll(\"_\", \"-\") // Replace underscores by hyphens (Url hosts cannot have underscores)\n .toLowerCase()\n .substring(0, MAX_PRETTY_BRANCH_LENGTH)\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/deploy/handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport {\n MAX_PRETTY_BRANCH_NAME as MAX_PRETTY_BRANCH_LENGTH,\n ZUPLO_SYSTEM_ENV_VAR,\n} from \"../common/constants.js\";\nimport { logger } from \"../common/logger.js\";\nimport {\n printCriticalFailureToConsoleAndExit,\n printDiagnosticsToConsole,\n printResultToConsoleAndExitGracefully,\n printSpinnerToConsole,\n printWarningToConsole,\n} from \"../common/output.js\";\nimport settings from \"../common/settings.js\";\nimport { RequiredProperties } from \"../common/utils/types.js\";\nimport { normalizeUrl } from \"../common/utils/urls.js\";\nimport { pullSystemConfig } from \"../common/populate.js\";\nimport { archive, generateMetadata } from \"./archive.js\";\nimport {\n UnableToAutoLinkToExistingProject,\n retrieveOrCreateEnvironment,\n} from \"./environments.js\";\nimport { upload } from \"./file-upload.js\";\nimport { pollBuild, pollDeployment } from \"./poll-deployment.js\";\n\nexport interface Arguments {\n account: string;\n project: string;\n dir: string;\n environment?: string;\n authToken: string;\n \"verify-remote\"?: boolean;\n \"self-hosted-endpoint\"?: string;\n \"override-repo-url\"?: string;\n}\n\nexport type SelfHostedArgs = RequiredProperties<\n Arguments,\n \"self-hosted-endpoint\"\n>;\n\nexport async function deploy(argv: Arguments) {\n if (argv[\"self-hosted-endpoint\"]) {\n const args = argv as SelfHostedArgs;\n await deployToSelfHosted(args);\n } else {\n await deployToSaas(argv);\n }\n}\n\nasync function deployToSaas(argv: Arguments) {\n // 1. Create the tarball locally\n const archiveMetadata = await archive(argv);\n logger.debug(`Tarball created locally at ${archiveMetadata.tarball}`);\n\n // 2. Build uploadUrl request\n const { account, project } = argv;\n\n const payload = {\n accountName: account,\n projectName: project,\n environment: archiveMetadata.metadata.branch,\n repositoryUrl: archiveMetadata.metadata.repoUrl,\n sha: archiveMetadata.metadata.sha,\n };\n\n const uploadUrlResponse = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/deployments/source-url`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${argv.authToken}`,\n },\n body: JSON.stringify(payload),\n }\n );\n\n logger.debug(`Upload URL response: ${uploadUrlResponse.status}`);\n\n if (uploadUrlResponse.ok) {\n // 3. Upload to request URL\n const { uploadUrl, deploymentId } = await uploadUrlResponse.json();\n\n printDiagnosticsToConsole(\n `Uploading source for deployment (${deploymentId})...`\n );\n\n const uploadResponse = await upload({\n tarballPath: archiveMetadata.tarball,\n uploadUrl,\n deploymentId,\n ...payload,\n });\n\n logger.debug(`Upload response: ${uploadResponse.status}`);\n\n if (uploadResponse.ok) {\n const spinner = printSpinnerToConsole(\n `Deploying the '${payload.environment}' environment to '${project}' on account '${account}'...`\n );\n\n const { url, logUrl } = await pollDeployment(\n argv,\n deploymentId,\n account,\n project,\n spinner\n );\n if (url) {\n await printResultToConsoleAndExitGracefully(\n `Deployed to ${url}`,\n spinner\n );\n } else {\n await printCriticalFailureToConsoleAndExit(\n `Failed to deploy the environment ${\n archiveMetadata.metadata.branch\n } to project ${project} on account ${account}.\\nFor more information, check the deployment logs in the Zuplo dashboard.\\n\n ${logUrl}`,\n spinner\n );\n }\n } else {\n logger.error(\n {\n status: uploadResponse.status,\n statusText: uploadResponse.statusText,\n },\n \"Failed to upload source to cloud storage\"\n );\n printDiagnosticsToConsole(\n \"Error: Failed to upload deployment source. Please try again.\"\n );\n }\n } else {\n logger.error(\n {\n status: uploadUrlResponse.status,\n statusText: uploadUrlResponse.statusText,\n },\n \"Failed to retrieve uploadUrl\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to upload deployment source. Please try again.\"\n );\n }\n}\n\nasync function deployToSelfHosted(argv: SelfHostedArgs) {\n const { account, project } = argv;\n\n let existingZuploEnv: string | undefined;\n\n try {\n // 0. Finagle the URL first\n const endpoint = normalizeUrl(argv[\"self-hosted-endpoint\"]);\n\n // 1. Perform the link on-behalf-of-the-user\n // Store the current .env.zuplo if there is one and restore it later\n existingZuploEnv = retrieveExistingZuploEnv(argv);\n const branch = (await generateMetadata(argv)).branch;\n try {\n const environmentToAutoLink = await retrieveOrCreateEnvironment(\n branch,\n argv\n );\n await pullSystemConfig({\n dir: argv.dir,\n environment: environmentToAutoLink.name,\n authToken: argv.authToken,\n });\n } catch (error) {\n if (\n error instanceof UnableToAutoLinkToExistingProject &&\n // eslint-disable-next-line node/no-process-env\n process.env.ZUPLO_ALLOW_DEPLOY_WITH_EMPTY_VARS\n ) {\n printWarningToConsole(\n `We are unable to fetch the environment variables from Zuplo for this project. \nDeployment will proceed because ZUPLO_ALLOW_DEPLOY_WITH_EMPTY_VARS is set. \nHowever, the environment variables will not be available. \nTo fix this, check that the project, ${argv.project} exists and this api-key has access to it.`\n );\n } else if (error instanceof UnableToAutoLinkToExistingProject) {\n await printCriticalFailureToConsoleAndExit(\n `We are unable to fetch the environment variables from Zuplo for this project. \nTo fix this, check that the project, ${argv.project} exists and this api-key has access to it.\nIf you want to force deployment without the environment variables, set ZUPLO_ALLOW_DEPLOY_WITH_EMPTY_VARS to true.`\n );\n } else {\n logger.error(error, \"Failed to fetch environment variables\");\n await printCriticalFailureToConsoleAndExit(\n `We are unable to fetch the environment variables from Zuplo for this project. \nTo fix this, check that the project, ${argv.project} exists and this api-key has access to it.`\n );\n }\n }\n\n // 2. Create the tarball locally\n const archiveMetadata = await archive(argv);\n logger.debug(`Tarball created locally at ${archiveMetadata.tarball}`);\n\n // 3. Build uploadUrl request\n const form = new FormData();\n const deploymentName = `${project}-${getPrettyBranch(\n archiveMetadata.metadata.branch\n )}`;\n form.set(\n \"file\",\n new Blob([readFileSync(archiveMetadata.tarball)], {\n type: \"application/gzip\",\n })\n );\n form.set(\"projectName\", project);\n form.set(\"deploymentName\", deploymentName);\n\n const uploadUrlResponse = await fetch(`${endpoint}/v1/deployments/build`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${argv.authToken}`,\n },\n body: form,\n });\n\n logger.debug(`Upload URL response: ${uploadUrlResponse.status}`);\n\n if (uploadUrlResponse.ok) {\n const spinner = printSpinnerToConsole(\n `Deploying the current branch ${archiveMetadata.metadata.branch} to project ${project} on account ${account}...`\n );\n\n // 4. Poll for build\n const { buildName } = await uploadUrlResponse.json();\n\n logger.debug(`Deployment started for ${buildName}`);\n\n const buildResult = await pollBuild(argv, endpoint, buildName, spinner);\n\n if (buildResult.conditionType === \"Complete\") {\n // Retrieve the deployment\n const deploymentResponse = await fetch(\n `${endpoint}/v1/deployments/${deploymentName}`,\n {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n const deploymentJSON: { deploymentUrl: string } =\n await deploymentResponse.json();\n restoreExistingZuploEnvAsNecessary(argv, existingZuploEnv);\n\n await printResultToConsoleAndExitGracefully(\n `Deployed to ${deploymentJSON.deploymentUrl}`,\n spinner\n );\n } else {\n restoreExistingZuploEnvAsNecessary(argv, existingZuploEnv);\n await printCriticalFailureToConsoleAndExit(\n `Failed to deploy the current environment. Here's the diagnostics: ${JSON.stringify(\n buildResult\n )}`,\n spinner\n );\n }\n } else {\n logger.error(\n await uploadUrlResponse.text(),\n \"Failed to upload to self-hosted build endpoint\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to upload to self-hosted build endpoint\"\n );\n }\n } catch (error) {\n logger.error(error);\n } finally {\n restoreExistingZuploEnvAsNecessary(argv, existingZuploEnv);\n }\n}\n\nfunction retrieveExistingZuploEnv(argv: SelfHostedArgs): string | undefined {\n const dir = argv.dir;\n const normalizedDir = join(relative(process.cwd(), dir));\n const envFilePath = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n if (existsSync(envFilePath)) {\n const envFileContent = readFileSync(envFilePath, \"utf-8\");\n return envFileContent;\n } else {\n return undefined;\n }\n}\n\nfunction restoreExistingZuploEnvAsNecessary(\n argv: SelfHostedArgs,\n originalValue: string | undefined\n) {\n if (originalValue) {\n const dir = argv.dir;\n const normalizedDir = join(relative(process.cwd(), dir));\n const envFilePath = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n writeFileSync(envFilePath, originalValue);\n }\n}\n\nconst getPrettyBranch = (branch: string): string => {\n // https://ricardometring.com/javascript-replace-special-characters\n return (\n branch\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\") // Remove accents\n .replace(/([^\\w]+|\\s+)/g, \"-\") // Replace space and other characters by hyphen\n // eslint-disable-next-line no-useless-escape\n .replace(/\\-\\-+/g, \"-\") // Replaces multiple hyphens by one hyphen\n .replace(/(^-+|-+$)/, \"\") // Remove extra hyphens from beginning or end of the string\n .replaceAll(\"_\", \"-\") // Replace underscores by hyphens (Url hosts cannot have underscores)\n .toLowerCase()\n .substring(0, MAX_PRETTY_BRANCH_LENGTH)\n );\n};\n"]}
|
package/dist/link/handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { printResultToConsoleAndExitGracefully } from "../common/output.js";
|
|
2
|
-
import {
|
|
2
|
+
import { pullLocalConfig, safeMergeConfig } from "../common/populate.js";
|
|
3
3
|
export async function link(argv) {
|
|
4
4
|
const account = argv.account;
|
|
5
5
|
const project = argv.project;
|
|
@@ -8,7 +8,7 @@ export async function link(argv) {
|
|
|
8
8
|
throw new Error("Invalid state: account, project, or environment is not set.");
|
|
9
9
|
}
|
|
10
10
|
await safeMergeConfig(argv.dir, project);
|
|
11
|
-
await
|
|
11
|
+
await pullLocalConfig(argv);
|
|
12
12
|
await printResultToConsoleAndExitGracefully(`
|
|
13
13
|
Successfully linked your local directory to the ${project} project in the ${account} account.
|
|
14
14
|
.env.zuplo and zuplo.jsonc have been updated with the new values.`);
|
package/dist/link/handler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/link/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/link/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAUzE,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAe;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IAErC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAGD,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAGzC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAE5B,MAAM,qCAAqC,CAAC;kDACI,OAAO,mBAAmB,OAAO;kEACjB,CAAC,CAAC;AACpE,CAAC","sourcesContent":["import { printResultToConsoleAndExitGracefully } from \"../common/output.js\";\nimport { pullLocalConfig, safeMergeConfig } from \"../common/populate.js\";\n\nexport interface Arguments {\n dir: string;\n authToken: string;\n account?: string;\n project?: string;\n environment?: string;\n}\n\nexport async function link(argv: Arguments) {\n const account = argv.account;\n const project = argv.project;\n const environment = argv.environment;\n\n if (!account || !project || !environment) {\n throw new Error(\n \"Invalid state: account, project, or environment is not set.\"\n );\n }\n\n // Create a zuplo.jsonc file if it doesn't exist\n await safeMergeConfig(argv.dir, project);\n\n // Safely merge in other auxiliary files\n await pullLocalConfig(argv);\n\n await printResultToConsoleAndExitGracefully(`\nSuccessfully linked your local directory to the ${project} project in the ${account} account.\n.env.zuplo and zuplo.jsonc have been updated with the new values.`);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/cli.ts","../src/types.d.ts","../src/__tests__/archive-utils.test.ts","../src/__tests__/engine.test.ts","../src/__tests__/import-openapi-utils.test.ts","../src/__tests__/import-openapi.test.ts","../src/__tests__/oas-test-data.ts","../src/__tests__/outdated.test.ts","../src/__tests__/tsconfig-upgrader.test.ts","../src/__tests__/integration/delete.integration.test.ts","../src/__tests__/integration/deploy.integration.test.ts","../src/__tests__/integration/jest-mocks-setup.ts","../src/__tests__/integration/jest-setup.ts","../src/__tests__/integration/link.integration.test.ts","../src/__tests__/integration/list.integration.test.ts","../src/__tests__/integration/test-utils.ts","../src/__tests__/integration/tunnel.integration.test.ts","../src/__tests__/integration/variable.integration.test.ts","../src/build/handler.ts","../src/cmds/build.ts","../src/cmds/compile.ts","../src/cmds/convert.ts","../src/cmds/delete.ts","../src/cmds/deploy.ts","../src/cmds/dev.ts","../src/cmds/editor.ts","../src/cmds/link.ts","../src/cmds/list.ts","../src/cmds/login.ts","../src/cmds/test.ts","../src/cmds/project/import-openapi.ts","../src/cmds/project/index.ts","../src/cmds/project/update.ts","../src/cmds/source/import-openapi.ts","../src/cmds/source/index.ts","../src/cmds/source/upgrade.ts","../src/cmds/tunnel/create.ts","../src/cmds/tunnel/delete.ts","../src/cmds/tunnel/describe.ts","../src/cmds/tunnel/index.ts","../src/cmds/tunnel/list.ts","../src/cmds/tunnel/rotate-token.ts","../src/cmds/tunnel/services/describe.ts","../src/cmds/tunnel/services/index.ts","../src/cmds/tunnel/services/update.ts","../src/cmds/variable/create.ts","../src/cmds/variable/index.ts","../src/cmds/variable/update.ts","../src/common/alias.ts","../src/common/args.ts","../src/common/constants.ts","../src/common/handler.ts","../src/common/logger.ts","../src/common/models.ts","../src/common/outdated.ts","../src/common/output.ts","../src/common/settings.ts","../src/common/worker-output.ts","../src/common/analytics/lib.ts","../src/common/api/lib.ts","../src/common/machine-id/lib.ts","../src/common/middleware/authentication.ts","../src/common/middleware/get-account-param.ts","../src/common/middleware/get-environment-param.ts","../src/common/middleware/get-project-param.ts","../src/common/middleware/logging.ts","../src/common/middleware/user-configuration.ts","../src/common/middleware/user-identification.ts","../src/common/upgraders/lib.ts","../src/common/upgraders/package-json-upgrader.ts","../src/common/upgraders/tsconfig-upgrader.ts","../src/common/upgraders/vscode-settings-json-upgrader.ts","../src/common/utils/box.ts","../src/common/utils/ports.ts","../src/common/utils/pretty-print-environment-prompt.ts","../src/common/utils/types.ts","../src/common/utils/urls.ts","../src/common/validators/file-system-validator.ts","../src/common/validators/lib.ts","../src/common/validators/project-name-validator.ts","../src/common/xdg/lib.ts","../src/compile/handler.ts","../src/convert/engine.ts","../src/convert/handler.ts","../src/convert/routes.legacy.ts","../src/delete/handler.ts","../src/delete/poll-deployment.ts","../src/deploy/archive.ts","../src/deploy/environments.ts","../src/deploy/file-upload.ts","../src/deploy/handler.ts","../src/deploy/poll-deployment.ts","../src/dev/handler.ts","../src/editor/handler.ts","../src/editor/assets/index-7e947de6.js","../src/editor/server/cors-plugin.ts","../src/editor/server/server.ts","../src/editor/server/xfs.ts","../src/link/handler.ts","../src/
|
|
1
|
+
{"root":["../src/cli.ts","../src/types.d.ts","../src/__tests__/archive-utils.test.ts","../src/__tests__/engine.test.ts","../src/__tests__/import-openapi-utils.test.ts","../src/__tests__/import-openapi.test.ts","../src/__tests__/oas-test-data.ts","../src/__tests__/outdated.test.ts","../src/__tests__/populate.test.ts","../src/__tests__/tsconfig-upgrader.test.ts","../src/__tests__/integration/delete.integration.test.ts","../src/__tests__/integration/deploy.integration.test.ts","../src/__tests__/integration/jest-mocks-setup.ts","../src/__tests__/integration/jest-setup.ts","../src/__tests__/integration/link.integration.test.ts","../src/__tests__/integration/list.integration.test.ts","../src/__tests__/integration/test-utils.ts","../src/__tests__/integration/tunnel.integration.test.ts","../src/__tests__/integration/variable.integration.test.ts","../src/build/handler.ts","../src/cmds/build.ts","../src/cmds/compile.ts","../src/cmds/convert.ts","../src/cmds/delete.ts","../src/cmds/deploy.ts","../src/cmds/dev.ts","../src/cmds/editor.ts","../src/cmds/link.ts","../src/cmds/list.ts","../src/cmds/login.ts","../src/cmds/test.ts","../src/cmds/project/import-openapi.ts","../src/cmds/project/index.ts","../src/cmds/project/update.ts","../src/cmds/source/import-openapi.ts","../src/cmds/source/index.ts","../src/cmds/source/upgrade.ts","../src/cmds/tunnel/create.ts","../src/cmds/tunnel/delete.ts","../src/cmds/tunnel/describe.ts","../src/cmds/tunnel/index.ts","../src/cmds/tunnel/list.ts","../src/cmds/tunnel/rotate-token.ts","../src/cmds/tunnel/services/describe.ts","../src/cmds/tunnel/services/index.ts","../src/cmds/tunnel/services/update.ts","../src/cmds/variable/create.ts","../src/cmds/variable/index.ts","../src/cmds/variable/update.ts","../src/common/alias.ts","../src/common/args.ts","../src/common/constants.ts","../src/common/handler.ts","../src/common/logger.ts","../src/common/models.ts","../src/common/outdated.ts","../src/common/output.ts","../src/common/populate.ts","../src/common/settings.ts","../src/common/worker-output.ts","../src/common/analytics/lib.ts","../src/common/api/lib.ts","../src/common/machine-id/lib.ts","../src/common/middleware/authentication.ts","../src/common/middleware/get-account-param.ts","../src/common/middleware/get-environment-param.ts","../src/common/middleware/get-project-param.ts","../src/common/middleware/logging.ts","../src/common/middleware/user-configuration.ts","../src/common/middleware/user-identification.ts","../src/common/upgraders/lib.ts","../src/common/upgraders/package-json-upgrader.ts","../src/common/upgraders/tsconfig-upgrader.ts","../src/common/upgraders/vscode-settings-json-upgrader.ts","../src/common/utils/box.ts","../src/common/utils/ports.ts","../src/common/utils/pretty-print-environment-prompt.ts","../src/common/utils/types.ts","../src/common/utils/urls.ts","../src/common/validators/file-system-validator.ts","../src/common/validators/lib.ts","../src/common/validators/project-name-validator.ts","../src/common/xdg/lib.ts","../src/compile/handler.ts","../src/convert/engine.ts","../src/convert/handler.ts","../src/convert/routes.legacy.ts","../src/delete/handler.ts","../src/delete/poll-deployment.ts","../src/deploy/archive.ts","../src/deploy/environments.ts","../src/deploy/file-upload.ts","../src/deploy/handler.ts","../src/deploy/poll-deployment.ts","../src/dev/handler.ts","../src/editor/handler.ts","../src/editor/assets/index-7e947de6.js","../src/editor/server/cors-plugin.ts","../src/editor/server/server.ts","../src/editor/server/xfs.ts","../src/link/handler.ts","../src/list/handler.ts","../src/login/html.ts","../src/login/login.ts","../src/login/server.ts","../src/login/tokens.ts","../src/project/import-openapi/handler.ts","../src/project/import-openapi/interfaces.ts","../src/project/import-openapi/utils.ts","../src/project/update/handler.ts","../src/test/esbuild-config.ts","../src/test/handler.ts","../src/test/invoke-test.ts","../src/test/test-files.test.ts","../src/test/test-files.ts","../src/test/esbuild-plugins/node-test-prep-plugin.ts","../src/tunnel/models.ts","../src/tunnel/create/handler.ts","../src/tunnel/delete/handler.ts","../src/tunnel/delete/poll-teardown-operation.ts","../src/tunnel/describe/handler.ts","../src/tunnel/list/handler.ts","../src/tunnel/rotate-token/handler.ts","../src/tunnel/services/describe/handler.ts","../src/tunnel/services/update/handler.ts","../src/tunnel/services/update/poll-provisioning-operations.ts","../src/variable/models.ts","../src/variable/create/handler.ts","../src/variable/update/handler.ts"],"version":"5.8.2"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuplo/cli",
|
|
3
|
-
"version": "6.52.
|
|
3
|
+
"version": "6.52.24",
|
|
4
4
|
"repository": "https://github.com/zuplo/zuplo",
|
|
5
5
|
"author": "Zuplo, Inc.",
|
|
6
6
|
"type": "module",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"@opentelemetry/api": "1.9.0",
|
|
30
30
|
"@sentry/node": "9.22.0",
|
|
31
31
|
"@swc/core": "1.10.18",
|
|
32
|
-
"@zuplo/core": "6.52.
|
|
33
|
-
"@zuplo/openapi-tools": "6.52.
|
|
34
|
-
"@zuplo/runtime": "6.52.
|
|
32
|
+
"@zuplo/core": "6.52.24",
|
|
33
|
+
"@zuplo/openapi-tools": "6.52.24",
|
|
34
|
+
"@zuplo/runtime": "6.52.24",
|
|
35
35
|
"as-table": "1.0.55",
|
|
36
36
|
"chalk": "5.4.1",
|
|
37
37
|
"chokidar": "3.5.3",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"populate.d.ts","sourceRoot":"","sources":["../../src/link/populate.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAkDjE;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,CAAC,iBAkD3D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"populate.js","sourceRoot":"","sources":["../../src/link/populate.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport { applyEdits, modify } from \"jsonc-parser\";\nimport { format } from \"prettier\";\nimport {\n ZUPLO_FALLBACK_JSON_FILE,\n ZUPLO_PREFERRED_JSON_FILE,\n ZUPLO_SYSTEM_ENV_VAR,\n} from \"../common/constants.js\";\nimport { logger } from \"../common/logger.js\";\nimport { printCriticalFailureToConsoleAndExit } from \"../common/output.js\";\nimport settings from \"../common/settings.js\";\nimport { Arguments } from \"../link/handler.js\";\n\nexport async function safeMergeConfig(dir: string, project: string) {\n const normalizedDir = join(relative(process.cwd(), dir));\n const zuploPreferredConfigFile = join(\n normalizedDir,\n ZUPLO_PREFERRED_JSON_FILE\n );\n const zuploFallbackConfigFile = join(normalizedDir, ZUPLO_FALLBACK_JSON_FILE);\n if (existsSync(zuploPreferredConfigFile)) {\n // Process the file, while respecting comments\n // Apply the edits sequentially\n const originalContents = await readFile(zuploPreferredConfigFile, \"utf-8\");\n const modifyProjectEdit = modify(originalContents, [\"project\"], project, {\n getInsertionIndex: () => 2,\n });\n const contentsPostProject = applyEdits(originalContents, modifyProjectEdit);\n const formatted = await format(contentsPostProject, {\n parser: \"json\",\n quoteProps: \"as-needed\",\n });\n await writeFile(zuploPreferredConfigFile, formatted);\n } else if (existsSync(zuploFallbackConfigFile)) {\n // Copy the file over\n const config = JSON.parse(await readFile(zuploFallbackConfigFile, \"utf-8\"));\n const formatted = await format(\n JSON.stringify({\n version: 1,\n project: project,\n compatibilityDate: config.compatibilityDate,\n }),\n {\n parser: \"json\",\n quoteProps: \"as-needed\",\n }\n );\n await writeFile(zuploPreferredConfigFile, formatted);\n } else {\n // Create new file\n const formatted = await format(\n JSON.stringify({\n version: 1,\n project: project,\n compatibilityDate: \"2023-03-14\",\n }),\n {\n parser: \"json\",\n quoteProps: \"as-needed\",\n }\n );\n await writeFile(zuploPreferredConfigFile, formatted);\n }\n}\n\nexport async function pullSystemConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = join(relative(process.cwd(), argv.dir));\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n\n const content = `\n# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\n\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}\n`;\n\n await writeFile(zuploPreferredConfigFile, content);\n}\n"]}
|