clever-tools 4.5.1 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/bin/clever.js +25 -22
- package/package.json +2 -2
- package/src/clever-client/auth-bridge.js +0 -25
- package/src/commands/README.md +1 -0
- package/src/commands/accesslogs/accesslogs.command.js +4 -1
- package/src/commands/accesslogs/accesslogs.docs.md +1 -1
- package/src/commands/addon/addon.create.command.js +26 -23
- package/src/commands/config/config.set.command.js +3 -3
- package/src/commands/config-provider/config-provider.args.js +8 -0
- package/src/commands/config-provider/config-provider.command.js +10 -0
- package/src/commands/config-provider/config-provider.docs.md +109 -0
- package/src/commands/config-provider/config-provider.get.command.js +36 -0
- package/src/commands/config-provider/config-provider.import.command.js +40 -0
- package/src/commands/config-provider/config-provider.list.command.js +45 -0
- package/src/commands/config-provider/config-provider.open.command.js +17 -0
- package/src/commands/config-provider/config-provider.rm.command.js +25 -0
- package/src/commands/config-provider/config-provider.set.command.js +37 -0
- package/src/commands/create/create.command.js +7 -6
- package/src/commands/curl/curl.command.js +18 -19
- package/src/commands/deploy/deploy.command.js +14 -8
- package/src/commands/deploy/deploy.docs.md +20 -0
- package/src/commands/diag/diag.command.js +52 -39
- package/src/commands/features/features.disable.command.js +1 -2
- package/src/commands/features/features.enable.command.js +1 -2
- package/src/commands/features/features.info.command.js +1 -1
- package/src/commands/features/features.list.command.js +1 -2
- package/src/commands/global.commands.js +22 -0
- package/src/commands/global.options.js +2 -2
- package/src/commands/login/login.command.js +119 -20
- package/src/commands/login/login.docs.md +9 -2
- package/src/commands/logout/logout.command.js +39 -7
- package/src/commands/logout/logout.docs.md +7 -1
- package/src/commands/logs/logs.command.js +7 -8
- package/src/commands/logs/logs.docs.md +1 -1
- package/src/commands/ng/ng.get-config.command.js +3 -3
- package/src/commands/notify-email/notify-email.add.command.js +5 -2
- package/src/commands/notify-email/notify-email.command.js +1 -2
- package/src/commands/notify-email/notify-email.docs.md +1 -1
- package/src/commands/profile/profile.command.js +13 -37
- package/src/commands/profile/profile.docs.md +28 -0
- package/src/commands/profile/profile.list.command.js +44 -0
- package/src/commands/profile/profile.switch.command.js +80 -0
- package/src/commands/restart/restart.command.js +3 -2
- package/src/commands/ssh/ssh.command.js +2 -2
- package/src/commands/tokens/tokens.command.js +3 -3
- package/src/commands/tokens/tokens.create.command.js +4 -4
- package/src/commands/webhooks/webhooks.add.command.js +5 -2
- package/src/commands/webhooks/webhooks.command.js +1 -2
- package/src/commands/webhooks/webhooks.docs.md +1 -1
- package/src/config/cache.js +60 -0
- package/src/config/config.js +233 -0
- package/src/config/features.js +167 -0
- package/src/config/paths.js +23 -0
- package/src/lib/date-utils.js +48 -0
- package/src/lib/fs.js +49 -0
- package/src/lib/operator-commands.js +4 -4
- package/src/lib/profile.js +116 -0
- package/src/logger.js +123 -69
- package/src/logger.types.d.ts +5 -0
- package/src/models/addon.js +1 -3
- package/src/models/app_configuration.js +42 -39
- package/src/models/application_configuration.js +30 -30
- package/src/models/config-provider.js +34 -0
- package/src/models/git-isomorphic.js +153 -0
- package/src/models/git-system.js +182 -0
- package/src/models/git.js +150 -128
- package/src/models/ids-resolver.js +1 -1
- package/src/models/log.js +141 -90
- package/src/models/notification.js +7 -6
- package/src/models/send-to-api.js +58 -33
- package/src/models/user.js +0 -11
- package/src/models/utils.js +2 -2
- package/src/experimental-features.js +0 -91
- package/src/lib/format-date.js +0 -3
- package/src/models/configuration.js +0 -140
- package/src/models/log-v4.js +0 -189
package/README.md
CHANGED
|
@@ -154,6 +154,16 @@ clever <command> --help # Get specific help
|
|
|
154
154
|
clever --format json <command> # JSON output for scripting
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
## AI Agent Integration
|
|
158
|
+
|
|
159
|
+
Clever Tools can be used with AI coding assistants (Claude Code, Cursor, Codex, GitHub Copilot, etc.):
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npx add-skill CleverCloud/clever-tools
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
This installs the Clever Tools skill, giving your AI assistant knowledge of all commands and Clever Cloud concepts.
|
|
166
|
+
|
|
157
167
|
## Support & Contributing
|
|
158
168
|
|
|
159
169
|
- **Issues & Questions**: [GitHub Issues](https://github.com/CleverCloud/clever-tools/issues)
|
package/bin/clever.js
CHANGED
|
@@ -14,11 +14,10 @@ import {
|
|
|
14
14
|
verboseOption,
|
|
15
15
|
versionOption,
|
|
16
16
|
} from '../src/commands/global.options.js';
|
|
17
|
-
import { EXPERIMENTAL_FEATURES } from '../src/
|
|
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
20
|
import { getDefault, isBoolean, isRequired } from '../src/lib/zod-utils.js';
|
|
21
|
-
import { getFeatures } from '../src/models/configuration.js';
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
23
|
* @typedef {import('../src/lib/define-command.types.js').CommandDefinition} CommandDefinition
|
|
@@ -150,25 +149,25 @@ function buildCommand(name, commandEntry, featuresFromConf) {
|
|
|
150
149
|
* @returns {Object} cliparse command
|
|
151
150
|
*/
|
|
152
151
|
function convertCommand(name, commandDef, subcommands = []) {
|
|
153
|
-
const
|
|
152
|
+
const cliparseConfig = {
|
|
154
153
|
description: commandDef.description,
|
|
155
154
|
};
|
|
156
155
|
|
|
157
156
|
if (commandDef.options != null) {
|
|
158
|
-
|
|
157
|
+
cliparseConfig.privateOptions = Object.values(commandDef.options).map(convertOption);
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
// Convert arguments
|
|
162
161
|
if (commandDef.args != null && commandDef.args.length > 0) {
|
|
163
|
-
|
|
162
|
+
cliparseConfig.args = commandDef.args.map(convertArgument);
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
// Add subcommands
|
|
167
166
|
if (subcommands.length > 0) {
|
|
168
|
-
|
|
167
|
+
cliparseConfig.commands = subcommands;
|
|
169
168
|
}
|
|
170
169
|
|
|
171
|
-
const command = cliparse.command(name,
|
|
170
|
+
const command = cliparse.command(name, cliparseConfig, commandDef.handler);
|
|
172
171
|
|
|
173
172
|
// Attach the original definition so cliparse-patched.js can use it for --help display
|
|
174
173
|
command._definition = commandDef;
|
|
@@ -182,26 +181,28 @@ function convertCommand(name, commandDef, subcommands = []) {
|
|
|
182
181
|
* @returns {Object} cliparse option
|
|
183
182
|
*/
|
|
184
183
|
function convertOption(option) {
|
|
185
|
-
const
|
|
184
|
+
const cliparseConfig = {
|
|
186
185
|
description: option.description,
|
|
187
186
|
};
|
|
188
187
|
|
|
189
188
|
if (option.aliases != null) {
|
|
190
|
-
|
|
189
|
+
cliparseConfig.aliases = option.aliases;
|
|
191
190
|
}
|
|
192
191
|
const optionDefault = getDefault(option.schema);
|
|
193
192
|
if (optionDefault != null) {
|
|
194
|
-
|
|
193
|
+
// Parse the default value through the schema to apply transforms
|
|
194
|
+
const parsed = option.schema.safeParse(optionDefault);
|
|
195
|
+
cliparseConfig.default = parsed.success ? parsed.data : optionDefault;
|
|
195
196
|
}
|
|
196
197
|
if (option.placeholder != null) {
|
|
197
|
-
|
|
198
|
+
cliparseConfig.metavar = option.placeholder;
|
|
198
199
|
}
|
|
199
200
|
if (option.complete != null) {
|
|
200
|
-
|
|
201
|
+
cliparseConfig.complete = option.complete;
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
// Use Zod's safeParse for validation (handles coercion, enums, refinements, etc.)
|
|
204
|
-
|
|
205
|
+
cliparseConfig.parser = (value) => {
|
|
205
206
|
// Log deprecation warning if option is deprecated
|
|
206
207
|
if (option.deprecated) {
|
|
207
208
|
const message = typeof option.deprecated === 'string' ? `, ${option.deprecated}.` : '';
|
|
@@ -217,16 +218,16 @@ function convertOption(option) {
|
|
|
217
218
|
|
|
218
219
|
// Mark as required if schema has no default and is not optional
|
|
219
220
|
if (isRequired(option.schema)) {
|
|
220
|
-
|
|
221
|
+
cliparseConfig.required = true;
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
// Boolean schemas: use cliparse.option with expects_value: false (like cliparse.flag does)
|
|
224
225
|
if (isBoolean(option.schema)) {
|
|
225
226
|
// eslint-disable-next-line camelcase -- cliparse API uses snake_case
|
|
226
|
-
|
|
227
|
+
cliparseConfig.expects_value = false;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
return cliparse.option(option.name,
|
|
230
|
+
return cliparse.option(option.name, cliparseConfig);
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
/**
|
|
@@ -235,16 +236,16 @@ function convertOption(option) {
|
|
|
235
236
|
* @returns {Object} cliparse argument
|
|
236
237
|
*/
|
|
237
238
|
function convertArgument(arg) {
|
|
238
|
-
const
|
|
239
|
+
const cliparseConfig = {
|
|
239
240
|
description: arg.description,
|
|
240
241
|
};
|
|
241
242
|
|
|
242
243
|
if (arg.complete) {
|
|
243
|
-
|
|
244
|
+
cliparseConfig.complete = arg.complete;
|
|
244
245
|
}
|
|
245
246
|
|
|
246
247
|
// Use Zod's safeParse for validation (handles coercion, enums, refinements, etc.)
|
|
247
|
-
|
|
248
|
+
cliparseConfig.parser = (value) => {
|
|
248
249
|
const result = arg.schema.safeParse(value);
|
|
249
250
|
if (!result.success) {
|
|
250
251
|
throw new Error(result.error.issues.map((i) => i.message).join(', '));
|
|
@@ -254,10 +255,12 @@ function convertArgument(arg) {
|
|
|
254
255
|
|
|
255
256
|
const argDefault = getDefault(arg.schema);
|
|
256
257
|
if (argDefault != null) {
|
|
257
|
-
|
|
258
|
+
// Parse the default value through the schema to apply transforms
|
|
259
|
+
const parsed = arg.schema.safeParse(argDefault);
|
|
260
|
+
cliparseConfig.default = parsed.success ? parsed.data : argDefault;
|
|
258
261
|
} else if (!isRequired(arg.schema)) {
|
|
259
|
-
|
|
262
|
+
cliparseConfig.default = '';
|
|
260
263
|
}
|
|
261
264
|
|
|
262
|
-
return cliparse.argument(arg.placeholder,
|
|
265
|
+
return cliparse.argument(arg.placeholder, cliparseConfig);
|
|
263
266
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clever-tools",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "Command Line Interface for Clever Cloud.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"lodash": "4.17.21",
|
|
64
64
|
"open": "10.2.0",
|
|
65
65
|
"semver": "7.7.3",
|
|
66
|
+
"simple-git": "3.30.0",
|
|
66
67
|
"slugify": "1.6.6",
|
|
67
68
|
"tldts": "7.0.19",
|
|
68
69
|
"update-notifier": "7.3.1",
|
|
@@ -89,7 +90,6 @@
|
|
|
89
90
|
"remark-parse": "11.0.0",
|
|
90
91
|
"remark-stringify": "11.0.0",
|
|
91
92
|
"rollup": "4.53.3",
|
|
92
|
-
"simple-git": "3.30.0",
|
|
93
93
|
"tinyglobby": "0.2.15",
|
|
94
94
|
"typescript": "5.9.3",
|
|
95
95
|
"unified": "11.0.5"
|
|
@@ -22,28 +22,3 @@ export function deleteApiToken(apiTokenId) {
|
|
|
22
22
|
headers: { Accept: 'application/json' },
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
export function addOauthHeaderPlaintext(tokens) {
|
|
27
|
-
return async function (requestParams) {
|
|
28
|
-
const authorizationHeader =
|
|
29
|
-
'OAuth ' +
|
|
30
|
-
[
|
|
31
|
-
`oauth_consumer_key="${tokens.OAUTH_CONSUMER_KEY}"`,
|
|
32
|
-
`oauth_token="${tokens.API_OAUTH_TOKEN}"`,
|
|
33
|
-
// %26 is URL escaped character "&"
|
|
34
|
-
`oauth_signature="${tokens.OAUTH_CONSUMER_SECRET}%26${tokens.API_OAUTH_TOKEN_SECRET}"`,
|
|
35
|
-
// oauth_nonce is not mandatory
|
|
36
|
-
// oauth_signature_method is not mandatory, it defaults to PLAINTEXT
|
|
37
|
-
// oauth_timestamp is not mandatory
|
|
38
|
-
// oauth_version is not mandatory, it defaults to 1.0
|
|
39
|
-
].join(', ');
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
...requestParams,
|
|
43
|
-
headers: {
|
|
44
|
-
authorization: authorizationHeader,
|
|
45
|
-
...requestParams.headers,
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
}
|
package/src/commands/README.md
CHANGED
|
@@ -22,6 +22,7 @@ These options are available for all commands:
|
|
|
22
22
|
|[`clever applications`](./applications/applications.docs.md)|List linked applications|
|
|
23
23
|
|[`clever cancel-deploy`](./cancel-deploy/cancel-deploy.docs.md)|Cancel an ongoing deployment|
|
|
24
24
|
|[`clever config`](./config/config.docs.md)|Display or edit the configuration of your application|
|
|
25
|
+
|[`clever config-provider`](./config-provider/config-provider.docs.md)|Manage configuration providers|
|
|
25
26
|
|[`clever console`](./console/console.docs.md)|Open an application in the Console|
|
|
26
27
|
|[`clever create`](./create/create.docs.md)|Create an application|
|
|
27
28
|
|[`clever curl`](./curl/curl.docs.md)|Query Clever Cloud's API using Clever Tools credentials|
|
|
@@ -145,7 +145,10 @@ export const accesslogsCommand = defineCommand({
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
// Properly close the stream
|
|
148
|
-
process.once('SIGINT', (signal) =>
|
|
148
|
+
process.once('SIGINT', (signal) => {
|
|
149
|
+
stream.close(signal);
|
|
150
|
+
process.kill(process.pid, 'SIGINT');
|
|
151
|
+
});
|
|
149
152
|
|
|
150
153
|
const closeReason = await stream.start();
|
|
151
154
|
|
|
@@ -12,7 +12,7 @@ clever accesslogs [options]
|
|
|
12
12
|
|
|
13
13
|
|Name|Description|
|
|
14
14
|
|---|---|
|
|
15
|
-
|`--addon` `<addon-id>`|Add-on ID|
|
|
15
|
+
|`--addon` `<addon-id>`|Add-on ID or real ID|
|
|
16
16
|
|`--after`, `--since` `<after>`|Fetch logs after this date/time (ISO8601 date, positive number in seconds or duration, e.g.: 1h)|
|
|
17
17
|
|`-a`, `--alias` `<alias>`|Short name for the application|
|
|
18
18
|
|`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import dedent from 'dedent';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { getOperator } from '../../clever-client/operators.js';
|
|
4
|
+
import { config } from '../../config/config.js';
|
|
4
5
|
import { defineCommand } from '../../lib/define-command.js';
|
|
5
6
|
import { defineOption } from '../../lib/define-option.js';
|
|
6
7
|
import { styleText } from '../../lib/style-text.js';
|
|
@@ -9,7 +10,6 @@ import * as Addon from '../../models/addon.js';
|
|
|
9
10
|
import { completePlan, completeRegion, parseAddonOptions } from '../../models/addon.js';
|
|
10
11
|
import * as AppConfig from '../../models/app_configuration.js';
|
|
11
12
|
import { listAvailableAliases } from '../../models/application.js';
|
|
12
|
-
import { conf } from '../../models/configuration.js';
|
|
13
13
|
import * as Organisation from '../../models/organisation.js';
|
|
14
14
|
import { sendToApi } from '../../models/send-to-api.js';
|
|
15
15
|
import * as User from '../../models/user.js';
|
|
@@ -20,39 +20,37 @@ import { addonNameArg, addonProviderArg } from './addon.args.js';
|
|
|
20
20
|
const ADDON_PROVIDERS = {
|
|
21
21
|
keycloak: {
|
|
22
22
|
name: 'Keycloak',
|
|
23
|
-
|
|
24
|
-
postCreateInstructions: `Learn more about Keycloak on Clever Cloud: ${
|
|
23
|
+
operatorProvider: 'keycloak',
|
|
24
|
+
postCreateInstructions: `Learn more about Keycloak on Clever Cloud: ${config.DOC_URL}/addons/keycloak/`,
|
|
25
25
|
},
|
|
26
26
|
kv: {
|
|
27
27
|
name: 'Materia KV',
|
|
28
|
-
isOperator: false,
|
|
29
28
|
status: 'beta',
|
|
30
29
|
postCreateInstructions: (addonId) => dedent`
|
|
31
30
|
${styleText('yellow', "You can easily use Materia KV with 'redis-cli', with such commands:")}
|
|
32
31
|
${styleText('blue', `source <(clever addon env ${addonId} -F shell)`)}
|
|
33
32
|
${styleText('blue', 'redis-cli -h $KV_HOST -p $KV_PORT --tls')}
|
|
34
|
-
Learn more about Materia KV on Clever Cloud: ${
|
|
33
|
+
Learn more about Materia KV on Clever Cloud: ${config.DOC_URL}/addons/materia-kv/
|
|
35
34
|
`,
|
|
36
35
|
},
|
|
37
36
|
'addon-matomo': {
|
|
38
37
|
name: 'Matomo',
|
|
39
|
-
|
|
40
|
-
postCreateInstructions: `Learn more about Matomo on Clever Cloud: ${
|
|
38
|
+
operatorProvider: 'matomo',
|
|
39
|
+
postCreateInstructions: `Learn more about Matomo on Clever Cloud: ${config.DOC_URL}/addons/matomo/`,
|
|
41
40
|
},
|
|
42
41
|
metabase: {
|
|
43
42
|
name: 'Metabase',
|
|
44
|
-
|
|
45
|
-
postCreateInstructions: `Learn more about Metabase on Clever Cloud: ${
|
|
43
|
+
operatorProvider: 'metabase',
|
|
44
|
+
postCreateInstructions: `Learn more about Metabase on Clever Cloud: ${config.DOC_URL}/addons/metabase/`,
|
|
46
45
|
},
|
|
47
46
|
otoroshi: {
|
|
48
47
|
name: 'Otoroshi with LLM',
|
|
49
|
-
|
|
50
|
-
postCreateInstructions: `Learn more about Otoroshi with LLM on Clever Cloud: ${
|
|
48
|
+
operatorProvider: 'otoroshi',
|
|
49
|
+
postCreateInstructions: `Learn more about Otoroshi with LLM on Clever Cloud: ${config.DOC_URL}/addons/otoroshi/`,
|
|
51
50
|
},
|
|
52
51
|
'addon-pulsar': {
|
|
53
52
|
name: 'Pulsar',
|
|
54
|
-
|
|
55
|
-
postCreateInstructions: `Learn more about Pulsar on Clever Cloud: ${conf.DOC_URL}/addons/pulsar/`,
|
|
53
|
+
postCreateInstructions: `Learn more about Pulsar on Clever Cloud: ${config.DOC_URL}/addons/pulsar/`,
|
|
56
54
|
},
|
|
57
55
|
};
|
|
58
56
|
|
|
@@ -90,7 +88,7 @@ export const addonCreateCommand = defineCommand({
|
|
|
90
88
|
placeholder: 'region',
|
|
91
89
|
complete: completeRegion,
|
|
92
90
|
}),
|
|
93
|
-
|
|
91
|
+
addonVersion: defineOption({
|
|
94
92
|
name: 'addon-version',
|
|
95
93
|
schema: z.string().optional(),
|
|
96
94
|
description: 'The version to use for the add-on',
|
|
@@ -98,7 +96,10 @@ export const addonCreateCommand = defineCommand({
|
|
|
98
96
|
}),
|
|
99
97
|
option: defineOption({
|
|
100
98
|
name: 'option',
|
|
101
|
-
schema: z
|
|
99
|
+
schema: z
|
|
100
|
+
.union([z.string(), z.array(z.string())])
|
|
101
|
+
.transform(addonOptions)
|
|
102
|
+
.optional(),
|
|
102
103
|
description:
|
|
103
104
|
'Option to enable for the add-on. Multiple --option argument can be passed to enable multiple options',
|
|
104
105
|
placeholder: 'option',
|
|
@@ -115,7 +116,7 @@ export const addonCreateCommand = defineCommand({
|
|
|
115
116
|
yes: skipConfirmation,
|
|
116
117
|
org: orgaIdOrName,
|
|
117
118
|
format,
|
|
118
|
-
|
|
119
|
+
addonVersion,
|
|
119
120
|
option: addonOptions,
|
|
120
121
|
} = options;
|
|
121
122
|
|
|
@@ -125,7 +126,7 @@ export const addonCreateCommand = defineCommand({
|
|
|
125
126
|
planName,
|
|
126
127
|
region,
|
|
127
128
|
skipConfirmation,
|
|
128
|
-
version:
|
|
129
|
+
version: addonVersion,
|
|
129
130
|
addonOptions: parseAddonOptions(addonOptions),
|
|
130
131
|
};
|
|
131
132
|
|
|
@@ -187,16 +188,18 @@ export const addonCreateCommand = defineCommand({
|
|
|
187
188
|
Logger.println(`Real ID: ${newAddon.realId}`);
|
|
188
189
|
Logger.println(`Name: ${newAddon.name}`);
|
|
189
190
|
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
const operatorProvider = ADDON_PROVIDERS[providerName]?.operatorProvider;
|
|
192
|
+
const operator =
|
|
193
|
+
operatorProvider != null
|
|
194
|
+
? await getOperator({ provider: operatorProvider, realId: newAddon.realId }).then(sendToApi)
|
|
195
|
+
: null;
|
|
193
196
|
|
|
194
|
-
if (operator) {
|
|
195
|
-
if (operator.accessUrl) {
|
|
197
|
+
if (operator != null) {
|
|
198
|
+
if (operator.accessUrl != null) {
|
|
196
199
|
Logger.println();
|
|
197
200
|
Logger.println(`Your ${ADDON_PROVIDERS[providerName].name} is starting:`);
|
|
198
201
|
Logger.println(` - Access it: ${operator.accessUrl}`);
|
|
199
|
-
Logger.println(` - Manage it: ${
|
|
202
|
+
Logger.println(` - Manage it: ${config.GOTO_URL}/${newAddon.id}`);
|
|
200
203
|
}
|
|
201
204
|
|
|
202
205
|
if (operator.initialCredentials) {
|
|
@@ -26,13 +26,13 @@ export const configSetCommand = defineCommand({
|
|
|
26
26
|
async handler(options, configurationName, configurationValue) {
|
|
27
27
|
const { alias, app: appIdOrName } = options;
|
|
28
28
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
29
|
-
const
|
|
29
|
+
const appConfig = ApplicationConfiguration.getById(configurationName);
|
|
30
30
|
const newOptions = {
|
|
31
|
-
[
|
|
31
|
+
[appConfig.name]: ApplicationConfiguration.parse(appConfig, configurationValue),
|
|
32
32
|
};
|
|
33
33
|
const app = await Application.updateOptions(ownerId, appId, newOptions);
|
|
34
34
|
Logger.printSuccess(
|
|
35
|
-
`Config ${styleText('green',
|
|
35
|
+
`Config ${styleText('green', appConfig.id)} successfully updated to ${styleText('green', ApplicationConfiguration.formatValue(appConfig, app[appConfig.name]).toString())}!`,
|
|
36
36
|
);
|
|
37
37
|
},
|
|
38
38
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineArgument } from '../../lib/define-argument.js';
|
|
3
|
+
|
|
4
|
+
export const configProviderIdOrNameArg = defineArgument({
|
|
5
|
+
schema: z.string(),
|
|
6
|
+
description: 'Add-on ID, real ID (config_xxx) or name (if unambiguous)',
|
|
7
|
+
placeholder: 'addon-id|config-provider-id|addon-name',
|
|
8
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineCommand } from '../../lib/define-command.js';
|
|
2
|
+
|
|
3
|
+
export const configProviderCommand = defineCommand({
|
|
4
|
+
description: 'Manage configuration providers',
|
|
5
|
+
since: '4.6.0',
|
|
6
|
+
options: {},
|
|
7
|
+
args: [],
|
|
8
|
+
// Parent command - no handler, only contains subcommands
|
|
9
|
+
handler: null,
|
|
10
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# 📖 `clever config-provider` command reference
|
|
2
|
+
|
|
3
|
+
## ➡️ `clever config-provider` <kbd>Since 4.6.0</kbd>
|
|
4
|
+
|
|
5
|
+
Manage configuration providers
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
clever config-provider
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## ➡️ `clever config-provider get` <kbd>Since 4.6.0</kbd>
|
|
12
|
+
|
|
13
|
+
List environment variables of a configuration provider
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
clever config-provider get <addon-id|config-provider-id|addon-name> [options]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 📥 Arguments
|
|
20
|
+
|
|
21
|
+
|Name|Description|
|
|
22
|
+
|---|---|
|
|
23
|
+
|`addon-id|config-provider-id|addon-name`|Add-on ID, real ID (config_xxx) or name (if unambiguous)|
|
|
24
|
+
|
|
25
|
+
### ⚙️ Options
|
|
26
|
+
|
|
27
|
+
|Name|Description|
|
|
28
|
+
|---|---|
|
|
29
|
+
|`-F`, `--format` `<format>`|Output format (human, json, shell) (default: human)|
|
|
30
|
+
|
|
31
|
+
## ➡️ `clever config-provider import` <kbd>Since 4.6.0</kbd>
|
|
32
|
+
|
|
33
|
+
Load environment variables from STDIN
|
|
34
|
+
(WARNING: this deletes all current variables and replaces them with the new list loaded from STDIN)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
clever config-provider import <addon-id|config-provider-id|addon-name> [options]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 📥 Arguments
|
|
41
|
+
|
|
42
|
+
|Name|Description|
|
|
43
|
+
|---|---|
|
|
44
|
+
|`addon-id|config-provider-id|addon-name`|Add-on ID, real ID (config_xxx) or name (if unambiguous)|
|
|
45
|
+
|
|
46
|
+
### ⚙️ Options
|
|
47
|
+
|
|
48
|
+
|Name|Description|
|
|
49
|
+
|---|---|
|
|
50
|
+
|`-F`, `--format` `<format>`|Input format (name-equals-value, json) (default: name-equals-value)|
|
|
51
|
+
|
|
52
|
+
## ➡️ `clever config-provider list` <kbd>Since 4.6.0</kbd>
|
|
53
|
+
|
|
54
|
+
List configuration providers
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
clever config-provider list [options]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### ⚙️ Options
|
|
61
|
+
|
|
62
|
+
|Name|Description|
|
|
63
|
+
|---|---|
|
|
64
|
+
|`-F`, `--format` `<format>`|Output format (human, json) (default: human)|
|
|
65
|
+
|
|
66
|
+
## ➡️ `clever config-provider open` <kbd>Since 4.6.0</kbd>
|
|
67
|
+
|
|
68
|
+
Open the configuration provider in Clever Cloud Console
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
clever config-provider open <addon-id|config-provider-id|addon-name>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 📥 Arguments
|
|
75
|
+
|
|
76
|
+
|Name|Description|
|
|
77
|
+
|---|---|
|
|
78
|
+
|`addon-id|config-provider-id|addon-name`|Add-on ID, real ID (config_xxx) or name (if unambiguous)|
|
|
79
|
+
|
|
80
|
+
## ➡️ `clever config-provider rm` <kbd>Since 4.6.0</kbd>
|
|
81
|
+
|
|
82
|
+
Remove an environment variable from a configuration provider
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
clever config-provider rm <addon-id|config-provider-id|addon-name> <variable-name>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 📥 Arguments
|
|
89
|
+
|
|
90
|
+
|Name|Description|
|
|
91
|
+
|---|---|
|
|
92
|
+
|`addon-id|config-provider-id|addon-name`|Add-on ID, real ID (config_xxx) or name (if unambiguous)|
|
|
93
|
+
|`variable-name`|Name of the environment variable|
|
|
94
|
+
|
|
95
|
+
## ➡️ `clever config-provider set` <kbd>Since 4.6.0</kbd>
|
|
96
|
+
|
|
97
|
+
Add or update an environment variable named <variable-name> with the value <variable-value>
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
clever config-provider set <addon-id|config-provider-id|addon-name> <variable-name> <variable-value>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 📥 Arguments
|
|
104
|
+
|
|
105
|
+
|Name|Description|
|
|
106
|
+
|---|---|
|
|
107
|
+
|`addon-id|config-provider-id|addon-name`|Add-on ID, real ID (config_xxx) or name (if unambiguous)|
|
|
108
|
+
|`variable-name`|Name of the environment variable|
|
|
109
|
+
|`variable-value`|Value of the environment variable|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getConfigProviderEnv } from '@clevercloud/client/esm/api/v4/addon.js';
|
|
2
|
+
import { toNameEqualsValueString } from '@clevercloud/client/esm/utils/env-vars.js';
|
|
3
|
+
import { defineCommand } from '../../lib/define-command.js';
|
|
4
|
+
import { Logger } from '../../logger.js';
|
|
5
|
+
import { resolveConfigProviderId } from '../../models/config-provider.js';
|
|
6
|
+
import { sendToApi } from '../../models/send-to-api.js';
|
|
7
|
+
import { envFormatOption } from '../global.options.js';
|
|
8
|
+
import { configProviderIdOrNameArg } from './config-provider.args.js';
|
|
9
|
+
|
|
10
|
+
export const configProviderGetCommand = defineCommand({
|
|
11
|
+
description: 'List environment variables of a configuration provider',
|
|
12
|
+
since: '4.6.0',
|
|
13
|
+
options: {
|
|
14
|
+
format: envFormatOption,
|
|
15
|
+
},
|
|
16
|
+
args: [configProviderIdOrNameArg],
|
|
17
|
+
async handler(options, addonIdOrRealIdOrName) {
|
|
18
|
+
const { format } = options;
|
|
19
|
+
const { realId } = await resolveConfigProviderId(addonIdOrRealIdOrName);
|
|
20
|
+
|
|
21
|
+
// API returns an array of { name, value } objects
|
|
22
|
+
const envVars = await getConfigProviderEnv({ configurationProviderId: realId }).then(sendToApi);
|
|
23
|
+
|
|
24
|
+
switch (format) {
|
|
25
|
+
case 'json':
|
|
26
|
+
Logger.printJson(envVars);
|
|
27
|
+
break;
|
|
28
|
+
case 'shell':
|
|
29
|
+
Logger.println(toNameEqualsValueString(envVars, { addExports: true }));
|
|
30
|
+
break;
|
|
31
|
+
case 'human':
|
|
32
|
+
default:
|
|
33
|
+
Logger.println(toNameEqualsValueString(envVars, { addExports: false }));
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { updateConfigProviderEnv } from '@clevercloud/client/esm/api/v4/addon.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { defineCommand } from '../../lib/define-command.js';
|
|
4
|
+
import { defineOption } from '../../lib/define-option.js';
|
|
5
|
+
import { Logger } from '../../logger.js';
|
|
6
|
+
import { resolveConfigProviderId } from '../../models/config-provider.js';
|
|
7
|
+
import { sendToApi } from '../../models/send-to-api.js';
|
|
8
|
+
import * as variables from '../../models/variables.js';
|
|
9
|
+
import { configProviderIdOrNameArg } from './config-provider.args.js';
|
|
10
|
+
|
|
11
|
+
const importFormatOption = defineOption({
|
|
12
|
+
name: 'format',
|
|
13
|
+
schema: z.enum(['name-equals-value', 'json']).default('name-equals-value'),
|
|
14
|
+
description: 'Input format (name-equals-value, json)',
|
|
15
|
+
aliases: ['F'],
|
|
16
|
+
placeholder: 'format',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const configProviderImportCommand = defineCommand({
|
|
20
|
+
description:
|
|
21
|
+
'Load environment variables from STDIN\n(WARNING: this deletes all current variables and replaces them with the new list loaded from STDIN)',
|
|
22
|
+
since: '4.6.0',
|
|
23
|
+
options: {
|
|
24
|
+
format: importFormatOption,
|
|
25
|
+
},
|
|
26
|
+
args: [configProviderIdOrNameArg],
|
|
27
|
+
async handler(options, addonIdOrRealIdOrName) {
|
|
28
|
+
const { format } = options;
|
|
29
|
+
const { realId } = await resolveConfigProviderId(addonIdOrRealIdOrName);
|
|
30
|
+
|
|
31
|
+
// readVariablesFromStdin returns { NAME: "value" } format
|
|
32
|
+
// but the API expects [{ name, value }] format
|
|
33
|
+
const envVarsObject = await variables.readVariablesFromStdin(format);
|
|
34
|
+
const envVarsArray = Object.entries(envVarsObject).map(([name, value]) => ({ name, value }));
|
|
35
|
+
|
|
36
|
+
await updateConfigProviderEnv({ configurationProviderId: realId }, envVarsArray).then(sendToApi);
|
|
37
|
+
|
|
38
|
+
Logger.println('Environment variables have been set');
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineCommand } from '../../lib/define-command.js';
|
|
2
|
+
import { styleText } from '../../lib/style-text.js';
|
|
3
|
+
import { Logger } from '../../logger.js';
|
|
4
|
+
import { findAddonsByAddonProvider } from '../../models/ids-resolver.js';
|
|
5
|
+
import { humanJsonOutputFormatOption } from '../global.options.js';
|
|
6
|
+
|
|
7
|
+
export const configProviderListCommand = defineCommand({
|
|
8
|
+
description: 'List configuration providers',
|
|
9
|
+
since: '4.6.0',
|
|
10
|
+
options: {
|
|
11
|
+
format: humanJsonOutputFormatOption,
|
|
12
|
+
},
|
|
13
|
+
args: [],
|
|
14
|
+
async handler(options) {
|
|
15
|
+
const { format } = options;
|
|
16
|
+
const deployed = await findAddonsByAddonProvider('config-provider');
|
|
17
|
+
const providersPerOwner = Object.groupBy(deployed, (provider) => provider.ownerId);
|
|
18
|
+
|
|
19
|
+
switch (format) {
|
|
20
|
+
case 'json':
|
|
21
|
+
Logger.printJson(providersPerOwner);
|
|
22
|
+
break;
|
|
23
|
+
case 'human':
|
|
24
|
+
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();
|
|
41
|
+
});
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { config } from '../../config/config.js';
|
|
2
|
+
import { defineCommand } from '../../lib/define-command.js';
|
|
3
|
+
import { styleText } from '../../lib/style-text.js';
|
|
4
|
+
import { resolveConfigProviderId } from '../../models/config-provider.js';
|
|
5
|
+
import { openBrowser } from '../../models/utils.js';
|
|
6
|
+
import { configProviderIdOrNameArg } from './config-provider.args.js';
|
|
7
|
+
|
|
8
|
+
export const configProviderOpenCommand = defineCommand({
|
|
9
|
+
description: 'Open the configuration provider in Clever Cloud Console',
|
|
10
|
+
since: '4.6.0',
|
|
11
|
+
options: {},
|
|
12
|
+
args: [configProviderIdOrNameArg],
|
|
13
|
+
async handler(_options, addonIdOrRealIdOrName) {
|
|
14
|
+
const { addonId } = await resolveConfigProviderId(addonIdOrRealIdOrName);
|
|
15
|
+
await openBrowser(`${config.GOTO_URL}/${addonId}`, `Opening ${styleText('blue', addonId)} in the browser...`);
|
|
16
|
+
},
|
|
17
|
+
});
|