@strapi/cloud-cli 0.0.0-next.b558642be856459a3e6c076f5d76fffbfc5fc5a1 → 0.0.0-next.bb6ff32f5168f3e380d3d9acba90a9d53bfcfb89

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/index.js CHANGED
@@ -24,6 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
25
25
  const crypto$1 = require("crypto");
26
26
  const fse = require("fs-extra");
27
+ const inquirer = require("inquirer");
27
28
  const path = require("path");
28
29
  const chalk = require("chalk");
29
30
  const axios = require("axios");
@@ -31,7 +32,6 @@ const crypto = require("node:crypto");
31
32
  const utils = require("@strapi/utils");
32
33
  const tar = require("tar");
33
34
  const minimatch = require("minimatch");
34
- const inquirer = require("inquirer");
35
35
  const fp = require("lodash/fp");
36
36
  const os = require("os");
37
37
  const XDGAppPaths = require("xdg-app-paths");
@@ -65,12 +65,12 @@ function _interopNamespace(e) {
65
65
  }
66
66
  const crypto__default = /* @__PURE__ */ _interopDefault(crypto$1);
67
67
  const fse__namespace = /* @__PURE__ */ _interopNamespace(fse);
68
+ const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
68
69
  const path__namespace = /* @__PURE__ */ _interopNamespace(path);
69
70
  const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
70
71
  const axios__default = /* @__PURE__ */ _interopDefault(axios);
71
72
  const crypto__namespace = /* @__PURE__ */ _interopNamespace(crypto);
72
73
  const tar__namespace = /* @__PURE__ */ _interopNamespace(tar);
73
- const inquirer__default = /* @__PURE__ */ _interopDefault(inquirer);
74
74
  const os__default = /* @__PURE__ */ _interopDefault(os);
75
75
  const XDGAppPaths__default = /* @__PURE__ */ _interopDefault(XDGAppPaths);
76
76
  const jwksClient__default = /* @__PURE__ */ _interopDefault(jwksClient);
@@ -193,7 +193,7 @@ async function saveLocalConfig(data) {
193
193
  await fse__namespace.default.writeJson(configFilePath, data, { encoding: "utf8", spaces: 2, mode: 384 });
194
194
  }
195
195
  const name = "@strapi/cloud-cli";
196
- const version = "5.0.2";
196
+ const version = "5.3.0";
197
197
  const description = "Commands to interact with the Strapi Cloud";
198
198
  const keywords = [
199
199
  "strapi",
@@ -267,7 +267,7 @@ const devDependencies = {
267
267
  tsconfig: "workspace:*"
268
268
  };
269
269
  const engines = {
270
- node: ">=18.0.0 <=20.x.x",
270
+ node: ">=18.0.0 <=22.x.x",
271
271
  npm: ">=6.0.0"
272
272
  };
273
273
  const packageJson = {
@@ -317,7 +317,7 @@ async function cloudApiFactory({ logger }, token) {
317
317
  deploy({ filePath, project }, { onUploadProgress }) {
318
318
  return axiosCloudAPI.post(
319
319
  `/deploy/${project.name}`,
320
- { file: fse__namespace.default.createReadStream(filePath) },
320
+ { file: fse__namespace.default.createReadStream(filePath), targetEnvironment: project.targetEnvironment },
321
321
  {
322
322
  headers: {
323
323
  "Content-Type": "multipart/form-data"
@@ -388,6 +388,20 @@ async function cloudApiFactory({ logger }, token) {
388
388
  throw error;
389
389
  }
390
390
  },
391
+ async listEnvironments({ name: name2 }) {
392
+ try {
393
+ const response = await axiosCloudAPI.get(`/projects/${name2}/environments`);
394
+ if (response.status !== 200) {
395
+ throw new Error("Error fetching cloud environments from the server.");
396
+ }
397
+ return response;
398
+ } catch (error) {
399
+ logger.debug(
400
+ "🥲 Oops! Couldn't retrieve your project's environments from the server. Please try again."
401
+ );
402
+ throw error;
403
+ }
404
+ },
391
405
  async getProject({ name: name2 }) {
392
406
  try {
393
407
  const response = await axiosCloudAPI.get(`/projects/${name2}`);
@@ -960,7 +974,7 @@ async function createProject$1(ctx, cloudApi, projectInput) {
960
974
  throw e;
961
975
  }
962
976
  }
963
- const action$4 = async (ctx) => {
977
+ const action$5 = async (ctx) => {
964
978
  const { logger } = ctx;
965
979
  const { getValidToken, eraseToken } = await tokenServiceFactory(ctx);
966
980
  const token = await getValidToken(ctx, promptLogin);
@@ -1089,6 +1103,32 @@ const buildLogsServiceFactory = ({ logger }) => {
1089
1103
  });
1090
1104
  };
1091
1105
  };
1106
+ const QUIT_OPTION$1 = "Quit";
1107
+ async function promptForEnvironment(environments) {
1108
+ const choices = environments.map((env) => ({ name: env, value: env }));
1109
+ const { selectedEnvironment } = await inquirer__default.default.prompt([
1110
+ {
1111
+ type: "list",
1112
+ name: "selectedEnvironment",
1113
+ message: "Select the environment to deploy:",
1114
+ choices: [...choices, { name: chalk__default.default.grey(`(${QUIT_OPTION$1})`), value: null }]
1115
+ }
1116
+ ]);
1117
+ if (selectedEnvironment === null) {
1118
+ process.exit(1);
1119
+ }
1120
+ const { confirm } = await inquirer__default.default.prompt([
1121
+ {
1122
+ type: "confirm",
1123
+ name: "confirm",
1124
+ message: `Do you want to proceed with deployment to ${chalk__default.default.cyan(selectedEnvironment)}?`
1125
+ }
1126
+ ]);
1127
+ if (!confirm) {
1128
+ process.exit(1);
1129
+ }
1130
+ return selectedEnvironment;
1131
+ }
1092
1132
  async function upload(ctx, project, token, maxProjectFileSize) {
1093
1133
  const cloudApi = await cloudApiFactory(ctx, token);
1094
1134
  try {
@@ -1167,11 +1207,11 @@ async function upload(ctx, project, token, maxProjectFileSize) {
1167
1207
  process.exit(1);
1168
1208
  }
1169
1209
  }
1170
- async function getProject(ctx) {
1210
+ async function getProject$1(ctx) {
1171
1211
  const { project } = await retrieve();
1172
1212
  if (!project) {
1173
1213
  try {
1174
- return await action$4(ctx);
1214
+ return await action$5(ctx);
1175
1215
  } catch (e) {
1176
1216
  ctx.logger.error("An error occurred while deploying the project. Please try again later.");
1177
1217
  ctx.logger.debug(e);
@@ -1192,22 +1232,24 @@ async function getConfig({
1192
1232
  return null;
1193
1233
  }
1194
1234
  }
1195
- const action$3 = async (ctx) => {
1235
+ const action$4 = async (ctx, opts) => {
1196
1236
  const { getValidToken } = await tokenServiceFactory(ctx);
1197
1237
  const token = await getValidToken(ctx, promptLogin);
1198
1238
  if (!token) {
1199
1239
  return;
1200
1240
  }
1201
- const project = await getProject(ctx);
1241
+ const project = await getProject$1(ctx);
1202
1242
  if (!project) {
1203
1243
  return;
1204
1244
  }
1205
1245
  const cloudApiService = await cloudApiFactory(ctx, token);
1246
+ let environments;
1206
1247
  try {
1207
1248
  const {
1208
1249
  data: { data: projectData, metadata }
1209
1250
  } = await cloudApiService.getProject({ name: project.name });
1210
1251
  const isProjectSuspended = projectData.suspendedAt;
1252
+ environments = projectData.environments;
1211
1253
  if (isProjectSuspended) {
1212
1254
  ctx.logger.log(
1213
1255
  "\n Oops! This project has been suspended. \n\n Please reactivate it from the dashboard to continue deploying: "
@@ -1254,6 +1296,17 @@ Please link your local project to an existing Strapi Cloud project using the ${c
1254
1296
  );
1255
1297
  maxSize = 1e8;
1256
1298
  }
1299
+ let targetEnvironment;
1300
+ if (opts.environment) {
1301
+ if (!environments.includes(opts.environment)) {
1302
+ ctx.logger.error(`Environment ${opts.environment} does not exist.`);
1303
+ return;
1304
+ }
1305
+ targetEnvironment = opts.environment;
1306
+ } else {
1307
+ targetEnvironment = environments.length > 1 ? await promptForEnvironment(environments) : environments[0];
1308
+ }
1309
+ project.targetEnvironment = targetEnvironment;
1257
1310
  const buildId = await upload(ctx, project, token, maxSize);
1258
1311
  if (!buildId) {
1259
1312
  return;
@@ -1303,14 +1356,14 @@ const runAction = (name2, action2) => (...args) => {
1303
1356
  process.exit(1);
1304
1357
  });
1305
1358
  };
1306
- const command$5 = ({ ctx }) => {
1307
- return commander.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").action(() => runAction("deploy", action$3)(ctx));
1359
+ const command$6 = ({ ctx }) => {
1360
+ return commander.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("-e, --environment <name>", "Specify the environment to deploy").action((opts) => runAction("deploy", action$4)(ctx, opts));
1308
1361
  };
1309
1362
  const deployProject = {
1310
1363
  name: "deploy-project",
1311
1364
  description: "Deploy a Strapi Cloud project",
1312
- action: action$3,
1313
- command: command$5
1365
+ action: action$4,
1366
+ command: command$6
1314
1367
  };
1315
1368
  const QUIT_OPTION = "Quit";
1316
1369
  async function getExistingConfig(ctx) {
@@ -1394,7 +1447,7 @@ async function getUserSelection(ctx, projects) {
1394
1447
  return null;
1395
1448
  }
1396
1449
  }
1397
- const action$2 = async (ctx) => {
1450
+ const action$3 = async (ctx) => {
1398
1451
  const { getValidToken } = await tokenServiceFactory(ctx);
1399
1452
  const token = await getValidToken(ctx, promptLogin);
1400
1453
  const { logger } = ctx;
@@ -1449,16 +1502,16 @@ const action$2 = async (ctx) => {
1449
1502
  });
1450
1503
  }
1451
1504
  };
1452
- const command$4 = ({ command: command2, ctx }) => {
1453
- 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$2)(ctx));
1505
+ const command$5 = ({ command: command2, ctx }) => {
1506
+ 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$3)(ctx));
1454
1507
  };
1455
1508
  const link = {
1456
1509
  name: "link-project",
1457
1510
  description: "Link a local directory to a Strapi Cloud project",
1458
- action: action$2,
1459
- command: command$4
1511
+ action: action$3,
1512
+ command: command$5
1460
1513
  };
1461
- const command$3 = ({ ctx }) => {
1514
+ const command$4 = ({ ctx }) => {
1462
1515
  return commander.createCommand("cloud:login").alias("login").description("Strapi Cloud Login").addHelpText(
1463
1516
  "after",
1464
1517
  "\nAfter running this command, you will be prompted to enter your authentication information."
@@ -1468,10 +1521,10 @@ const login = {
1468
1521
  name: "login",
1469
1522
  description: "Strapi Cloud Login",
1470
1523
  action: loginAction,
1471
- command: command$3
1524
+ command: command$4
1472
1525
  };
1473
1526
  const openModule = import("open");
1474
- const action$1 = async (ctx) => {
1527
+ const action$2 = async (ctx) => {
1475
1528
  const { logger } = ctx;
1476
1529
  const { retrieveToken, eraseToken } = await tokenServiceFactory(ctx);
1477
1530
  const token = await retrieveToken();
@@ -1503,25 +1556,25 @@ const action$1 = async (ctx) => {
1503
1556
  }
1504
1557
  await trackEvent(ctx, cloudApiService, "didLogout", { loginMethod: "cli" });
1505
1558
  };
1506
- const command$2 = ({ ctx }) => {
1507
- return commander.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$1)(ctx));
1559
+ const command$3 = ({ ctx }) => {
1560
+ return commander.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$2)(ctx));
1508
1561
  };
1509
1562
  const logout = {
1510
1563
  name: "logout",
1511
1564
  description: "Strapi Cloud Logout",
1512
- action: action$1,
1513
- command: command$2
1565
+ action: action$2,
1566
+ command: command$3
1514
1567
  };
1515
- const command$1 = ({ ctx }) => {
1516
- return commander.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$4)(ctx));
1568
+ const command$2 = ({ ctx }) => {
1569
+ return commander.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$5)(ctx));
1517
1570
  };
1518
1571
  const createProject = {
1519
1572
  name: "create-project",
1520
1573
  description: "Create a new project",
1521
- action: action$4,
1522
- command: command$1
1574
+ action: action$5,
1575
+ command: command$2
1523
1576
  };
1524
- const action = async (ctx) => {
1577
+ const action$1 = async (ctx) => {
1525
1578
  const { getValidToken } = await tokenServiceFactory(ctx);
1526
1579
  const token = await getValidToken(ctx, promptLogin);
1527
1580
  const { logger } = ctx;
@@ -1541,12 +1594,94 @@ const action = async (ctx) => {
1541
1594
  spinner.fail("An error occurred while fetching your projects from Strapi Cloud.");
1542
1595
  }
1543
1596
  };
1544
- const command = ({ command: command2, ctx }) => {
1545
- 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)(ctx));
1597
+ const command$1 = ({ command: command2, ctx }) => {
1598
+ 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$1)(ctx));
1546
1599
  };
1547
1600
  const listProjects = {
1548
1601
  name: "list-projects",
1549
1602
  description: "List Strapi Cloud projects",
1603
+ action: action$1,
1604
+ command: command$1
1605
+ };
1606
+ async function getProject(ctx) {
1607
+ const { project } = await retrieve();
1608
+ if (!project) {
1609
+ ctx.logger.warn(
1610
+ `
1611
+ We couldn't find a valid local project config.
1612
+ Please link your local project to an existing Strapi Cloud project using the ${chalk__default.default.cyan(
1613
+ "link"
1614
+ )} command`
1615
+ );
1616
+ process.exit(1);
1617
+ }
1618
+ return project;
1619
+ }
1620
+ const action = async (ctx) => {
1621
+ const { getValidToken } = await tokenServiceFactory(ctx);
1622
+ const token = await getValidToken(ctx, promptLogin);
1623
+ const { logger } = ctx;
1624
+ if (!token) {
1625
+ return;
1626
+ }
1627
+ const project = await getProject(ctx);
1628
+ if (!project) {
1629
+ ctx.logger.debug(`No valid local project configuration was found.`);
1630
+ return;
1631
+ }
1632
+ const cloudApiService = await cloudApiFactory(ctx, token);
1633
+ const spinner = logger.spinner("Fetching environments...").start();
1634
+ await trackEvent(ctx, cloudApiService, "willListEnvironment", {
1635
+ projectInternalName: project.name
1636
+ });
1637
+ try {
1638
+ const {
1639
+ data: { data: environmentsList }
1640
+ } = await cloudApiService.listEnvironments({ name: project.name });
1641
+ spinner.succeed();
1642
+ logger.log(environmentsList);
1643
+ await trackEvent(ctx, cloudApiService, "didListEnvironment", {
1644
+ projectInternalName: project.name
1645
+ });
1646
+ } catch (e) {
1647
+ if (e.response && e.response.status === 404) {
1648
+ spinner.succeed();
1649
+ logger.warn(
1650
+ `
1651
+ The project associated with this folder does not exist in Strapi Cloud.
1652
+ Please link your local project to an existing Strapi Cloud project using the ${chalk__default.default.cyan(
1653
+ "link"
1654
+ )} command`
1655
+ );
1656
+ } else {
1657
+ spinner.fail("An error occurred while fetching environments data from Strapi Cloud.");
1658
+ logger.debug("Failed to list environments", e);
1659
+ }
1660
+ await trackEvent(ctx, cloudApiService, "didNotListEnvironment", {
1661
+ projectInternalName: project.name
1662
+ });
1663
+ }
1664
+ };
1665
+ function defineCloudNamespace(command2, ctx) {
1666
+ const cloud = command2.command("cloud").description("Manage Strapi Cloud projects");
1667
+ cloud.command("environments").description("Alias for cloud environment list").action(() => runAction("list", action)(ctx));
1668
+ return cloud;
1669
+ }
1670
+ let environmentCmd = null;
1671
+ const initializeEnvironmentCommand = (command2, ctx) => {
1672
+ if (!environmentCmd) {
1673
+ const cloud = defineCloudNamespace(command2, ctx);
1674
+ environmentCmd = cloud.command("environment").description("Manage environments");
1675
+ }
1676
+ return environmentCmd;
1677
+ };
1678
+ const command = ({ command: command2, ctx }) => {
1679
+ const environmentCmd2 = initializeEnvironmentCommand(command2, ctx);
1680
+ 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)(ctx));
1681
+ };
1682
+ const listEnvironments = {
1683
+ name: "list-environments",
1684
+ description: "List Strapi Cloud environments",
1550
1685
  action,
1551
1686
  command
1552
1687
  };
@@ -1556,9 +1691,10 @@ const cli = {
1556
1691
  login,
1557
1692
  logout,
1558
1693
  createProject,
1559
- listProjects
1694
+ listProjects,
1695
+ listEnvironments
1560
1696
  };
1561
- const cloudCommands = [deployProject, link, login, logout, listProjects];
1697
+ const cloudCommands = [deployProject, link, login, logout, listProjects, listEnvironments];
1562
1698
  async function initCloudCLIConfig() {
1563
1699
  const localConfig = await getLocalConfig();
1564
1700
  if (!localConfig.deviceId) {