plugship 1.0.4 → 1.0.5
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/package.json +2 -2
- package/src/lib/deployer.js +49 -25
- package/src/lib/zipper.js +50 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plugship",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Deploy local WordPress plugins to remote sites from the command line",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
],
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@inquirer/prompts": "^7.2.1",
|
|
37
38
|
"archiver": "^7.0.1",
|
|
38
39
|
"chalk": "^5.3.0",
|
|
39
40
|
"commander": "^12.1.0",
|
|
40
|
-
"@inquirer/prompts": "^7.2.1",
|
|
41
41
|
"form-data": "^4.0.1",
|
|
42
42
|
"ora": "^8.1.1"
|
|
43
43
|
}
|
package/src/lib/deployer.js
CHANGED
|
@@ -4,7 +4,7 @@ import { select, confirm } from '@inquirer/prompts';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { getSite, listSites } from './config.js';
|
|
6
6
|
import { detectPlugin } from './plugin-detector.js';
|
|
7
|
-
import { createPluginZip } from './zipper.js';
|
|
7
|
+
import { createPluginZip, getIgnoreSource } from './zipper.js';
|
|
8
8
|
import { WordPressApi } from './wordpress-api.js';
|
|
9
9
|
import { DeployError, ConfigError } from './errors.js';
|
|
10
10
|
import { RECEIVER_DOWNLOAD_URL } from './constants.js';
|
|
@@ -48,18 +48,19 @@ async function getAllSites() {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
async function checkIgnoreFile(cwd) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
51
|
+
const source = await getIgnoreSource(cwd);
|
|
52
|
+
if (source) {
|
|
53
|
+
logger.info(`Using ${source} for file exclusions`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
logger.warn('No .plugshipignore or .distignore file found.');
|
|
57
|
+
const create = await confirm({
|
|
58
|
+
message: 'Create .plugshipignore with default template?',
|
|
59
|
+
default: true,
|
|
60
|
+
});
|
|
61
|
+
if (create) {
|
|
62
|
+
const { ignoreCommand } = await import('../commands/ignore.js');
|
|
63
|
+
await ignoreCommand([]);
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -90,23 +91,46 @@ export async function deploy({ siteName, activate = true, dryRun = false, all =
|
|
|
90
91
|
try {
|
|
91
92
|
const zipStat = await stat(existingZipPath);
|
|
92
93
|
const sizeMB = (zipStat.size / 1024 / 1024).toFixed(2);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
|
|
95
|
+
// Check if ignore file was modified after the ZIP was built
|
|
96
|
+
let ignoreStale = false;
|
|
97
|
+
for (const ignoreFile of ['.plugshipignore', '.distignore']) {
|
|
98
|
+
try {
|
|
99
|
+
const ignoreStat = await stat(join(cwd, ignoreFile));
|
|
100
|
+
if (ignoreStat.mtimeMs > zipStat.mtimeMs) {
|
|
101
|
+
ignoreStale = true;
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
} catch {
|
|
105
|
+
// file not found, try next
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (ignoreStale) {
|
|
110
|
+
logger.warn('Ignore file changed since last build — rebuilding ZIP...');
|
|
102
111
|
const spin = logger.spinner('Creating ZIP archive...');
|
|
103
112
|
spin.start();
|
|
104
113
|
({ zipPath, size } = await createPluginZip(cwd, plugin.slug));
|
|
105
114
|
spin.succeed(`ZIP created (${(size / 1024 / 1024).toFixed(2)} MB)`);
|
|
106
115
|
} else {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
logger.info(`Existing ZIP found: builds/${plugin.slug}.zip (${sizeMB} MB)`);
|
|
117
|
+
const action = await select({
|
|
118
|
+
message: 'What do you want to do?',
|
|
119
|
+
choices: [
|
|
120
|
+
{ name: 'Use existing ZIP', value: 'existing' },
|
|
121
|
+
{ name: 'Build a new ZIP', value: 'rebuild' },
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
if (action === 'rebuild') {
|
|
125
|
+
const spin = logger.spinner('Creating ZIP archive...');
|
|
126
|
+
spin.start();
|
|
127
|
+
({ zipPath, size } = await createPluginZip(cwd, plugin.slug));
|
|
128
|
+
spin.succeed(`ZIP created (${(size / 1024 / 1024).toFixed(2)} MB)`);
|
|
129
|
+
} else {
|
|
130
|
+
zipPath = existingZipPath;
|
|
131
|
+
size = zipStat.size;
|
|
132
|
+
logger.success(`Using existing ZIP (${sizeMB} MB)`);
|
|
133
|
+
}
|
|
110
134
|
}
|
|
111
135
|
} catch {
|
|
112
136
|
const spin = logger.spinner('Creating ZIP archive...');
|
package/src/lib/zipper.js
CHANGED
|
@@ -4,19 +4,46 @@ import { stat, mkdir, readFile } from 'node:fs/promises';
|
|
|
4
4
|
import archiver from 'archiver';
|
|
5
5
|
import { DEFAULT_EXCLUDES } from './constants.js';
|
|
6
6
|
|
|
7
|
+
async function loadIgnoreFile(filePath) {
|
|
8
|
+
const content = await readFile(filePath, 'utf-8');
|
|
9
|
+
const patterns = [];
|
|
10
|
+
for (const line of content.split('\n')) {
|
|
11
|
+
const trimmed = line.trim();
|
|
12
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
13
|
+
patterns.push(trimmed);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return patterns;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function getIgnoreSource(sourceDir) {
|
|
20
|
+
try {
|
|
21
|
+
await readFile(join(sourceDir, '.plugshipignore'), 'utf-8');
|
|
22
|
+
return '.plugshipignore';
|
|
23
|
+
} catch {
|
|
24
|
+
try {
|
|
25
|
+
await readFile(join(sourceDir, '.distignore'), 'utf-8');
|
|
26
|
+
return '.distignore';
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
7
33
|
async function loadIgnorePatterns(sourceDir) {
|
|
8
34
|
const patterns = [...DEFAULT_EXCLUDES];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
35
|
+
|
|
36
|
+
// .plugshipignore takes priority, then .distignore
|
|
37
|
+
for (const file of ['.plugshipignore', '.distignore']) {
|
|
38
|
+
try {
|
|
39
|
+
const extra = await loadIgnoreFile(join(sourceDir, file));
|
|
40
|
+
patterns.push(...extra);
|
|
41
|
+
return patterns;
|
|
42
|
+
} catch {
|
|
43
|
+
// file not found, try next
|
|
16
44
|
}
|
|
17
|
-
} catch {
|
|
18
|
-
// No .plugshipignore file — use defaults only
|
|
19
45
|
}
|
|
46
|
+
|
|
20
47
|
return patterns;
|
|
21
48
|
}
|
|
22
49
|
|
|
@@ -52,11 +79,16 @@ export async function createPluginZip(sourceDir, slug) {
|
|
|
52
79
|
}
|
|
53
80
|
|
|
54
81
|
function matchGlob(filePath, pattern) {
|
|
55
|
-
// Strip trailing
|
|
56
|
-
if (pattern.endsWith('/**')) {
|
|
57
|
-
const dir = pattern.
|
|
82
|
+
// Strip trailing /**, /* or / for directory matching
|
|
83
|
+
if (pattern.endsWith('/**') || pattern.endsWith('/*') || pattern.endsWith('/')) {
|
|
84
|
+
const dir = pattern.replace(/\/\*{0,2}$/, '');
|
|
58
85
|
return filePath === dir || filePath.startsWith(dir + '/');
|
|
59
86
|
}
|
|
87
|
+
// **/*.ext — match extension at any depth
|
|
88
|
+
if (pattern.startsWith('**/')) {
|
|
89
|
+
const sub = pattern.slice(3);
|
|
90
|
+
return matchGlob(filePath, sub) || filePath.split('/').some((seg) => matchGlob(seg, sub));
|
|
91
|
+
}
|
|
60
92
|
// Exact match or wildcard prefix
|
|
61
93
|
if (pattern.startsWith('*.')) {
|
|
62
94
|
return filePath.endsWith(pattern.slice(1));
|
|
@@ -66,5 +98,10 @@ function matchGlob(filePath, pattern) {
|
|
|
66
98
|
const firstSegment = filePath.split('/')[0];
|
|
67
99
|
return firstSegment.startsWith('.');
|
|
68
100
|
}
|
|
69
|
-
|
|
101
|
+
// Exact match (file or directory name)
|
|
102
|
+
// "resources" matches "resources", "resources/file.js", "resources/sub/file.js"
|
|
103
|
+
if (filePath === pattern || filePath.startsWith(pattern + '/')) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
70
107
|
}
|