@strapi/cloud-cli 0.0.0-next.80375f19ecbd1a8f298515d011c3ddb5ed05f924 → 0.0.0-next.820adfc37c687bbcc4a213ae6929c541358b71e8
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/bin.js +2 -2
- package/dist/bin.js.map +1 -1
- package/dist/index.js +805 -165
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +802 -159
- package/dist/index.mjs.map +1 -1
- package/dist/src/cloud/command.d.ts +3 -0
- package/dist/src/cloud/command.d.ts.map +1 -0
- package/dist/src/create-project/action.d.ts.map +1 -1
- package/dist/src/create-project/command.d.ts.map +1 -1
- package/dist/src/create-project/utils/get-project-name-from-pkg.d.ts +3 -0
- package/dist/src/create-project/utils/get-project-name-from-pkg.d.ts.map +1 -0
- package/dist/src/create-project/utils/project-questions.utils.d.ts +20 -0
- package/dist/src/create-project/utils/project-questions.utils.d.ts.map +1 -0
- package/dist/src/deploy-project/action.d.ts +5 -1
- package/dist/src/deploy-project/action.d.ts.map +1 -1
- package/dist/src/deploy-project/command.d.ts.map +1 -1
- package/dist/src/environment/command.d.ts +3 -0
- package/dist/src/environment/command.d.ts.map +1 -0
- package/dist/src/environment/link/action.d.ts +4 -0
- package/dist/src/environment/link/action.d.ts.map +1 -0
- package/dist/src/environment/link/command.d.ts +4 -0
- package/dist/src/environment/link/command.d.ts.map +1 -0
- package/dist/src/environment/link/index.d.ts +7 -0
- package/dist/src/environment/link/index.d.ts.map +1 -0
- package/dist/src/environment/list/action.d.ts +4 -0
- package/dist/src/environment/list/action.d.ts.map +1 -0
- package/dist/src/environment/list/command.d.ts +4 -0
- package/dist/src/environment/list/command.d.ts.map +1 -0
- package/dist/src/environment/list/index.d.ts +7 -0
- package/dist/src/environment/list/index.d.ts.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/link/action.d.ts +4 -0
- package/dist/src/link/action.d.ts.map +1 -0
- package/dist/src/link/command.d.ts +7 -0
- package/dist/src/link/command.d.ts.map +1 -0
- package/dist/src/link/index.d.ts +7 -0
- package/dist/src/link/index.d.ts.map +1 -0
- package/dist/src/list-projects/action.d.ts +4 -0
- package/dist/src/list-projects/action.d.ts.map +1 -0
- package/dist/src/list-projects/command.d.ts +7 -0
- package/dist/src/list-projects/command.d.ts.map +1 -0
- package/dist/src/list-projects/index.d.ts +7 -0
- package/dist/src/list-projects/index.d.ts.map +1 -0
- package/dist/src/login/action.d.ts.map +1 -1
- package/dist/src/login/command.d.ts.map +1 -1
- package/dist/src/logout/action.d.ts.map +1 -1
- package/dist/src/logout/command.d.ts.map +1 -1
- package/dist/src/services/build-logs.d.ts.map +1 -1
- package/dist/src/services/cli-api.d.ts +64 -9
- package/dist/src/services/cli-api.d.ts.map +1 -1
- package/dist/src/services/strapi-info-save.d.ts +15 -2
- package/dist/src/services/strapi-info-save.d.ts.map +1 -1
- package/dist/src/services/token.d.ts.map +1 -1
- package/dist/src/types.d.ts +8 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/analytics.d.ts +4 -0
- package/dist/src/utils/analytics.d.ts.map +1 -0
- package/dist/src/utils/compress-files.d.ts.map +1 -1
- package/dist/src/utils/get-local-config.d.ts +6 -0
- package/dist/src/utils/get-local-config.d.ts.map +1 -0
- package/dist/src/utils/helpers.d.ts.map +1 -1
- package/dist/src/utils/pkg.d.ts.map +1 -1
- package/package.json +12 -10
package/dist/index.mjs
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import crypto$1 from "crypto";
|
|
2
|
-
import fse from "fs-extra";
|
|
2
|
+
import * as fse from "fs-extra";
|
|
3
|
+
import fse__default from "fs-extra";
|
|
4
|
+
import inquirer from "inquirer";
|
|
5
|
+
import boxen from "boxen";
|
|
3
6
|
import * as path from "path";
|
|
4
7
|
import path__default from "path";
|
|
5
8
|
import chalk from "chalk";
|
|
6
9
|
import axios, { AxiosError } from "axios";
|
|
7
10
|
import * as crypto from "node:crypto";
|
|
8
11
|
import { env } from "@strapi/utils";
|
|
9
|
-
import * as fs from "fs";
|
|
10
12
|
import * as tar from "tar";
|
|
11
13
|
import { minimatch } from "minimatch";
|
|
12
|
-
import inquirer from "inquirer";
|
|
13
14
|
import { defaults, has } from "lodash/fp";
|
|
14
15
|
import os from "os";
|
|
15
16
|
import XDGAppPaths from "xdg-app-paths";
|
|
17
|
+
import { merge } from "lodash";
|
|
16
18
|
import jwksClient from "jwks-rsa";
|
|
17
19
|
import jwt from "jsonwebtoken";
|
|
18
20
|
import stringify from "fast-safe-stringify";
|
|
19
21
|
import ora from "ora";
|
|
20
22
|
import * as cliProgress from "cli-progress";
|
|
21
|
-
import EventSource from "eventsource";
|
|
22
|
-
import fs$1 from "fs/promises";
|
|
23
23
|
import pkgUp from "pkg-up";
|
|
24
24
|
import * as yup from "yup";
|
|
25
|
+
import EventSource from "eventsource";
|
|
26
|
+
import { createCommand } from "commander";
|
|
25
27
|
const apiConfig = {
|
|
26
28
|
apiBaseUrl: env("STRAPI_CLI_CLOUD_API", "https://cloud-cli-api.strapi.io"),
|
|
27
29
|
dashboardBaseUrl: env("STRAPI_CLI_CLOUD_DASHBOARD", "https://cloud.strapi.io")
|
|
@@ -40,23 +42,6 @@ const IGNORED_PATTERNS = [
|
|
|
40
42
|
"**/.idea/**",
|
|
41
43
|
"**/.vscode/**"
|
|
42
44
|
];
|
|
43
|
-
const getFiles = (dirPath, ignorePatterns = [], arrayOfFiles = [], subfolder = "") => {
|
|
44
|
-
const entries = fs.readdirSync(path.join(dirPath, subfolder));
|
|
45
|
-
entries.forEach((entry) => {
|
|
46
|
-
const entryPathFromRoot = path.join(subfolder, entry);
|
|
47
|
-
const entryPath = path.relative(dirPath, entryPathFromRoot);
|
|
48
|
-
const isIgnored = isIgnoredFile(dirPath, entryPathFromRoot, ignorePatterns);
|
|
49
|
-
if (isIgnored) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (fs.statSync(entryPath).isDirectory()) {
|
|
53
|
-
getFiles(dirPath, ignorePatterns, arrayOfFiles, entryPathFromRoot);
|
|
54
|
-
} else {
|
|
55
|
-
arrayOfFiles.push(entryPath);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
return arrayOfFiles;
|
|
59
|
-
};
|
|
60
45
|
const isIgnoredFile = (folderPath, file, ignorePatterns) => {
|
|
61
46
|
ignorePatterns.push(...IGNORED_PATTERNS);
|
|
62
47
|
const relativeFilePath = path.join(folderPath, file);
|
|
@@ -74,16 +59,34 @@ const isIgnoredFile = (folderPath, file, ignorePatterns) => {
|
|
|
74
59
|
}
|
|
75
60
|
return isIgnored;
|
|
76
61
|
};
|
|
77
|
-
const
|
|
62
|
+
const getFiles = async (dirPath, ignorePatterns = [], subfolder = "") => {
|
|
63
|
+
const arrayOfFiles = [];
|
|
64
|
+
const entries = await fse.readdir(path.join(dirPath, subfolder));
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
const entryPathFromRoot = path.join(subfolder, entry);
|
|
67
|
+
const entryPath = path.relative(dirPath, entryPathFromRoot);
|
|
68
|
+
const isIgnored = isIgnoredFile(dirPath, entryPathFromRoot, ignorePatterns);
|
|
69
|
+
if (!isIgnored) {
|
|
70
|
+
if (fse.statSync(entryPath).isDirectory()) {
|
|
71
|
+
const subFiles = await getFiles(dirPath, ignorePatterns, entryPathFromRoot);
|
|
72
|
+
arrayOfFiles.push(...subFiles);
|
|
73
|
+
} else {
|
|
74
|
+
arrayOfFiles.push(entryPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return arrayOfFiles;
|
|
79
|
+
};
|
|
80
|
+
const readGitignore = async (folderPath) => {
|
|
78
81
|
const gitignorePath = path.resolve(folderPath, ".gitignore");
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const gitignoreContent =
|
|
82
|
+
const pathExist = await fse.pathExists(gitignorePath);
|
|
83
|
+
if (!pathExist) return [];
|
|
84
|
+
const gitignoreContent = await fse.readFile(gitignorePath, "utf8");
|
|
82
85
|
return gitignoreContent.split(/\r?\n/).filter((line) => Boolean(line.trim()) && !line.startsWith("#"));
|
|
83
86
|
};
|
|
84
87
|
const compressFilesToTar = async (storagePath, folderToCompress, filename) => {
|
|
85
|
-
const ignorePatterns = readGitignore(folderToCompress);
|
|
86
|
-
const filesToCompress = getFiles(folderToCompress, ignorePatterns);
|
|
88
|
+
const ignorePatterns = await readGitignore(folderToCompress);
|
|
89
|
+
const filesToCompress = await getFiles(folderToCompress, ignorePatterns);
|
|
87
90
|
return tar.c(
|
|
88
91
|
{
|
|
89
92
|
gzip: true,
|
|
@@ -96,7 +99,7 @@ const APP_FOLDER_NAME = "com.strapi.cli";
|
|
|
96
99
|
const CONFIG_FILENAME = "config.json";
|
|
97
100
|
async function checkDirectoryExists(directoryPath) {
|
|
98
101
|
try {
|
|
99
|
-
const fsStat = await
|
|
102
|
+
const fsStat = await fse__default.lstat(directoryPath);
|
|
100
103
|
return fsStat.isDirectory();
|
|
101
104
|
} catch (e) {
|
|
102
105
|
return false;
|
|
@@ -104,24 +107,24 @@ async function checkDirectoryExists(directoryPath) {
|
|
|
104
107
|
}
|
|
105
108
|
async function getTmpStoragePath() {
|
|
106
109
|
const storagePath = path__default.join(os.tmpdir(), APP_FOLDER_NAME);
|
|
107
|
-
await
|
|
110
|
+
await fse__default.ensureDir(storagePath);
|
|
108
111
|
return storagePath;
|
|
109
112
|
}
|
|
110
113
|
async function getConfigPath() {
|
|
111
114
|
const configDirs = XDGAppPaths(APP_FOLDER_NAME).configDirs();
|
|
112
115
|
const configPath = configDirs.find(checkDirectoryExists);
|
|
113
116
|
if (!configPath) {
|
|
114
|
-
await
|
|
117
|
+
await fse__default.ensureDir(configDirs[0]);
|
|
115
118
|
return configDirs[0];
|
|
116
119
|
}
|
|
117
120
|
return configPath;
|
|
118
121
|
}
|
|
119
|
-
async function getLocalConfig() {
|
|
122
|
+
async function getLocalConfig$1() {
|
|
120
123
|
const configPath = await getConfigPath();
|
|
121
124
|
const configFilePath = path__default.join(configPath, CONFIG_FILENAME);
|
|
122
|
-
await
|
|
125
|
+
await fse__default.ensureFile(configFilePath);
|
|
123
126
|
try {
|
|
124
|
-
return await
|
|
127
|
+
return await fse__default.readJSON(configFilePath, { encoding: "utf8", throws: true });
|
|
125
128
|
} catch (e) {
|
|
126
129
|
return {};
|
|
127
130
|
}
|
|
@@ -129,10 +132,10 @@ async function getLocalConfig() {
|
|
|
129
132
|
async function saveLocalConfig(data) {
|
|
130
133
|
const configPath = await getConfigPath();
|
|
131
134
|
const configFilePath = path__default.join(configPath, CONFIG_FILENAME);
|
|
132
|
-
await
|
|
135
|
+
await fse__default.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
|
|
133
136
|
}
|
|
134
137
|
const name = "@strapi/cloud-cli";
|
|
135
|
-
const version = "
|
|
138
|
+
const version = "5.5.0";
|
|
136
139
|
const description = "Commands to interact with the Strapi Cloud";
|
|
137
140
|
const keywords = [
|
|
138
141
|
"strapi",
|
|
@@ -173,17 +176,19 @@ const scripts = {
|
|
|
173
176
|
build: "pack-up build",
|
|
174
177
|
clean: "run -T rimraf ./dist",
|
|
175
178
|
lint: "run -T eslint .",
|
|
179
|
+
"test:unit": "run -T jest",
|
|
176
180
|
watch: "pack-up watch"
|
|
177
181
|
};
|
|
178
182
|
const dependencies = {
|
|
179
|
-
"@strapi/utils": "
|
|
180
|
-
axios: "1.
|
|
183
|
+
"@strapi/utils": "workspace:*",
|
|
184
|
+
axios: "1.7.4",
|
|
185
|
+
boxen: "5.1.2",
|
|
181
186
|
chalk: "4.1.2",
|
|
182
187
|
"cli-progress": "3.12.0",
|
|
183
188
|
commander: "8.3.0",
|
|
184
189
|
eventsource: "2.0.2",
|
|
185
190
|
"fast-safe-stringify": "2.1.1",
|
|
186
|
-
"fs-extra": "
|
|
191
|
+
"fs-extra": "11.2.0",
|
|
187
192
|
inquirer: "8.2.5",
|
|
188
193
|
jsonwebtoken: "9.0.0",
|
|
189
194
|
"jwks-rsa": "3.1.0",
|
|
@@ -192,22 +197,23 @@ const dependencies = {
|
|
|
192
197
|
open: "8.4.0",
|
|
193
198
|
ora: "5.4.1",
|
|
194
199
|
"pkg-up": "3.1.0",
|
|
195
|
-
tar: "6.1
|
|
200
|
+
tar: "6.2.1",
|
|
196
201
|
"xdg-app-paths": "8.3.0",
|
|
197
202
|
yup: "0.32.9"
|
|
198
203
|
};
|
|
199
204
|
const devDependencies = {
|
|
200
|
-
"@strapi/pack-up": "
|
|
205
|
+
"@strapi/pack-up": "5.0.2",
|
|
201
206
|
"@types/cli-progress": "3.11.5",
|
|
202
207
|
"@types/eventsource": "1.1.15",
|
|
203
208
|
"@types/lodash": "^4.14.191",
|
|
204
|
-
"eslint-config-custom": "
|
|
205
|
-
tsconfig: "
|
|
209
|
+
"eslint-config-custom": "workspace:*",
|
|
210
|
+
tsconfig: "workspace:*"
|
|
206
211
|
};
|
|
207
212
|
const engines = {
|
|
208
|
-
node: ">=18.0.0 <=
|
|
213
|
+
node: ">=18.0.0 <=22.x.x",
|
|
209
214
|
npm: ">=6.0.0"
|
|
210
215
|
};
|
|
216
|
+
const gitHead = "7d785703f52464577d077c4618cbe68b44f8a9cd";
|
|
211
217
|
const packageJson = {
|
|
212
218
|
name,
|
|
213
219
|
version,
|
|
@@ -228,11 +234,12 @@ const packageJson = {
|
|
|
228
234
|
scripts,
|
|
229
235
|
dependencies,
|
|
230
236
|
devDependencies,
|
|
231
|
-
engines
|
|
237
|
+
engines,
|
|
238
|
+
gitHead
|
|
232
239
|
};
|
|
233
240
|
const VERSION = "v1";
|
|
234
241
|
async function cloudApiFactory({ logger }, token) {
|
|
235
|
-
const localConfig = await getLocalConfig();
|
|
242
|
+
const localConfig = await getLocalConfig$1();
|
|
236
243
|
const customHeaders = {
|
|
237
244
|
"x-device-id": localConfig.deviceId,
|
|
238
245
|
"x-app-version": packageJson.version,
|
|
@@ -255,7 +262,7 @@ async function cloudApiFactory({ logger }, token) {
|
|
|
255
262
|
deploy({ filePath, project }, { onUploadProgress }) {
|
|
256
263
|
return axiosCloudAPI.post(
|
|
257
264
|
`/deploy/${project.name}`,
|
|
258
|
-
{ file:
|
|
265
|
+
{ file: fse__default.createReadStream(filePath), targetEnvironment: project.targetEnvironment },
|
|
259
266
|
{
|
|
260
267
|
headers: {
|
|
261
268
|
"Content-Type": "multipart/form-data"
|
|
@@ -298,8 +305,75 @@ async function cloudApiFactory({ logger }, token) {
|
|
|
298
305
|
throw error;
|
|
299
306
|
}
|
|
300
307
|
},
|
|
301
|
-
listProjects() {
|
|
302
|
-
|
|
308
|
+
async listProjects() {
|
|
309
|
+
try {
|
|
310
|
+
const response = await axiosCloudAPI.get("/projects");
|
|
311
|
+
if (response.status !== 200) {
|
|
312
|
+
throw new Error("Error fetching cloud projects from the server.");
|
|
313
|
+
}
|
|
314
|
+
return response;
|
|
315
|
+
} catch (error) {
|
|
316
|
+
logger.debug(
|
|
317
|
+
"🥲 Oops! Couldn't retrieve your project's list from the server. Please try again."
|
|
318
|
+
);
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
async listLinkProjects() {
|
|
323
|
+
try {
|
|
324
|
+
const response = await axiosCloudAPI.get("/projects-linkable");
|
|
325
|
+
if (response.status !== 200) {
|
|
326
|
+
throw new Error("Error fetching cloud projects from the server.");
|
|
327
|
+
}
|
|
328
|
+
return response;
|
|
329
|
+
} catch (error) {
|
|
330
|
+
logger.debug(
|
|
331
|
+
"🥲 Oops! Couldn't retrieve your project's list from the server. Please try again."
|
|
332
|
+
);
|
|
333
|
+
throw error;
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
async listEnvironments({ name: name2 }) {
|
|
337
|
+
try {
|
|
338
|
+
const response = await axiosCloudAPI.get(`/projects/${name2}/environments`);
|
|
339
|
+
if (response.status !== 200) {
|
|
340
|
+
throw new Error("Error fetching cloud environments from the server.");
|
|
341
|
+
}
|
|
342
|
+
return response;
|
|
343
|
+
} catch (error) {
|
|
344
|
+
logger.debug(
|
|
345
|
+
"🥲 Oops! Couldn't retrieve your project's environments from the server. Please try again."
|
|
346
|
+
);
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
async listLinkEnvironments({ name: name2 }) {
|
|
351
|
+
try {
|
|
352
|
+
const response = await axiosCloudAPI.get(`/projects/${name2}/environments-linkable`);
|
|
353
|
+
if (response.status !== 200) {
|
|
354
|
+
throw new Error("Error fetching cloud environments from the server.");
|
|
355
|
+
}
|
|
356
|
+
return response;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
logger.debug(
|
|
359
|
+
"🥲 Oops! Couldn't retrieve your project's environments from the server. Please try again."
|
|
360
|
+
);
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
async getProject({ name: name2 }) {
|
|
365
|
+
try {
|
|
366
|
+
const response = await axiosCloudAPI.get(`/projects/${name2}`);
|
|
367
|
+
if (response.status !== 200) {
|
|
368
|
+
throw new Error("Error fetching project's details.");
|
|
369
|
+
}
|
|
370
|
+
return response;
|
|
371
|
+
} catch (error) {
|
|
372
|
+
logger.debug(
|
|
373
|
+
"🥲 Oops! There was a problem retrieving your project's details. Please try again."
|
|
374
|
+
);
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
303
377
|
},
|
|
304
378
|
track(event, payload = {}) {
|
|
305
379
|
return axiosCloudAPI.post("/track", {
|
|
@@ -310,26 +384,43 @@ async function cloudApiFactory({ logger }, token) {
|
|
|
310
384
|
};
|
|
311
385
|
}
|
|
312
386
|
const LOCAL_SAVE_FILENAME = ".strapi-cloud.json";
|
|
387
|
+
const getFilePath = (directoryPath) => path__default.join(directoryPath || process.cwd(), LOCAL_SAVE_FILENAME);
|
|
313
388
|
async function save(data, { directoryPath } = {}) {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
await fse.ensureDir(path__default.dirname(pathToFile));
|
|
318
|
-
await fse.writeJson(pathToFile, storedData, { encoding: "utf8" });
|
|
389
|
+
const pathToFile = getFilePath(directoryPath);
|
|
390
|
+
await fse__default.ensureDir(path__default.dirname(pathToFile));
|
|
391
|
+
await fse__default.writeJson(pathToFile, data, { encoding: "utf8" });
|
|
319
392
|
}
|
|
320
393
|
async function retrieve({
|
|
321
394
|
directoryPath
|
|
322
395
|
} = {}) {
|
|
323
|
-
const pathToFile =
|
|
324
|
-
const pathExists = await
|
|
396
|
+
const pathToFile = getFilePath(directoryPath);
|
|
397
|
+
const pathExists = await fse__default.pathExists(pathToFile);
|
|
325
398
|
if (!pathExists) {
|
|
326
399
|
return {};
|
|
327
400
|
}
|
|
328
|
-
return
|
|
401
|
+
return fse__default.readJSON(pathToFile, { encoding: "utf8" });
|
|
402
|
+
}
|
|
403
|
+
async function patch(patchData, { directoryPath } = {}) {
|
|
404
|
+
const pathToFile = getFilePath(directoryPath);
|
|
405
|
+
const existingData = await retrieve({ directoryPath });
|
|
406
|
+
if (!existingData) {
|
|
407
|
+
throw new Error("No configuration data found to patch.");
|
|
408
|
+
}
|
|
409
|
+
const newData = merge(existingData, patchData);
|
|
410
|
+
await fse__default.writeJson(pathToFile, newData, { encoding: "utf8" });
|
|
411
|
+
}
|
|
412
|
+
async function deleteConfig({ directoryPath } = {}) {
|
|
413
|
+
const pathToFile = getFilePath(directoryPath);
|
|
414
|
+
const pathExists = await fse__default.pathExists(pathToFile);
|
|
415
|
+
if (pathExists) {
|
|
416
|
+
await fse__default.remove(pathToFile);
|
|
417
|
+
}
|
|
329
418
|
}
|
|
330
419
|
const strapiInfoSave = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
331
420
|
__proto__: null,
|
|
332
421
|
LOCAL_SAVE_FILENAME,
|
|
422
|
+
deleteConfig,
|
|
423
|
+
patch,
|
|
333
424
|
retrieve,
|
|
334
425
|
save
|
|
335
426
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
@@ -337,7 +428,7 @@ let cliConfig;
|
|
|
337
428
|
async function tokenServiceFactory({ logger }) {
|
|
338
429
|
const cloudApiService = await cloudApiFactory({ logger });
|
|
339
430
|
async function saveToken(str) {
|
|
340
|
-
const appConfig = await getLocalConfig();
|
|
431
|
+
const appConfig = await getLocalConfig$1();
|
|
341
432
|
if (!appConfig) {
|
|
342
433
|
logger.error("There was a problem saving your token. Please try again.");
|
|
343
434
|
return;
|
|
@@ -351,7 +442,7 @@ async function tokenServiceFactory({ logger }) {
|
|
|
351
442
|
}
|
|
352
443
|
}
|
|
353
444
|
async function retrieveToken() {
|
|
354
|
-
const appConfig = await getLocalConfig();
|
|
445
|
+
const appConfig = await getLocalConfig$1();
|
|
355
446
|
if (appConfig.token) {
|
|
356
447
|
if (await isTokenValid(appConfig.token)) {
|
|
357
448
|
return appConfig.token;
|
|
@@ -413,7 +504,7 @@ async function tokenServiceFactory({ logger }) {
|
|
|
413
504
|
}
|
|
414
505
|
}
|
|
415
506
|
async function eraseToken() {
|
|
416
|
-
const appConfig = await getLocalConfig();
|
|
507
|
+
const appConfig = await getLocalConfig$1();
|
|
417
508
|
if (!appConfig) {
|
|
418
509
|
return;
|
|
419
510
|
}
|
|
@@ -434,8 +525,7 @@ async function tokenServiceFactory({ logger }) {
|
|
|
434
525
|
logger.log(
|
|
435
526
|
token ? "Oops! Your token seems expired or invalid. Please login again." : "We couldn't find a valid token. You need to be logged in to use this feature."
|
|
436
527
|
);
|
|
437
|
-
if (!await loginAction2(ctx))
|
|
438
|
-
return null;
|
|
528
|
+
if (!await loginAction2(ctx)) return null;
|
|
439
529
|
token = await retrieveToken();
|
|
440
530
|
}
|
|
441
531
|
return token;
|
|
@@ -570,6 +660,56 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
570
660
|
local: strapiInfoSave,
|
|
571
661
|
tokenServiceFactory
|
|
572
662
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
663
|
+
yup.object({
|
|
664
|
+
name: yup.string().required(),
|
|
665
|
+
exports: yup.lazy(
|
|
666
|
+
(value) => yup.object(
|
|
667
|
+
typeof value === "object" ? Object.entries(value).reduce(
|
|
668
|
+
(acc, [key, value2]) => {
|
|
669
|
+
if (typeof value2 === "object") {
|
|
670
|
+
acc[key] = yup.object({
|
|
671
|
+
types: yup.string().optional(),
|
|
672
|
+
source: yup.string().required(),
|
|
673
|
+
module: yup.string().optional(),
|
|
674
|
+
import: yup.string().required(),
|
|
675
|
+
require: yup.string().required(),
|
|
676
|
+
default: yup.string().required()
|
|
677
|
+
}).noUnknown(true);
|
|
678
|
+
} else {
|
|
679
|
+
acc[key] = yup.string().matches(/^\.\/.*\.json$/).required();
|
|
680
|
+
}
|
|
681
|
+
return acc;
|
|
682
|
+
},
|
|
683
|
+
{}
|
|
684
|
+
) : void 0
|
|
685
|
+
).optional()
|
|
686
|
+
)
|
|
687
|
+
});
|
|
688
|
+
const loadPkg = async ({ cwd, logger }) => {
|
|
689
|
+
const pkgPath = await pkgUp({ cwd });
|
|
690
|
+
if (!pkgPath) {
|
|
691
|
+
throw new Error("Could not find a package.json in the current directory");
|
|
692
|
+
}
|
|
693
|
+
const buffer = await fse.readFile(pkgPath);
|
|
694
|
+
const pkg = JSON.parse(buffer.toString());
|
|
695
|
+
logger.debug("Loaded package.json:", os.EOL, pkg);
|
|
696
|
+
return pkg;
|
|
697
|
+
};
|
|
698
|
+
async function getProjectNameFromPackageJson(ctx) {
|
|
699
|
+
try {
|
|
700
|
+
const packageJson2 = await loadPkg(ctx);
|
|
701
|
+
return packageJson2.name || "my-strapi-project";
|
|
702
|
+
} catch (e) {
|
|
703
|
+
return "my-strapi-project";
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
const trackEvent = async (ctx, cloudApiService, eventName, eventData) => {
|
|
707
|
+
try {
|
|
708
|
+
await cloudApiService.track(eventName, eventData);
|
|
709
|
+
} catch (e) {
|
|
710
|
+
ctx.logger.debug(`Failed to track ${eventName}`, e);
|
|
711
|
+
}
|
|
712
|
+
};
|
|
573
713
|
const openModule$1 = import("open");
|
|
574
714
|
async function promptLogin(ctx) {
|
|
575
715
|
const response = await inquirer.prompt([
|
|
@@ -590,13 +730,6 @@ async function loginAction(ctx) {
|
|
|
590
730
|
const tokenService = await tokenServiceFactory(ctx);
|
|
591
731
|
const existingToken = await tokenService.retrieveToken();
|
|
592
732
|
const cloudApiService = await cloudApiFactory(ctx, existingToken || void 0);
|
|
593
|
-
const trackFailedLogin = async () => {
|
|
594
|
-
try {
|
|
595
|
-
await cloudApiService.track("didNotLogin", { loginMethod: "cli" });
|
|
596
|
-
} catch (e) {
|
|
597
|
-
logger.debug("Failed to track failed login", e);
|
|
598
|
-
}
|
|
599
|
-
};
|
|
600
733
|
if (existingToken) {
|
|
601
734
|
const isTokenValid = await tokenService.isTokenValid(existingToken);
|
|
602
735
|
if (isTokenValid) {
|
|
@@ -628,11 +761,7 @@ async function loginAction(ctx) {
|
|
|
628
761
|
logger.debug(e);
|
|
629
762
|
return false;
|
|
630
763
|
}
|
|
631
|
-
|
|
632
|
-
await cloudApiService.track("willLoginAttempt", {});
|
|
633
|
-
} catch (e) {
|
|
634
|
-
logger.debug("Failed to track login attempt", e);
|
|
635
|
-
}
|
|
764
|
+
await trackEvent(ctx, cloudApiService, "willLoginAttempt", {});
|
|
636
765
|
logger.debug("🔐 Creating device authentication request...", {
|
|
637
766
|
client_id: cliConfig2.clientId,
|
|
638
767
|
scope: cliConfig2.scope,
|
|
@@ -712,13 +841,13 @@ async function loginAction(ctx) {
|
|
|
712
841
|
"There seems to be a problem with your login information. Please try logging in again."
|
|
713
842
|
);
|
|
714
843
|
spinnerFail();
|
|
715
|
-
await
|
|
844
|
+
await trackEvent(ctx, cloudApiService, "didNotLogin", { loginMethod: "cli" });
|
|
716
845
|
return false;
|
|
717
846
|
}
|
|
718
847
|
if (e.response?.data.error && !["authorization_pending", "slow_down"].includes(e.response.data.error)) {
|
|
719
848
|
logger.debug(e);
|
|
720
849
|
spinnerFail();
|
|
721
|
-
await
|
|
850
|
+
await trackEvent(ctx, cloudApiService, "didNotLogin", { loginMethod: "cli" });
|
|
722
851
|
return false;
|
|
723
852
|
}
|
|
724
853
|
await new Promise((resolve) => {
|
|
@@ -732,15 +861,50 @@ async function loginAction(ctx) {
|
|
|
732
861
|
"To access your dashboard, please copy and paste the following URL into your web browser:"
|
|
733
862
|
);
|
|
734
863
|
logger.log(chalk.underline(`${apiConfig.dashboardBaseUrl}/projects`));
|
|
735
|
-
|
|
736
|
-
await cloudApiService.track("didLogin", { loginMethod: "cli" });
|
|
737
|
-
} catch (e) {
|
|
738
|
-
logger.debug("Failed to track login", e);
|
|
739
|
-
}
|
|
864
|
+
await trackEvent(ctx, cloudApiService, "didLogin", { loginMethod: "cli" });
|
|
740
865
|
};
|
|
741
866
|
await authenticate();
|
|
742
867
|
return isAuthenticated;
|
|
743
868
|
}
|
|
869
|
+
function questionDefaultValuesMapper(questionsMap) {
|
|
870
|
+
return (questions) => {
|
|
871
|
+
return questions.map((question) => {
|
|
872
|
+
const questionName = question.name;
|
|
873
|
+
if (questionName in questionsMap) {
|
|
874
|
+
const questionDefault = questionsMap[questionName];
|
|
875
|
+
if (typeof questionDefault === "function") {
|
|
876
|
+
return {
|
|
877
|
+
...question,
|
|
878
|
+
default: questionDefault(question)
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
...question,
|
|
883
|
+
default: questionDefault
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
return question;
|
|
887
|
+
});
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
function getDefaultsFromQuestions(questions) {
|
|
891
|
+
return questions.reduce((acc, question) => {
|
|
892
|
+
if (question.default && question.name) {
|
|
893
|
+
return { ...acc, [question.name]: question.default };
|
|
894
|
+
}
|
|
895
|
+
return acc;
|
|
896
|
+
}, {});
|
|
897
|
+
}
|
|
898
|
+
function getProjectNodeVersionDefault(question) {
|
|
899
|
+
const currentNodeVersion = process.versions.node.split(".")[0];
|
|
900
|
+
if (question.type === "list" && Array.isArray(question.choices)) {
|
|
901
|
+
const choice = question.choices.find((choice2) => choice2.value === currentNodeVersion);
|
|
902
|
+
if (choice) {
|
|
903
|
+
return choice.value;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return question.default;
|
|
907
|
+
}
|
|
744
908
|
async function handleError(ctx, error) {
|
|
745
909
|
const { logger } = ctx;
|
|
746
910
|
logger.debug(error);
|
|
@@ -785,7 +949,7 @@ async function createProject$1(ctx, cloudApi, projectInput) {
|
|
|
785
949
|
throw e;
|
|
786
950
|
}
|
|
787
951
|
}
|
|
788
|
-
const action$
|
|
952
|
+
const action$6 = async (ctx) => {
|
|
789
953
|
const { logger } = ctx;
|
|
790
954
|
const { getValidToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
791
955
|
const token = await getValidToken(ctx, promptLogin);
|
|
@@ -794,7 +958,16 @@ const action$2 = async (ctx) => {
|
|
|
794
958
|
}
|
|
795
959
|
const cloudApi = await cloudApiFactory(ctx, token);
|
|
796
960
|
const { data: config } = await cloudApi.config();
|
|
797
|
-
const
|
|
961
|
+
const projectName = await getProjectNameFromPackageJson(ctx);
|
|
962
|
+
const defaultAnswersMapper = questionDefaultValuesMapper({
|
|
963
|
+
name: projectName,
|
|
964
|
+
nodeVersion: getProjectNodeVersionDefault
|
|
965
|
+
});
|
|
966
|
+
const questions = defaultAnswersMapper(config.projectCreation.questions);
|
|
967
|
+
const defaultValues = {
|
|
968
|
+
...config.projectCreation.defaults,
|
|
969
|
+
...getDefaultsFromQuestions(questions)
|
|
970
|
+
};
|
|
798
971
|
const projectAnswersDefaulted = defaults(defaultValues);
|
|
799
972
|
const projectAnswers = await inquirer.prompt(questions);
|
|
800
973
|
const projectInput = projectAnswersDefaulted(projectAnswers);
|
|
@@ -843,38 +1016,6 @@ function notificationServiceFactory({ logger }) {
|
|
|
843
1016
|
};
|
|
844
1017
|
};
|
|
845
1018
|
}
|
|
846
|
-
yup.object({
|
|
847
|
-
name: yup.string().required(),
|
|
848
|
-
exports: yup.lazy(
|
|
849
|
-
(value) => yup.object(
|
|
850
|
-
typeof value === "object" ? Object.entries(value).reduce((acc, [key, value2]) => {
|
|
851
|
-
if (typeof value2 === "object") {
|
|
852
|
-
acc[key] = yup.object({
|
|
853
|
-
types: yup.string().optional(),
|
|
854
|
-
source: yup.string().required(),
|
|
855
|
-
module: yup.string().optional(),
|
|
856
|
-
import: yup.string().required(),
|
|
857
|
-
require: yup.string().required(),
|
|
858
|
-
default: yup.string().required()
|
|
859
|
-
}).noUnknown(true);
|
|
860
|
-
} else {
|
|
861
|
-
acc[key] = yup.string().matches(/^\.\/.*\.json$/).required();
|
|
862
|
-
}
|
|
863
|
-
return acc;
|
|
864
|
-
}, {}) : void 0
|
|
865
|
-
).optional()
|
|
866
|
-
)
|
|
867
|
-
});
|
|
868
|
-
const loadPkg = async ({ cwd, logger }) => {
|
|
869
|
-
const pkgPath = await pkgUp({ cwd });
|
|
870
|
-
if (!pkgPath) {
|
|
871
|
-
throw new Error("Could not find a package.json in the current directory");
|
|
872
|
-
}
|
|
873
|
-
const buffer = await fs$1.readFile(pkgPath);
|
|
874
|
-
const pkg = JSON.parse(buffer.toString());
|
|
875
|
-
logger.debug("Loaded package.json:", os.EOL, pkg);
|
|
876
|
-
return pkg;
|
|
877
|
-
};
|
|
878
1019
|
const buildLogsServiceFactory = ({ logger }) => {
|
|
879
1020
|
return async (url, token, cliConfig2) => {
|
|
880
1021
|
const CONN_TIMEOUT = Number(cliConfig2.buildLogsConnectionTimeout);
|
|
@@ -928,6 +1069,7 @@ const buildLogsServiceFactory = ({ logger }) => {
|
|
|
928
1069
|
if (retries > MAX_RETRIES) {
|
|
929
1070
|
spinner.fail("We were unable to connect to the server to get build logs at this time.");
|
|
930
1071
|
es.close();
|
|
1072
|
+
clearExistingTimeout();
|
|
931
1073
|
reject(new Error("Max retries reached"));
|
|
932
1074
|
}
|
|
933
1075
|
};
|
|
@@ -936,6 +1078,29 @@ const buildLogsServiceFactory = ({ logger }) => {
|
|
|
936
1078
|
});
|
|
937
1079
|
};
|
|
938
1080
|
};
|
|
1081
|
+
const boxenOptions = {
|
|
1082
|
+
padding: 1,
|
|
1083
|
+
margin: 1,
|
|
1084
|
+
align: "center",
|
|
1085
|
+
borderColor: "yellow",
|
|
1086
|
+
borderStyle: "round"
|
|
1087
|
+
};
|
|
1088
|
+
const QUIT_OPTION$2 = "Quit";
|
|
1089
|
+
async function promptForEnvironment(environments) {
|
|
1090
|
+
const choices = environments.map((env2) => ({ name: env2, value: env2 }));
|
|
1091
|
+
const { selectedEnvironment } = await inquirer.prompt([
|
|
1092
|
+
{
|
|
1093
|
+
type: "list",
|
|
1094
|
+
name: "selectedEnvironment",
|
|
1095
|
+
message: "Select the environment to deploy:",
|
|
1096
|
+
choices: [...choices, { name: chalk.grey(`(${QUIT_OPTION$2})`), value: null }]
|
|
1097
|
+
}
|
|
1098
|
+
]);
|
|
1099
|
+
if (selectedEnvironment === null) {
|
|
1100
|
+
process.exit(1);
|
|
1101
|
+
}
|
|
1102
|
+
return selectedEnvironment;
|
|
1103
|
+
}
|
|
939
1104
|
async function upload(ctx, project, token, maxProjectFileSize) {
|
|
940
1105
|
const cloudApi = await cloudApiFactory(ctx, token);
|
|
941
1106
|
try {
|
|
@@ -970,13 +1135,13 @@ async function upload(ctx, project, token, maxProjectFileSize) {
|
|
|
970
1135
|
process.exit(1);
|
|
971
1136
|
}
|
|
972
1137
|
const tarFilePath = path__default.resolve(storagePath, compressedFilename);
|
|
973
|
-
const fileStats = await
|
|
1138
|
+
const fileStats = await fse__default.stat(tarFilePath);
|
|
974
1139
|
if (fileStats.size > maxProjectFileSize) {
|
|
975
1140
|
ctx.logger.log(
|
|
976
1141
|
"Unable to proceed: Your project is too big to be transferred, please use a git repo instead."
|
|
977
1142
|
);
|
|
978
1143
|
try {
|
|
979
|
-
await
|
|
1144
|
+
await fse__default.remove(tarFilePath);
|
|
980
1145
|
} catch (e) {
|
|
981
1146
|
ctx.logger.log("Unable to remove file: ", tarFilePath);
|
|
982
1147
|
ctx.logger.debug(e);
|
|
@@ -1002,20 +1167,10 @@ async function upload(ctx, project, token, maxProjectFileSize) {
|
|
|
1002
1167
|
return data.build_id;
|
|
1003
1168
|
} catch (e) {
|
|
1004
1169
|
progressBar.stop();
|
|
1005
|
-
|
|
1006
|
-
if (e.response.status === 404) {
|
|
1007
|
-
ctx.logger.error(
|
|
1008
|
-
`The project does not exist. Remove the ${LOCAL_SAVE_FILENAME} file and try again.`
|
|
1009
|
-
);
|
|
1010
|
-
} else {
|
|
1011
|
-
ctx.logger.error(e.response.data);
|
|
1012
|
-
}
|
|
1013
|
-
} else {
|
|
1014
|
-
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
1015
|
-
}
|
|
1170
|
+
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
1016
1171
|
ctx.logger.debug(e);
|
|
1017
1172
|
} finally {
|
|
1018
|
-
await
|
|
1173
|
+
await fse__default.remove(tarFilePath);
|
|
1019
1174
|
}
|
|
1020
1175
|
process.exit(0);
|
|
1021
1176
|
} catch (e) {
|
|
@@ -1028,7 +1183,7 @@ async function getProject(ctx) {
|
|
|
1028
1183
|
const { project } = await retrieve();
|
|
1029
1184
|
if (!project) {
|
|
1030
1185
|
try {
|
|
1031
|
-
return await action$
|
|
1186
|
+
return await action$6(ctx);
|
|
1032
1187
|
} catch (e) {
|
|
1033
1188
|
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
1034
1189
|
ctx.logger.debug(e);
|
|
@@ -1037,7 +1192,45 @@ async function getProject(ctx) {
|
|
|
1037
1192
|
}
|
|
1038
1193
|
return project;
|
|
1039
1194
|
}
|
|
1040
|
-
|
|
1195
|
+
async function getConfig({
|
|
1196
|
+
ctx,
|
|
1197
|
+
cloudApiService
|
|
1198
|
+
}) {
|
|
1199
|
+
try {
|
|
1200
|
+
const { data: cliConfig2 } = await cloudApiService.config();
|
|
1201
|
+
return cliConfig2;
|
|
1202
|
+
} catch (e) {
|
|
1203
|
+
ctx.logger.debug("Failed to get cli config", e);
|
|
1204
|
+
return null;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
function validateEnvironment(ctx, environment, environments) {
|
|
1208
|
+
if (!environments.includes(environment)) {
|
|
1209
|
+
ctx.logger.error(`Environment ${environment} does not exist.`);
|
|
1210
|
+
process.exit(1);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
async function getTargetEnvironment(ctx, opts, project, environments) {
|
|
1214
|
+
if (opts.env) {
|
|
1215
|
+
validateEnvironment(ctx, opts.env, environments);
|
|
1216
|
+
return opts.env;
|
|
1217
|
+
}
|
|
1218
|
+
if (project.targetEnvironment) {
|
|
1219
|
+
return project.targetEnvironment;
|
|
1220
|
+
}
|
|
1221
|
+
if (environments.length > 1) {
|
|
1222
|
+
return promptForEnvironment(environments);
|
|
1223
|
+
}
|
|
1224
|
+
return environments[0];
|
|
1225
|
+
}
|
|
1226
|
+
function hasPendingOrLiveDeployment(environments, targetEnvironment) {
|
|
1227
|
+
const environment = environments.find((env2) => env2.name === targetEnvironment);
|
|
1228
|
+
if (!environment) {
|
|
1229
|
+
throw new Error(`Environment details ${targetEnvironment} not found.`);
|
|
1230
|
+
}
|
|
1231
|
+
return environment.hasPendingDeployment || environment.hasLiveDeployment || false;
|
|
1232
|
+
}
|
|
1233
|
+
const action$5 = async (ctx, opts) => {
|
|
1041
1234
|
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
1042
1235
|
const token = await getValidToken(ctx, promptLogin);
|
|
1043
1236
|
if (!token) {
|
|
@@ -1047,15 +1240,57 @@ const action$1 = async (ctx) => {
|
|
|
1047
1240
|
if (!project) {
|
|
1048
1241
|
return;
|
|
1049
1242
|
}
|
|
1050
|
-
const cloudApiService = await cloudApiFactory(ctx);
|
|
1243
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1244
|
+
let projectData;
|
|
1245
|
+
let environments;
|
|
1246
|
+
let environmentsDetails;
|
|
1051
1247
|
try {
|
|
1052
|
-
|
|
1248
|
+
const {
|
|
1249
|
+
data: { data, metadata }
|
|
1250
|
+
} = await cloudApiService.getProject({ name: project.name });
|
|
1251
|
+
projectData = data;
|
|
1252
|
+
environments = projectData.environments;
|
|
1253
|
+
environmentsDetails = projectData.environmentsDetails;
|
|
1254
|
+
const isProjectSuspended = projectData.suspendedAt;
|
|
1255
|
+
if (isProjectSuspended) {
|
|
1256
|
+
ctx.logger.log(
|
|
1257
|
+
"\n Oops! This project has been suspended. \n\n Please reactivate it from the dashboard to continue deploying: "
|
|
1258
|
+
);
|
|
1259
|
+
ctx.logger.log(chalk.underline(`${metadata.dashboardUrls.project}`));
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1053
1262
|
} catch (e) {
|
|
1054
|
-
|
|
1263
|
+
if (e instanceof AxiosError && e.response?.data) {
|
|
1264
|
+
if (e.response.status === 404) {
|
|
1265
|
+
ctx.logger.warn(
|
|
1266
|
+
`The project associated with this folder does not exist in Strapi Cloud.
|
|
1267
|
+
Please link your local project to an existing Strapi Cloud project using the ${chalk.cyan(
|
|
1268
|
+
"link"
|
|
1269
|
+
)} command before deploying.`
|
|
1270
|
+
);
|
|
1271
|
+
} else {
|
|
1272
|
+
ctx.logger.error(e.response.data);
|
|
1273
|
+
}
|
|
1274
|
+
} else {
|
|
1275
|
+
ctx.logger.error(
|
|
1276
|
+
"An error occurred while retrieving the project's information. Please try again later."
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
ctx.logger.debug(e);
|
|
1280
|
+
return;
|
|
1055
1281
|
}
|
|
1282
|
+
await trackEvent(ctx, cloudApiService, "willDeployWithCLI", {
|
|
1283
|
+
projectInternalName: project.name
|
|
1284
|
+
});
|
|
1056
1285
|
const notificationService = notificationServiceFactory(ctx);
|
|
1057
1286
|
const buildLogsService = buildLogsServiceFactory(ctx);
|
|
1058
|
-
const
|
|
1287
|
+
const cliConfig2 = await getConfig({ ctx, cloudApiService });
|
|
1288
|
+
if (!cliConfig2) {
|
|
1289
|
+
ctx.logger.error(
|
|
1290
|
+
"An error occurred while retrieving data from Strapi Cloud. Please check your network or try again later."
|
|
1291
|
+
);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1059
1294
|
let maxSize = parseInt(cliConfig2.maxProjectFileSize, 10);
|
|
1060
1295
|
if (Number.isNaN(maxSize)) {
|
|
1061
1296
|
ctx.logger.debug(
|
|
@@ -1063,11 +1298,34 @@ const action$1 = async (ctx) => {
|
|
|
1063
1298
|
);
|
|
1064
1299
|
maxSize = 1e8;
|
|
1065
1300
|
}
|
|
1301
|
+
project.targetEnvironment = await getTargetEnvironment(ctx, opts, project, environments);
|
|
1302
|
+
if (!opts.force) {
|
|
1303
|
+
const shouldDisplayWarning = hasPendingOrLiveDeployment(
|
|
1304
|
+
environmentsDetails,
|
|
1305
|
+
project.targetEnvironment
|
|
1306
|
+
);
|
|
1307
|
+
if (shouldDisplayWarning) {
|
|
1308
|
+
ctx.logger.log(boxen(cliConfig2.projectDeployment.confirmationText, boxenOptions));
|
|
1309
|
+
const { confirm } = await inquirer.prompt([
|
|
1310
|
+
{
|
|
1311
|
+
type: "confirm",
|
|
1312
|
+
name: "confirm",
|
|
1313
|
+
message: `Do you want to proceed with deployment to ${chalk.cyan(projectData.displayName)} on ${chalk.cyan(project.targetEnvironment)} environment?`
|
|
1314
|
+
}
|
|
1315
|
+
]);
|
|
1316
|
+
if (!confirm) {
|
|
1317
|
+
process.exit(1);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1066
1321
|
const buildId = await upload(ctx, project, token, maxSize);
|
|
1067
1322
|
if (!buildId) {
|
|
1068
1323
|
return;
|
|
1069
1324
|
}
|
|
1070
1325
|
try {
|
|
1326
|
+
ctx.logger.log(
|
|
1327
|
+
`🚀 Deploying project to ${chalk.cyan(project.targetEnvironment ?? `production`)} environment...`
|
|
1328
|
+
);
|
|
1071
1329
|
notificationService(`${apiConfig.apiBaseUrl}/notifications`, token, cliConfig2);
|
|
1072
1330
|
await buildLogsService(`${apiConfig.apiBaseUrl}/v1/logs/${buildId}`, token, cliConfig2);
|
|
1073
1331
|
ctx.logger.log(
|
|
@@ -1077,10 +1335,11 @@ const action$1 = async (ctx) => {
|
|
|
1077
1335
|
chalk.underline(`${apiConfig.dashboardBaseUrl}/projects/${project.name}/deployments`)
|
|
1078
1336
|
);
|
|
1079
1337
|
} catch (e) {
|
|
1338
|
+
ctx.logger.debug(e);
|
|
1080
1339
|
if (e instanceof Error) {
|
|
1081
1340
|
ctx.logger.error(e.message);
|
|
1082
1341
|
} else {
|
|
1083
|
-
|
|
1342
|
+
ctx.logger.error("An error occurred while deploying the project. Please try again later.");
|
|
1084
1343
|
}
|
|
1085
1344
|
}
|
|
1086
1345
|
};
|
|
@@ -1111,17 +1370,179 @@ const runAction = (name2, action2) => (...args) => {
|
|
|
1111
1370
|
process.exit(1);
|
|
1112
1371
|
});
|
|
1113
1372
|
};
|
|
1114
|
-
const command$
|
|
1115
|
-
|
|
1373
|
+
const command$7 = ({ ctx }) => {
|
|
1374
|
+
return createCommand("cloud:deploy").alias("deploy").description("Deploy a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").option("-f, --force", "Skip confirmation to deploy").option("-e, --env <name>", "Specify the environment to deploy").action((opts) => runAction("deploy", action$5)(ctx, opts));
|
|
1116
1375
|
};
|
|
1117
1376
|
const deployProject = {
|
|
1118
1377
|
name: "deploy-project",
|
|
1119
1378
|
description: "Deploy a Strapi Cloud project",
|
|
1120
|
-
action: action$
|
|
1121
|
-
command: command$
|
|
1379
|
+
action: action$5,
|
|
1380
|
+
command: command$7
|
|
1122
1381
|
};
|
|
1123
|
-
|
|
1124
|
-
|
|
1382
|
+
async function getLocalConfig(ctx) {
|
|
1383
|
+
try {
|
|
1384
|
+
return await retrieve();
|
|
1385
|
+
} catch (e) {
|
|
1386
|
+
ctx.logger.debug("Failed to get project config", e);
|
|
1387
|
+
ctx.logger.error("An error occurred while retrieving config data from your local project.");
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
async function getLocalProject(ctx) {
|
|
1392
|
+
const localConfig = await getLocalConfig(ctx);
|
|
1393
|
+
if (!localConfig || !localConfig.project) {
|
|
1394
|
+
ctx.logger.warn(
|
|
1395
|
+
`
|
|
1396
|
+
We couldn't find a valid local project config.
|
|
1397
|
+
Please link your local project to an existing Strapi Cloud project using the ${chalk.cyan(
|
|
1398
|
+
"link"
|
|
1399
|
+
)} command.`
|
|
1400
|
+
);
|
|
1401
|
+
process.exit(1);
|
|
1402
|
+
}
|
|
1403
|
+
return localConfig.project;
|
|
1404
|
+
}
|
|
1405
|
+
const QUIT_OPTION$1 = "Quit";
|
|
1406
|
+
async function promptForRelink(ctx, cloudApiService, existingConfig) {
|
|
1407
|
+
if (existingConfig && existingConfig.project) {
|
|
1408
|
+
const { shouldRelink } = await inquirer.prompt([
|
|
1409
|
+
{
|
|
1410
|
+
type: "confirm",
|
|
1411
|
+
name: "shouldRelink",
|
|
1412
|
+
message: `A project named ${chalk.cyan(
|
|
1413
|
+
existingConfig.project.displayName ? existingConfig.project.displayName : existingConfig.project.name
|
|
1414
|
+
)} is already linked to this local folder. Do you want to update the link?`,
|
|
1415
|
+
default: false
|
|
1416
|
+
}
|
|
1417
|
+
]);
|
|
1418
|
+
if (!shouldRelink) {
|
|
1419
|
+
await trackEvent(ctx, cloudApiService, "didNotLinkProject", {
|
|
1420
|
+
currentProjectName: existingConfig.project?.name
|
|
1421
|
+
});
|
|
1422
|
+
return false;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
async function getProjectsList(ctx, cloudApiService, existingConfig) {
|
|
1428
|
+
const spinner = ctx.logger.spinner("Fetching your projects...\n").start();
|
|
1429
|
+
try {
|
|
1430
|
+
const {
|
|
1431
|
+
data: { data: projectList }
|
|
1432
|
+
} = await cloudApiService.listLinkProjects();
|
|
1433
|
+
spinner.succeed();
|
|
1434
|
+
if (!Array.isArray(projectList)) {
|
|
1435
|
+
ctx.logger.log("We couldn't find any projects available for linking in Strapi Cloud.");
|
|
1436
|
+
return null;
|
|
1437
|
+
}
|
|
1438
|
+
const projects = projectList.filter(
|
|
1439
|
+
(project) => !(project.isMaintainer || project.name === existingConfig?.project?.name)
|
|
1440
|
+
).map((project) => {
|
|
1441
|
+
return {
|
|
1442
|
+
name: project.displayName,
|
|
1443
|
+
value: { name: project.name, displayName: project.displayName }
|
|
1444
|
+
};
|
|
1445
|
+
});
|
|
1446
|
+
if (projects.length === 0) {
|
|
1447
|
+
ctx.logger.log("We couldn't find any projects available for linking in Strapi Cloud.");
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
return projects;
|
|
1451
|
+
} catch (e) {
|
|
1452
|
+
spinner.fail("An error occurred while fetching your projects from Strapi Cloud.");
|
|
1453
|
+
ctx.logger.debug("Failed to list projects", e);
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
async function getUserSelection(ctx, projects) {
|
|
1458
|
+
const { logger } = ctx;
|
|
1459
|
+
try {
|
|
1460
|
+
const answer = await inquirer.prompt([
|
|
1461
|
+
{
|
|
1462
|
+
type: "list",
|
|
1463
|
+
name: "linkProject",
|
|
1464
|
+
message: "Which project do you want to link?",
|
|
1465
|
+
choices: [...projects, { name: chalk.grey(`(${QUIT_OPTION$1})`), value: null }]
|
|
1466
|
+
}
|
|
1467
|
+
]);
|
|
1468
|
+
if (!answer.linkProject) {
|
|
1469
|
+
return null;
|
|
1470
|
+
}
|
|
1471
|
+
return answer;
|
|
1472
|
+
} catch (e) {
|
|
1473
|
+
logger.debug("Failed to get user input", e);
|
|
1474
|
+
logger.error("An error occurred while trying to get your input.");
|
|
1475
|
+
return null;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
const action$4 = async (ctx) => {
|
|
1479
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
1480
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
1481
|
+
const { logger } = ctx;
|
|
1482
|
+
if (!token) {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1486
|
+
const existingConfig = await getLocalConfig(ctx);
|
|
1487
|
+
const shouldRelink = await promptForRelink(ctx, cloudApiService, existingConfig);
|
|
1488
|
+
if (!shouldRelink) {
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
await trackEvent(ctx, cloudApiService, "willLinkProject", {});
|
|
1492
|
+
const projects = await getProjectsList(
|
|
1493
|
+
ctx,
|
|
1494
|
+
cloudApiService,
|
|
1495
|
+
existingConfig
|
|
1496
|
+
);
|
|
1497
|
+
if (!projects) {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const answer = await getUserSelection(ctx, projects);
|
|
1501
|
+
if (!answer) {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
try {
|
|
1505
|
+
const { confirmAction } = await inquirer.prompt([
|
|
1506
|
+
{
|
|
1507
|
+
type: "confirm",
|
|
1508
|
+
name: "confirmAction",
|
|
1509
|
+
message: "Warning: Once linked, deploying from CLI will replace the existing project and its data. Confirm to proceed:",
|
|
1510
|
+
default: false
|
|
1511
|
+
}
|
|
1512
|
+
]);
|
|
1513
|
+
if (!confirmAction) {
|
|
1514
|
+
await trackEvent(ctx, cloudApiService, "didNotLinkProject", {
|
|
1515
|
+
cancelledProjectName: answer.linkProject.name,
|
|
1516
|
+
currentProjectName: existingConfig ? existingConfig.project?.name : null
|
|
1517
|
+
});
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
await save({ project: answer.linkProject });
|
|
1521
|
+
logger.log(
|
|
1522
|
+
` You have successfully linked your project to ${chalk.cyan(answer.linkProject.displayName)}. You are now able to deploy your project.`
|
|
1523
|
+
);
|
|
1524
|
+
await trackEvent(ctx, cloudApiService, "didLinkProject", {
|
|
1525
|
+
projectInternalName: answer.linkProject
|
|
1526
|
+
});
|
|
1527
|
+
} catch (e) {
|
|
1528
|
+
logger.debug("Failed to link project", e);
|
|
1529
|
+
logger.error("An error occurred while linking the project.");
|
|
1530
|
+
await trackEvent(ctx, cloudApiService, "didNotLinkProject", {
|
|
1531
|
+
projectInternalName: answer.linkProject
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
const command$6 = ({ command: command2, ctx }) => {
|
|
1536
|
+
command2.command("cloud:link").alias("link").description("Link a local directory to a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("link", action$4)(ctx));
|
|
1537
|
+
};
|
|
1538
|
+
const link = {
|
|
1539
|
+
name: "link-project",
|
|
1540
|
+
description: "Link a local directory to a Strapi Cloud project",
|
|
1541
|
+
action: action$4,
|
|
1542
|
+
command: command$6
|
|
1543
|
+
};
|
|
1544
|
+
const command$5 = ({ ctx }) => {
|
|
1545
|
+
return createCommand("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
|
|
1125
1546
|
"after",
|
|
1126
1547
|
"\nAfter running this command, you will be prompted to enter your authentication information."
|
|
1127
1548
|
).option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("login", loginAction)(ctx));
|
|
@@ -1130,10 +1551,10 @@ const login = {
|
|
|
1130
1551
|
name: "login",
|
|
1131
1552
|
description: "Strapi Cloud Login",
|
|
1132
1553
|
action: loginAction,
|
|
1133
|
-
command: command$
|
|
1554
|
+
command: command$5
|
|
1134
1555
|
};
|
|
1135
1556
|
const openModule = import("open");
|
|
1136
|
-
const action = async (ctx) => {
|
|
1557
|
+
const action$3 = async (ctx) => {
|
|
1137
1558
|
const { logger } = ctx;
|
|
1138
1559
|
const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
|
|
1139
1560
|
const token = await retrieveToken();
|
|
@@ -1163,39 +1584,258 @@ const action = async (ctx) => {
|
|
|
1163
1584
|
logger.error("🥲 Oops! Something went wrong while logging you out. Please try again.");
|
|
1164
1585
|
logger.debug(e);
|
|
1165
1586
|
}
|
|
1166
|
-
|
|
1167
|
-
await cloudApiService.track("didLogout", { loginMethod: "cli" });
|
|
1168
|
-
} catch (e) {
|
|
1169
|
-
logger.debug("Failed to track logout event", e);
|
|
1170
|
-
}
|
|
1587
|
+
await trackEvent(ctx, cloudApiService, "didLogout", { loginMethod: "cli" });
|
|
1171
1588
|
};
|
|
1172
|
-
const command$
|
|
1173
|
-
|
|
1589
|
+
const command$4 = ({ ctx }) => {
|
|
1590
|
+
return createCommand("cloud:logout").alias("logout").description("Strapi Cloud Logout").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("logout", action$3)(ctx));
|
|
1174
1591
|
};
|
|
1175
1592
|
const logout = {
|
|
1176
1593
|
name: "logout",
|
|
1177
1594
|
description: "Strapi Cloud Logout",
|
|
1178
|
-
action,
|
|
1179
|
-
command: command$
|
|
1595
|
+
action: action$3,
|
|
1596
|
+
command: command$4
|
|
1180
1597
|
};
|
|
1181
|
-
const command = ({
|
|
1182
|
-
|
|
1598
|
+
const command$3 = ({ ctx }) => {
|
|
1599
|
+
return createCommand("cloud:create-project").description("Create a Strapi Cloud project").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("cloud:create-project", action$6)(ctx));
|
|
1183
1600
|
};
|
|
1184
1601
|
const createProject = {
|
|
1185
1602
|
name: "create-project",
|
|
1186
1603
|
description: "Create a new project",
|
|
1604
|
+
action: action$6,
|
|
1605
|
+
command: command$3
|
|
1606
|
+
};
|
|
1607
|
+
const action$2 = async (ctx) => {
|
|
1608
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
1609
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
1610
|
+
const { logger } = ctx;
|
|
1611
|
+
if (!token) {
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1615
|
+
const spinner = logger.spinner("Fetching your projects...").start();
|
|
1616
|
+
try {
|
|
1617
|
+
const {
|
|
1618
|
+
data: { data: projectList }
|
|
1619
|
+
} = await cloudApiService.listProjects();
|
|
1620
|
+
spinner.succeed();
|
|
1621
|
+
logger.log(projectList);
|
|
1622
|
+
} catch (e) {
|
|
1623
|
+
ctx.logger.debug("Failed to list projects", e);
|
|
1624
|
+
spinner.fail("An error occurred while fetching your projects from Strapi Cloud.");
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1627
|
+
const command$2 = ({ command: command2, ctx }) => {
|
|
1628
|
+
command2.command("cloud:projects").alias("projects").description("List Strapi Cloud projects").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("projects", action$2)(ctx));
|
|
1629
|
+
};
|
|
1630
|
+
const listProjects = {
|
|
1631
|
+
name: "list-projects",
|
|
1632
|
+
description: "List Strapi Cloud projects",
|
|
1187
1633
|
action: action$2,
|
|
1634
|
+
command: command$2
|
|
1635
|
+
};
|
|
1636
|
+
const action$1 = async (ctx) => {
|
|
1637
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
1638
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
1639
|
+
const { logger } = ctx;
|
|
1640
|
+
if (!token) {
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
const project = await getLocalProject(ctx);
|
|
1644
|
+
if (!project) {
|
|
1645
|
+
ctx.logger.debug(`No valid local project configuration was found.`);
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1649
|
+
const spinner = logger.spinner("Fetching environments...").start();
|
|
1650
|
+
await trackEvent(ctx, cloudApiService, "willListEnvironment", {
|
|
1651
|
+
projectInternalName: project.name
|
|
1652
|
+
});
|
|
1653
|
+
try {
|
|
1654
|
+
const {
|
|
1655
|
+
data: { data: environmentsList }
|
|
1656
|
+
} = await cloudApiService.listEnvironments({ name: project.name });
|
|
1657
|
+
spinner.succeed();
|
|
1658
|
+
logger.log(environmentsList);
|
|
1659
|
+
await trackEvent(ctx, cloudApiService, "didListEnvironment", {
|
|
1660
|
+
projectInternalName: project.name
|
|
1661
|
+
});
|
|
1662
|
+
} catch (e) {
|
|
1663
|
+
if (e.response && e.response.status === 404) {
|
|
1664
|
+
spinner.succeed();
|
|
1665
|
+
logger.warn(
|
|
1666
|
+
`
|
|
1667
|
+
The project associated with this folder does not exist in Strapi Cloud.
|
|
1668
|
+
Please link your local project to an existing Strapi Cloud project using the ${chalk.cyan(
|
|
1669
|
+
"link"
|
|
1670
|
+
)} command`
|
|
1671
|
+
);
|
|
1672
|
+
} else {
|
|
1673
|
+
spinner.fail("An error occurred while fetching environments data from Strapi Cloud.");
|
|
1674
|
+
logger.debug("Failed to list environments", e);
|
|
1675
|
+
}
|
|
1676
|
+
await trackEvent(ctx, cloudApiService, "didNotListEnvironment", {
|
|
1677
|
+
projectInternalName: project.name
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
function defineCloudNamespace(command2, ctx) {
|
|
1682
|
+
const cloud = command2.command("cloud").description("Manage Strapi Cloud projects");
|
|
1683
|
+
cloud.command("environments").description("Alias for cloud environment list").action(() => runAction("list", action$1)(ctx));
|
|
1684
|
+
return cloud;
|
|
1685
|
+
}
|
|
1686
|
+
let environmentCmd = null;
|
|
1687
|
+
const initializeEnvironmentCommand = (command2, ctx) => {
|
|
1688
|
+
if (!environmentCmd) {
|
|
1689
|
+
const cloud = defineCloudNamespace(command2, ctx);
|
|
1690
|
+
environmentCmd = cloud.command("environment").description("Manage environments");
|
|
1691
|
+
}
|
|
1692
|
+
return environmentCmd;
|
|
1693
|
+
};
|
|
1694
|
+
const command$1 = ({ command: command2, ctx }) => {
|
|
1695
|
+
const environmentCmd2 = initializeEnvironmentCommand(command2, ctx);
|
|
1696
|
+
environmentCmd2.command("list").description("List Strapi Cloud project environments").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("list", action$1)(ctx));
|
|
1697
|
+
};
|
|
1698
|
+
const listEnvironments = {
|
|
1699
|
+
name: "list-environments",
|
|
1700
|
+
description: "List Strapi Cloud environments",
|
|
1701
|
+
action: action$1,
|
|
1702
|
+
command: command$1
|
|
1703
|
+
};
|
|
1704
|
+
const QUIT_OPTION = "Quit";
|
|
1705
|
+
const action = async (ctx) => {
|
|
1706
|
+
const { getValidToken } = await tokenServiceFactory(ctx);
|
|
1707
|
+
const token = await getValidToken(ctx, promptLogin);
|
|
1708
|
+
const { logger } = ctx;
|
|
1709
|
+
if (!token) {
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
const project = await getLocalProject(ctx);
|
|
1713
|
+
if (!project) {
|
|
1714
|
+
logger.debug(`No valid local project configuration was found.`);
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
const cloudApiService = await cloudApiFactory(ctx, token);
|
|
1718
|
+
const environments = await getEnvironmentsList(ctx, cloudApiService, project);
|
|
1719
|
+
if (!environments) {
|
|
1720
|
+
logger.debug(`Fetching environments failed.`);
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
if (environments.length === 0) {
|
|
1724
|
+
logger.log(
|
|
1725
|
+
`The only available environment is already linked. You can add a new one from your project settings on the Strapi Cloud dashboard.`
|
|
1726
|
+
);
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
const answer = await promptUserForEnvironment(ctx, environments);
|
|
1730
|
+
if (!answer) {
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
await trackEvent(ctx, cloudApiService, "willLinkEnvironment", {
|
|
1734
|
+
projectName: project.name,
|
|
1735
|
+
environmentName: answer.targetEnvironment
|
|
1736
|
+
});
|
|
1737
|
+
try {
|
|
1738
|
+
await patch({ project: { targetEnvironment: answer.targetEnvironment } });
|
|
1739
|
+
} catch (e) {
|
|
1740
|
+
await trackEvent(ctx, cloudApiService, "didNotLinkEnvironment", {
|
|
1741
|
+
projectName: project.name,
|
|
1742
|
+
environmentName: answer.targetEnvironment
|
|
1743
|
+
});
|
|
1744
|
+
logger.debug("Failed to link environment", e);
|
|
1745
|
+
logger.error(
|
|
1746
|
+
"Failed to link the environment. If this issue persists, try re-linking your project or contact support."
|
|
1747
|
+
);
|
|
1748
|
+
process.exit(1);
|
|
1749
|
+
}
|
|
1750
|
+
logger.log(
|
|
1751
|
+
` You have successfully linked your project to ${chalk.cyan(answer.targetEnvironment)}, on ${chalk.cyan(project.displayName)}. You are now able to deploy your project.`
|
|
1752
|
+
);
|
|
1753
|
+
await trackEvent(ctx, cloudApiService, "didLinkEnvironment", {
|
|
1754
|
+
projectName: project.name,
|
|
1755
|
+
environmentName: answer.targetEnvironment
|
|
1756
|
+
});
|
|
1757
|
+
};
|
|
1758
|
+
async function promptUserForEnvironment(ctx, environments) {
|
|
1759
|
+
const { logger } = ctx;
|
|
1760
|
+
try {
|
|
1761
|
+
const answer = await inquirer.prompt([
|
|
1762
|
+
{
|
|
1763
|
+
type: "list",
|
|
1764
|
+
name: "targetEnvironment",
|
|
1765
|
+
message: "Which environment do you want to link?",
|
|
1766
|
+
choices: [...environments, { name: chalk.grey(`(${QUIT_OPTION})`), value: null }]
|
|
1767
|
+
}
|
|
1768
|
+
]);
|
|
1769
|
+
if (!answer.targetEnvironment) {
|
|
1770
|
+
return null;
|
|
1771
|
+
}
|
|
1772
|
+
return answer;
|
|
1773
|
+
} catch (e) {
|
|
1774
|
+
logger.debug("Failed to get user input", e);
|
|
1775
|
+
logger.error("An error occurred while trying to get your environment selection.");
|
|
1776
|
+
return null;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
async function getEnvironmentsList(ctx, cloudApiService, project) {
|
|
1780
|
+
const spinner = ctx.logger.spinner("Fetching environments...\n").start();
|
|
1781
|
+
try {
|
|
1782
|
+
const {
|
|
1783
|
+
data: { data: environmentsList }
|
|
1784
|
+
} = await cloudApiService.listLinkEnvironments({ name: project.name });
|
|
1785
|
+
if (!Array.isArray(environmentsList) || environmentsList.length === 0) {
|
|
1786
|
+
throw new Error("Environments not found in server response");
|
|
1787
|
+
}
|
|
1788
|
+
spinner.succeed();
|
|
1789
|
+
return environmentsList.filter(
|
|
1790
|
+
(environment) => environment.name !== project.targetEnvironment
|
|
1791
|
+
);
|
|
1792
|
+
} catch (e) {
|
|
1793
|
+
if (e.response && e.response.status === 404) {
|
|
1794
|
+
spinner.succeed();
|
|
1795
|
+
ctx.logger.warn(
|
|
1796
|
+
`
|
|
1797
|
+
The project associated with this folder does not exist in Strapi Cloud.
|
|
1798
|
+
Please link your local project to an existing Strapi Cloud project using the ${chalk.cyan(
|
|
1799
|
+
"link"
|
|
1800
|
+
)} command.`
|
|
1801
|
+
);
|
|
1802
|
+
} else {
|
|
1803
|
+
spinner.fail("An error occurred while fetching environments data from Strapi Cloud.");
|
|
1804
|
+
ctx.logger.debug("Failed to list environments", e);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
const command = ({ command: command2, ctx }) => {
|
|
1809
|
+
const environmentCmd2 = initializeEnvironmentCommand(command2, ctx);
|
|
1810
|
+
environmentCmd2.command("link").description("Link project to a specific Strapi Cloud project environment").option("-d, --debug", "Enable debugging mode with verbose logs").option("-s, --silent", "Don't log anything").action(() => runAction("link", action)(ctx));
|
|
1811
|
+
};
|
|
1812
|
+
const linkEnvironment = {
|
|
1813
|
+
name: "link-environment",
|
|
1814
|
+
description: "Link Strapi Cloud environment to a local project",
|
|
1815
|
+
action,
|
|
1188
1816
|
command
|
|
1189
1817
|
};
|
|
1190
1818
|
const cli = {
|
|
1191
1819
|
deployProject,
|
|
1820
|
+
link,
|
|
1192
1821
|
login,
|
|
1193
1822
|
logout,
|
|
1194
|
-
createProject
|
|
1823
|
+
createProject,
|
|
1824
|
+
linkEnvironment,
|
|
1825
|
+
listProjects,
|
|
1826
|
+
listEnvironments
|
|
1195
1827
|
};
|
|
1196
|
-
const cloudCommands = [
|
|
1828
|
+
const cloudCommands = [
|
|
1829
|
+
deployProject,
|
|
1830
|
+
link,
|
|
1831
|
+
login,
|
|
1832
|
+
logout,
|
|
1833
|
+
linkEnvironment,
|
|
1834
|
+
listProjects,
|
|
1835
|
+
listEnvironments
|
|
1836
|
+
];
|
|
1197
1837
|
async function initCloudCLIConfig() {
|
|
1198
|
-
const localConfig = await getLocalConfig();
|
|
1838
|
+
const localConfig = await getLocalConfig$1();
|
|
1199
1839
|
if (!localConfig.deviceId) {
|
|
1200
1840
|
localConfig.deviceId = crypto$1.randomUUID();
|
|
1201
1841
|
}
|
|
@@ -1209,7 +1849,10 @@ async function buildStrapiCloudCommands({
|
|
|
1209
1849
|
await initCloudCLIConfig();
|
|
1210
1850
|
for (const cloudCommand of cloudCommands) {
|
|
1211
1851
|
try {
|
|
1212
|
-
await cloudCommand.command({ command: command2, ctx, argv });
|
|
1852
|
+
const subCommand = await cloudCommand.command({ command: command2, ctx, argv });
|
|
1853
|
+
if (subCommand) {
|
|
1854
|
+
command2.addCommand(subCommand);
|
|
1855
|
+
}
|
|
1213
1856
|
} catch (e) {
|
|
1214
1857
|
console.error(`Failed to load command ${cloudCommand.name}`, e);
|
|
1215
1858
|
}
|