@localctl/cli 0.2.0 → 0.3.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 (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +398 -431
  3. package/assets/manifests/namespace-addons.yaml +4 -4
  4. package/assets/manifests/tls-store.yaml +8 -8
  5. package/bin/localctl.js +2 -2
  6. package/package.json +61 -54
  7. package/src/commands/addons.js +56 -56
  8. package/src/commands/doctor.js +44 -43
  9. package/src/commands/down.js +35 -35
  10. package/src/commands/exec.js +15 -15
  11. package/src/commands/generateManifests.js +12 -12
  12. package/src/commands/hosts.js +23 -23
  13. package/src/commands/logs.js +45 -45
  14. package/src/commands/profiles.js +180 -180
  15. package/src/commands/prune.js +49 -49
  16. package/src/commands/registryInfo.js +18 -18
  17. package/src/commands/reload.js +44 -44
  18. package/src/commands/secrets.js +75 -75
  19. package/src/commands/setup.js +36 -36
  20. package/src/commands/status.js +136 -136
  21. package/src/commands/up.js +123 -123
  22. package/src/index.js +38 -36
  23. package/src/lib/addonDirs.js +43 -43
  24. package/src/lib/addonLoader.js +190 -190
  25. package/src/lib/addons/cluster/logging/addon.yaml +46 -46
  26. package/src/lib/addons/cluster/logging/config/all-logs.json +21 -21
  27. package/src/lib/addons/cluster/monitoring/addon.yaml +33 -33
  28. package/src/lib/addons/mongo/addon.yaml +18 -18
  29. package/src/lib/addons/postgres/addon.yaml +39 -39
  30. package/src/lib/addons/redis/addon.yaml +29 -29
  31. package/src/lib/appSecrets.js +60 -60
  32. package/src/lib/clusterAddons.js +59 -59
  33. package/src/lib/clusterProvision.js +171 -170
  34. package/src/lib/configSchema.js +103 -103
  35. package/src/lib/constants.js +16 -16
  36. package/src/lib/engine.js +36 -20
  37. package/src/lib/exec.js +77 -77
  38. package/src/lib/hostsFile.js +79 -79
  39. package/src/lib/loadConfig.js +51 -51
  40. package/src/lib/logger.js +9 -9
  41. package/src/lib/manifestGen.js +210 -210
  42. package/src/lib/paths.js +41 -41
  43. package/src/lib/podman.js +72 -72
  44. package/src/lib/profileStore.js +134 -134
  45. package/src/lib/projectContext.js +32 -32
  46. package/src/lib/prompt.js +97 -97
  47. package/src/lib/toolInstall.js +30 -30
  48. package/src/lib/ui.js +50 -50
  49. package/src/lib/updateCheck.js +84 -0
  50. package/src/lib/updateCheckWorker.js +46 -0
  51. package/src/lib/workloadReadiness.js +35 -35
  52. package/templates/Tiltfile.tmpl +35 -35
package/src/lib/engine.js CHANGED
@@ -1,20 +1,36 @@
1
- const { commandExists, capture } = require('./exec');
2
-
3
- // Returns { engine, bin } - `engine` names what's actually running (docker/podman/rancher-desktop),
4
- // `bin` is the CLI to drive it with (usually the same, except Rancher Desktop, which exposes
5
- // docker or nerdctl depending on how it's configured). Returns null if nothing usable is found.
6
- function detectEngine() {
7
- if (commandExists('docker') && capture('docker', ['info']).status === 0) {
8
- return { engine: 'docker', bin: 'docker' };
9
- }
10
- if (commandExists('podman') && capture('podman', ['info']).status === 0) {
11
- return { engine: 'podman', bin: 'podman' };
12
- }
13
- if (commandExists('rdctl')) {
14
- if (commandExists('docker')) return { engine: 'rancher-desktop', bin: 'docker' };
15
- if (commandExists('nerdctl')) return { engine: 'rancher-desktop', bin: 'nerdctl' };
16
- }
17
- return null;
18
- }
19
-
20
- module.exports = { detectEngine };
1
+ const { commandExists, capture } = require('./exec');
2
+ const logger = require('./logger');
3
+
4
+ // Support status per engine lives in cli/package.json ("localctl.containerEngines"), so marking an
5
+ // engine as tested is a one-word config change, not a code change. "tested" means verified end to
6
+ // end; anything else (or an engine missing from the map) gets the experimental warning.
7
+ const { localctl: { containerEngines = {} } = {} } = require('../../package.json');
8
+ const ENGINE_LABELS = { docker: 'Docker Desktop', podman: 'Podman', 'rancher-desktop': 'Rancher Desktop' };
9
+ const ISSUES_URL = 'https://github.com/psilvmoreira/localctl/issues';
10
+
11
+ // Returns { engine, bin } - `engine` names what's actually running (docker/podman/rancher-desktop),
12
+ // `bin` is the CLI to drive it with (usually the same, except Rancher Desktop, which exposes
13
+ // docker or nerdctl depending on how it's configured). Returns null if nothing usable is found.
14
+ function detectEngine() {
15
+ if (commandExists('docker') && capture('docker', ['info']).status === 0) {
16
+ return { engine: 'docker', bin: 'docker' };
17
+ }
18
+ if (commandExists('podman') && capture('podman', ['info']).status === 0) {
19
+ return { engine: 'podman', bin: 'podman' };
20
+ }
21
+ if (commandExists('rdctl')) {
22
+ if (commandExists('docker')) return { engine: 'rancher-desktop', bin: 'docker' };
23
+ if (commandExists('nerdctl')) return { engine: 'rancher-desktop', bin: 'nerdctl' };
24
+ }
25
+ return null;
26
+ }
27
+
28
+ function warnIfExperimental(engine) {
29
+ if (containerEngines[engine] === 'tested') return;
30
+ const tested = Object.keys(containerEngines).filter((e) => containerEngines[e] === 'tested');
31
+ const testedList = tested.map((e) => ENGINE_LABELS[e] || e).join(', ') || 'none';
32
+ logger.warn(`${ENGINE_LABELS[engine] || engine} support is experimental - fully tested so far: ${testedList}.`);
33
+ logger.warn(`If something breaks, please report it: ${ISSUES_URL}`);
34
+ }
35
+
36
+ module.exports = { detectEngine, warnIfExperimental };
package/src/lib/exec.js CHANGED
@@ -1,77 +1,77 @@
1
- const { spawnSync, spawn } = require('child_process');
2
- const fs = require('fs');
3
- const net = require('net');
4
-
5
- function run(cmd, args, opts = {}) {
6
- const res = spawnSync(cmd, args, { stdio: 'inherit', ...opts });
7
- if (res.error) throw res.error;
8
- if (res.status !== 0 && !opts.allowFail) {
9
- throw new Error(`Command failed (${res.status}): ${cmd} ${args.join(' ')}`);
10
- }
11
- return res;
12
- }
13
-
14
- function capture(cmd, args, opts = {}) {
15
- const res = spawnSync(cmd, args, { encoding: 'utf8', ...opts });
16
- return {
17
- status: res.status,
18
- stdout: (res.stdout || '').trim(),
19
- stderr: (res.stderr || '').trim(),
20
- };
21
- }
22
-
23
- function commandExists(cmd) {
24
- const probe = process.platform === 'win32' ? 'where' : 'which';
25
- const res = spawnSync(probe, [cmd], { stdio: 'ignore' });
26
- return res.status === 0;
27
- }
28
-
29
- // Blocking sleep with no native dependency - used for poll loops (e.g. waiting on a CRD to
30
- // register) where an async setTimeout would need restructuring the whole command as a promise
31
- // chain for no real benefit.
32
- function sleepSync(ms) {
33
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
34
- }
35
-
36
- // Starts a fully detached child that outlives this process (and the terminal it's running in) -
37
- // used for `localctl up --detach`. stdout/stderr go to logFile since there's no terminal to
38
- // inherit once the parent exits. Returns the child's pid.
39
- function spawnDetached(cmd, args, { cwd, env, logFile } = {}) {
40
- const out = fs.openSync(logFile, 'a');
41
- const child = spawn(cmd, args, {
42
- cwd,
43
- env,
44
- detached: true,
45
- stdio: ['ignore', out, out],
46
- });
47
- child.unref();
48
- return child.pid;
49
- }
50
-
51
- // True if a process with this pid is currently running (doesn't actually signal it).
52
- function isRunning(pid) {
53
- try {
54
- process.kill(pid, 0);
55
- return true;
56
- } catch (e) {
57
- return false;
58
- }
59
- }
60
-
61
- // Asks the OS for a free TCP port (binds to port 0, reads back what it picked). Used to give each
62
- // app's Tilt instance its own web UI port - Tilt otherwise always binds the same default port,
63
- // so two apps running `localctl up` at once (the whole point of detached mode) collide outright,
64
- // and the resulting error doesn't explain why.
65
- function getFreePort() {
66
- return new Promise((resolve, reject) => {
67
- const srv = net.createServer();
68
- srv.unref();
69
- srv.on('error', reject);
70
- srv.listen(0, '127.0.0.1', () => {
71
- const { port } = srv.address();
72
- srv.close(() => resolve(port));
73
- });
74
- });
75
- }
76
-
77
- module.exports = { run, capture, commandExists, sleepSync, spawnDetached, isRunning, getFreePort };
1
+ const { spawnSync, spawn } = require('child_process');
2
+ const fs = require('fs');
3
+ const net = require('net');
4
+
5
+ function run(cmd, args, opts = {}) {
6
+ const res = spawnSync(cmd, args, { stdio: 'inherit', ...opts });
7
+ if (res.error) throw res.error;
8
+ if (res.status !== 0 && !opts.allowFail) {
9
+ throw new Error(`Command failed (${res.status}): ${cmd} ${args.join(' ')}`);
10
+ }
11
+ return res;
12
+ }
13
+
14
+ function capture(cmd, args, opts = {}) {
15
+ const res = spawnSync(cmd, args, { encoding: 'utf8', ...opts });
16
+ return {
17
+ status: res.status,
18
+ stdout: (res.stdout || '').trim(),
19
+ stderr: (res.stderr || '').trim(),
20
+ };
21
+ }
22
+
23
+ function commandExists(cmd) {
24
+ const probe = process.platform === 'win32' ? 'where' : 'which';
25
+ const res = spawnSync(probe, [cmd], { stdio: 'ignore' });
26
+ return res.status === 0;
27
+ }
28
+
29
+ // Blocking sleep with no native dependency - used for poll loops (e.g. waiting on a CRD to
30
+ // register) where an async setTimeout would need restructuring the whole command as a promise
31
+ // chain for no real benefit.
32
+ function sleepSync(ms) {
33
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
34
+ }
35
+
36
+ // Starts a fully detached child that outlives this process (and the terminal it's running in) -
37
+ // used for `localctl up --detach`. stdout/stderr go to logFile since there's no terminal to
38
+ // inherit once the parent exits. Returns the child's pid.
39
+ function spawnDetached(cmd, args, { cwd, env, logFile } = {}) {
40
+ const out = fs.openSync(logFile, 'a');
41
+ const child = spawn(cmd, args, {
42
+ cwd,
43
+ env,
44
+ detached: true,
45
+ stdio: ['ignore', out, out],
46
+ });
47
+ child.unref();
48
+ return child.pid;
49
+ }
50
+
51
+ // True if a process with this pid is currently running (doesn't actually signal it).
52
+ function isRunning(pid) {
53
+ try {
54
+ process.kill(pid, 0);
55
+ return true;
56
+ } catch (e) {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ // Asks the OS for a free TCP port (binds to port 0, reads back what it picked). Used to give each
62
+ // app's Tilt instance its own web UI port - Tilt otherwise always binds the same default port,
63
+ // so two apps running `localctl up` at once (the whole point of detached mode) collide outright,
64
+ // and the resulting error doesn't explain why.
65
+ function getFreePort() {
66
+ return new Promise((resolve, reject) => {
67
+ const srv = net.createServer();
68
+ srv.unref();
69
+ srv.on('error', reject);
70
+ srv.listen(0, '127.0.0.1', () => {
71
+ const { port } = srv.address();
72
+ srv.close(() => resolve(port));
73
+ });
74
+ });
75
+ }
76
+
77
+ module.exports = { run, capture, commandExists, sleepSync, spawnDetached, isRunning, getFreePort };
@@ -1,79 +1,79 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
- const { spawnSync } = require('child_process');
5
- const logger = require('./logger');
6
- const { ensureHomeState, APPS_REGISTRY_PATH } = require('./paths');
7
- const { DOMAIN } = require('./constants');
8
-
9
- const MARK_START = '# >>> localctl managed block >>>';
10
- const MARK_END = '# <<< localctl managed block <<<';
11
- const HOSTS_PATH =
12
- process.platform === 'win32' ? 'C:\\Windows\\System32\\drivers\\etc\\hosts' : '/etc/hosts';
13
-
14
- function registerApp(subdomain) {
15
- ensureHomeState();
16
- const registry = JSON.parse(fs.readFileSync(APPS_REGISTRY_PATH, 'utf8'));
17
- registry[subdomain] = true;
18
- fs.writeFileSync(APPS_REGISTRY_PATH, JSON.stringify(registry, null, 2));
19
- }
20
-
21
- function listApps() {
22
- ensureHomeState();
23
- const registry = JSON.parse(fs.readFileSync(APPS_REGISTRY_PATH, 'utf8'));
24
- return Object.keys(registry);
25
- }
26
-
27
- function writeHosts(next, current) {
28
- if (next === current) {
29
- logger.info('Hosts file already up to date.');
30
- return;
31
- }
32
-
33
- try {
34
- fs.writeFileSync(HOSTS_PATH, next);
35
- logger.success(`Updated ${HOSTS_PATH}`);
36
- } catch (e) {
37
- if (e.code !== 'EACCES' && e.code !== 'EPERM') throw e;
38
- const tmp = path.join(os.tmpdir(), 'localctl-hosts-new');
39
- fs.writeFileSync(tmp, next);
40
- if (process.platform === 'win32') {
41
- logger.warn('Need Administrator rights to update the hosts file. Run in an elevated PowerShell:');
42
- console.log(` Copy-Item "${tmp}" "${HOSTS_PATH}" -Force`);
43
- } else {
44
- logger.warn('Need sudo to update the hosts file.');
45
- const res = spawnSync('sudo', ['cp', tmp, HOSTS_PATH], { stdio: 'inherit' });
46
- if (res.status === 0) logger.success(`Updated ${HOSTS_PATH}`);
47
- else logger.warn(`Run manually: sudo cp ${tmp} ${HOSTS_PATH}`);
48
- }
49
- }
50
- }
51
-
52
- function syncHosts() {
53
- const apps = listApps();
54
- const lines = [
55
- MARK_START,
56
- ...apps.map((s) => `127.0.0.1 ${s}.${DOMAIN}`),
57
- `127.0.0.1 ${DOMAIN}`,
58
- MARK_END,
59
- ];
60
- const block = lines.join(os.EOL);
61
-
62
- const current = fs.readFileSync(HOSTS_PATH, 'utf8');
63
- const re = new RegExp(`${MARK_START}[\\s\\S]*?${MARK_END}`, 'm');
64
- const next = re.test(current)
65
- ? current.replace(re, block)
66
- : `${current.trimEnd()}${os.EOL}${block}${os.EOL}`;
67
-
68
- writeHosts(next, current);
69
- }
70
-
71
- // Used by uninstall: strips the whole managed block, leaving the rest of the hosts file alone.
72
- function clearHosts() {
73
- const current = fs.readFileSync(HOSTS_PATH, 'utf8');
74
- const re = new RegExp(`(${os.EOL}|\\n)?${MARK_START}[\\s\\S]*?${MARK_END}(${os.EOL}|\\n)?`, 'm');
75
- const next = current.replace(re, os.EOL);
76
- writeHosts(next, current);
77
- }
78
-
79
- module.exports = { syncHosts, clearHosts, registerApp, listApps };
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const { spawnSync } = require('child_process');
5
+ const logger = require('./logger');
6
+ const { ensureHomeState, APPS_REGISTRY_PATH } = require('./paths');
7
+ const { DOMAIN } = require('./constants');
8
+
9
+ const MARK_START = '# >>> localctl managed block >>>';
10
+ const MARK_END = '# <<< localctl managed block <<<';
11
+ const HOSTS_PATH =
12
+ process.platform === 'win32' ? 'C:\\Windows\\System32\\drivers\\etc\\hosts' : '/etc/hosts';
13
+
14
+ function registerApp(subdomain) {
15
+ ensureHomeState();
16
+ const registry = JSON.parse(fs.readFileSync(APPS_REGISTRY_PATH, 'utf8'));
17
+ registry[subdomain] = true;
18
+ fs.writeFileSync(APPS_REGISTRY_PATH, JSON.stringify(registry, null, 2));
19
+ }
20
+
21
+ function listApps() {
22
+ ensureHomeState();
23
+ const registry = JSON.parse(fs.readFileSync(APPS_REGISTRY_PATH, 'utf8'));
24
+ return Object.keys(registry);
25
+ }
26
+
27
+ function writeHosts(next, current) {
28
+ if (next === current) {
29
+ logger.info('Hosts file already up to date.');
30
+ return;
31
+ }
32
+
33
+ try {
34
+ fs.writeFileSync(HOSTS_PATH, next);
35
+ logger.success(`Updated ${HOSTS_PATH}`);
36
+ } catch (e) {
37
+ if (e.code !== 'EACCES' && e.code !== 'EPERM') throw e;
38
+ const tmp = path.join(os.tmpdir(), 'localctl-hosts-new');
39
+ fs.writeFileSync(tmp, next);
40
+ if (process.platform === 'win32') {
41
+ logger.warn('Need Administrator rights to update the hosts file. Run in an elevated PowerShell:');
42
+ console.log(` Copy-Item "${tmp}" "${HOSTS_PATH}" -Force`);
43
+ } else {
44
+ logger.warn('Need sudo to update the hosts file.');
45
+ const res = spawnSync('sudo', ['cp', tmp, HOSTS_PATH], { stdio: 'inherit' });
46
+ if (res.status === 0) logger.success(`Updated ${HOSTS_PATH}`);
47
+ else logger.warn(`Run manually: sudo cp ${tmp} ${HOSTS_PATH}`);
48
+ }
49
+ }
50
+ }
51
+
52
+ function syncHosts() {
53
+ const apps = listApps();
54
+ const lines = [
55
+ MARK_START,
56
+ ...apps.map((s) => `127.0.0.1 ${s}.${DOMAIN}`),
57
+ `127.0.0.1 ${DOMAIN}`,
58
+ MARK_END,
59
+ ];
60
+ const block = lines.join(os.EOL);
61
+
62
+ const current = fs.readFileSync(HOSTS_PATH, 'utf8');
63
+ const re = new RegExp(`${MARK_START}[\\s\\S]*?${MARK_END}`, 'm');
64
+ const next = re.test(current)
65
+ ? current.replace(re, block)
66
+ : `${current.trimEnd()}${os.EOL}${block}${os.EOL}`;
67
+
68
+ writeHosts(next, current);
69
+ }
70
+
71
+ // Used by uninstall: strips the whole managed block, leaving the rest of the hosts file alone.
72
+ function clearHosts() {
73
+ const current = fs.readFileSync(HOSTS_PATH, 'utf8');
74
+ const re = new RegExp(`(${os.EOL}|\\n)?${MARK_START}[\\s\\S]*?${MARK_END}(${os.EOL}|\\n)?`, 'm');
75
+ const next = current.replace(re, os.EOL);
76
+ writeHosts(next, current);
77
+ }
78
+
79
+ module.exports = { syncHosts, clearHosts, registerApp, listApps };
@@ -1,51 +1,51 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { appConfigSchema } = require('./configSchema');
4
- const { CONFIG_PATH } = require('./paths');
5
- const { resolveProfileName } = require('./projectContext');
6
- const { getProfile, clusterNameFor, namespaceScopeFor } = require('./profileStore');
7
-
8
- function loadConfig(configPath = CONFIG_PATH) {
9
- if (!fs.existsSync(configPath)) {
10
- throw new Error(`No config found at ${configPath}. Run "localctl app new" first.`);
11
- }
12
- const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
13
- const parsed = appConfigSchema.safeParse(raw);
14
- if (!parsed.success) {
15
- const issues = parsed.error.issues
16
- .map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`)
17
- .join('\n');
18
- throw new Error(`Invalid .local/config.json:\n${issues}`);
19
- }
20
- const cfg = parsed.data;
21
- cfg.namespace = cfg.namespace || cfg.name;
22
- cfg.subdomain = cfg.subdomain || cfg.name;
23
-
24
- // Which project this app belongs to - walking up from the app's own directory for the nearest
25
- // .local/project.json, same lookup as git finding .git (see projectContext.js). No
26
- // project.json anywhere above it -> the app belongs to "default", today's single cluster,
27
- // unchanged.
28
- const appDir = path.dirname(path.dirname(configPath));
29
- const profileName = resolveProfileName(appDir);
30
- const profile = getProfile(profileName);
31
- if (!profile) {
32
- throw new Error(
33
- `Profile "${profileName}" (from .local/project.json) isn't registered on this machine. ` +
34
- `Run "localctl profiles new ${profileName}" first.`,
35
- );
36
- }
37
-
38
- // A namespace-level project shares its parent's cluster, isolated only by a namespace/subdomain
39
- // prefix - a Main (cluster-isolation) project owns its whole cluster, nothing to prefix.
40
- const scope = namespaceScopeFor(profileName);
41
- if (scope) {
42
- cfg.namespace = `${scope}-${cfg.namespace}`;
43
- cfg.subdomain = `${scope}-${cfg.subdomain}`;
44
- }
45
-
46
- cfg.profile = profileName;
47
- cfg.clusterName = clusterNameFor(profileName);
48
- return cfg;
49
- }
50
-
51
- module.exports = { loadConfig };
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { appConfigSchema } = require('./configSchema');
4
+ const { CONFIG_PATH } = require('./paths');
5
+ const { resolveProfileName } = require('./projectContext');
6
+ const { getProfile, clusterNameFor, namespaceScopeFor } = require('./profileStore');
7
+
8
+ function loadConfig(configPath = CONFIG_PATH) {
9
+ if (!fs.existsSync(configPath)) {
10
+ throw new Error(`No config found at ${configPath}. Run "localctl app new" first.`);
11
+ }
12
+ const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
13
+ const parsed = appConfigSchema.safeParse(raw);
14
+ if (!parsed.success) {
15
+ const issues = parsed.error.issues
16
+ .map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`)
17
+ .join('\n');
18
+ throw new Error(`Invalid .local/config.json:\n${issues}`);
19
+ }
20
+ const cfg = parsed.data;
21
+ cfg.namespace = cfg.namespace || cfg.name;
22
+ cfg.subdomain = cfg.subdomain || cfg.name;
23
+
24
+ // Which project this app belongs to - walking up from the app's own directory for the nearest
25
+ // .local/project.json, same lookup as git finding .git (see projectContext.js). No
26
+ // project.json anywhere above it -> the app belongs to "default", today's single cluster,
27
+ // unchanged.
28
+ const appDir = path.dirname(path.dirname(configPath));
29
+ const profileName = resolveProfileName(appDir);
30
+ const profile = getProfile(profileName);
31
+ if (!profile) {
32
+ throw new Error(
33
+ `Profile "${profileName}" (from .local/project.json) isn't registered on this machine. ` +
34
+ `Run "localctl profiles new ${profileName}" first.`,
35
+ );
36
+ }
37
+
38
+ // A namespace-level project shares its parent's cluster, isolated only by a namespace/subdomain
39
+ // prefix - a Main (cluster-isolation) project owns its whole cluster, nothing to prefix.
40
+ const scope = namespaceScopeFor(profileName);
41
+ if (scope) {
42
+ cfg.namespace = `${scope}-${cfg.namespace}`;
43
+ cfg.subdomain = `${scope}-${cfg.subdomain}`;
44
+ }
45
+
46
+ cfg.profile = profileName;
47
+ cfg.clusterName = clusterNameFor(profileName);
48
+ return cfg;
49
+ }
50
+
51
+ module.exports = { loadConfig };
package/src/lib/logger.js CHANGED
@@ -1,9 +1,9 @@
1
- const chalk = require('chalk');
2
-
3
- module.exports = {
4
- info: (msg) => console.log(chalk.cyan('info'), msg),
5
- warn: (msg) => console.log(chalk.yellow('warn'), msg),
6
- error: (msg) => console.error(chalk.red('error'), msg),
7
- success: (msg) => console.log(chalk.green('ok'), msg),
8
- step: (msg) => console.log(chalk.magenta('>'), msg),
9
- };
1
+ const chalk = require('chalk');
2
+
3
+ module.exports = {
4
+ info: (msg) => console.log(chalk.cyan('info'), msg),
5
+ warn: (msg) => console.log(chalk.yellow('warn'), msg),
6
+ error: (msg) => console.error(chalk.red('error'), msg),
7
+ success: (msg) => console.log(chalk.green('ok'), msg),
8
+ step: (msg) => console.log(chalk.magenta('>'), msg),
9
+ };