@bootmap/wpep-cli 1.0.8 ā 1.1.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/bin/wpep.js +14 -1
- package/package.json +1 -1
- package/src/commands/deploy.js +40 -16
- package/src/commands/github.js +68 -0
package/bin/wpep.js
CHANGED
|
@@ -3,12 +3,13 @@ import { Command } from 'commander';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import initCommand from '../src/commands/init.js';
|
|
5
5
|
import deployCommand from '../src/commands/deploy.js';
|
|
6
|
+
import githubCommand from '../src/commands/github.js';
|
|
6
7
|
|
|
7
8
|
const program = new Command();
|
|
8
9
|
|
|
9
10
|
program
|
|
10
11
|
.name('wpep')
|
|
11
|
-
.description('Deploy Next.js
|
|
12
|
+
.description('Deploy static sites (Next.js, Astro, React) to WordPress via WPEP')
|
|
12
13
|
.version('1.0.0');
|
|
13
14
|
|
|
14
15
|
program
|
|
@@ -39,6 +40,18 @@ program
|
|
|
39
40
|
}
|
|
40
41
|
});
|
|
41
42
|
|
|
43
|
+
program
|
|
44
|
+
.command('github')
|
|
45
|
+
.description('Generate a GitHub Actions workflow for auto-deploy on git push')
|
|
46
|
+
.action(async () => {
|
|
47
|
+
try {
|
|
48
|
+
await githubCommand();
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
42
55
|
program.parse(process.argv);
|
|
43
56
|
|
|
44
57
|
if (!process.argv.slice(2).length) {
|
package/package.json
CHANGED
package/src/commands/deploy.js
CHANGED
|
@@ -101,23 +101,26 @@ export default async function deployCommand(options) {
|
|
|
101
101
|
let outputDir = options.dir || 'wpep-build';
|
|
102
102
|
const targetDir = path.join(process.cwd(), 'wpep-build');
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
for (const d of possibleDirs) {
|
|
109
|
-
if (fs.existsSync(path.join(process.cwd(), d))) {
|
|
110
|
-
foundDir = d;
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
104
|
+
// Always clear previous wpep-build so we deploy fresh output
|
|
105
|
+
if (fs.existsSync(targetDir)) {
|
|
106
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
114
108
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
// Auto-detect build output and copy to wpep-build
|
|
110
|
+
const possibleDirs = ['out', 'dist', 'build'];
|
|
111
|
+
let foundDir = null;
|
|
112
|
+
for (const d of possibleDirs) {
|
|
113
|
+
if (fs.existsSync(path.join(process.cwd(), d))) {
|
|
114
|
+
foundDir = d;
|
|
115
|
+
break;
|
|
118
116
|
}
|
|
119
117
|
}
|
|
120
118
|
|
|
119
|
+
if (foundDir) {
|
|
120
|
+
console.log(chalk.gray(`Auto-detected build in "${foundDir}". Copying to "wpep-build"...`));
|
|
121
|
+
fs.cpSync(path.join(process.cwd(), foundDir), targetDir, { recursive: true });
|
|
122
|
+
}
|
|
123
|
+
|
|
121
124
|
outputDir = 'wpep-build';
|
|
122
125
|
const outDir = path.join(process.cwd(), outputDir);
|
|
123
126
|
|
|
@@ -138,6 +141,7 @@ export default async function deployCommand(options) {
|
|
|
138
141
|
spinner.text = `Creating deployment session for ${allFiles.length} files...`;
|
|
139
142
|
|
|
140
143
|
let deployId;
|
|
144
|
+
let remoteManifest = null;
|
|
141
145
|
try {
|
|
142
146
|
const createRes = await fetch(`${url}/wp-json/wpep/v1/deployments/create`, {
|
|
143
147
|
method: 'POST',
|
|
@@ -154,6 +158,7 @@ export default async function deployCommand(options) {
|
|
|
154
158
|
throw new Error(`Invalid response from server: ${JSON.stringify(createData)}`);
|
|
155
159
|
}
|
|
156
160
|
deployId = createData.deployment_id;
|
|
161
|
+
remoteManifest = createData.remote_manifest;
|
|
157
162
|
} catch (e) {
|
|
158
163
|
spinner.fail('Failed to create deployment session.');
|
|
159
164
|
throw e;
|
|
@@ -161,9 +166,27 @@ export default async function deployCommand(options) {
|
|
|
161
166
|
|
|
162
167
|
spinner.succeed(`Created deployment session: ${chalk.bold(deployId)}`);
|
|
163
168
|
|
|
164
|
-
|
|
169
|
+
// Build a set of unchanged files by comparing hashes with the remote manifest
|
|
170
|
+
const unchangedFiles = new Set();
|
|
171
|
+
if (remoteManifest && remoteManifest.files) {
|
|
172
|
+
for (const [filePath, localHash] of Object.entries(filesList)) {
|
|
173
|
+
const remoteMeta = remoteManifest.files[filePath];
|
|
174
|
+
if (remoteMeta && remoteMeta === localHash) {
|
|
175
|
+
unchangedFiles.add(filePath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const changedFiles = allFiles.filter(f => !unchangedFiles.has(path.relative(outDir, f)));
|
|
181
|
+
const skippedCount = allFiles.length - changedFiles.length;
|
|
182
|
+
|
|
183
|
+
if (skippedCount > 0) {
|
|
184
|
+
console.log(chalk.green(`\nā” ${skippedCount} unchanged files will be copied server-side (not re-uploaded).`));
|
|
185
|
+
}
|
|
186
|
+
console.log(chalk.gray(`Uploading ${changedFiles.length} changed files...\n`));
|
|
187
|
+
|
|
165
188
|
let uploaded = 0;
|
|
166
|
-
for (const file of
|
|
189
|
+
for (const file of changedFiles) {
|
|
167
190
|
const relativePath = path.relative(outDir, file);
|
|
168
191
|
const data = fs.readFileSync(file);
|
|
169
192
|
const base64Data = data.toString('base64');
|
|
@@ -203,5 +226,6 @@ export default async function deployCommand(options) {
|
|
|
203
226
|
throw e;
|
|
204
227
|
}
|
|
205
228
|
|
|
206
|
-
console.log(chalk.green.bold(`\nš Success! Your site is live at ${url}
|
|
229
|
+
console.log(chalk.green.bold(`\nš Success! Your site is live at ${url}`));
|
|
230
|
+
console.log(chalk.gray(` ${uploaded} files uploaded, ${skippedCount} files copied from previous deployment.\n`));
|
|
207
231
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
const WORKFLOW_TEMPLATE = `name: Deploy to WordPress (WPEP)
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
deploy:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
node-version: '20'
|
|
20
|
+
cache: 'npm'
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm ci
|
|
24
|
+
|
|
25
|
+
- name: Deploy to WordPress
|
|
26
|
+
run: npx @bootmap/wpep-cli deploy --url \${{ secrets.WPEP_URL }} --key \${{ secrets.WPEP_API_KEY }}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
export default async function githubCommand() {
|
|
30
|
+
const cwd = process.cwd();
|
|
31
|
+
const workflowDir = path.join(cwd, '.github', 'workflows');
|
|
32
|
+
const workflowPath = path.join(workflowDir, 'wpep-deploy.yml');
|
|
33
|
+
|
|
34
|
+
// Create .github/workflows if it doesn't exist
|
|
35
|
+
if (!fs.existsSync(workflowDir)) {
|
|
36
|
+
fs.mkdirSync(workflowDir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Write the workflow file
|
|
40
|
+
fs.writeFileSync(workflowPath, WORKFLOW_TEMPLATE, 'utf8');
|
|
41
|
+
|
|
42
|
+
// Read .wpeprc.json to show the user their URL
|
|
43
|
+
let siteUrl = 'https://your-site.com';
|
|
44
|
+
const rcPath = path.join(cwd, '.wpeprc.json');
|
|
45
|
+
if (fs.existsSync(rcPath)) {
|
|
46
|
+
try {
|
|
47
|
+
const config = JSON.parse(fs.readFileSync(rcPath, 'utf8'));
|
|
48
|
+
if (config.url) siteUrl = config.url;
|
|
49
|
+
} catch (e) { /* ignore */ }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log(chalk.green.bold('\nā
GitHub Actions workflow created!\n'));
|
|
53
|
+
console.log(chalk.gray(` File: .github/workflows/wpep-deploy.yml\n`));
|
|
54
|
+
|
|
55
|
+
console.log(chalk.yellow.bold('š Next steps:\n'));
|
|
56
|
+
console.log(chalk.white('1. Go to your GitHub repo ā Settings ā Secrets and variables ā Actions'));
|
|
57
|
+
console.log(chalk.white('2. Add these two repository secrets:\n'));
|
|
58
|
+
|
|
59
|
+
console.log(chalk.cyan(' WPEP_URL') + chalk.gray(` ā ${siteUrl}`));
|
|
60
|
+
console.log(chalk.cyan(' WPEP_API_KEY') + chalk.gray(` ā (copy from WordPress ā WPEP ā Settings)\n`));
|
|
61
|
+
|
|
62
|
+
console.log(chalk.white('3. Push to the ') + chalk.green('main') + chalk.white(' branch:\n'));
|
|
63
|
+
console.log(chalk.gray(' git add .'));
|
|
64
|
+
console.log(chalk.gray(' git commit -m "Add WPEP auto-deploy"'));
|
|
65
|
+
console.log(chalk.gray(' git push origin main\n'));
|
|
66
|
+
|
|
67
|
+
console.log(chalk.green.bold('š After that, every push to main will auto-deploy to WordPress!\n'));
|
|
68
|
+
}
|