clever-tools 4.7.1 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/bin/clever.js +11 -1
  2. package/package.json +2 -2
  3. package/src/clever-client/drains.js +18 -18
  4. package/src/clever-client/k8s.js +197 -0
  5. package/src/commands/README.md +1 -0
  6. package/src/commands/accesslogs/accesslogs.command.js +2 -2
  7. package/src/commands/activity/activity.command.js +1 -1
  8. package/src/commands/addon/addon.create.command.js +2 -3
  9. package/src/commands/addon/addon.delete.command.js +2 -2
  10. package/src/commands/addon/addon.docs.md +2 -2
  11. package/src/commands/addon/addon.env.command.js +4 -6
  12. package/src/commands/config-provider/config-provider.command.js +0 -4
  13. package/src/commands/config-provider/config-provider.import.command.js +1 -1
  14. package/src/commands/config-provider/config-provider.list.command.js +8 -19
  15. package/src/commands/config-provider/config-provider.open.command.js +1 -1
  16. package/src/commands/console/console.command.js +3 -2
  17. package/src/commands/curl/curl.command.js +0 -1
  18. package/src/commands/database/database.backups.command.js +4 -7
  19. package/src/commands/database/database.backups.download.command.js +5 -7
  20. package/src/commands/database/database.command.js +0 -4
  21. package/src/commands/database/database.docs.md +2 -2
  22. package/src/commands/deploy/deploy.command.js +1 -1
  23. package/src/commands/deploy/deploy.docs.md +1 -1
  24. package/src/commands/drain/drain.command.js +14 -9
  25. package/src/commands/drain/drain.create.command.js +9 -13
  26. package/src/commands/drain/drain.disable.command.js +7 -7
  27. package/src/commands/drain/drain.docs.md +6 -0
  28. package/src/commands/drain/drain.enable.command.js +7 -7
  29. package/src/commands/drain/drain.get.command.js +12 -8
  30. package/src/commands/drain/drain.remove.command.js +7 -7
  31. package/src/commands/emails/emails.open.command.js +1 -4
  32. package/src/commands/global.commands.js +52 -0
  33. package/src/commands/global.options.js +7 -7
  34. package/src/commands/help/help.command.js +0 -3
  35. package/src/commands/k8s/k8s.activity.command.js +53 -0
  36. package/src/commands/k8s/k8s.args.js +6 -0
  37. package/src/commands/k8s/k8s.command.js +0 -4
  38. package/src/commands/k8s/k8s.create.command.js +87 -3
  39. package/src/commands/k8s/k8s.delete.command.js +15 -20
  40. package/src/commands/k8s/k8s.docs.md +264 -1
  41. package/src/commands/k8s/k8s.get.command.js +65 -4
  42. package/src/commands/k8s/k8s.nodegroups.command.js +7 -0
  43. package/src/commands/k8s/k8s.nodegroups.create.command.js +79 -0
  44. package/src/commands/k8s/k8s.nodegroups.delete.command.js +34 -0
  45. package/src/commands/k8s/k8s.nodegroups.get.command.js +66 -0
  46. package/src/commands/k8s/k8s.nodegroups.list.command.js +49 -0
  47. package/src/commands/k8s/k8s.nodegroups.update.command.js +86 -0
  48. package/src/commands/k8s/k8s.quota.command.js +77 -0
  49. package/src/commands/k8s/k8s.update.command.js +72 -0
  50. package/src/commands/k8s/k8s.version.check.command.js +18 -0
  51. package/src/commands/k8s/k8s.version.command.js +18 -0
  52. package/src/commands/k8s/k8s.version.update.command.js +18 -0
  53. package/src/commands/logs/logs.command.js +4 -5
  54. package/src/commands/ng/ng.docs.md +0 -1
  55. package/src/commands/ng/ng.get-config.command.js +3 -14
  56. package/src/commands/ng/ng.options.js +1 -1
  57. package/src/commands/notify-email/notify-email.remove.command.js +2 -2
  58. package/src/commands/oauth-consumers/oauth-consumers.args.js +8 -0
  59. package/src/commands/oauth-consumers/oauth-consumers.command.js +6 -0
  60. package/src/commands/oauth-consumers/oauth-consumers.create.command.js +64 -0
  61. package/src/commands/oauth-consumers/oauth-consumers.delete.command.js +33 -0
  62. package/src/commands/oauth-consumers/oauth-consumers.docs.md +130 -0
  63. package/src/commands/oauth-consumers/oauth-consumers.get.command.js +67 -0
  64. package/src/commands/oauth-consumers/oauth-consumers.list.command.js +34 -0
  65. package/src/commands/oauth-consumers/oauth-consumers.open.command.js +18 -0
  66. package/src/commands/oauth-consumers/oauth-consumers.options.js +48 -0
  67. package/src/commands/oauth-consumers/oauth-consumers.update.command.js +83 -0
  68. package/src/commands/open/open.command.js +1 -1
  69. package/src/commands/otoroshi/otoroshi.docs.md +14 -0
  70. package/src/commands/otoroshi/otoroshi.open.swaggerui.command.js +13 -0
  71. package/src/commands/profile/profile.open.command.js +1 -1
  72. package/src/commands/restart/restart.docs.md +1 -1
  73. package/src/commands/ssh-keys/ssh-keys.open.command.js +1 -1
  74. package/src/commands/webhooks/webhooks.remove.command.js +2 -2
  75. package/src/lib/cliparse-patched.js +2 -0
  76. package/src/lib/get-command-info.js +3 -1
  77. package/src/lib/get-command-info.types.d.ts +4 -0
  78. package/src/lib/k8s.js +411 -11
  79. package/src/lib/operator-commands.js +24 -24
  80. package/src/lib/print-items-by-owner.js +38 -0
  81. package/src/lib/prompts.js +29 -3
  82. package/src/lib/zod-utils.js +51 -0
  83. package/src/models/drain.js +17 -0
  84. package/src/models/ids-resolver.js +38 -20
  85. package/src/models/ng.js +2 -2
  86. package/src/models/notification.js +0 -4
  87. package/src/models/oauth-consumer.js +77 -0
  88. package/src/models/utils.js +1 -1
  89. package/src/parsers.js +10 -0
package/bin/clever.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  import { EXPERIMENTAL_FEATURES, getFeatures } from '../src/config/features.js';
18
18
  import { cliparse } from '../src/lib/cliparse-patched.js';
19
19
  import { styleText } from '../src/lib/style-text.js';
20
- import { getDefault, isBoolean, isRequired } from '../src/lib/zod-utils.js';
20
+ import { getDefault, getEnumValues, isBoolean, isRequired } from '../src/lib/zod-utils.js';
21
21
 
22
22
  /**
23
23
  * @typedef {import('../src/lib/define-command.types.js').CommandDefinition} CommandDefinition
@@ -199,6 +199,11 @@ function convertOption(option) {
199
199
  }
200
200
  if (option.complete != null) {
201
201
  cliparseConfig.complete = option.complete;
202
+ } else {
203
+ const enumValues = getEnumValues(option.schema);
204
+ if (enumValues != null) {
205
+ cliparseConfig.complete = enumValues;
206
+ }
202
207
  }
203
208
 
204
209
  // Use Zod's safeParse for validation (handles coercion, enums, refinements, etc.)
@@ -242,6 +247,11 @@ function convertArgument(arg) {
242
247
 
243
248
  if (arg.complete) {
244
249
  cliparseConfig.complete = arg.complete;
250
+ } else {
251
+ const enumValues = getEnumValues(arg.schema);
252
+ if (enumValues != null) {
253
+ cliparseConfig.complete = enumValues;
254
+ }
245
255
  }
246
256
 
247
257
  // Use Zod's safeParse for validation (handles coercion, enums, refinements, etc.)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clever-tools",
3
- "version": "4.7.1",
3
+ "version": "4.9.0",
4
4
  "description": "Command Line Interface for Clever Cloud.",
5
5
  "keywords": [
6
6
  "cli",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@babel/traverse": "7.28.5",
53
- "@clevercloud/client": "11.3.0",
53
+ "@clevercloud/client": "12.0.0",
54
54
  "@inquirer/prompts": "7.8.4",
55
55
  "char-regex": "2.0.2",
56
56
  "cliparse": "0.5.0",
@@ -1,10 +1,10 @@
1
1
  // TODO: Move this to the Clever Cloud JS Client
2
2
 
3
3
  /**
4
- * GET /v4/drains/organisations/{ownerId}/applications/{applicationId}/drains?status={status}&executionStatus={executionStatus}&executionStatusNotIn={executionStatusNotIn}
4
+ * GET /v4/drains/organisations/{ownerId}/resources/{resourceId}/drains?status={status}&executionStatus={executionStatus}&executionStatusNotIn={executionStatusNotIn}
5
5
  * @param {Object} params
6
6
  * @param {String} params.ownerId
7
- * @param {String} params.applicationId
7
+ * @param {String} params.resourceId
8
8
  * @param {String} params.status
9
9
  * @param {String} params.executionStatus
10
10
  * @param {String} params.executionStatusNotIn
@@ -13,7 +13,7 @@ export function getDrains(params) {
13
13
  // no multipath for /self or /organisations/{id}
14
14
  return Promise.resolve({
15
15
  method: 'get',
16
- url: `/v4/drains/organisations/${params.ownerId}/applications/${params.applicationId}/drains`,
16
+ url: `/v4/drains/organisations/${params.ownerId}/resources/${params.resourceId}/drains`,
17
17
  headers: { Accept: 'application/json' },
18
18
  queryParams: {
19
19
  status: params.status,
@@ -25,85 +25,85 @@ export function getDrains(params) {
25
25
  }
26
26
 
27
27
  /**
28
- * POST /v4/drains/organisations/{ownerId}/applications/{applicationId}/drains
28
+ * POST /v4/drains/organisations/{ownerId}/resources/{resourceId}/drains
29
29
  * @param {Object} params
30
30
  * @param {String} params.ownerId
31
- * @param {String} params.applicationId
31
+ * @param {String} params.resourceId
32
32
  * @param {Object} params.body
33
33
  */
34
34
  export function createDrain(params) {
35
35
  // no multipath for /self or /organisations/{id}
36
36
  return Promise.resolve({
37
37
  method: 'post',
38
- url: `/v4/drains/organisations/${params.ownerId}/applications/${params.applicationId}/drains`,
38
+ url: `/v4/drains/organisations/${params.ownerId}/resources/${params.resourceId}/drains`,
39
39
  headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
40
40
  body: params.body,
41
41
  });
42
42
  }
43
43
 
44
44
  /**
45
- * DELETE /v4/drains/organisations/{ownerId}/applications/{applicationId}/drains/{drainId}
45
+ * DELETE /v4/drains/organisations/{ownerId}/resources/{resourceId}/drains/{drainId}
46
46
  * @param {Object} params
47
47
  * @param {String} params.ownerId
48
- * @param {String} params.applicationId
48
+ * @param {String} params.resourceId
49
49
  * @param {String} params.drainId
50
50
  */
51
51
  export function deleteDrain(params) {
52
52
  // no multipath for /self or /organisations/{id}
53
53
  return Promise.resolve({
54
54
  method: 'delete',
55
- url: `/v4/drains/organisations/${params.ownerId}/applications/${params.applicationId}/drains/${params.drainId}`,
55
+ url: `/v4/drains/organisations/${params.ownerId}/resources/${params.resourceId}/drains/${params.drainId}`,
56
56
  headers: { Accept: 'application/json' },
57
57
  // no body
58
58
  });
59
59
  }
60
60
 
61
61
  /**
62
- * GET /v4/drains/organisations/{ownerId}/applications/{applicationId}/drains/{drainId}
62
+ * GET /v4/drains/organisations/{ownerId}/resources/{resourceId}/drains/{drainId}
63
63
  * @param {Object} params
64
64
  * @param {String} params.ownerId
65
- * @param {String} params.applicationId
65
+ * @param {String} params.resourceId
66
66
  * @param {String} params.drainId
67
67
  */
68
68
  export function getDrain(params) {
69
69
  // no multipath for /self or /organisations/{id}
70
70
  return Promise.resolve({
71
71
  method: 'get',
72
- url: `/v4/drains/organisations/${params.ownerId}/applications/${params.applicationId}/drains/${params.drainId}`,
72
+ url: `/v4/drains/organisations/${params.ownerId}/resources/${params.resourceId}/drains/${params.drainId}`,
73
73
  headers: { Accept: 'application/json' },
74
74
  // no body
75
75
  });
76
76
  }
77
77
 
78
78
  /**
79
- * PUT /v4/drains/organisations/{ownerId}/applications/{applicationId}/drains/{drainId}/disable
79
+ * PUT /v4/drains/organisations/{ownerId}/resources/{resourceId}/drains/{drainId}/disable
80
80
  * @param {Object} params
81
81
  * @param {String} params.ownerId
82
- * @param {String} params.applicationId
82
+ * @param {String} params.resourceId
83
83
  * @param {String} params.drainId
84
84
  */
85
85
  export function disableDrain(params) {
86
86
  // no multipath for /self or /organisations/{id}
87
87
  return Promise.resolve({
88
88
  method: 'put',
89
- url: `/v4/drains/organisations/${params.ownerId}/applications/${params.applicationId}/drains/${params.drainId}/disable`,
89
+ url: `/v4/drains/organisations/${params.ownerId}/resources/${params.resourceId}/drains/${params.drainId}/disable`,
90
90
  headers: { Accept: 'application/json' },
91
91
  // no body
92
92
  });
93
93
  }
94
94
 
95
95
  /**
96
- * PUT /v4/drains/organisations/{ownerId}/applications/{applicationId}/drains/{drainId}/enable
96
+ * PUT /v4/drains/organisations/{ownerId}/resources/{resourceId}/drains/{drainId}/enable
97
97
  * @param {Object} params
98
98
  * @param {String} params.ownerId
99
- * @param {String} params.applicationId
99
+ * @param {String} params.resourceId
100
100
  * @param {String} params.drainId
101
101
  */
102
102
  export function enableDrain(params) {
103
103
  // no multipath for /self or /organisations/{id}
104
104
  return Promise.resolve({
105
105
  method: 'put',
106
- url: `/v4/drains/organisations/${params.ownerId}/applications/${params.applicationId}/drains/${params.drainId}/enable`,
106
+ url: `/v4/drains/organisations/${params.ownerId}/resources/${params.resourceId}/drains/${params.drainId}/enable`,
107
107
  headers: { Accept: 'application/json' },
108
108
  // no body
109
109
  });
@@ -16,6 +16,23 @@ export function createK8sCluster(params, body) {
16
16
  });
17
17
  }
18
18
 
19
+ /**
20
+ * PATCH /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}
21
+ * @param {Object} params
22
+ * @param {String} params.ownerId
23
+ * @param {String} params.clusterId
24
+ * @param {Object} body
25
+ */
26
+ export function updateK8sCluster(params, body) {
27
+ return Promise.resolve({
28
+ method: 'PATCH',
29
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}`,
30
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
31
+ // no queryParams
32
+ body,
33
+ });
34
+ }
35
+
19
36
  /**
20
37
  * DELETE /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}
21
38
  * @param {Object} params
@@ -94,3 +111,183 @@ export function addK8sPersistentStorage(params) {
94
111
  // no body
95
112
  });
96
113
  }
114
+
115
+ /**
116
+ * PATCH /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/node-groups/{nodeGroupId}
117
+ * @param {Object} params
118
+ * @param {String} params.ownerId
119
+ * @param {String} params.clusterId
120
+ * @param {String} params.nodeGroupId
121
+ * @param {Object} body
122
+ */
123
+ export function updateK8sNodeGroup(params, body) {
124
+ return Promise.resolve({
125
+ method: 'PATCH',
126
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/node-groups/${params.nodeGroupId}`,
127
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
128
+ // no queryParams
129
+ body,
130
+ });
131
+ }
132
+
133
+ /**
134
+ * DELETE /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/node-groups/{nodeGroupId}
135
+ * @param {Object} params
136
+ * @param {String} params.ownerId
137
+ * @param {String} params.clusterId
138
+ * @param {String} params.nodeGroupId
139
+ */
140
+ export function deleteK8sNodeGroup(params) {
141
+ return Promise.resolve({
142
+ method: 'delete',
143
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/node-groups/${params.nodeGroupId}`,
144
+ headers: { Accept: 'application/json' },
145
+ // no queryParams
146
+ // no body
147
+ });
148
+ }
149
+
150
+ /**
151
+ * POST /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/node-groups
152
+ * @param {Object} params
153
+ * @param {String} params.ownerId
154
+ * @param {String} params.clusterId
155
+ * @param {Object} body
156
+ */
157
+ export function createK8sNodeGroup(params, body) {
158
+ return Promise.resolve({
159
+ method: 'post',
160
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/node-groups`,
161
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
162
+ // no queryParams
163
+ body,
164
+ });
165
+ }
166
+
167
+ /**
168
+ * GET /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/node-groups
169
+ * @param {Object} params
170
+ * @param {String} params.ownerId
171
+ * @param {String} params.clusterId
172
+ */
173
+ export function listK8sNodeGroups(params) {
174
+ return Promise.resolve({
175
+ method: 'get',
176
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/node-groups`,
177
+ headers: { Accept: 'application/json' },
178
+ // no queryParams
179
+ // no body
180
+ });
181
+ }
182
+
183
+ /**
184
+ * GET /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/node-groups/{nodeGroupId}
185
+ * @param {Object} params
186
+ * @param {String} params.ownerId
187
+ * @param {String} params.clusterId
188
+ * @param {String} params.nodeGroupId
189
+ */
190
+ export function getK8sNodeGroup(params) {
191
+ return Promise.resolve({
192
+ method: 'get',
193
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/node-groups/${params.nodeGroupId}`,
194
+ headers: { Accept: 'application/json' },
195
+ // no queryParams
196
+ // no body
197
+ });
198
+ }
199
+
200
+ /**
201
+ * GET /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/deployment-events
202
+ * @param {Object} params
203
+ * @param {String} params.ownerId
204
+ * @param {String} params.clusterId
205
+ * @param {Object} [queryParams]
206
+ * @param {Number} [queryParams.limit]
207
+ */
208
+ export function listK8sDeploymentEvents(params, queryParams = {}) {
209
+ return Promise.resolve({
210
+ method: 'get',
211
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/deployment-events`,
212
+ headers: { Accept: 'application/json' },
213
+ queryParams,
214
+ // no body
215
+ });
216
+ }
217
+
218
+ /**
219
+ * GET /v4/kubernetes-product
220
+ */
221
+ export function getK8sProduct() {
222
+ return Promise.resolve({
223
+ method: 'get',
224
+ url: `/v4/kubernetes-product`,
225
+ headers: { Accept: 'application/json' },
226
+ // no queryParams
227
+ // no body
228
+ });
229
+ }
230
+
231
+ /**
232
+ * GET /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/version/check
233
+ * @param {Object} params
234
+ * @param {String} params.ownerId
235
+ * @param {String} params.clusterId
236
+ */
237
+ export function getK8sVersionCheck(params) {
238
+ return Promise.resolve({
239
+ method: 'get',
240
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/version/check`,
241
+ headers: { Accept: 'application/json' },
242
+ // no queryParams
243
+ // no body
244
+ });
245
+ }
246
+
247
+ /**
248
+ * POST /v4/kubernetes/organisations/{ownerId}/clusters/{clusterId}/version/update
249
+ * @param {Object} params
250
+ * @param {String} params.ownerId
251
+ * @param {String} params.clusterId
252
+ * @param {Object} body
253
+ * @param {String} body.targetVersion
254
+ */
255
+ export function updateK8sVersion(params, body) {
256
+ return Promise.resolve({
257
+ method: 'post',
258
+ url: `/v4/kubernetes/organisations/${params.ownerId}/clusters/${params.clusterId}/version/update`,
259
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
260
+ // no queryParams
261
+ body,
262
+ });
263
+ }
264
+
265
+ /**
266
+ * GET /v4/kubernetes/organisations/{ownerId}/quota
267
+ * @param {Object} params
268
+ * @param {String} params.ownerId
269
+ */
270
+ export function getK8sQuota(params) {
271
+ return Promise.resolve({
272
+ method: 'get',
273
+ url: `/v4/kubernetes/organisations/${params.ownerId}/quota`,
274
+ headers: { Accept: 'application/json' },
275
+ // no queryParams
276
+ // no body
277
+ });
278
+ }
279
+
280
+ /**
281
+ * GET /v4/kubernetes/organisations/{ownerId}/usage
282
+ * @param {Object} params
283
+ * @param {String} params.ownerId
284
+ */
285
+ export function listK8sUsage(params) {
286
+ return Promise.resolve({
287
+ method: 'get',
288
+ url: `/v4/kubernetes/organisations/${params.ownerId}/usage`,
289
+ headers: { Accept: 'application/json' },
290
+ // no queryParams
291
+ // no body
292
+ });
293
+ }
@@ -47,6 +47,7 @@ These options are available for all commands:
47
47
  |[`clever matomo`](./matomo/matomo.docs.md)|Manage Clever Cloud Matomo services|
48
48
  |[`clever metabase`](./metabase/metabase.docs.md)|Manage Clever Cloud Metabase services|
49
49
  |[`clever ng`](./ng/ng.docs.md)|List Network Groups|
50
+ |[`clever oauth-consumers`](./oauth-consumers/oauth-consumers.docs.md)|Manage OAuth consumers used with a Clever Cloud login|
50
51
  |[`clever notify-email`](./notify-email/notify-email.docs.md)|Manage email notifications|
51
52
  |[`clever open`](./open/open.docs.md)|Open an application in the Console|
52
53
  |[`clever otoroshi`](./otoroshi/otoroshi.docs.md)|Manage Clever Cloud Otoroshi services|
@@ -8,7 +8,7 @@ import { JsonArray } from '../../models/json-array.js';
8
8
  import { getHostAndTokens } from '../../models/send-to-api.js';
9
9
  import { truncateWithEllipsis } from '../../models/utils.js';
10
10
  import {
11
- addonIdOption,
11
+ addonIdOrRealIdOption,
12
12
  afterOption,
13
13
  aliasOption,
14
14
  appIdOrNameOption,
@@ -79,7 +79,7 @@ export const accesslogsCommand = defineCommand({
79
79
  format: logsFormatOption,
80
80
  before: beforeOption,
81
81
  after: afterOption,
82
- addon: addonIdOption,
82
+ addon: addonIdOrRealIdOption,
83
83
  },
84
84
  args: [],
85
85
  async handler(options) {
@@ -174,7 +174,7 @@ export const activityCommand = defineCommand({
174
174
  format: defineOption({
175
175
  name: 'format',
176
176
  schema: z.enum(['human', 'json', 'json-stream']).default('human'),
177
- description: 'Output format (human, json, json-stream)',
177
+ description: 'Output format',
178
178
  aliases: ['F'],
179
179
  placeholder: 'format',
180
180
  }),
@@ -10,9 +10,8 @@ import * as Addon from '../../models/addon.js';
10
10
  import { completePlan, completeRegion, parseAddonOptions } from '../../models/addon.js';
11
11
  import * as AppConfig from '../../models/app_configuration.js';
12
12
  import { listAvailableAliases } from '../../models/application.js';
13
- import * as Organisation from '../../models/organisation.js';
13
+ import { getOwnerIdFromOrgIdOrName } from '../../models/ids-resolver.js';
14
14
  import { sendToApi } from '../../models/send-to-api.js';
15
- import * as User from '../../models/user.js';
16
15
  import { addonOptions } from '../../parsers.js';
17
16
  import { humanJsonOutputFormatOption, orgaIdOrNameOption } from '../global.options.js';
18
17
  import { addonNameArg, addonProviderArg } from './addon.args.js';
@@ -130,7 +129,7 @@ export const addonCreateCommand = defineCommand({
130
129
  addonOptions: parseAddonOptions(addonOptions),
131
130
  };
132
131
 
133
- const ownerId = orgaIdOrName != null ? await Organisation.getId(orgaIdOrName) : await User.getCurrentId();
132
+ const ownerId = await getOwnerIdFromOrgIdOrName(orgaIdOrName);
134
133
  if (linkedAppAlias != null) {
135
134
  const linkedAppData = await AppConfig.getAppDetails({ alias: linkedAppAlias });
136
135
  if (orgaIdOrName != null && linkedAppData.ownerId !== ownerId && format === 'human') {
@@ -3,14 +3,14 @@ import { Logger } from '../../logger.js';
3
3
  import * as Addon from '../../models/addon.js';
4
4
  import * as Organisation from '../../models/organisation.js';
5
5
  import { addonIdOrNameArg } from '../global.args.js';
6
- import { confirmAddonDeletionOption, orgaIdOrNameOption } from '../global.options.js';
6
+ import { orgaIdOrNameOption, skipConfirmationOption } from '../global.options.js';
7
7
 
8
8
  export const addonDeleteCommand = defineCommand({
9
9
  description: 'Delete an add-on',
10
10
  since: '0.2.3',
11
11
  options: {
12
12
  org: orgaIdOrNameOption,
13
- yes: confirmAddonDeletionOption,
13
+ yes: skipConfirmationOption,
14
14
  },
15
15
  args: [addonIdOrNameArg],
16
16
  async handler(options, addon) {
@@ -62,7 +62,7 @@ clever addon delete <addon-id|addon-name> [options]
62
62
  |Name|Description|
63
63
  |---|---|
64
64
  |`-o`, `--org`, `--owner` `<org-id\|org-name>`|Organisation to target by its ID (or name, if unambiguous)|
65
- |`-y`, `--yes`|Skip confirmation and delete the add-on directly|
65
+ |`-y`, `--yes`|Skip confirmation prompts|
66
66
 
67
67
  ## ➡️ `clever addon env` <kbd>Since 2.11.0</kbd>
68
68
 
@@ -83,7 +83,7 @@ clever addon env <addon-id> [options]
83
83
  |Name|Description|
84
84
  |---|---|
85
85
  |`-F`, `--format` `<format>`|Output format (human, json, shell) (default: human)|
86
- |`-o`, `--org`, `--owner` `<org-id\|org-name>`|Organisation to target by its ID (or name, if unambiguous)|
86
+ |`-o`, `--org`, `--owner` `<org-id\|org-name>`|Organisation to target by its ID (or name, if unambiguous) *(deprecated, organisation is now resolved automatically)*|
87
87
 
88
88
  ## ➡️ `clever addon list` <kbd>Since 0.2.3</kbd>
89
89
 
@@ -4,8 +4,7 @@ import { z } from 'zod';
4
4
  import { defineArgument } from '../../lib/define-argument.js';
5
5
  import { defineCommand } from '../../lib/define-command.js';
6
6
  import { Logger } from '../../logger.js';
7
- import { findOwnerId } from '../../models/addon.js';
8
- import { resolveAddonId } from '../../models/ids-resolver.js';
7
+ import { resolveAddon } from '../../models/ids-resolver.js';
9
8
  import { sendToApi } from '../../models/send-to-api.js';
10
9
  import { envFormatOption, orgaIdOrNameOption } from '../global.options.js';
11
10
 
@@ -13,7 +12,7 @@ export const addonEnvCommand = defineCommand({
13
12
  description: 'List environment variables for an add-on',
14
13
  since: '2.11.0',
15
14
  options: {
16
- org: orgaIdOrNameOption,
15
+ org: { ...orgaIdOrNameOption, deprecated: 'organisation is now resolved automatically' },
17
16
  format: envFormatOption,
18
17
  },
19
18
  args: [
@@ -24,10 +23,9 @@ export const addonEnvCommand = defineCommand({
24
23
  }),
25
24
  ],
26
25
  async handler(options, addonIdOrRealId) {
27
- const { org, format } = options;
26
+ const { format } = options;
28
27
 
29
- const addonId = await resolveAddonId(addonIdOrRealId);
30
- const ownerId = await findOwnerId(org, addonId);
28
+ const { ownerId, addonId } = await resolveAddon(addonIdOrRealId);
31
29
 
32
30
  const envFromAddon = await getAllEnvVars({ id: ownerId, addonId }).then(sendToApi);
33
31
 
@@ -3,8 +3,4 @@ import { defineCommand } from '../../lib/define-command.js';
3
3
  export const configProviderCommand = defineCommand({
4
4
  description: 'Manage configuration providers',
5
5
  since: '4.6.0',
6
- options: {},
7
- args: [],
8
- // Parent command - no handler, only contains subcommands
9
- handler: null,
10
6
  });
@@ -11,7 +11,7 @@ import { configProviderIdOrNameArg } from './config-provider.args.js';
11
11
  const importFormatOption = defineOption({
12
12
  name: 'format',
13
13
  schema: z.enum(['name-equals-value', 'json']).default('name-equals-value'),
14
- description: 'Input format (name-equals-value, json)',
14
+ description: 'Input format',
15
15
  aliases: ['F'],
16
16
  placeholder: 'format',
17
17
  });
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from '../../lib/define-command.js';
2
- import { styleText } from '../../lib/style-text.js';
2
+ import { printItemsByOwner } from '../../lib/print-items-by-owner.js';
3
3
  import { Logger } from '../../logger.js';
4
4
  import { findAddonsByAddonProvider } from '../../models/ids-resolver.js';
5
5
  import { humanJsonOutputFormatOption } from '../global.options.js';
@@ -14,30 +14,19 @@ export const configProviderListCommand = defineCommand({
14
14
  async handler(options) {
15
15
  const { format } = options;
16
16
  const deployed = await findAddonsByAddonProvider('config-provider');
17
- const providersPerOwner = Object.groupBy(deployed, (provider) => provider.ownerId);
18
17
 
19
18
  switch (format) {
20
- case 'json':
19
+ case 'json': {
20
+ const providersPerOwner = Object.groupBy(deployed, (p) => p.ownerId);
21
21
  Logger.printJson(providersPerOwner);
22
22
  break;
23
+ }
23
24
  case 'human':
24
25
  default:
25
- if (deployed.length === 0) {
26
- Logger.println(
27
- `No configuration provider found, create one with ${styleText('blue', 'clever addon create config-provider')} command`,
28
- );
29
- return;
30
- }
31
-
32
- Logger.println(`Found ${deployed.length} configuration provider${deployed.length > 1 ? 's' : ''}:`);
33
- Logger.println();
34
-
35
- Object.values(providersPerOwner).forEach((providers) => {
36
- Logger.println(`${styleText('bold', `${providers[0].ownerId} (${providers[0].ownerName})`)}`);
37
- providers.forEach((provider) => {
38
- Logger.println(` ${provider.name} ${styleText('grey', `(${provider.realId})`)}`);
39
- });
40
- Logger.println();
26
+ printItemsByOwner(deployed, {
27
+ itemName: 'configuration provider',
28
+ emptyCommand: 'clever addon create config-provider',
29
+ getItemId: (p) => p.realId,
41
30
  });
42
31
  break;
43
32
  }
@@ -12,6 +12,6 @@ export const configProviderOpenCommand = defineCommand({
12
12
  args: [configProviderIdOrNameArg],
13
13
  async handler(_options, addonIdOrRealIdOrName) {
14
14
  const { addonId } = await resolveConfigProviderId(addonIdOrRealIdOrName);
15
- await openBrowser(`${config.GOTO_URL}/${addonId}`, `Opening ${styleText('blue', addonId)} in the browser...`);
15
+ await openBrowser(`${config.GOTO_URL}/${addonId}`, `Opening ${styleText('blue', addonId)} in the browser…`);
16
16
  },
17
17
  });
@@ -1,4 +1,5 @@
1
1
  import { defineCommand } from '../../lib/define-command.js';
2
+ import { styleText } from '../../lib/style-text.js';
2
3
  import * as AppConfig from '../../models/app_configuration.js';
3
4
  import * as Application from '../../models/application.js';
4
5
  import { openBrowser } from '../../models/utils.js';
@@ -18,7 +19,7 @@ export const consoleCommand = defineCommand({
18
19
  const { apps } = await AppConfig.loadApplicationConf();
19
20
  // If no app is linked or asked, open the Console without any context
20
21
  if (apps.length === 0 && !appIdOrName) {
21
- await openBrowser('/', 'Opening the Console in your browser');
22
+ await openBrowser('/', 'Opening the Console in the browser');
22
23
  return;
23
24
  }
24
25
 
@@ -26,6 +27,6 @@ export const consoleCommand = defineCommand({
26
27
  const prefixPath = ownerId.startsWith('user_') ? 'users/me' : `organisations/${ownerId}`;
27
28
  const consolePath = `/${prefixPath}/applications/${appId}`;
28
29
 
29
- await openBrowser(consolePath, `Opening the Console in your browser for application ${appId}`);
30
+ await openBrowser(consolePath, `Opening ${styleText('blue', appId)} in the browser…`);
30
31
  },
31
32
  });
@@ -73,5 +73,4 @@ export async function curl() {
73
73
  export const curlCommand = defineCommand({
74
74
  description: "Query Clever Cloud's API using Clever Tools credentials",
75
75
  since: '2.10.0',
76
- handler: null,
77
76
  });
@@ -2,8 +2,7 @@ import { getBackups } from '@clevercloud/client/esm/api/v2/backups.js';
2
2
  import { formatTable } from '../../format-table.js';
3
3
  import { defineCommand } from '../../lib/define-command.js';
4
4
  import { Logger } from '../../logger.js';
5
- import { findOwnerId } from '../../models/addon.js';
6
- import { resolveAddonId, resolveRealId } from '../../models/ids-resolver.js';
5
+ import { resolveAddon } from '../../models/ids-resolver.js';
7
6
  import { sendToApi } from '../../models/send-to-api.js';
8
7
  import { humanJsonOutputFormatOption, orgaIdOrNameOption } from '../global.options.js';
9
8
  import { databaseIdArg } from './database.args.js';
@@ -12,16 +11,14 @@ export const databaseBackupsCommand = defineCommand({
12
11
  description: 'List available database backups',
13
12
  since: '2.10.0',
14
13
  options: {
15
- org: orgaIdOrNameOption,
14
+ org: { ...orgaIdOrNameOption, deprecated: 'organisation is now resolved automatically' },
16
15
  format: humanJsonOutputFormatOption,
17
16
  },
18
17
  args: [databaseIdArg],
19
18
  async handler(options, addonIdOrRealId) {
20
- const { org, format } = options;
19
+ const { format } = options;
21
20
 
22
- const realId = await resolveRealId(addonIdOrRealId);
23
- const addonId = await resolveAddonId(addonIdOrRealId);
24
- const ownerId = await findOwnerId(org, realId);
21
+ const { ownerId, addonId, realId } = await resolveAddon(addonIdOrRealId);
25
22
 
26
23
  const backups = await getBackups({ ownerId, ref: realId }).then(sendToApi);
27
24