@loopress/cli 0.4.0 â 0.5.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 +37 -75
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.js +73 -0
- package/dist/commands/plugin/push.d.ts +2 -2
- package/dist/commands/plugin/push.js +5 -3
- package/dist/commands/project/config.js +2 -2
- package/dist/commands/snippet/list.d.ts +1 -1
- package/dist/commands/snippet/list.js +3 -3
- package/dist/commands/snippet/pull.d.ts +4 -1
- package/dist/commands/snippet/pull.js +26 -37
- package/dist/commands/snippet/push.d.ts +4 -5
- package/dist/commands/snippet/push.js +50 -39
- package/dist/config/auth.manager.js +2 -2
- package/dist/config/project-config.manager.js +2 -2
- package/dist/lib/base.d.ts +1 -1
- package/dist/lib/base.js +18 -6
- package/dist/lib/push-command.d.ts +7 -0
- package/dist/lib/push-command.js +32 -0
- package/dist/utils/loopress-config.d.ts +3 -2
- package/dist/utils/snippet-plugin.js +1 -1
- package/oclif.manifest.json +27 -123
- package/package.json +13 -17
- package/dist/commands/style/pull.d.ts +0 -12
- package/dist/commands/style/pull.js +0 -52
- package/dist/commands/style/push.d.ts +0 -13
- package/dist/commands/style/push.js +0 -78
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @loopress/cli
|
|
|
20
20
|
$ lps COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ lps (--version)
|
|
23
|
-
@loopress/cli/0.
|
|
23
|
+
@loopress/cli/0.5.0 linux-x64 node-v24.17.0
|
|
24
24
|
$ lps --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ lps COMMAND
|
|
@@ -32,6 +32,7 @@ USAGE
|
|
|
32
32
|
|
|
33
33
|
<!-- commands -->
|
|
34
34
|
* [`lps help [COMMAND]`](#lps-help-command)
|
|
35
|
+
* [`lps init`](#lps-init)
|
|
35
36
|
* [`lps login`](#lps-login)
|
|
36
37
|
* [`lps logout`](#lps-logout)
|
|
37
38
|
* [`lps plugin pull`](#lps-plugin-pull)
|
|
@@ -46,8 +47,6 @@ USAGE
|
|
|
46
47
|
* [`lps snippet list`](#lps-snippet-list)
|
|
47
48
|
* [`lps snippet pull [PATH]`](#lps-snippet-pull-path)
|
|
48
49
|
* [`lps snippet push [PATH]`](#lps-snippet-push-path)
|
|
49
|
-
* [`lps style pull`](#lps-style-pull)
|
|
50
|
-
* [`lps style push`](#lps-style-push)
|
|
51
50
|
|
|
52
51
|
## `lps help [COMMAND]`
|
|
53
52
|
|
|
@@ -67,7 +66,24 @@ DESCRIPTION
|
|
|
67
66
|
Display help for lps.
|
|
68
67
|
```
|
|
69
68
|
|
|
70
|
-
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.
|
|
69
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.52/src/commands/help.ts)_
|
|
70
|
+
|
|
71
|
+
## `lps init`
|
|
72
|
+
|
|
73
|
+
Initialize a loopress.json config file in the current directory
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
USAGE
|
|
77
|
+
$ lps init
|
|
78
|
+
|
|
79
|
+
DESCRIPTION
|
|
80
|
+
Initialize a loopress.json config file in the current directory
|
|
81
|
+
|
|
82
|
+
EXAMPLES
|
|
83
|
+
$ lps init
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
_See code: [src/commands/init.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/init.ts)_
|
|
71
87
|
|
|
72
88
|
## `lps login`
|
|
73
89
|
|
|
@@ -84,7 +100,7 @@ EXAMPLES
|
|
|
84
100
|
$ lps login
|
|
85
101
|
```
|
|
86
102
|
|
|
87
|
-
_See code: [src/commands/login.ts](https://github.com/loopress/loopress/blob/v0.
|
|
103
|
+
_See code: [src/commands/login.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/login.ts)_
|
|
88
104
|
|
|
89
105
|
## `lps logout`
|
|
90
106
|
|
|
@@ -101,7 +117,7 @@ EXAMPLES
|
|
|
101
117
|
$ lps logout
|
|
102
118
|
```
|
|
103
119
|
|
|
104
|
-
_See code: [src/commands/logout.ts](https://github.com/loopress/loopress/blob/v0.
|
|
120
|
+
_See code: [src/commands/logout.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/logout.ts)_
|
|
105
121
|
|
|
106
122
|
## `lps plugin pull`
|
|
107
123
|
|
|
@@ -128,7 +144,7 @@ EXAMPLES
|
|
|
128
144
|
$ lps plugins pull --dry-run
|
|
129
145
|
```
|
|
130
146
|
|
|
131
|
-
_See code: [src/commands/plugin/pull.ts](https://github.com/loopress/loopress/blob/v0.
|
|
147
|
+
_See code: [src/commands/plugin/pull.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/plugin/pull.ts)_
|
|
132
148
|
|
|
133
149
|
## `lps plugin push`
|
|
134
150
|
|
|
@@ -155,7 +171,7 @@ EXAMPLES
|
|
|
155
171
|
$ lps plugins push --dry-run
|
|
156
172
|
```
|
|
157
173
|
|
|
158
|
-
_See code: [src/commands/plugin/push.ts](https://github.com/loopress/loopress/blob/v0.
|
|
174
|
+
_See code: [src/commands/plugin/push.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/plugin/push.ts)_
|
|
159
175
|
|
|
160
176
|
## `lps plugin require SLUG [VERSION]`
|
|
161
177
|
|
|
@@ -188,7 +204,7 @@ EXAMPLES
|
|
|
188
204
|
$ lps plugins require contact-form-7 --dry-run
|
|
189
205
|
```
|
|
190
206
|
|
|
191
|
-
_See code: [src/commands/plugin/require.ts](https://github.com/loopress/loopress/blob/v0.
|
|
207
|
+
_See code: [src/commands/plugin/require.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/plugin/require.ts)_
|
|
192
208
|
|
|
193
209
|
## `lps project config`
|
|
194
210
|
|
|
@@ -205,7 +221,7 @@ EXAMPLES
|
|
|
205
221
|
$ lps project config
|
|
206
222
|
```
|
|
207
223
|
|
|
208
|
-
_See code: [src/commands/project/config.ts](https://github.com/loopress/loopress/blob/v0.
|
|
224
|
+
_See code: [src/commands/project/config.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/project/config.ts)_
|
|
209
225
|
|
|
210
226
|
## `lps project list`
|
|
211
227
|
|
|
@@ -222,7 +238,7 @@ EXAMPLES
|
|
|
222
238
|
$ lps project list
|
|
223
239
|
```
|
|
224
240
|
|
|
225
|
-
_See code: [src/commands/project/list.ts](https://github.com/loopress/loopress/blob/v0.
|
|
241
|
+
_See code: [src/commands/project/list.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/project/list.ts)_
|
|
226
242
|
|
|
227
243
|
## `lps project remove`
|
|
228
244
|
|
|
@@ -239,7 +255,7 @@ EXAMPLES
|
|
|
239
255
|
$ lps project remove
|
|
240
256
|
```
|
|
241
257
|
|
|
242
|
-
_See code: [src/commands/project/remove.ts](https://github.com/loopress/loopress/blob/v0.
|
|
258
|
+
_See code: [src/commands/project/remove.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/project/remove.ts)_
|
|
243
259
|
|
|
244
260
|
## `lps project remove-env`
|
|
245
261
|
|
|
@@ -256,7 +272,7 @@ EXAMPLES
|
|
|
256
272
|
$ lps project remove-env
|
|
257
273
|
```
|
|
258
274
|
|
|
259
|
-
_See code: [src/commands/project/remove-env.ts](https://github.com/loopress/loopress/blob/v0.
|
|
275
|
+
_See code: [src/commands/project/remove-env.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/project/remove-env.ts)_
|
|
260
276
|
|
|
261
277
|
## `lps project switch`
|
|
262
278
|
|
|
@@ -273,7 +289,7 @@ EXAMPLES
|
|
|
273
289
|
$ lps project switch
|
|
274
290
|
```
|
|
275
291
|
|
|
276
|
-
_See code: [src/commands/project/switch.ts](https://github.com/loopress/loopress/blob/v0.
|
|
292
|
+
_See code: [src/commands/project/switch.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/project/switch.ts)_
|
|
277
293
|
|
|
278
294
|
## `lps project switch-env`
|
|
279
295
|
|
|
@@ -290,7 +306,7 @@ EXAMPLES
|
|
|
290
306
|
$ lps project switch-env
|
|
291
307
|
```
|
|
292
308
|
|
|
293
|
-
_See code: [src/commands/project/switch-env.ts](https://github.com/loopress/loopress/blob/v0.
|
|
309
|
+
_See code: [src/commands/project/switch-env.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/project/switch-env.ts)_
|
|
294
310
|
|
|
295
311
|
## `lps snippet list`
|
|
296
312
|
|
|
@@ -302,7 +318,7 @@ USAGE
|
|
|
302
318
|
|
|
303
319
|
FLAGS
|
|
304
320
|
-j, --json Output in JSON format
|
|
305
|
-
-p, --plugin=<option>
|
|
321
|
+
-p, --plugin=<option> WordPress snippet plugin to target (overrides loopress.json)
|
|
306
322
|
<options: code-snippets|wpcode>
|
|
307
323
|
|
|
308
324
|
GLOBAL FLAGS
|
|
@@ -321,7 +337,7 @@ EXAMPLES
|
|
|
321
337
|
$ lps snippets list --plugin wpcode
|
|
322
338
|
```
|
|
323
339
|
|
|
324
|
-
_See code: [src/commands/snippet/list.ts](https://github.com/loopress/loopress/blob/v0.
|
|
340
|
+
_See code: [src/commands/snippet/list.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/snippet/list.ts)_
|
|
325
341
|
|
|
326
342
|
## `lps snippet pull [PATH]`
|
|
327
343
|
|
|
@@ -336,7 +352,7 @@ ARGUMENTS
|
|
|
336
352
|
|
|
337
353
|
FLAGS
|
|
338
354
|
-d, --dryRun Dry run - show what would happen without making changes
|
|
339
|
-
-p, --plugin=<option>
|
|
355
|
+
-p, --plugin=<option> WordPress snippet plugin to target (overrides loopress.json)
|
|
340
356
|
<options: code-snippets|wpcode>
|
|
341
357
|
|
|
342
358
|
GLOBAL FLAGS
|
|
@@ -357,7 +373,7 @@ EXAMPLES
|
|
|
357
373
|
$ lps snippets pull --plugin wpcode
|
|
358
374
|
```
|
|
359
375
|
|
|
360
|
-
_See code: [src/commands/snippet/pull.ts](https://github.com/loopress/loopress/blob/v0.
|
|
376
|
+
_See code: [src/commands/snippet/pull.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/snippet/pull.ts)_
|
|
361
377
|
|
|
362
378
|
## `lps snippet push [PATH]`
|
|
363
379
|
|
|
@@ -372,7 +388,7 @@ ARGUMENTS
|
|
|
372
388
|
|
|
373
389
|
FLAGS
|
|
374
390
|
-d, --dryRun Dry run - show what would happen without making changes
|
|
375
|
-
-p, --plugin=<option>
|
|
391
|
+
-p, --plugin=<option> WordPress snippet plugin to target (overrides loopress.json)
|
|
376
392
|
<options: code-snippets|wpcode>
|
|
377
393
|
|
|
378
394
|
GLOBAL FLAGS
|
|
@@ -393,59 +409,5 @@ EXAMPLES
|
|
|
393
409
|
$ lps snippets push --plugin wpcode
|
|
394
410
|
```
|
|
395
411
|
|
|
396
|
-
_See code: [src/commands/snippet/push.ts](https://github.com/loopress/loopress/blob/v0.
|
|
397
|
-
|
|
398
|
-
## `lps style pull`
|
|
399
|
-
|
|
400
|
-
Pull Global Styles from WordPress
|
|
401
|
-
|
|
402
|
-
```
|
|
403
|
-
USAGE
|
|
404
|
-
$ lps style pull [--password <value>] [--url <value>] [--user <value>] [-d]
|
|
405
|
-
|
|
406
|
-
FLAGS
|
|
407
|
-
-d, --dryRun Dry run - show what would happen without making changes
|
|
408
|
-
|
|
409
|
-
GLOBAL FLAGS
|
|
410
|
-
--password=<value> WordPress application password (fallback; prefer `lps project config`)
|
|
411
|
-
--url=<value> WordPress URL (fallback; prefer `lps project config`)
|
|
412
|
-
--user=<value> WordPress username (fallback; prefer `lps project config`)
|
|
413
|
-
|
|
414
|
-
DESCRIPTION
|
|
415
|
-
Pull Global Styles from WordPress
|
|
416
|
-
|
|
417
|
-
EXAMPLES
|
|
418
|
-
$ lps styles pull
|
|
419
|
-
|
|
420
|
-
$ lps styles pull --url http://example.com
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
_See code: [src/commands/style/pull.ts](https://github.com/loopress/loopress/blob/v0.4.0/src/commands/style/pull.ts)_
|
|
424
|
-
|
|
425
|
-
## `lps style push`
|
|
426
|
-
|
|
427
|
-
Push Global Styles to WordPress
|
|
428
|
-
|
|
429
|
-
```
|
|
430
|
-
USAGE
|
|
431
|
-
$ lps style push [--password <value>] [--url <value>] [--user <value>] [-d]
|
|
432
|
-
|
|
433
|
-
FLAGS
|
|
434
|
-
-d, --dryRun Dry run - show what would happen without making changes
|
|
435
|
-
|
|
436
|
-
GLOBAL FLAGS
|
|
437
|
-
--password=<value> WordPress application password (fallback; prefer `lps project config`)
|
|
438
|
-
--url=<value> WordPress URL (fallback; prefer `lps project config`)
|
|
439
|
-
--user=<value> WordPress username (fallback; prefer `lps project config`)
|
|
440
|
-
|
|
441
|
-
DESCRIPTION
|
|
442
|
-
Push Global Styles to WordPress
|
|
443
|
-
|
|
444
|
-
EXAMPLES
|
|
445
|
-
$ lps styles push
|
|
446
|
-
|
|
447
|
-
$ lps styles push --url http://example.com
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
_See code: [src/commands/style/push.ts](https://github.com/loopress/loopress/blob/v0.4.0/src/commands/style/push.ts)_
|
|
412
|
+
_See code: [src/commands/snippet/push.ts](https://github.com/loopress/loopress/blob/v0.5.0/src/commands/snippet/push.ts)_
|
|
451
413
|
<!-- commandsstop -->
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { confirm, input, select } from '@inquirer/prompts';
|
|
2
|
+
import { Command } from '@oclif/core';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { configManager } from '../config/project-config.manager.js';
|
|
6
|
+
import { writeLocalConfig } from '../utils/loopress-config.js';
|
|
7
|
+
export default class Init extends Command {
|
|
8
|
+
static description = 'Initialize a loopress.json config file in the current directory';
|
|
9
|
+
static examples = ['$ lps init'];
|
|
10
|
+
async run() {
|
|
11
|
+
await this.parse(Init);
|
|
12
|
+
const configPath = join(process.cwd(), 'loopress.json');
|
|
13
|
+
if (existsSync(configPath)) {
|
|
14
|
+
const overwrite = await confirm({
|
|
15
|
+
default: false,
|
|
16
|
+
message: 'loopress.json already exists. Overwrite?',
|
|
17
|
+
});
|
|
18
|
+
if (!overwrite) {
|
|
19
|
+
this.log('Aborted.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const projects = configManager.listProjects();
|
|
24
|
+
let projectId;
|
|
25
|
+
if (projects.length > 0) {
|
|
26
|
+
const choices = [
|
|
27
|
+
...projects.map((p) => ({ name: p.name, value: p.name })),
|
|
28
|
+
{ name: 'Enter a project ID manually', value: '__manual__' },
|
|
29
|
+
];
|
|
30
|
+
const choice = await select({
|
|
31
|
+
choices,
|
|
32
|
+
message: 'WordPress project',
|
|
33
|
+
});
|
|
34
|
+
projectId = choice === '__manual__' ? (await input({
|
|
35
|
+
message: 'Project ID',
|
|
36
|
+
validate: (value) => (value.trim().length > 0 ? true : 'Project ID cannot be empty'),
|
|
37
|
+
})) : choice;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.log('No projects configured yet. Run `lps project config` to add one first.');
|
|
41
|
+
projectId = await input({
|
|
42
|
+
message: 'Project ID',
|
|
43
|
+
validate: (value) => (value.trim().length > 0 ? true : 'Project ID cannot be empty'),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const snippetPlugin = await select({
|
|
47
|
+
choices: [
|
|
48
|
+
{ name: 'WPCode', value: 'wpcode' },
|
|
49
|
+
{ name: 'Code Snippets', value: 'code-snippets' },
|
|
50
|
+
],
|
|
51
|
+
message: 'Snippet plugin',
|
|
52
|
+
});
|
|
53
|
+
const rootDir = await input({
|
|
54
|
+
default: '.',
|
|
55
|
+
message: 'Root directory',
|
|
56
|
+
});
|
|
57
|
+
const snippetsDir = await input({
|
|
58
|
+
default: 'snippets',
|
|
59
|
+
message: 'Snippets directory (relative to root)',
|
|
60
|
+
});
|
|
61
|
+
const config = {
|
|
62
|
+
projectId,
|
|
63
|
+
rootDir,
|
|
64
|
+
snippetPlugin: snippetPlugin,
|
|
65
|
+
snippetsDir,
|
|
66
|
+
};
|
|
67
|
+
await writeLocalConfig(config);
|
|
68
|
+
this.log(`\nâ loopress.json created`);
|
|
69
|
+
this.log(` Project: ${projectId}`);
|
|
70
|
+
this.log(` Plugin: ${snippetPlugin}`);
|
|
71
|
+
this.log(` Snippets: ${join(rootDir, snippetsDir)}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class Push extends
|
|
1
|
+
import { PushCommand } from '../../lib/push-command.js';
|
|
2
|
+
export default class Push extends PushCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { Flags } from '@oclif/core';
|
|
3
3
|
import got from 'got';
|
|
4
|
-
import {
|
|
4
|
+
import { PushCommand } from '../../lib/push-command.js';
|
|
5
5
|
import { readLocalConfig } from '../../utils/loopress-config.js';
|
|
6
6
|
import { diffPlugins } from '../../utils/plugins.js';
|
|
7
|
-
export default class Push extends
|
|
7
|
+
export default class Push extends PushCommand {
|
|
8
8
|
static description = 'Sync plugins on WordPress to match loopress.json';
|
|
9
9
|
static examples = ['$ lps plugins push', '$ lps plugins push --dry-run'];
|
|
10
10
|
static flags = {
|
|
11
|
-
...
|
|
11
|
+
...PushCommand.baseFlags,
|
|
12
12
|
'dry-run': Flags.boolean({ char: 'd', description: 'Show what would change without making changes' }),
|
|
13
13
|
};
|
|
14
14
|
async run() {
|
|
15
15
|
const { flags } = await this.parse(Push);
|
|
16
16
|
const dryRun = flags['dry-run'];
|
|
17
|
+
this.dryRun = dryRun;
|
|
17
18
|
const { url } = this.siteConfig;
|
|
18
19
|
const localConfig = await readLocalConfig();
|
|
19
20
|
const manifest = localConfig.plugins;
|
|
@@ -96,6 +97,7 @@ export default class Push extends LoopressCommand {
|
|
|
96
97
|
}
|
|
97
98
|
await this.activatePlugin(url, headers, action.slug);
|
|
98
99
|
}
|
|
100
|
+
await this.recordSuccess();
|
|
99
101
|
}
|
|
100
102
|
async activatePlugin(url, headers, slug) {
|
|
101
103
|
try {
|
|
@@ -17,9 +17,9 @@ export default class Config extends Command {
|
|
|
17
17
|
});
|
|
18
18
|
const envChoice = await select({
|
|
19
19
|
choices: [
|
|
20
|
-
{ name: '
|
|
20
|
+
{ name: 'local', value: 'local' },
|
|
21
21
|
{ name: 'staging', value: 'staging' },
|
|
22
|
-
{ name: '
|
|
22
|
+
{ name: 'production', value: 'production' },
|
|
23
23
|
{ name: 'CustomâĻ', value: '__custom__' },
|
|
24
24
|
],
|
|
25
25
|
message: 'Environment',
|
|
@@ -4,7 +4,7 @@ export default class List extends LoopressCommand {
|
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
6
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
-
plugin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
plugin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -14,8 +14,7 @@ export default class List extends LoopressCommand {
|
|
|
14
14
|
json: Flags.boolean({ char: 'j', description: 'Output in JSON format' }),
|
|
15
15
|
plugin: Flags.string({
|
|
16
16
|
char: 'p',
|
|
17
|
-
|
|
18
|
-
description: 'WordPress snippet plugin to target',
|
|
17
|
+
description: 'WordPress snippet plugin to target (overrides loopress.json)',
|
|
19
18
|
options: ['code-snippets', 'wpcode'],
|
|
20
19
|
}),
|
|
21
20
|
};
|
|
@@ -23,8 +22,9 @@ export default class List extends LoopressCommand {
|
|
|
23
22
|
const { flags } = await this.parse(List);
|
|
24
23
|
const { json, plugin } = flags;
|
|
25
24
|
const { url } = this.siteConfig;
|
|
25
|
+
const resolvedPlugin = await this.resolveSnippetPlugin(plugin);
|
|
26
26
|
try {
|
|
27
|
-
const adapter = getSnippetPlugin(
|
|
27
|
+
const adapter = getSnippetPlugin(resolvedPlugin);
|
|
28
28
|
const endpoint = adapter.endpoint(url);
|
|
29
29
|
const headers = await this.buildAuthHeaders();
|
|
30
30
|
const remoteList = await got.get(endpoint, { headers }).json();
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { LoopressCommand } from '../../lib/base.js';
|
|
2
|
+
import { NormalizedSnippet } from '../../utils/snippet-plugin.js';
|
|
3
|
+
export declare function buildSnippetFile(snippet: NormalizedSnippet): string;
|
|
4
|
+
export declare function buildMetaFile(snippet: NormalizedSnippet): string;
|
|
2
5
|
export default class Pull extends LoopressCommand {
|
|
3
6
|
static args: {
|
|
4
7
|
path: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
@@ -7,7 +10,7 @@ export default class Pull extends LoopressCommand {
|
|
|
7
10
|
static examples: string[];
|
|
8
11
|
static flags: {
|
|
9
12
|
dryRun: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
-
plugin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
plugin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
14
|
password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
15
|
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
16
|
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -10,39 +10,24 @@ const EXTENSIONS = {
|
|
|
10
10
|
php: 'php',
|
|
11
11
|
text: 'txt',
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
`id: ${snippet.id}`,
|
|
17
|
-
`name: ${sanitize(snippet.name)}`,
|
|
18
|
-
...(snippet.description ? [`description: ${sanitize(snippet.description)}`] : []),
|
|
19
|
-
`type: ${snippet.type}`,
|
|
20
|
-
...(snippet.tags.length > 0 ? [`tags: ${snippet.tags.map((t) => sanitize(t)).join(', ')}`] : []),
|
|
21
|
-
`active: ${snippet.active}`,
|
|
22
|
-
];
|
|
23
|
-
}
|
|
24
|
-
function buildSnippetFile(snippet) {
|
|
25
|
-
const meta = buildMetaLines(snippet);
|
|
26
|
-
switch (snippet.type) {
|
|
27
|
-
case 'css':
|
|
28
|
-
case 'js': {
|
|
29
|
-
const header = ['/**', ...meta.map((l) => ` * ${l}`), ' */'].join('\n');
|
|
30
|
-
return `${header}\n\n${snippet.code}`;
|
|
31
|
-
}
|
|
32
|
-
case 'html': {
|
|
33
|
-
const header = ['<!--', ...meta.map((l) => ` ${l}`), '-->'].join('\n');
|
|
34
|
-
return `${header}\n\n${snippet.code}`;
|
|
35
|
-
}
|
|
36
|
-
case 'text': {
|
|
37
|
-
return snippet.code;
|
|
38
|
-
}
|
|
39
|
-
case 'php':
|
|
40
|
-
default: {
|
|
41
|
-
const header = ['<?php', '/**', ...meta.map((l) => ` * ${l}`), ' */'].join('\n');
|
|
42
|
-
const body = snippet.code.replace(/^<\?php\s*/i, '');
|
|
43
|
-
return `${header}\n\n${body}`;
|
|
44
|
-
}
|
|
13
|
+
export function buildSnippetFile(snippet) {
|
|
14
|
+
if (snippet.type === 'php' && !snippet.code.trimStart().startsWith('<?')) {
|
|
15
|
+
return `<?php\n\n${snippet.code}`;
|
|
45
16
|
}
|
|
17
|
+
return snippet.code;
|
|
18
|
+
}
|
|
19
|
+
export function buildMetaFile(snippet) {
|
|
20
|
+
const meta = {
|
|
21
|
+
id: snippet.id,
|
|
22
|
+
name: snippet.name,
|
|
23
|
+
type: snippet.type,
|
|
24
|
+
active: snippet.active,
|
|
25
|
+
};
|
|
26
|
+
if (snippet.description)
|
|
27
|
+
meta.description = snippet.description;
|
|
28
|
+
if (snippet.tags.length > 0)
|
|
29
|
+
meta.tags = snippet.tags;
|
|
30
|
+
return JSON.stringify(meta, null, 2) + '\n';
|
|
46
31
|
}
|
|
47
32
|
export default class Pull extends LoopressCommand {
|
|
48
33
|
static args = {
|
|
@@ -60,8 +45,7 @@ export default class Pull extends LoopressCommand {
|
|
|
60
45
|
dryRun: Flags.boolean({ char: 'd', description: 'Dry run - show what would happen without making changes' }),
|
|
61
46
|
plugin: Flags.string({
|
|
62
47
|
char: 'p',
|
|
63
|
-
|
|
64
|
-
description: 'WordPress snippet plugin to target',
|
|
48
|
+
description: 'WordPress snippet plugin to target (overrides loopress.json)',
|
|
65
49
|
options: ['code-snippets', 'wpcode'],
|
|
66
50
|
}),
|
|
67
51
|
};
|
|
@@ -70,11 +54,12 @@ export default class Pull extends LoopressCommand {
|
|
|
70
54
|
const { dryRun, plugin } = flags;
|
|
71
55
|
const { url } = this.siteConfig;
|
|
72
56
|
const path = await this.resolveSnippetsPath(args.path);
|
|
73
|
-
|
|
57
|
+
const resolvedPlugin = await this.resolveSnippetPlugin(plugin);
|
|
58
|
+
this.log(`đĨ Pulling snippets from ${url} via ${resolvedPlugin}`);
|
|
74
59
|
this.log(`đ From snippet path: ${path}`);
|
|
75
60
|
this.log(`đ Dry run: ${dryRun ? 'yes' : 'no'}`);
|
|
76
61
|
try {
|
|
77
|
-
const adapter = getSnippetPlugin(
|
|
62
|
+
const adapter = getSnippetPlugin(resolvedPlugin);
|
|
78
63
|
const endpoint = adapter.endpoint(url);
|
|
79
64
|
const headers = await this.buildAuthHeaders();
|
|
80
65
|
const remoteList = await got.get(endpoint, { headers }).json();
|
|
@@ -94,8 +79,12 @@ export default class Pull extends LoopressCommand {
|
|
|
94
79
|
continue;
|
|
95
80
|
}
|
|
96
81
|
const ext = EXTENSIONS[snippet.type];
|
|
97
|
-
const
|
|
82
|
+
const slug = slugify(snippet.name, { lower: true, strict: true });
|
|
83
|
+
const base = `${snippet.id}-${slug}`;
|
|
84
|
+
const filePath = `${path}/${base}.${ext}`;
|
|
85
|
+
const metaPath = `${path}/${base}.json`;
|
|
98
86
|
await fs.writeFile(filePath, buildSnippetFile(snippet));
|
|
87
|
+
await fs.writeFile(metaPath, buildMetaFile(snippet));
|
|
99
88
|
count++;
|
|
100
89
|
this.log(`â
Pulled: ${snippet.name}`);
|
|
101
90
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class Push extends
|
|
1
|
+
import { PushCommand } from '../../lib/push-command.js';
|
|
2
|
+
export default class Push extends PushCommand {
|
|
3
3
|
static args: {
|
|
4
4
|
path: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
5
|
};
|
|
@@ -7,14 +7,13 @@ export default class Push extends LoopressCommand {
|
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
9
|
dryRun: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
-
plugin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
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 injectIdIntoMeta;
|
|
17
17
|
private loadSnippets;
|
|
18
|
-
private parseMetaFromContent;
|
|
19
18
|
private pushSnippet;
|
|
20
19
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import got from 'got';
|
|
3
|
-
import {
|
|
3
|
+
import { PushCommand } from '../../lib/push-command.js';
|
|
4
4
|
import { getSnippetPlugin } from '../../utils/snippet-plugin.js';
|
|
5
|
-
export default class Push extends
|
|
5
|
+
export default class Push extends PushCommand {
|
|
6
6
|
static args = {
|
|
7
7
|
path: Args.string({ description: 'Path to snippets directory (overrides project config)' }),
|
|
8
8
|
};
|
|
@@ -14,68 +14,86 @@ export default class Push extends LoopressCommand {
|
|
|
14
14
|
'$ lps snippets push --plugin wpcode',
|
|
15
15
|
];
|
|
16
16
|
static flags = {
|
|
17
|
-
...
|
|
17
|
+
...PushCommand.baseFlags,
|
|
18
18
|
dryRun: Flags.boolean({ char: 'd', description: 'Dry run - show what would happen without making changes' }),
|
|
19
19
|
plugin: Flags.string({
|
|
20
20
|
char: 'p',
|
|
21
|
-
|
|
22
|
-
description: 'WordPress snippet plugin to target',
|
|
21
|
+
description: 'WordPress snippet plugin to target (overrides loopress.json)',
|
|
23
22
|
options: ['code-snippets', 'wpcode'],
|
|
24
23
|
}),
|
|
25
24
|
};
|
|
26
25
|
async run() {
|
|
27
26
|
const { args, flags } = await this.parse(Push);
|
|
28
27
|
const { dryRun, plugin } = flags;
|
|
28
|
+
this.dryRun = dryRun;
|
|
29
29
|
const { url } = this.siteConfig;
|
|
30
30
|
const path = await this.resolveSnippetsPath(args.path);
|
|
31
|
-
|
|
31
|
+
const resolvedPlugin = await this.resolveSnippetPlugin(plugin);
|
|
32
|
+
this.log(`đ Pushing snippets to ${url} via ${resolvedPlugin}`);
|
|
32
33
|
this.log(`đ From snippet path: ${path}`);
|
|
33
34
|
this.log(`đ Dry run: ${dryRun ? 'yes' : 'no'}`);
|
|
35
|
+
let snippets = [];
|
|
34
36
|
try {
|
|
35
|
-
|
|
37
|
+
snippets = await this.loadSnippets(path);
|
|
36
38
|
this.log(`â
Found ${snippets.length} snippets to push`);
|
|
37
39
|
const headers = await this.buildAuthHeaders();
|
|
38
|
-
const adapter = getSnippetPlugin(
|
|
40
|
+
const adapter = getSnippetPlugin(resolvedPlugin);
|
|
39
41
|
for (const snippet of snippets) {
|
|
40
|
-
await this.pushSnippet(snippet,
|
|
42
|
+
await this.pushSnippet(snippet, { adapter, dryRun, headers, url });
|
|
41
43
|
}
|
|
44
|
+
await this.recordSuccess();
|
|
42
45
|
this.log('đ All snippets pushed successfully!');
|
|
43
46
|
}
|
|
44
47
|
catch (error) {
|
|
45
48
|
this.error(error.message);
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
|
-
async
|
|
51
|
+
async injectIdIntoMeta(filePath, id) {
|
|
49
52
|
const fs = await import('node:fs/promises');
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
updated = content.replace('<!--', `<!--\n id: ${id}`);
|
|
53
|
+
const metaPath = filePath.replace(/\.[^.]+$/, '.json');
|
|
54
|
+
let meta = {};
|
|
55
|
+
try {
|
|
56
|
+
const existing = await fs.readFile(metaPath, 'utf8');
|
|
57
|
+
meta = JSON.parse(existing);
|
|
56
58
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error.code !== 'ENOENT')
|
|
61
|
+
throw error;
|
|
59
62
|
}
|
|
60
|
-
|
|
63
|
+
meta.id = id;
|
|
64
|
+
await fs.writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
61
65
|
}
|
|
62
66
|
async loadSnippets(path) {
|
|
63
67
|
const fs = await import('node:fs/promises');
|
|
64
68
|
const snippets = [];
|
|
69
|
+
const SNIPPET_EXTENSIONS = new Set(['.css', '.html', '.js', '.php', '.txt']);
|
|
65
70
|
try {
|
|
66
71
|
const files = await fs.readdir(path);
|
|
67
72
|
for (const file of files) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
const ext = file.slice(file.lastIndexOf('.'));
|
|
74
|
+
if (!SNIPPET_EXTENSIONS.has(ext))
|
|
75
|
+
continue;
|
|
76
|
+
const filePath = `${path}/${file}`;
|
|
77
|
+
const metaPath = filePath.slice(0, filePath.lastIndexOf('.')) + '.json';
|
|
78
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
79
|
+
let id;
|
|
80
|
+
let name;
|
|
81
|
+
try {
|
|
82
|
+
const metaContent = await fs.readFile(metaPath, 'utf8');
|
|
83
|
+
const meta = JSON.parse(metaContent);
|
|
84
|
+
id = meta.id ? Number(meta.id) : undefined;
|
|
85
|
+
name = meta.name ? String(meta.name) : undefined;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code !== 'ENOENT')
|
|
89
|
+
throw error;
|
|
78
90
|
}
|
|
91
|
+
snippets.push({
|
|
92
|
+
code: content,
|
|
93
|
+
id,
|
|
94
|
+
name: name ?? file.slice(0, file.lastIndexOf('.')),
|
|
95
|
+
path: filePath,
|
|
96
|
+
});
|
|
79
97
|
}
|
|
80
98
|
}
|
|
81
99
|
catch (error) {
|
|
@@ -83,15 +101,8 @@ export default class Push extends LoopressCommand {
|
|
|
83
101
|
}
|
|
84
102
|
return snippets;
|
|
85
103
|
}
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
const nameMatch = content.match(/[\s*]*name:\s*(.+)/);
|
|
89
|
-
return {
|
|
90
|
-
id: idMatch ? Number(idMatch[1]) : undefined,
|
|
91
|
-
name: nameMatch ? nameMatch[1].trim() : undefined,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
async pushSnippet(snippet, url, headers, dryRun, adapter) {
|
|
104
|
+
async pushSnippet(snippet, ctx) {
|
|
105
|
+
const { adapter, dryRun, headers, url } = ctx;
|
|
95
106
|
if (dryRun) {
|
|
96
107
|
this.log(`đ [DRY RUN] Would push snippet: ${snippet.name}`);
|
|
97
108
|
this.log(`đ Code preview: ${snippet.code.slice(0, 100)}...`);
|
|
@@ -109,7 +120,7 @@ export default class Push extends LoopressCommand {
|
|
|
109
120
|
this.log(`â Creating new snippet: ${snippet.name}`);
|
|
110
121
|
const response = await got.post(endpoint, { headers, json: payload }).json();
|
|
111
122
|
const created = adapter.fromRemote(response);
|
|
112
|
-
await this.
|
|
123
|
+
await this.injectIdIntoMeta(snippet.path, created.id);
|
|
113
124
|
this.log(`â
Created: ${snippet.name} (id: ${created.id})`);
|
|
114
125
|
}
|
|
115
126
|
catch (error) {
|
|
@@ -30,10 +30,10 @@ export class AuthManager {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
getAuthFilePath() {
|
|
33
|
-
return join(this.homeDir, '.
|
|
33
|
+
return join(this.homeDir, '.loopress', 'auth.json');
|
|
34
34
|
}
|
|
35
35
|
setAuth(auth) {
|
|
36
|
-
const dir = join(this.homeDir, '.
|
|
36
|
+
const dir = join(this.homeDir, '.loopress');
|
|
37
37
|
if (!existsSync(dir))
|
|
38
38
|
mkdirSync(dir, { recursive: true });
|
|
39
39
|
const filePath = this.getAuthFilePath();
|
|
@@ -14,13 +14,13 @@ export class ProjectConfigManager {
|
|
|
14
14
|
return ProjectConfigManager.instance;
|
|
15
15
|
}
|
|
16
16
|
ensureConfigDir() {
|
|
17
|
-
const dir = join(this.homeDir, '.
|
|
17
|
+
const dir = join(this.homeDir, '.loopress');
|
|
18
18
|
if (!existsSync(dir)) {
|
|
19
19
|
mkdirSync(dir, { recursive: true });
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
getConfigFilePath() {
|
|
23
|
-
return join(this.homeDir, '.
|
|
23
|
+
return join(this.homeDir, '.loopress', 'config.json');
|
|
24
24
|
}
|
|
25
25
|
getCurrentEnv() {
|
|
26
26
|
const project = this.getCurrentProject();
|
package/dist/lib/base.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export declare abstract class LoopressCommand extends Command {
|
|
|
9
9
|
protected siteConfig: EnvironmentConfig;
|
|
10
10
|
buildAuthHeaders(): Promise<Record<string, string>>;
|
|
11
11
|
init(): Promise<void>;
|
|
12
|
+
protected resolveSnippetPlugin(flag?: string): Promise<'code-snippets' | 'wpcode'>;
|
|
12
13
|
protected resolveSnippetsPath(override?: string): Promise<string>;
|
|
13
|
-
protected resolveStylesPath(override?: string): Promise<string>;
|
|
14
14
|
}
|
package/dist/lib/base.js
CHANGED
|
@@ -27,6 +27,18 @@ export class LoopressCommand extends Command {
|
|
|
27
27
|
}
|
|
28
28
|
async init() {
|
|
29
29
|
await super.init();
|
|
30
|
+
const localConfig = await readLocalConfig();
|
|
31
|
+
if (localConfig.projectId) {
|
|
32
|
+
const project = configManager.getProject(localConfig.projectId);
|
|
33
|
+
if (!project) {
|
|
34
|
+
this.error(`Project "${localConfig.projectId}" (from loopress.json) not found. Run \`lps project config\` to configure it.`);
|
|
35
|
+
}
|
|
36
|
+
if (!project.currentEnv || !project.environments[project.currentEnv]) {
|
|
37
|
+
this.error(`Project "${localConfig.projectId}" has no active environment. Run \`lps project config\` to configure one.`);
|
|
38
|
+
}
|
|
39
|
+
this.siteConfig = project.environments[project.currentEnv];
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
30
42
|
const env = configManager.getCurrentEnv();
|
|
31
43
|
if (env) {
|
|
32
44
|
this.siteConfig = env;
|
|
@@ -34,16 +46,16 @@ export class LoopressCommand extends Command {
|
|
|
34
46
|
}
|
|
35
47
|
this.error('No environment configured. Run `lps project config` first.');
|
|
36
48
|
}
|
|
37
|
-
async
|
|
38
|
-
if (
|
|
39
|
-
return
|
|
49
|
+
async resolveSnippetPlugin(flag) {
|
|
50
|
+
if (flag)
|
|
51
|
+
return flag;
|
|
40
52
|
const config = await readLocalConfig();
|
|
41
|
-
return
|
|
53
|
+
return config.snippetPlugin ?? 'wpcode';
|
|
42
54
|
}
|
|
43
|
-
async
|
|
55
|
+
async resolveSnippetsPath(override) {
|
|
44
56
|
if (override)
|
|
45
57
|
return override;
|
|
46
58
|
const config = await readLocalConfig();
|
|
47
|
-
return join(config.rootDir ?? '.', config.
|
|
59
|
+
return join(config.rootDir ?? '.', config.snippetsDir ?? 'snippets');
|
|
48
60
|
}
|
|
49
61
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { LoopressCommand } from './base.js';
|
|
2
|
+
export declare abstract class PushCommand extends LoopressCommand {
|
|
3
|
+
protected dryRun: boolean;
|
|
4
|
+
catch(err: Error): Promise<void>;
|
|
5
|
+
protected recordDeployment(status: 'failure' | 'success'): Promise<void>;
|
|
6
|
+
protected recordSuccess(): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import got from 'got';
|
|
2
|
+
import { authManager } from '../config/auth.manager.js';
|
|
3
|
+
import { LoopressCommand } from './base.js';
|
|
4
|
+
const API_URL = process.env.LPS_API_URL ?? 'https://api.loopress.dev';
|
|
5
|
+
export class PushCommand extends LoopressCommand {
|
|
6
|
+
dryRun = false;
|
|
7
|
+
async catch(err) {
|
|
8
|
+
if (!this.dryRun && this.siteConfig) {
|
|
9
|
+
await this.recordDeployment('failure');
|
|
10
|
+
}
|
|
11
|
+
return super.catch(err);
|
|
12
|
+
}
|
|
13
|
+
async recordDeployment(status) {
|
|
14
|
+
const token = process.env.LPS_TOKEN ?? authManager.getAuth()?.token ?? null;
|
|
15
|
+
if (!token)
|
|
16
|
+
return;
|
|
17
|
+
try {
|
|
18
|
+
await got.post(`${API_URL}/deployments`, {
|
|
19
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
20
|
+
json: { status, url: this.siteConfig.url },
|
|
21
|
+
timeout: { request: 3000 },
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// non-blocking: recording must never interrupt the push flow
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async recordSuccess() {
|
|
29
|
+
if (!this.dryRun)
|
|
30
|
+
await this.recordDeployment('success');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export interface LoopressLocalConfig {
|
|
2
2
|
plugins?: Record<string, string>;
|
|
3
|
+
projectId?: string;
|
|
3
4
|
rootDir?: string;
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
snippetPlugin?: 'code-snippets' | 'wpcode';
|
|
6
|
+
snippetsDir?: string;
|
|
6
7
|
}
|
|
7
8
|
export declare function readLocalConfig(): Promise<LoopressLocalConfig>;
|
|
8
9
|
export declare function writeLocalConfig(config: LoopressLocalConfig): Promise<void>;
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
|
+
"init": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {},
|
|
6
|
+
"description": "Initialize a loopress.json config file in the current directory",
|
|
7
|
+
"examples": [
|
|
8
|
+
"$ lps init"
|
|
9
|
+
],
|
|
10
|
+
"flags": {},
|
|
11
|
+
"hasDynamicHelp": false,
|
|
12
|
+
"hiddenAliases": [],
|
|
13
|
+
"id": "init",
|
|
14
|
+
"pluginAlias": "@loopress/cli",
|
|
15
|
+
"pluginName": "@loopress/cli",
|
|
16
|
+
"pluginType": "core",
|
|
17
|
+
"strict": true,
|
|
18
|
+
"enableJsonFlag": false,
|
|
19
|
+
"isESM": true,
|
|
20
|
+
"relativePath": [
|
|
21
|
+
"dist",
|
|
22
|
+
"commands",
|
|
23
|
+
"init.js"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
3
26
|
"login": {
|
|
4
27
|
"aliases": [],
|
|
5
28
|
"args": {},
|
|
@@ -151,7 +174,6 @@
|
|
|
151
174
|
"pluginName": "@loopress/cli",
|
|
152
175
|
"pluginType": "core",
|
|
153
176
|
"strict": true,
|
|
154
|
-
"enableJsonFlag": false,
|
|
155
177
|
"isESM": true,
|
|
156
178
|
"relativePath": [
|
|
157
179
|
"dist",
|
|
@@ -415,9 +437,8 @@
|
|
|
415
437
|
},
|
|
416
438
|
"plugin": {
|
|
417
439
|
"char": "p",
|
|
418
|
-
"description": "WordPress snippet plugin to target",
|
|
440
|
+
"description": "WordPress snippet plugin to target (overrides loopress.json)",
|
|
419
441
|
"name": "plugin",
|
|
420
|
-
"default": "code-snippets",
|
|
421
442
|
"hasDynamicHelp": false,
|
|
422
443
|
"multiple": false,
|
|
423
444
|
"options": [
|
|
@@ -492,9 +513,8 @@
|
|
|
492
513
|
},
|
|
493
514
|
"plugin": {
|
|
494
515
|
"char": "p",
|
|
495
|
-
"description": "WordPress snippet plugin to target",
|
|
516
|
+
"description": "WordPress snippet plugin to target (overrides loopress.json)",
|
|
496
517
|
"name": "plugin",
|
|
497
|
-
"default": "code-snippets",
|
|
498
518
|
"hasDynamicHelp": false,
|
|
499
519
|
"multiple": false,
|
|
500
520
|
"options": [
|
|
@@ -569,9 +589,8 @@
|
|
|
569
589
|
},
|
|
570
590
|
"plugin": {
|
|
571
591
|
"char": "p",
|
|
572
|
-
"description": "WordPress snippet plugin to target",
|
|
592
|
+
"description": "WordPress snippet plugin to target (overrides loopress.json)",
|
|
573
593
|
"name": "plugin",
|
|
574
|
-
"default": "code-snippets",
|
|
575
594
|
"hasDynamicHelp": false,
|
|
576
595
|
"multiple": false,
|
|
577
596
|
"options": [
|
|
@@ -588,7 +607,6 @@
|
|
|
588
607
|
"pluginName": "@loopress/cli",
|
|
589
608
|
"pluginType": "core",
|
|
590
609
|
"strict": true,
|
|
591
|
-
"enableJsonFlag": false,
|
|
592
610
|
"isESM": true,
|
|
593
611
|
"relativePath": [
|
|
594
612
|
"dist",
|
|
@@ -596,121 +614,7 @@
|
|
|
596
614
|
"snippet",
|
|
597
615
|
"push.js"
|
|
598
616
|
]
|
|
599
|
-
},
|
|
600
|
-
"style:pull": {
|
|
601
|
-
"aliases": [],
|
|
602
|
-
"args": {},
|
|
603
|
-
"description": "Pull Global Styles from WordPress",
|
|
604
|
-
"examples": [
|
|
605
|
-
"$ lps styles pull",
|
|
606
|
-
"$ lps styles pull --url http://example.com"
|
|
607
|
-
],
|
|
608
|
-
"flags": {
|
|
609
|
-
"password": {
|
|
610
|
-
"description": "WordPress application password (fallback; prefer `lps project config`)",
|
|
611
|
-
"helpGroup": "GLOBAL",
|
|
612
|
-
"name": "password",
|
|
613
|
-
"hasDynamicHelp": false,
|
|
614
|
-
"multiple": false,
|
|
615
|
-
"type": "option"
|
|
616
|
-
},
|
|
617
|
-
"url": {
|
|
618
|
-
"description": "WordPress URL (fallback; prefer `lps project config`)",
|
|
619
|
-
"helpGroup": "GLOBAL",
|
|
620
|
-
"name": "url",
|
|
621
|
-
"hasDynamicHelp": false,
|
|
622
|
-
"multiple": false,
|
|
623
|
-
"type": "option"
|
|
624
|
-
},
|
|
625
|
-
"user": {
|
|
626
|
-
"description": "WordPress username (fallback; prefer `lps project config`)",
|
|
627
|
-
"helpGroup": "GLOBAL",
|
|
628
|
-
"name": "user",
|
|
629
|
-
"hasDynamicHelp": false,
|
|
630
|
-
"multiple": false,
|
|
631
|
-
"type": "option"
|
|
632
|
-
},
|
|
633
|
-
"dryRun": {
|
|
634
|
-
"char": "d",
|
|
635
|
-
"description": "Dry run - show what would happen without making changes",
|
|
636
|
-
"name": "dryRun",
|
|
637
|
-
"allowNo": false,
|
|
638
|
-
"type": "boolean"
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
"hasDynamicHelp": false,
|
|
642
|
-
"hiddenAliases": [],
|
|
643
|
-
"id": "style:pull",
|
|
644
|
-
"pluginAlias": "@loopress/cli",
|
|
645
|
-
"pluginName": "@loopress/cli",
|
|
646
|
-
"pluginType": "core",
|
|
647
|
-
"strict": true,
|
|
648
|
-
"enableJsonFlag": false,
|
|
649
|
-
"isESM": true,
|
|
650
|
-
"relativePath": [
|
|
651
|
-
"dist",
|
|
652
|
-
"commands",
|
|
653
|
-
"style",
|
|
654
|
-
"pull.js"
|
|
655
|
-
]
|
|
656
|
-
},
|
|
657
|
-
"style:push": {
|
|
658
|
-
"aliases": [],
|
|
659
|
-
"args": {},
|
|
660
|
-
"description": "Push Global Styles to WordPress",
|
|
661
|
-
"examples": [
|
|
662
|
-
"$ lps styles push",
|
|
663
|
-
"$ lps styles push --url http://example.com"
|
|
664
|
-
],
|
|
665
|
-
"flags": {
|
|
666
|
-
"password": {
|
|
667
|
-
"description": "WordPress application password (fallback; prefer `lps project config`)",
|
|
668
|
-
"helpGroup": "GLOBAL",
|
|
669
|
-
"name": "password",
|
|
670
|
-
"hasDynamicHelp": false,
|
|
671
|
-
"multiple": false,
|
|
672
|
-
"type": "option"
|
|
673
|
-
},
|
|
674
|
-
"url": {
|
|
675
|
-
"description": "WordPress URL (fallback; prefer `lps project config`)",
|
|
676
|
-
"helpGroup": "GLOBAL",
|
|
677
|
-
"name": "url",
|
|
678
|
-
"hasDynamicHelp": false,
|
|
679
|
-
"multiple": false,
|
|
680
|
-
"type": "option"
|
|
681
|
-
},
|
|
682
|
-
"user": {
|
|
683
|
-
"description": "WordPress username (fallback; prefer `lps project config`)",
|
|
684
|
-
"helpGroup": "GLOBAL",
|
|
685
|
-
"name": "user",
|
|
686
|
-
"hasDynamicHelp": false,
|
|
687
|
-
"multiple": false,
|
|
688
|
-
"type": "option"
|
|
689
|
-
},
|
|
690
|
-
"dryRun": {
|
|
691
|
-
"char": "d",
|
|
692
|
-
"description": "Dry run - show what would happen without making changes",
|
|
693
|
-
"name": "dryRun",
|
|
694
|
-
"allowNo": false,
|
|
695
|
-
"type": "boolean"
|
|
696
|
-
}
|
|
697
|
-
},
|
|
698
|
-
"hasDynamicHelp": false,
|
|
699
|
-
"hiddenAliases": [],
|
|
700
|
-
"id": "style:push",
|
|
701
|
-
"pluginAlias": "@loopress/cli",
|
|
702
|
-
"pluginName": "@loopress/cli",
|
|
703
|
-
"pluginType": "core",
|
|
704
|
-
"strict": true,
|
|
705
|
-
"enableJsonFlag": false,
|
|
706
|
-
"isESM": true,
|
|
707
|
-
"relativePath": [
|
|
708
|
-
"dist",
|
|
709
|
-
"commands",
|
|
710
|
-
"style",
|
|
711
|
-
"push.js"
|
|
712
|
-
]
|
|
713
617
|
}
|
|
714
618
|
},
|
|
715
|
-
"version": "0.
|
|
619
|
+
"version": "0.5.0"
|
|
716
620
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopress/cli",
|
|
3
3
|
"description": "CLI tool for syncing WordPress CodeSnippets, styles, and menus via the REST API",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"author": "jean-smaug",
|
|
6
6
|
"bin": {
|
|
7
7
|
"loopress": "bin/run.js",
|
|
@@ -12,31 +12,27 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@inquirer/prompts": "^8.5.2",
|
|
15
|
-
"@oclif/core": "^4.11.
|
|
16
|
-
"@oclif/plugin-help": "^6.2.
|
|
17
|
-
"@oclif/plugin-plugins": "^5.4.
|
|
15
|
+
"@oclif/core": "^4.11.11",
|
|
16
|
+
"@oclif/plugin-help": "^6.2.52",
|
|
17
|
+
"@oclif/plugin-plugins": "^5.4.80",
|
|
18
18
|
"glob": "13.0.6",
|
|
19
|
-
"got": "^15.0.
|
|
19
|
+
"got": "^15.0.7",
|
|
20
20
|
"slugify": "^1.6.9"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@eslint/compat": "2.1.0",
|
|
24
24
|
"@oclif/prettier-config": "^0.2.1",
|
|
25
|
-
"@oclif/test": "^4",
|
|
26
|
-
"@types/
|
|
27
|
-
"@types/mocha": "^10.0.10",
|
|
28
|
-
"@types/node": "25.9.3",
|
|
29
|
-
"chai": "^6.2.2",
|
|
25
|
+
"@oclif/test": "^4.1.20",
|
|
26
|
+
"@types/node": "26.0.1",
|
|
30
27
|
"eslint": "^9",
|
|
31
|
-
"eslint-config-oclif": "^6",
|
|
28
|
+
"eslint-config-oclif": "^6.0.174",
|
|
32
29
|
"eslint-config-prettier": "^10",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"prettier": "3.8.4",
|
|
30
|
+
"oclif": "^4.23.22",
|
|
31
|
+
"prettier": "3.9.1",
|
|
36
32
|
"shx": "^0.4.0",
|
|
37
|
-
"ts-node": "^10",
|
|
38
33
|
"tsx": "4.22.4",
|
|
39
|
-
"typescript": "^6.0.3"
|
|
34
|
+
"typescript": "^6.0.3",
|
|
35
|
+
"vitest": "^3.2.4"
|
|
40
36
|
},
|
|
41
37
|
"engines": {
|
|
42
38
|
"node": ">=18.0.0"
|
|
@@ -80,7 +76,7 @@
|
|
|
80
76
|
"build": "shx rm -rf dist && tsc -b",
|
|
81
77
|
"lint": "eslint",
|
|
82
78
|
"posttest": "pnpm run lint",
|
|
83
|
-
"test": "
|
|
79
|
+
"test": "vitest run",
|
|
84
80
|
"version": "oclif readme && git add README.md",
|
|
85
81
|
"format": "prettier . --write"
|
|
86
82
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { LoopressCommand } from '../../lib/base.js';
|
|
2
|
-
export default class Pull extends LoopressCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
dryRun: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
-
password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
};
|
|
11
|
-
run(): Promise<void>;
|
|
12
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import got from 'got';
|
|
3
|
-
import { LoopressCommand } from '../../lib/base.js';
|
|
4
|
-
export default class Pull extends LoopressCommand {
|
|
5
|
-
static description = 'Pull Global Styles from WordPress';
|
|
6
|
-
static examples = ['$ lps styles pull', '$ lps styles pull --url http://example.com'];
|
|
7
|
-
static flags = {
|
|
8
|
-
...LoopressCommand.baseFlags,
|
|
9
|
-
dryRun: Flags.boolean({ char: 'd', description: 'Dry run - show what would happen without making changes' }),
|
|
10
|
-
};
|
|
11
|
-
async run() {
|
|
12
|
-
const { flags } = await this.parse(Pull);
|
|
13
|
-
const { dryRun } = flags;
|
|
14
|
-
const { url } = this.siteConfig;
|
|
15
|
-
const stylesDir = await this.resolveStylesPath();
|
|
16
|
-
const outputPath = `${stylesDir}/global-styles.json`;
|
|
17
|
-
this.log(`đĨ Pulling Global Styles from ${url}`);
|
|
18
|
-
this.log(`đ Target file: ${outputPath}`);
|
|
19
|
-
this.log(`đ Dry run: ${dryRun ? 'yes' : 'no'}`);
|
|
20
|
-
try {
|
|
21
|
-
const headers = await this.buildAuthHeaders();
|
|
22
|
-
this.log('đ Finding active theme...');
|
|
23
|
-
const themes = await got.get(`${url}/wp-json/wp/v2/themes?status=active`, { headers }).json();
|
|
24
|
-
if (!themes || themes.length === 0) {
|
|
25
|
-
this.error('â No active theme found.');
|
|
26
|
-
}
|
|
27
|
-
const activeTheme = themes[0];
|
|
28
|
-
const globalStylesEndpoint = activeTheme._links['wp:user-global-styles'][0].href;
|
|
29
|
-
if (!globalStylesEndpoint) {
|
|
30
|
-
this.error(`â Active theme "${activeTheme.name}" does not have global styles endpoint.`);
|
|
31
|
-
}
|
|
32
|
-
const globalStyles = await got.get(globalStylesEndpoint, { headers }).json();
|
|
33
|
-
const dataToSave = {
|
|
34
|
-
id: globalStyles.id,
|
|
35
|
-
settings: globalStyles.settings,
|
|
36
|
-
styles: globalStyles.styles,
|
|
37
|
-
};
|
|
38
|
-
if (dryRun) {
|
|
39
|
-
this.log(`đ [DRY RUN] Would pull styles and settings for ID: ${globalStyles.id}`);
|
|
40
|
-
this.log(`đ Data preview: ${JSON.stringify(dataToSave).slice(0, 100)}...`);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const fs = await import('node:fs/promises');
|
|
44
|
-
await fs.mkdir(stylesDir, { recursive: true });
|
|
45
|
-
await fs.writeFile(outputPath, JSON.stringify(dataToSave, null, 2));
|
|
46
|
-
this.log(`â
Successfully pulled global styles to ${outputPath}`);
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
this.error(`â Error pulling global styles: ${error.message}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { LoopressCommand } from '../../lib/base.js';
|
|
2
|
-
export default class Push extends LoopressCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
dryRun: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
-
password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
user: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
};
|
|
11
|
-
run(): Promise<void>;
|
|
12
|
-
private readOrFetchGlobalStyles;
|
|
13
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import { glob } from 'glob';
|
|
3
|
-
import got from 'got';
|
|
4
|
-
import { LoopressCommand } from '../../lib/base.js';
|
|
5
|
-
export default class Push extends LoopressCommand {
|
|
6
|
-
static description = 'Push Global Styles to WordPress';
|
|
7
|
-
static examples = ['$ lps styles push', '$ lps styles push --url http://example.com'];
|
|
8
|
-
static flags = {
|
|
9
|
-
...LoopressCommand.baseFlags,
|
|
10
|
-
dryRun: Flags.boolean({ char: 'd', description: 'Dry run - show what would happen without making changes' }),
|
|
11
|
-
};
|
|
12
|
-
async run() {
|
|
13
|
-
const { flags } = await this.parse(Push);
|
|
14
|
-
const { dryRun } = flags;
|
|
15
|
-
const { url } = this.siteConfig;
|
|
16
|
-
const stylesDir = await this.resolveStylesPath();
|
|
17
|
-
const jsonPath = `${stylesDir}/global-styles.json`;
|
|
18
|
-
this.log(`đ¤ Pushing Global Styles to ${url}`);
|
|
19
|
-
this.log(`đ From directory: ${stylesDir}`);
|
|
20
|
-
this.log(`đ Dry run: ${dryRun ? 'yes' : 'no'}`);
|
|
21
|
-
try {
|
|
22
|
-
const fs = await import('node:fs/promises');
|
|
23
|
-
const headers = await this.buildAuthHeaders();
|
|
24
|
-
const data = await this.readOrFetchGlobalStyles(jsonPath, url, headers, fs);
|
|
25
|
-
this.log('đ¨ Bundling CSS files in memory...');
|
|
26
|
-
const cssFiles = await glob(`${stylesDir}/**/*.css`);
|
|
27
|
-
let bundledCss = '';
|
|
28
|
-
if (cssFiles.length > 0) {
|
|
29
|
-
const cssContents = await Promise.all(cssFiles.map((file) => fs.readFile(file, 'utf8')));
|
|
30
|
-
bundledCss = cssContents.join('\n').trim();
|
|
31
|
-
this.log(`⨠Bundled ${cssFiles.length} CSS files`);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
this.log(`â ī¸ No CSS files found in ${stylesDir}/**/*.css`);
|
|
35
|
-
}
|
|
36
|
-
const endpoint = `${url}/wp-json/wp/v2/global-styles/${data.id}`;
|
|
37
|
-
const payload = {
|
|
38
|
-
settings: data.settings,
|
|
39
|
-
styles: {
|
|
40
|
-
...data.styles,
|
|
41
|
-
...(bundledCss ? { css: bundledCss } : {}),
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
if (dryRun) {
|
|
45
|
-
this.log(`đ [DRY RUN] Would push to ${endpoint}`);
|
|
46
|
-
this.log(`đ Payload preview: ${JSON.stringify(payload).slice(0, 100)}...`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
await got.post(endpoint, { headers, json: payload });
|
|
50
|
-
this.log(`â
Successfully pushed global styles to ID: ${data.id}`);
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
this.error(`â Error pushing global styles: ${error.message}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
async readOrFetchGlobalStyles(jsonPath, url, headers, fs) {
|
|
57
|
-
try {
|
|
58
|
-
const content = await fs.readFile(jsonPath, 'utf8');
|
|
59
|
-
return JSON.parse(content);
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
if (error.code !== 'ENOENT')
|
|
63
|
-
throw error;
|
|
64
|
-
}
|
|
65
|
-
this.log('âšī¸ No local cache found â fetching global styles from WordPress...');
|
|
66
|
-
const themes = await got.get(`${url}/wp-json/wp/v2/themes?status=active`, { headers }).json();
|
|
67
|
-
if (!themes || themes.length === 0) {
|
|
68
|
-
this.error('â No active theme found.');
|
|
69
|
-
}
|
|
70
|
-
const globalStylesEndpoint = themes[0]._links['wp:user-global-styles'][0].href;
|
|
71
|
-
const globalStyles = await got.get(globalStylesEndpoint, { headers }).json();
|
|
72
|
-
const data = { id: globalStyles.id, settings: globalStyles.settings, styles: globalStyles.styles };
|
|
73
|
-
await fs.mkdir(jsonPath.replace(/\/[^/]+$/, ''), { recursive: true });
|
|
74
|
-
await fs.writeFile(jsonPath, JSON.stringify(data, null, 2));
|
|
75
|
-
this.log(`đž Cached to ${jsonPath}`);
|
|
76
|
-
return data;
|
|
77
|
-
}
|
|
78
|
-
}
|