@loopress/cli 0.6.0 → 0.7.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 +71 -90
- package/dist/commands/composer/pull.js +1 -1
- package/dist/commands/composer/push.js +1 -1
- package/dist/commands/init.js +15 -6
- package/dist/commands/login.js +1 -1
- package/dist/commands/logout.js +1 -1
- package/dist/commands/plugin/add.d.ts +0 -2
- package/dist/commands/plugin/add.js +2 -23
- package/dist/commands/plugin/pull.js +1 -1
- package/dist/commands/plugin/push.js +3 -3
- package/dist/commands/project/config.d.ts +1 -0
- package/dist/commands/project/config.js +36 -17
- package/dist/commands/project/list.js +4 -5
- package/dist/commands/project/remove.js +33 -14
- package/dist/commands/project/switch.d.ts +2 -0
- package/dist/commands/project/switch.js +28 -9
- package/dist/commands/snippet/list.js +3 -3
- package/dist/commands/snippet/pull.d.ts +1 -1
- package/dist/commands/snippet/pull.js +7 -6
- package/dist/commands/snippet/push.d.ts +2 -2
- package/dist/commands/snippet/push.js +47 -15
- package/dist/commands/{project/remove-env.d.ts → status.d.ts} +3 -1
- package/dist/commands/status.js +66 -0
- package/dist/config/project-config.manager.d.ts +17 -10
- package/dist/config/project-config.manager.js +91 -44
- package/dist/config/types.d.ts +5 -2
- package/dist/lib/base.js +13 -3
- package/dist/types/snippet.d.ts +2 -0
- package/dist/utils/snippet-plugin.d.ts +2 -1
- package/dist/utils/snippet-plugin.js +5 -4
- package/oclif.manifest.json +149 -175
- package/package.json +17 -2
- package/dist/commands/project/remove-env.js +0 -33
- package/dist/commands/project/switch-env.d.ts +0 -6
- package/dist/commands/project/switch-env.js +0 -33
|
@@ -12,17 +12,16 @@ export default class List extends Command {
|
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
for (const project of projects) {
|
|
15
|
-
const envs =
|
|
15
|
+
const envs = configManager.listEnvironments(project.id);
|
|
16
16
|
const marker = project.isCurrent ? c('green', '●') : c('dim', '○');
|
|
17
17
|
const name = project.isCurrent ? c('green', project.name) : project.name;
|
|
18
18
|
const currentTag = project.isCurrent ? ` ${c('green', '[current]')}` : '';
|
|
19
19
|
this.log(`${marker} ${name}${currentTag}`);
|
|
20
20
|
for (const env of envs) {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const envName = isActiveEnv ? c('cyan', env.name.padEnd(15)) : c('dim', env.name.padEnd(15));
|
|
21
|
+
const envMarker = env.isCurrent ? c('cyan', '·') : c('dim', '·');
|
|
22
|
+
const envName = env.isCurrent ? c('cyan', env.name.padEnd(15)) : c('dim', env.name.padEnd(15));
|
|
24
23
|
const envUrl = c('dim', env.url);
|
|
25
|
-
const activeTag =
|
|
24
|
+
const activeTag = env.isCurrent ? ` ${c('cyan', '←')}` : '';
|
|
26
25
|
this.log(` ${envMarker} ${envName} ${envUrl}${activeTag}`);
|
|
27
26
|
}
|
|
28
27
|
this.log('');
|
|
@@ -2,7 +2,7 @@ import { checkbox } from '@inquirer/prompts';
|
|
|
2
2
|
import { Command } from '@oclif/core';
|
|
3
3
|
import { configManager } from '../../config/project-config.manager.js';
|
|
4
4
|
export default class Remove extends Command {
|
|
5
|
-
static description = 'Remove one or more WordPress
|
|
5
|
+
static description = 'Remove one or more WordPress projects or environments';
|
|
6
6
|
static examples = ['$ lps project remove'];
|
|
7
7
|
async run() {
|
|
8
8
|
await this.parse(Remove);
|
|
@@ -10,25 +10,44 @@ export default class Remove extends Command {
|
|
|
10
10
|
if (projects.length === 0) {
|
|
11
11
|
this.error('No projects configured.');
|
|
12
12
|
}
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const targets = [];
|
|
14
|
+
const choices = projects.flatMap((project) => {
|
|
15
|
+
const envCount = Object.keys(project.environments).length;
|
|
16
|
+
const envLabel = `${envCount} env${envCount > 1 ? 's' : ''}`;
|
|
17
|
+
const currentMarker = project.isCurrent ? ' [current]' : '';
|
|
18
|
+
targets.push({ kind: 'project', projectId: project.id, projectName: project.name });
|
|
19
|
+
const projectChoice = {
|
|
20
|
+
name: `${project.isCurrent ? '●' : '○'} ${project.name.padEnd(20)} (${envLabel})${currentMarker}`,
|
|
21
|
+
value: String(targets.length - 1),
|
|
22
|
+
};
|
|
23
|
+
const envChoices = configManager.listEnvironments(project.id).map((env) => {
|
|
24
|
+
targets.push({ env: env.name, kind: 'env', projectId: project.id, projectName: project.name });
|
|
18
25
|
return {
|
|
19
|
-
name:
|
|
20
|
-
value:
|
|
26
|
+
name: ` ${env.isCurrent ? '●' : '○'} ${env.name.padEnd(20)} ${env.url}${env.isCurrent ? ' [current]' : ''}`,
|
|
27
|
+
value: String(targets.length - 1),
|
|
21
28
|
};
|
|
22
|
-
})
|
|
23
|
-
|
|
29
|
+
});
|
|
30
|
+
return [projectChoice, ...envChoices];
|
|
31
|
+
});
|
|
32
|
+
const chosen = await checkbox({
|
|
33
|
+
choices,
|
|
34
|
+
message: 'Select projects or environments to remove',
|
|
24
35
|
});
|
|
25
36
|
if (chosen.length === 0) {
|
|
26
37
|
this.log('Nothing removed.');
|
|
27
38
|
return;
|
|
28
39
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
const selected = chosen.map((index) => targets[Number(index)]);
|
|
41
|
+
const projectsToRemove = new Map(selected.filter((target) => target.kind === 'project').map((target) => [target.projectId, target.projectName]));
|
|
42
|
+
const envsToRemove = selected.filter((target) => target.kind === 'env' && !projectsToRemove.has(target.projectId));
|
|
43
|
+
for (const projectId of projectsToRemove.keys())
|
|
44
|
+
configManager.removeProject(projectId);
|
|
45
|
+
for (const { env, projectId } of envsToRemove)
|
|
46
|
+
configManager.removeEnvironment(projectId, env);
|
|
47
|
+
const removedLabels = [
|
|
48
|
+
...projectsToRemove.values(),
|
|
49
|
+
...envsToRemove.map(({ env, projectName }) => `${projectName}/${env}`),
|
|
50
|
+
];
|
|
51
|
+
this.log(`✓ Removed: ${removedLabels.join(', ')}`);
|
|
33
52
|
}
|
|
34
53
|
}
|
|
@@ -2,7 +2,7 @@ import { select } from '@inquirer/prompts';
|
|
|
2
2
|
import { Command } from '@oclif/core';
|
|
3
3
|
import { configManager } from '../../config/project-config.manager.js';
|
|
4
4
|
export default class Switch extends Command {
|
|
5
|
-
static description = 'Switch the active project';
|
|
5
|
+
static description = 'Switch the active project and environment';
|
|
6
6
|
static examples = ['$ lps project switch'];
|
|
7
7
|
async run() {
|
|
8
8
|
await this.parse(Switch);
|
|
@@ -10,11 +10,30 @@ export default class Switch extends Command {
|
|
|
10
10
|
if (projects.length === 0) {
|
|
11
11
|
this.error('No projects configured. Run `lps project config` first.');
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const { id: projectId, name: projectName } = await this.resolveProject(projects);
|
|
14
|
+
const envName = await this.resolveEnvironment(projectId, projectName);
|
|
15
|
+
configManager.setCurrent(projectId, envName);
|
|
16
|
+
this.log(`✓ Switched to "${projectName}/${envName}"`);
|
|
17
|
+
}
|
|
18
|
+
async resolveEnvironment(projectId, projectName) {
|
|
19
|
+
const envs = configManager.listEnvironments(projectId);
|
|
20
|
+
if (envs.length === 0) {
|
|
21
|
+
this.error(`No environments configured for "${projectName}". Run \`lps project config\` first.`);
|
|
17
22
|
}
|
|
23
|
+
if (envs.length === 1)
|
|
24
|
+
return envs[0].name;
|
|
25
|
+
return select({
|
|
26
|
+
choices: envs.map((env) => ({
|
|
27
|
+
name: `${env.isCurrent ? '●' : '○'} ${env.name.padEnd(20)} ${env.url}${env.isCurrent ? ' [current]' : ''}`,
|
|
28
|
+
value: env.name,
|
|
29
|
+
})),
|
|
30
|
+
default: envs.find((env) => env.isCurrent)?.name,
|
|
31
|
+
message: `Select environment for "${projectName}"`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async resolveProject(projects) {
|
|
35
|
+
if (projects.length === 1)
|
|
36
|
+
return { id: projects[0].id, name: projects[0].name };
|
|
18
37
|
const chosen = await select({
|
|
19
38
|
choices: projects.map((project) => {
|
|
20
39
|
const envCount = Object.keys(project.environments).length;
|
|
@@ -22,13 +41,13 @@ export default class Switch extends Command {
|
|
|
22
41
|
const currentMarker = project.isCurrent ? ' [current]' : '';
|
|
23
42
|
return {
|
|
24
43
|
name: `${project.isCurrent ? '●' : '○'} ${project.name.padEnd(20)} (${envLabel})${currentMarker}`,
|
|
25
|
-
value: project.
|
|
44
|
+
value: project.id,
|
|
26
45
|
};
|
|
27
46
|
}),
|
|
28
|
-
default: projects.find((
|
|
47
|
+
default: projects.find((project) => project.isCurrent)?.id,
|
|
29
48
|
message: 'Select active project',
|
|
30
49
|
});
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
const project = projects.find((p) => p.id === chosen);
|
|
51
|
+
return { id: project.id, name: project.name };
|
|
33
52
|
}
|
|
34
53
|
}
|
|
@@ -5,9 +5,9 @@ import { getSnippetPlugin } from '../../utils/snippet-plugin.js';
|
|
|
5
5
|
export default class List extends LoopressCommand {
|
|
6
6
|
static description = 'List snippets from WordPress';
|
|
7
7
|
static examples = [
|
|
8
|
-
'$ lps
|
|
9
|
-
'$ lps
|
|
10
|
-
'$ lps
|
|
8
|
+
'$ lps snippet list',
|
|
9
|
+
'$ lps snippet list --url http://example.com',
|
|
10
|
+
'$ lps snippet list --plugin wpcode',
|
|
11
11
|
];
|
|
12
12
|
static flags = {
|
|
13
13
|
...LoopressCommand.baseFlags,
|
|
@@ -9,7 +9,7 @@ export default class Pull extends LoopressCommand {
|
|
|
9
9
|
static description: string;
|
|
10
10
|
static examples: string[];
|
|
11
11
|
static flags: {
|
|
12
|
-
|
|
12
|
+
'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
13
|
plugin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
14
|
password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
15
|
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -35,14 +35,14 @@ export default class Pull extends LoopressCommand {
|
|
|
35
35
|
};
|
|
36
36
|
static description = 'Pull snippets from WordPress';
|
|
37
37
|
static examples = [
|
|
38
|
-
'$ lps
|
|
39
|
-
'$ lps
|
|
40
|
-
'$ lps
|
|
41
|
-
'$ lps
|
|
38
|
+
'$ lps snippet pull',
|
|
39
|
+
'$ lps snippet pull --url http://example.com',
|
|
40
|
+
'$ lps snippet pull --path ./snippets',
|
|
41
|
+
'$ lps snippet pull --plugin wpcode',
|
|
42
42
|
];
|
|
43
43
|
static flags = {
|
|
44
44
|
...LoopressCommand.baseFlags,
|
|
45
|
-
|
|
45
|
+
'dry-run': Flags.boolean({ char: 'd', description: 'Show what would be written without making changes' }),
|
|
46
46
|
plugin: Flags.string({
|
|
47
47
|
char: 'p',
|
|
48
48
|
description: 'WordPress snippet plugin to target (overrides loopress.json)',
|
|
@@ -51,7 +51,8 @@ export default class Pull extends LoopressCommand {
|
|
|
51
51
|
};
|
|
52
52
|
async run() {
|
|
53
53
|
const { args, flags } = await this.parse(Pull);
|
|
54
|
-
const
|
|
54
|
+
const dryRun = flags['dry-run'];
|
|
55
|
+
const { plugin } = flags;
|
|
55
56
|
const { url } = this.siteConfig;
|
|
56
57
|
const path = await this.resolveSnippetsPath(args.path);
|
|
57
58
|
const resolvedPlugin = await this.resolveSnippetPlugin(plugin);
|
|
@@ -6,14 +6,14 @@ export default class Push extends PushCommand {
|
|
|
6
6
|
static description: string;
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
|
-
|
|
9
|
+
'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
plugin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
13
|
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
14
|
};
|
|
15
15
|
run(): Promise<void>;
|
|
16
|
-
private
|
|
16
|
+
private ensureCanonicalFilename;
|
|
17
17
|
private loadSnippets;
|
|
18
18
|
private pushSnippet;
|
|
19
19
|
}
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import got from 'got';
|
|
3
|
+
import { basename, dirname, extname, join } from 'node:path';
|
|
4
|
+
import slugify from 'slugify';
|
|
3
5
|
import { PushCommand } from '../../lib/push-command.js';
|
|
4
|
-
import { getSnippetPlugin } from '../../utils/snippet-plugin.js';
|
|
6
|
+
import { getSnippetPlugin, parseType } from '../../utils/snippet-plugin.js';
|
|
7
|
+
const TYPE_BY_EXTENSION = {
|
|
8
|
+
'.css': 'css',
|
|
9
|
+
'.html': 'html',
|
|
10
|
+
'.js': 'js',
|
|
11
|
+
'.php': 'php',
|
|
12
|
+
'.txt': 'text',
|
|
13
|
+
};
|
|
5
14
|
export default class Push extends PushCommand {
|
|
6
15
|
static args = {
|
|
7
16
|
path: Args.string({ description: 'Path to snippets directory (overrides project config)' }),
|
|
8
17
|
};
|
|
9
|
-
static description = 'Push snippets to WordPress';
|
|
18
|
+
static description = 'Push snippets to WordPress. Local snippet files created or updated remotely are renamed on disk to the `<id>-<slug>` convention.';
|
|
10
19
|
static examples = [
|
|
11
|
-
'$ lps
|
|
12
|
-
'$ lps
|
|
13
|
-
'$ lps
|
|
14
|
-
'$ lps
|
|
20
|
+
'$ lps snippet push',
|
|
21
|
+
'$ lps snippet push --url http://example.com',
|
|
22
|
+
'$ lps snippet push --path ./snippets',
|
|
23
|
+
'$ lps snippet push --plugin wpcode',
|
|
15
24
|
];
|
|
16
25
|
static flags = {
|
|
17
26
|
...PushCommand.baseFlags,
|
|
18
|
-
|
|
27
|
+
'dry-run': Flags.boolean({ char: 'd', description: 'Show what would change without making changes' }),
|
|
19
28
|
plugin: Flags.string({
|
|
20
29
|
char: 'p',
|
|
21
30
|
description: 'WordPress snippet plugin to target (overrides loopress.json)',
|
|
@@ -24,7 +33,8 @@ export default class Push extends PushCommand {
|
|
|
24
33
|
};
|
|
25
34
|
async run() {
|
|
26
35
|
const { args, flags } = await this.parse(Push);
|
|
27
|
-
const
|
|
36
|
+
const dryRun = flags['dry-run'];
|
|
37
|
+
const { plugin } = flags;
|
|
28
38
|
this.dryRun = dryRun;
|
|
29
39
|
const { url } = this.siteConfig;
|
|
30
40
|
const path = await this.resolveSnippetsPath(args.path);
|
|
@@ -48,12 +58,19 @@ export default class Push extends PushCommand {
|
|
|
48
58
|
this.error(error.message);
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
|
-
|
|
61
|
+
// Renames the local file pair to the `<id>-<slug>` convention used by `snippet pull` whenever
|
|
62
|
+
// it doesn't already match (e.g. a hand-created `demo.php` with no id, or a stale slug after a rename).
|
|
63
|
+
// This is a side effect of `push`: local files on disk are renamed, not just the remote snippet.
|
|
64
|
+
async ensureCanonicalFilename(snippet, id, name) {
|
|
52
65
|
const fs = await import('node:fs/promises');
|
|
53
|
-
const
|
|
66
|
+
const dir = dirname(snippet.path);
|
|
67
|
+
const ext = extname(snippet.path);
|
|
68
|
+
const currentBase = basename(snippet.path, ext);
|
|
69
|
+
const canonicalBase = `${id}-${slugify(name, { lower: true, strict: true })}`;
|
|
70
|
+
const oldMetaPath = join(dir, `${currentBase}.json`);
|
|
54
71
|
let meta = {};
|
|
55
72
|
try {
|
|
56
|
-
const existing = await fs.readFile(
|
|
73
|
+
const existing = await fs.readFile(oldMetaPath, 'utf8');
|
|
57
74
|
meta = JSON.parse(existing);
|
|
58
75
|
}
|
|
59
76
|
catch (error) {
|
|
@@ -61,12 +78,23 @@ export default class Push extends PushCommand {
|
|
|
61
78
|
throw error;
|
|
62
79
|
}
|
|
63
80
|
meta.id = id;
|
|
64
|
-
|
|
81
|
+
meta.name = name;
|
|
82
|
+
if (currentBase === canonicalBase) {
|
|
83
|
+
await fs.writeFile(oldMetaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const newPath = join(dir, `${canonicalBase}${ext}`);
|
|
87
|
+
const newMetaPath = join(dir, `${canonicalBase}.json`);
|
|
88
|
+
await fs.rename(snippet.path, newPath);
|
|
89
|
+
await fs.writeFile(newMetaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
90
|
+
if (oldMetaPath !== newMetaPath)
|
|
91
|
+
await fs.rm(oldMetaPath, { force: true });
|
|
92
|
+
this.log(`📁 Renamed: ${snippet.path} → ${newPath}`);
|
|
65
93
|
}
|
|
66
94
|
async loadSnippets(path) {
|
|
67
95
|
const fs = await import('node:fs/promises');
|
|
68
96
|
const snippets = [];
|
|
69
|
-
const SNIPPET_EXTENSIONS = new Set(
|
|
97
|
+
const SNIPPET_EXTENSIONS = new Set(Object.keys(TYPE_BY_EXTENSION));
|
|
70
98
|
try {
|
|
71
99
|
const files = await fs.readdir(path);
|
|
72
100
|
for (const file of files) {
|
|
@@ -78,11 +106,13 @@ export default class Push extends PushCommand {
|
|
|
78
106
|
const content = await fs.readFile(filePath, 'utf8');
|
|
79
107
|
let id;
|
|
80
108
|
let name;
|
|
109
|
+
let type;
|
|
81
110
|
try {
|
|
82
111
|
const metaContent = await fs.readFile(metaPath, 'utf8');
|
|
83
112
|
const meta = JSON.parse(metaContent);
|
|
84
113
|
id = meta.id ? Number(meta.id) : undefined;
|
|
85
114
|
name = meta.name ? String(meta.name) : undefined;
|
|
115
|
+
type = parseType(meta.type) ?? undefined;
|
|
86
116
|
}
|
|
87
117
|
catch (error) {
|
|
88
118
|
if (error.code !== 'ENOENT')
|
|
@@ -93,6 +123,7 @@ export default class Push extends PushCommand {
|
|
|
93
123
|
id,
|
|
94
124
|
name: name ?? file.slice(0, file.lastIndexOf('.')),
|
|
95
125
|
path: filePath,
|
|
126
|
+
type: type ?? TYPE_BY_EXTENSION[ext] ?? 'php',
|
|
96
127
|
});
|
|
97
128
|
}
|
|
98
129
|
}
|
|
@@ -110,18 +141,19 @@ export default class Push extends PushCommand {
|
|
|
110
141
|
}
|
|
111
142
|
try {
|
|
112
143
|
const endpoint = adapter.endpoint(url);
|
|
113
|
-
const payload = adapter.toPayload(snippet.name, snippet.code, snippet.path);
|
|
144
|
+
const payload = adapter.toPayload(snippet.name, snippet.code, snippet.path, snippet.type);
|
|
114
145
|
if (snippet.id) {
|
|
115
146
|
this.log(`🔄 Updating snippet by id (${snippet.id}): ${snippet.name}`);
|
|
116
147
|
await got.put(`${endpoint}/${snippet.id}`, { headers, json: payload });
|
|
117
148
|
this.log(`✅ Updated: ${snippet.name}`);
|
|
149
|
+
await this.ensureCanonicalFilename(snippet, snippet.id, snippet.name);
|
|
118
150
|
return;
|
|
119
151
|
}
|
|
120
152
|
this.log(`➕ Creating new snippet: ${snippet.name}`);
|
|
121
153
|
const response = await got.post(endpoint, { headers, json: payload }).json();
|
|
122
154
|
const created = adapter.fromRemote(response);
|
|
123
|
-
await this.injectIdIntoMeta(snippet.path, created.id);
|
|
124
155
|
this.log(`✅ Created: ${snippet.name} (id: ${created.id})`);
|
|
156
|
+
await this.ensureCanonicalFilename(snippet, created.id, created.name);
|
|
125
157
|
}
|
|
126
158
|
catch (error) {
|
|
127
159
|
this.error(`❌ Error pushing snippet ${snippet.name}: ${error.message}`);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
export default class
|
|
2
|
+
export default class Status extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
run(): Promise<void>;
|
|
6
|
+
private reportActiveProject;
|
|
7
|
+
private reportPinnedProject;
|
|
6
8
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Command, ux } from '@oclif/core';
|
|
2
|
+
import { configManager } from '../config/project-config.manager.js';
|
|
3
|
+
import { readLocalConfig } from '../utils/loopress-config.js';
|
|
4
|
+
const c = ux.colorize;
|
|
5
|
+
export default class Status extends Command {
|
|
6
|
+
static description = 'Show which WordPress project and environment commands will target';
|
|
7
|
+
static examples = ['$ lps status'];
|
|
8
|
+
async run() {
|
|
9
|
+
await this.parse(Status);
|
|
10
|
+
const localConfig = await readLocalConfig();
|
|
11
|
+
if (localConfig.projectId) {
|
|
12
|
+
this.reportPinnedProject(localConfig.projectId);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
this.reportActiveProject();
|
|
16
|
+
}
|
|
17
|
+
reportActiveProject() {
|
|
18
|
+
const env = configManager.getCurrentEnv();
|
|
19
|
+
if (!env) {
|
|
20
|
+
this.log('No project configured. Run `lps project config` first.');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const project = configManager.getCurrentProject();
|
|
24
|
+
if (!project) {
|
|
25
|
+
this.log('No project configured. Run `lps project config` first.');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.log(`Project: ${project.name} (${env.name})`);
|
|
29
|
+
this.log(`URL: ${env.url}`);
|
|
30
|
+
}
|
|
31
|
+
reportPinnedProject(projectId) {
|
|
32
|
+
const project = configManager.getProject(projectId);
|
|
33
|
+
if (!project) {
|
|
34
|
+
this.log(`loopress.json pins project "${projectId}", but it no longer exists.`);
|
|
35
|
+
this.log('Run `lps project config` to configure it.');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const envNames = Object.keys(project.environments);
|
|
39
|
+
if (envNames.length === 0) {
|
|
40
|
+
this.log(`Project: ${project.name}`);
|
|
41
|
+
this.log('No environments configured for this project. Run `lps project config` to add one.');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (envNames.length === 1) {
|
|
45
|
+
const env = project.environments[envNames[0]];
|
|
46
|
+
this.log(`Project: ${project.name} (${env.name})`);
|
|
47
|
+
this.log(`URL: ${env.url}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const current = configManager.getCurrentProject();
|
|
51
|
+
const currentEnv = current?.id === projectId ? configManager.getCurrentEnv() : null;
|
|
52
|
+
if (!currentEnv) {
|
|
53
|
+
this.log(`Project: ${project.name} ${c('yellow', '(ambiguous)')}`);
|
|
54
|
+
this.log(`Environments: ${envNames.join(', ')}`);
|
|
55
|
+
this.log('');
|
|
56
|
+
this.warn(`"${project.name}" has multiple environments and isn't the globally active project.`);
|
|
57
|
+
this.log('Run `lps project switch` to pick one before running commands here.');
|
|
58
|
+
if (current) {
|
|
59
|
+
this.log(`(Globally active project right now: "${current.name}")`);
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
this.log(`Project: ${project.name} (${currentEnv.name})`);
|
|
64
|
+
this.log(`URL: ${currentEnv.url}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -4,25 +4,32 @@ export declare class ProjectConfigManager {
|
|
|
4
4
|
private static instance;
|
|
5
5
|
constructor(homeDir?: string);
|
|
6
6
|
static getInstance(): ProjectConfigManager;
|
|
7
|
+
createProjectId(): string;
|
|
7
8
|
ensureConfigDir(): void;
|
|
8
9
|
getConfigFilePath(): string;
|
|
9
10
|
getCurrentEnv(): EnvironmentConfig | null;
|
|
10
|
-
getCurrentProject(): null | ProjectConfig
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
getCurrentProject(): null | (ProjectConfig & {
|
|
12
|
+
id: string;
|
|
13
|
+
});
|
|
14
|
+
getEnvironment(projectId: string, envName: string): EnvironmentConfig | null;
|
|
15
|
+
getProject(id: string): null | ProjectConfig;
|
|
16
|
+
listEnvironments(projectId: string): Array<EnvironmentConfig & {
|
|
14
17
|
isCurrent: boolean;
|
|
15
18
|
}>;
|
|
16
19
|
listProjects(): Array<ProjectConfig & {
|
|
20
|
+
id: string;
|
|
17
21
|
isCurrent: boolean;
|
|
18
22
|
}>;
|
|
19
23
|
readConfig(): LoopressConfig;
|
|
20
|
-
removeEnvironment(
|
|
21
|
-
removeProject(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
setProject(name: string, project: ProjectConfig): void;
|
|
24
|
+
removeEnvironment(projectId: string, envName: string): void;
|
|
25
|
+
removeProject(id: string): void;
|
|
26
|
+
setCurrent(projectId: string, envName: string): void;
|
|
27
|
+
setEnvironment(projectId: string, envName: string, env: EnvironmentConfig): void;
|
|
28
|
+
setProject(id: string, project: ProjectConfig): void;
|
|
26
29
|
writeConfig(config: LoopressConfig): void;
|
|
30
|
+
private isProjectConfig;
|
|
31
|
+
private sanitizeConfig;
|
|
32
|
+
private sanitizeCurrentProject;
|
|
33
|
+
private sanitizeProjects;
|
|
27
34
|
}
|
|
28
35
|
export declare const configManager: ProjectConfigManager;
|