@joltdesign/scripts 0.21.0 → 0.22.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/dist/Command/AWS.js.map +1 -1
- package/dist/Command/Prepare.js.map +1 -1
- package/dist/Command/WP.js +321 -243
- package/dist/Command/WP.js.map +1 -1
- package/dist/Config.js +77 -12
- package/dist/Config.js.map +1 -1
- package/dist/schemas.js +7 -0
- package/dist/schemas.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/compose.js +2 -0
- package/dist/types/compose.js.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/package.js +2 -0
- package/dist/types/package.js.map +1 -0
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
package/dist/Command/WP.js
CHANGED
|
@@ -113,9 +113,10 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
113
113
|
this.skipCore = Option.Boolean('--skip-core', false, { description: 'Skip WordPress core updates' });
|
|
114
114
|
this.skipPlugins = Option.Boolean('--skip-plugins', false, { description: 'Skip plugin updates' });
|
|
115
115
|
this.skipThemes = Option.Boolean('--skip-themes', false, { description: 'Skip theme updates' });
|
|
116
|
+
this.skipLanguages = Option.Boolean('--skip-languages', false, { description: 'Skip language/translation updates' });
|
|
116
117
|
}
|
|
117
118
|
async command() {
|
|
118
|
-
const { config, context: { stdout, stderr }, skipCore, skipPlugins, skipThemes, logo, } = this;
|
|
119
|
+
const { config, context: { stdout, stderr }, skipCore, skipPlugins, skipThemes, skipLanguages, logo, } = this;
|
|
119
120
|
stdout.write(ansis.bold(`${logo} WordPress Updates\n\n`));
|
|
120
121
|
// Load configuration
|
|
121
122
|
const wpConfig = await config.loadWordPressConfig();
|
|
@@ -127,30 +128,19 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
127
128
|
let updatedPluginCount = 0;
|
|
128
129
|
let updatedThemeCount = 0;
|
|
129
130
|
let updatedCore = false;
|
|
131
|
+
// Track detailed update information for summary
|
|
132
|
+
const updateSummary = {
|
|
133
|
+
plugins: [],
|
|
134
|
+
themes: [],
|
|
135
|
+
core: null,
|
|
136
|
+
translations: false,
|
|
137
|
+
};
|
|
130
138
|
// Get current status
|
|
131
139
|
if (!skipPlugins) {
|
|
132
|
-
|
|
133
|
-
const yarnCommand = await config.command('yarn');
|
|
134
|
-
const pluginsResult = await execC(yarnCommand, ['jolt', 'wp', 'cli', 'plugin', 'list', '--json'], {
|
|
135
|
-
reject: false,
|
|
136
|
-
});
|
|
137
|
-
const pluginsJson = pluginsResult.exitCode === 0 ? String(pluginsResult.stdout || '') : null;
|
|
138
|
-
if (pluginsJson) {
|
|
139
|
-
const plugins = this.parsePluginJson(pluginsJson);
|
|
140
|
-
stdout.write(`Found ${plugins.length} plugins\n`);
|
|
141
|
-
}
|
|
140
|
+
await this.getItems('plugin');
|
|
142
141
|
}
|
|
143
142
|
if (!skipThemes) {
|
|
144
|
-
|
|
145
|
-
const yarnCommand = await config.command('yarn');
|
|
146
|
-
const themesResult = await execC(yarnCommand, ['jolt', 'wp', 'cli', 'theme', 'list', '--json'], {
|
|
147
|
-
reject: false,
|
|
148
|
-
});
|
|
149
|
-
const themesJson = themesResult.exitCode === 0 ? String(themesResult.stdout || '') : null;
|
|
150
|
-
if (themesJson) {
|
|
151
|
-
const themes = this.parseThemeJson(themesJson);
|
|
152
|
-
stdout.write(`Found ${themes.length} themes\n`);
|
|
153
|
-
}
|
|
143
|
+
await this.getItems('theme');
|
|
154
144
|
}
|
|
155
145
|
// We'll create the update branch only when we need to make our first commit
|
|
156
146
|
const branchRef = { branch: undefined, created: false };
|
|
@@ -158,45 +148,21 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
158
148
|
const originalHookPath = await this.disableGitHooks();
|
|
159
149
|
try {
|
|
160
150
|
// Update plugins
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const pluginsResult = await execC(yarnCommand, ['jolt', 'wp', 'cli', 'plugin', 'list', '--json'], {
|
|
165
|
-
reject: false,
|
|
166
|
-
});
|
|
167
|
-
const pluginsJson = pluginsResult.exitCode === 0 ? String(pluginsResult.stdout || '') : null;
|
|
168
|
-
if (pluginsJson) {
|
|
169
|
-
const plugins = this.parsePluginJson(pluginsJson);
|
|
170
|
-
for (const plugin of plugins) {
|
|
171
|
-
const didUpdate = await this.maybeUpdatePlugin(plugin, wpConfig, branchRef);
|
|
172
|
-
if (didUpdate) {
|
|
173
|
-
updatedPluginCount++;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
151
|
+
const pluginUpdates = await this.processItemUpdates('plugin', skipPlugins, wpConfig, branchRef);
|
|
152
|
+
updatedPluginCount = pluginUpdates.count;
|
|
153
|
+
updateSummary.plugins = pluginUpdates.details;
|
|
178
154
|
// Update themes
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const themesResult = await execC(yarnCommand, ['jolt', 'wp', 'cli', 'theme', 'list', '--json'], {
|
|
183
|
-
reject: false,
|
|
184
|
-
});
|
|
185
|
-
const themesJson = themesResult.exitCode === 0 ? String(themesResult.stdout || '') : null;
|
|
186
|
-
if (themesJson) {
|
|
187
|
-
const themes = this.parseThemeJson(themesJson);
|
|
188
|
-
for (const theme of themes) {
|
|
189
|
-
const didUpdate = await this.maybeUpdateTheme(theme, wpConfig, branchRef);
|
|
190
|
-
if (didUpdate) {
|
|
191
|
-
updatedThemeCount++;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
155
|
+
const themeUpdates = await this.processItemUpdates('theme', skipThemes, wpConfig, branchRef);
|
|
156
|
+
updatedThemeCount = themeUpdates.count;
|
|
157
|
+
updateSummary.themes = themeUpdates.details;
|
|
196
158
|
// Update core
|
|
197
159
|
if (!skipCore) {
|
|
198
160
|
stdout.write(ansis.cyan('📦 Checking WordPress core...\n'));
|
|
199
|
-
|
|
161
|
+
const coreResult = await this.maybeUpdateCore(wpConfig, branchRef);
|
|
162
|
+
updatedCore = coreResult.updated;
|
|
163
|
+
if (coreResult.updated && coreResult.details) {
|
|
164
|
+
updateSummary.core = coreResult.details;
|
|
165
|
+
}
|
|
200
166
|
}
|
|
201
167
|
}
|
|
202
168
|
finally {
|
|
@@ -210,218 +176,260 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
210
176
|
stdout.write(ansis.cyan('📦 Updated WordPress core\n'));
|
|
211
177
|
}
|
|
212
178
|
const totalUpdates = updatedPluginCount + updatedThemeCount + (updatedCore ? 1 : 0);
|
|
179
|
+
// Update translations if possible
|
|
180
|
+
let updatedTranslations = false;
|
|
181
|
+
if (!skipLanguages && (totalUpdates > 0 || !branchRef.created)) {
|
|
182
|
+
stdout.write(ansis.cyan('🌐 Updating translations...\n'));
|
|
183
|
+
updatedTranslations = await this.maybeUpdateTranslations(branchRef);
|
|
184
|
+
updateSummary.translations = updatedTranslations;
|
|
185
|
+
}
|
|
186
|
+
// Show detailed update summary
|
|
187
|
+
if (totalUpdates > 0 || updatedTranslations) {
|
|
188
|
+
stdout.write(ansis.bold('\n📋 Update Summary:\n'));
|
|
189
|
+
if (updateSummary.plugins.length > 0) {
|
|
190
|
+
stdout.write(ansis.green('🔌 Plugins updated:\n'));
|
|
191
|
+
for (const plugin of updateSummary.plugins) {
|
|
192
|
+
stdout.write(ansis.cyan(` • ${plugin.title} (${plugin.fromVersion} → ${plugin.toVersion})\n`));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (updateSummary.themes.length > 0) {
|
|
196
|
+
stdout.write(ansis.green('🎨 Themes updated:\n'));
|
|
197
|
+
for (const theme of updateSummary.themes) {
|
|
198
|
+
stdout.write(ansis.cyan(` • ${theme.title} (${theme.fromVersion} → ${theme.toVersion})\n`));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (updateSummary.core) {
|
|
202
|
+
stdout.write(ansis.green('📦 WordPress core updated:\n'));
|
|
203
|
+
stdout.write(ansis.cyan(` • WordPress (${updateSummary.core.fromVersion} → ${updateSummary.core.toVersion})\n`));
|
|
204
|
+
}
|
|
205
|
+
if (updateSummary.translations) {
|
|
206
|
+
stdout.write(ansis.green('🌐 Translations updated\n'));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
213
209
|
if (totalUpdates > 0 && branchRef.created) {
|
|
214
210
|
stdout.write(ansis.yellow('\nNext steps:\n'));
|
|
215
|
-
stdout.write(`• Review updates: ${ansis.dim('
|
|
211
|
+
stdout.write(`• Review updates: ${ansis.dim(await this.getUpdateCommand('modify'))}\n`);
|
|
216
212
|
// Use root config value directly
|
|
217
|
-
stdout.write(`• Merge to ${await config.get('branch')}: ${ansis.dim('
|
|
213
|
+
stdout.write(`• Merge to ${await config.get('branch')}: ${ansis.dim(await this.getUpdateCommand('merge'))}\n`);
|
|
218
214
|
}
|
|
219
|
-
else if (totalUpdates === 0) {
|
|
215
|
+
else if (totalUpdates === 0 && !updatedTranslations) {
|
|
220
216
|
stdout.write(ansis.green('\n✅ No updates available - staying on current branch\n'));
|
|
221
217
|
}
|
|
222
218
|
return 0;
|
|
223
219
|
}
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return JSON.parse(trimmed);
|
|
235
|
-
}
|
|
236
|
-
// (No helper) obtain the package runner directly via config.command('yarn') where needed
|
|
237
|
-
async createBranch() {
|
|
238
|
-
const { config, context } = this;
|
|
239
|
-
const isoDate = new Date().toISOString().replace(/[:.]/g, '-').replace(/T/, '_').slice(0, -5);
|
|
240
|
-
const branchName = `joltWpUpdate/${isoDate}`;
|
|
241
|
-
const gitCommand = await config.command('git');
|
|
242
|
-
await execC(gitCommand, ['checkout', '-b', branchName], { context });
|
|
243
|
-
return branchName;
|
|
244
|
-
}
|
|
245
|
-
async ensureBranchCreated(_wpConfig, branchRef) {
|
|
246
|
-
if (!branchRef.created) {
|
|
247
|
-
branchRef.branch = await this.createBranch();
|
|
248
|
-
branchRef.created = true;
|
|
249
|
-
const { context: { stdout }, } = this;
|
|
250
|
-
stdout.write(ansis.green(`📋 Created update branch ${branchRef.branch}\n`));
|
|
251
|
-
}
|
|
252
|
-
return branchRef.branch;
|
|
253
|
-
}
|
|
254
|
-
async disableGitHooks() {
|
|
255
|
-
const { config, context } = this;
|
|
256
|
-
const gitCommand = await config.command('git');
|
|
257
|
-
try {
|
|
258
|
-
const result = await execC(gitCommand, ['config', '--get', 'core.hooksPath'], { context, reject: false });
|
|
259
|
-
const originalHookPath = String(result.stdout || '').trim();
|
|
260
|
-
await execC(gitCommand, ['config', 'core.hooksPath', '/dev/null'], { context });
|
|
261
|
-
return originalHookPath;
|
|
262
|
-
}
|
|
263
|
-
catch (_a) {
|
|
264
|
-
await execC(gitCommand, ['config', 'core.hooksPath', '/dev/null'], { context });
|
|
265
|
-
return '';
|
|
220
|
+
// Helper method to get the appropriate command format (short or long form)
|
|
221
|
+
async getUpdateCommand(subCommand) {
|
|
222
|
+
var _a;
|
|
223
|
+
const { config } = this;
|
|
224
|
+
const yarnCommand = await config.command('yarn');
|
|
225
|
+
const packageJson = await config.getPackageJson();
|
|
226
|
+
// Check if there's an 'update' script that acts as a shortcut for 'jolt wp update'
|
|
227
|
+
const updateScript = (_a = packageJson === null || packageJson === void 0 ? void 0 : packageJson.scripts) === null || _a === void 0 ? void 0 : _a.update;
|
|
228
|
+
if (updateScript && (updateScript === 'jolt wp update' || updateScript.startsWith('jolt wp update '))) {
|
|
229
|
+
return `${yarnCommand} update ${subCommand}`;
|
|
266
230
|
}
|
|
231
|
+
// Fall back to the full command
|
|
232
|
+
return `${yarnCommand} jolt wp update ${subCommand}`;
|
|
267
233
|
}
|
|
268
|
-
|
|
234
|
+
// Helper method to execute WP CLI commands
|
|
235
|
+
async executeWpCli(args, options) {
|
|
269
236
|
const { config, context } = this;
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
|
|
237
|
+
const yarnCommand = await config.command('yarn');
|
|
238
|
+
// For silent operations, don't pass context to suppress output
|
|
239
|
+
const execOptions = {
|
|
240
|
+
reject: false,
|
|
241
|
+
...options,
|
|
242
|
+
...(!(options === null || options === void 0 ? void 0 : options.silent) ? { context } : {}),
|
|
243
|
+
};
|
|
244
|
+
const result = await execC(yarnCommand, ['jolt', 'wp', 'cli', ...args], execOptions);
|
|
245
|
+
return {
|
|
246
|
+
exitCode: result.exitCode || 0,
|
|
247
|
+
stdout: result.exitCode === 0 ? String(result.stdout || '') : null,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
// Configuration for different item types
|
|
251
|
+
getItemConfig(type) {
|
|
252
|
+
const configs = {
|
|
253
|
+
plugin: {
|
|
254
|
+
type: 'plugin',
|
|
255
|
+
icon: '🔌',
|
|
256
|
+
listCommand: ['plugin', 'list', '--json'],
|
|
257
|
+
updateCommand: (name) => ['plugin', 'update', name],
|
|
258
|
+
getFolder: (wpConfig) => wpConfig.pluginFolder,
|
|
259
|
+
commitPrefix: 'Update',
|
|
260
|
+
},
|
|
261
|
+
theme: {
|
|
262
|
+
type: 'theme',
|
|
263
|
+
icon: '🎨',
|
|
264
|
+
listCommand: ['theme', 'list', '--json'],
|
|
265
|
+
updateCommand: (name) => ['theme', 'update', name],
|
|
266
|
+
getFolder: (wpConfig) => wpConfig.themeFolder,
|
|
267
|
+
commitPrefix: 'Update theme',
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
return configs[type];
|
|
271
|
+
}
|
|
272
|
+
// Generic method to get and parse item lists
|
|
273
|
+
async getItems(type) {
|
|
279
274
|
const { context: { stdout }, } = this;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
275
|
+
const itemConfig = this.getItemConfig(type);
|
|
276
|
+
stdout.write(ansis.cyan(`${itemConfig.icon} Checking ${type}s...\n`));
|
|
277
|
+
const result = await this.executeWpCli(itemConfig.listCommand, { silent: true });
|
|
278
|
+
if (!result.stdout) {
|
|
279
|
+
return [];
|
|
280
|
+
}
|
|
281
|
+
const items = this.parseItemJson(result.stdout);
|
|
282
|
+
stdout.write(`Found ${items.length} ${type}s\n`);
|
|
283
|
+
return items;
|
|
284
|
+
}
|
|
285
|
+
// Generic method to parse item JSON (plugins/themes have same structure)
|
|
286
|
+
parseItemJson(itemJson) {
|
|
287
|
+
// Trim off any preceding warnings, try to look for the start of the actual JSON.
|
|
288
|
+
const trimmed = itemJson.substring(itemJson.indexOf('[{'));
|
|
289
|
+
const allItems = JSON.parse(trimmed);
|
|
290
|
+
// For plugins, filter out dropin and must-use plugins
|
|
291
|
+
return allItems.filter((item) => !['dropin', 'must-use'].includes(item.status));
|
|
292
|
+
}
|
|
293
|
+
// Generic method to handle updating items
|
|
294
|
+
async processItemUpdates(type, skip, wpConfig, branchRef) {
|
|
295
|
+
if (skip) {
|
|
296
|
+
return { count: 0, details: [] };
|
|
297
|
+
}
|
|
298
|
+
const itemConfig = this.getItemConfig(type);
|
|
299
|
+
const items = await this.getItems(type);
|
|
300
|
+
const updateDetails = [];
|
|
301
|
+
let count = 0;
|
|
302
|
+
if (items.length > 0) {
|
|
303
|
+
this.context.stdout.write(ansis.cyan(`${itemConfig.icon} Updating ${type}s...\n`));
|
|
304
|
+
for (const item of items) {
|
|
305
|
+
const result = await this.maybeUpdateItem(item, wpConfig, branchRef, itemConfig);
|
|
306
|
+
if (result.updated) {
|
|
307
|
+
count++;
|
|
308
|
+
if (result.details) {
|
|
309
|
+
updateDetails.push(result.details);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
297
313
|
}
|
|
298
|
-
return
|
|
314
|
+
return { count, details: updateDetails };
|
|
299
315
|
}
|
|
300
|
-
|
|
316
|
+
// Generic method to check and maybe update an item (plugin/theme)
|
|
317
|
+
async maybeUpdateItem(item, wpConfig, branchRef, itemConfig) {
|
|
301
318
|
const { context: { stdout }, } = this;
|
|
302
|
-
if (wpConfig.doNotUpdate.includes(
|
|
303
|
-
stdout.write(ansis.dim(` Skipping ${
|
|
304
|
-
return false;
|
|
319
|
+
if (wpConfig.doNotUpdate.includes(item.name)) {
|
|
320
|
+
stdout.write(ansis.dim(` Skipping ${item.name} (configured to skip)\n`));
|
|
321
|
+
return { updated: false };
|
|
305
322
|
}
|
|
306
|
-
stdout.write(` Checking ${
|
|
307
|
-
if (
|
|
323
|
+
stdout.write(` Checking ${item.name}...`);
|
|
324
|
+
if (item.update === 'available') {
|
|
308
325
|
stdout.write(ansis.green(' updating\n'));
|
|
309
|
-
return await this.
|
|
326
|
+
return await this.updateItem(item, wpConfig, branchRef, itemConfig);
|
|
310
327
|
}
|
|
311
|
-
if (
|
|
328
|
+
if (item.update === 'none') {
|
|
312
329
|
stdout.write(ansis.dim(' up to date\n'));
|
|
313
330
|
}
|
|
314
|
-
else if (
|
|
315
|
-
stdout.write(ansis.yellow(` local version ${
|
|
331
|
+
else if (item.update === 'version higher than expected') {
|
|
332
|
+
stdout.write(ansis.yellow(` local version ${item.version} is higher than remote\n`));
|
|
316
333
|
}
|
|
317
334
|
else {
|
|
318
|
-
stdout.write(ansis.red(` unknown status: ${
|
|
335
|
+
stdout.write(ansis.red(` unknown status: ${item.update}\n`));
|
|
319
336
|
}
|
|
320
|
-
return false;
|
|
337
|
+
return { updated: false };
|
|
321
338
|
}
|
|
322
|
-
|
|
323
|
-
|
|
339
|
+
// Generic method to update an item (plugin/theme)
|
|
340
|
+
async updateItem(item, wpConfig, branchRef, itemConfig) {
|
|
341
|
+
const { config, context: { stdout, stderr }, } = this;
|
|
324
342
|
try {
|
|
325
343
|
const gitCommand = await config.command('git');
|
|
326
|
-
const details = await this.
|
|
344
|
+
const details = await this.getDetails(item.name, itemConfig.type);
|
|
327
345
|
if (!details) {
|
|
328
|
-
return false;
|
|
346
|
+
return { updated: false };
|
|
329
347
|
}
|
|
330
348
|
const fromVersion = details.version;
|
|
331
349
|
const prettyTitle = this.cleanTitle(details.title);
|
|
332
|
-
const location = `${wpConfig
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const updateResultStr = updateResult.exitCode === 0 ? String(updateResult.stdout || '') : null;
|
|
338
|
-
if (!updateResultStr) {
|
|
339
|
-
stderr.write(ansis.red(` Error updating ${plugin.name}\n`));
|
|
340
|
-
return false;
|
|
350
|
+
const location = `${itemConfig.getFolder(wpConfig)}/${item.name}`;
|
|
351
|
+
const updateResult = await this.executeWpCli(itemConfig.updateCommand(item.name), { silent: true });
|
|
352
|
+
if (updateResult.exitCode !== 0) {
|
|
353
|
+
stderr.write(ansis.red(` Error updating ${item.name}\n`));
|
|
354
|
+
return { updated: false };
|
|
341
355
|
}
|
|
342
|
-
const newDetails = await this.
|
|
356
|
+
const newDetails = await this.getDetails(item.name, itemConfig.type);
|
|
343
357
|
if (!newDetails || newDetails.version === details.version) {
|
|
344
358
|
stderr.write(ansis.red(' Update failed!\n'));
|
|
345
|
-
return false;
|
|
359
|
+
return { updated: false };
|
|
346
360
|
}
|
|
347
361
|
// Ensure branch is created before making our first commit
|
|
348
362
|
await this.ensureBranchCreated(wpConfig, branchRef);
|
|
349
|
-
const commitMessage = this.sanitizeCommitMessage(
|
|
350
|
-
await execC(gitCommand, ['add', location]
|
|
363
|
+
const commitMessage = this.sanitizeCommitMessage(`${itemConfig.commitPrefix} ${prettyTitle} to ${newDetails.version}`);
|
|
364
|
+
await execC(gitCommand, ['add', location]);
|
|
351
365
|
await execC(gitCommand, ['commit', '-m', commitMessage], {
|
|
352
|
-
context,
|
|
353
366
|
shell: false,
|
|
354
367
|
env: { SKIP: 'prepare-commit-msg' },
|
|
355
368
|
});
|
|
356
369
|
stdout.write(ansis.green(` Updated ${prettyTitle} from ${fromVersion} to ${newDetails.version}\n`));
|
|
357
|
-
return
|
|
370
|
+
return {
|
|
371
|
+
updated: true,
|
|
372
|
+
details: {
|
|
373
|
+
name: item.name,
|
|
374
|
+
title: prettyTitle,
|
|
375
|
+
fromVersion,
|
|
376
|
+
toVersion: newDetails.version,
|
|
377
|
+
},
|
|
378
|
+
};
|
|
358
379
|
}
|
|
359
380
|
catch (error) {
|
|
360
|
-
stderr.write(ansis.red(` Error updating ${
|
|
361
|
-
return false;
|
|
381
|
+
stderr.write(ansis.red(` Error updating ${item.name}: ${error}\n`));
|
|
382
|
+
return { updated: false };
|
|
362
383
|
}
|
|
363
384
|
}
|
|
364
|
-
async
|
|
365
|
-
const { config
|
|
385
|
+
async createBranch() {
|
|
386
|
+
const { config } = this;
|
|
387
|
+
const isoDate = new Date().toISOString().replace(/[:.]/g, '-').replace(/T/, '_').slice(0, -5);
|
|
388
|
+
const branchName = `joltWpUpdate/${isoDate}`;
|
|
389
|
+
const gitCommand = await config.command('git');
|
|
390
|
+
await execC(gitCommand, ['checkout', '-b', branchName]);
|
|
391
|
+
return branchName;
|
|
392
|
+
}
|
|
393
|
+
async ensureBranchCreated(_wpConfig, branchRef) {
|
|
394
|
+
if (!branchRef.created) {
|
|
395
|
+
branchRef.branch = await this.createBranch();
|
|
396
|
+
branchRef.created = true;
|
|
397
|
+
const { context: { stdout }, } = this;
|
|
398
|
+
stdout.write(ansis.green(`📋 Created update branch ${branchRef.branch}\n`));
|
|
399
|
+
}
|
|
400
|
+
return branchRef.branch;
|
|
401
|
+
}
|
|
402
|
+
async disableGitHooks() {
|
|
403
|
+
const { config, context } = this;
|
|
404
|
+
const gitCommand = await config.command('git');
|
|
366
405
|
try {
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
const fromVersion = details.version;
|
|
373
|
-
const prettyTitle = this.cleanTitle(details.title);
|
|
374
|
-
const location = `${wpConfig.themeFolder}/${theme.name}`;
|
|
375
|
-
const yarnCommand = await config.command('yarn');
|
|
376
|
-
const updateResult = await execC(yarnCommand, ['jolt', 'wp', 'cli', 'theme', 'update', theme.name], {
|
|
377
|
-
reject: false,
|
|
378
|
-
});
|
|
379
|
-
const updateResultStr = updateResult.exitCode === 0 ? String(updateResult.stdout || '') : null;
|
|
380
|
-
if (!updateResultStr) {
|
|
381
|
-
stderr.write(ansis.red(` Error updating ${theme.name}\n`));
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
const newDetails = await this.getThemeDetails(theme.name);
|
|
385
|
-
if (!newDetails || newDetails.version === details.version) {
|
|
386
|
-
stderr.write(ansis.red(' Update failed!\n'));
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
// Ensure branch is created before making our first commit
|
|
390
|
-
await this.ensureBranchCreated(wpConfig, branchRef);
|
|
391
|
-
const commitMessage = this.sanitizeCommitMessage(`Update theme ${prettyTitle} to ${newDetails.version}`);
|
|
392
|
-
await execC(gitCommand, ['add', location], { context });
|
|
393
|
-
await execC(gitCommand, ['commit', '-m', commitMessage], {
|
|
394
|
-
context,
|
|
395
|
-
shell: false,
|
|
396
|
-
env: { SKIP: 'prepare-commit-msg' },
|
|
397
|
-
});
|
|
398
|
-
stdout.write(ansis.green(` Updated theme ${prettyTitle} from ${fromVersion} to ${newDetails.version}\n`));
|
|
399
|
-
return true;
|
|
406
|
+
const result = await execC(gitCommand, ['config', '--get', 'core.hooksPath'], { context, reject: false });
|
|
407
|
+
const originalHookPath = String(result.stdout || '').trim();
|
|
408
|
+
await execC(gitCommand, ['config', 'core.hooksPath', '/dev/null'], { context });
|
|
409
|
+
return originalHookPath;
|
|
400
410
|
}
|
|
401
|
-
catch (
|
|
402
|
-
|
|
403
|
-
return
|
|
411
|
+
catch (_a) {
|
|
412
|
+
await execC(gitCommand, ['config', 'core.hooksPath', '/dev/null'], { context });
|
|
413
|
+
return '';
|
|
404
414
|
}
|
|
405
415
|
}
|
|
406
|
-
async
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
416
|
+
async rollbackGitHooks(originalHookPath) {
|
|
417
|
+
const { config, context } = this;
|
|
418
|
+
const gitCommand = await config.command('git');
|
|
419
|
+
if (originalHookPath) {
|
|
420
|
+
await execC(gitCommand, ['config', 'core.hooksPath', originalHookPath], { context });
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
await execC(gitCommand, ['config', '--unset', 'core.hooksPath'], { context, reject: false });
|
|
424
|
+
}
|
|
411
425
|
}
|
|
412
426
|
async getDetails(name, type) {
|
|
413
|
-
const { config } = this;
|
|
414
|
-
const cmdType = type === 'plugin' ? 'plugin' : 'theme';
|
|
415
427
|
try {
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
reject: false,
|
|
419
|
-
});
|
|
420
|
-
const out = detailsResult.exitCode === 0 ? String(detailsResult.stdout || '') : null;
|
|
421
|
-
if (!out) {
|
|
428
|
+
const result = await this.executeWpCli([type, 'get', '--json', name], { silent: true });
|
|
429
|
+
if (!result.stdout) {
|
|
422
430
|
return null;
|
|
423
431
|
}
|
|
424
|
-
let output =
|
|
432
|
+
let output = result.stdout;
|
|
425
433
|
if (output.startsWith('$')) {
|
|
426
434
|
// Older Yarn versions include the script name in stdout so we need to trim the first line off
|
|
427
435
|
output = output.substring(1 + output.indexOf('\n'));
|
|
@@ -449,8 +457,10 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
449
457
|
const newVersion = await this.hasCoreUpdate();
|
|
450
458
|
if (!newVersion) {
|
|
451
459
|
stdout.write(ansis.dim(' WordPress core is up to date\n'));
|
|
452
|
-
return false;
|
|
460
|
+
return { updated: false };
|
|
453
461
|
}
|
|
462
|
+
// Get current version before updating
|
|
463
|
+
const currentVersion = await this.getCurrentCoreVersion();
|
|
454
464
|
stdout.write(ansis.green(` Updating WordPress core to ${newVersion}\n`));
|
|
455
465
|
const shouldStash = await this.hasGitChanges(wpConfig.wpRoot);
|
|
456
466
|
if (shouldStash) {
|
|
@@ -460,7 +470,13 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
460
470
|
try {
|
|
461
471
|
await this.doCoreUpdate(wpConfig.wpRoot, newVersion, wpConfig, branchRef);
|
|
462
472
|
stdout.write(ansis.green(` Updated WordPress core to ${newVersion}\n`));
|
|
463
|
-
return
|
|
473
|
+
return {
|
|
474
|
+
updated: true,
|
|
475
|
+
details: {
|
|
476
|
+
fromVersion: currentVersion || 'unknown',
|
|
477
|
+
toVersion: newVersion,
|
|
478
|
+
},
|
|
479
|
+
};
|
|
464
480
|
}
|
|
465
481
|
finally {
|
|
466
482
|
if (shouldStash) {
|
|
@@ -469,22 +485,23 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
469
485
|
}
|
|
470
486
|
}
|
|
471
487
|
}
|
|
488
|
+
async getCurrentCoreVersion() {
|
|
489
|
+
try {
|
|
490
|
+
const result = await this.executeWpCli(['core', 'version'], { silent: true });
|
|
491
|
+
return result.stdout ? result.stdout.trim() : null;
|
|
492
|
+
}
|
|
493
|
+
catch (_a) {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
472
497
|
async hasCoreUpdate() {
|
|
473
498
|
var _a;
|
|
474
|
-
const { config } = this;
|
|
475
499
|
try {
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
reject: false,
|
|
479
|
-
});
|
|
480
|
-
if (!coreResult || coreResult.exitCode !== 0) {
|
|
500
|
+
const result = await this.executeWpCli(['core', 'check-update', '--json'], { silent: true });
|
|
501
|
+
if (!result.stdout || !result.stdout.trim() || result.stdout.trim() === '[]') {
|
|
481
502
|
return false;
|
|
482
503
|
}
|
|
483
|
-
const
|
|
484
|
-
if (!stdoutStr.trim() || stdoutStr.trim() === '[]') {
|
|
485
|
-
return false;
|
|
486
|
-
}
|
|
487
|
-
const trimmed = stdoutStr.substring(stdoutStr.indexOf('[{'));
|
|
504
|
+
const trimmed = result.stdout.substring(result.stdout.indexOf('[{'));
|
|
488
505
|
const parsed = JSON.parse(trimmed);
|
|
489
506
|
return ((_a = parsed[0]) === null || _a === void 0 ? void 0 : _a.version) || false;
|
|
490
507
|
}
|
|
@@ -493,11 +510,10 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
493
510
|
}
|
|
494
511
|
}
|
|
495
512
|
async hasGitChanges(path) {
|
|
496
|
-
const { config
|
|
513
|
+
const { config } = this;
|
|
497
514
|
try {
|
|
498
515
|
const gitCommand = await config.command('git');
|
|
499
516
|
const result = await execC(gitCommand, ['status', '--porcelain=v1', '--', path], {
|
|
500
|
-
context,
|
|
501
517
|
reject: false,
|
|
502
518
|
});
|
|
503
519
|
return String(result.stdout || '').trim() !== '';
|
|
@@ -507,36 +523,92 @@ export class WPUpdateCommand extends JoltCommand {
|
|
|
507
523
|
}
|
|
508
524
|
}
|
|
509
525
|
async stashChanges() {
|
|
510
|
-
const { config
|
|
526
|
+
const { config } = this;
|
|
511
527
|
const date = new Date().toISOString();
|
|
512
528
|
const gitCommand = await config.command('git');
|
|
513
|
-
await execC(gitCommand, ['add', '.']
|
|
529
|
+
await execC(gitCommand, ['add', '.']);
|
|
514
530
|
await execC(gitCommand, ['stash', 'save', '--', `Automated stash by Jolt WP Updater at ${date}`], {
|
|
515
|
-
context,
|
|
516
531
|
shell: false,
|
|
517
532
|
});
|
|
518
533
|
}
|
|
519
534
|
async unstashChanges() {
|
|
520
|
-
const { config
|
|
535
|
+
const { config } = this;
|
|
521
536
|
const gitCommand = await config.command('git');
|
|
522
|
-
await execC(gitCommand, ['stash', 'pop']
|
|
523
|
-
await execC(gitCommand, ['reset', 'HEAD', '--']
|
|
537
|
+
await execC(gitCommand, ['stash', 'pop']);
|
|
538
|
+
await execC(gitCommand, ['reset', 'HEAD', '--']);
|
|
524
539
|
}
|
|
525
540
|
async doCoreUpdate(path, version, wpConfig, branchRef) {
|
|
526
|
-
const { config
|
|
541
|
+
const { config } = this;
|
|
527
542
|
// Ensure branch is created before making our first commit
|
|
528
543
|
await this.ensureBranchCreated(wpConfig, branchRef);
|
|
529
544
|
const gitCommand = await config.command('git');
|
|
530
|
-
|
|
531
|
-
await execC(
|
|
532
|
-
await execC(gitCommand, ['add', path], { context });
|
|
545
|
+
await this.executeWpCli(['core', 'update'], { silent: true });
|
|
546
|
+
await execC(gitCommand, ['add', path]);
|
|
533
547
|
const commitMessage = this.sanitizeCommitMessage(`Update WordPress to ${version}`);
|
|
534
548
|
await execC(gitCommand, ['commit', '-m', commitMessage], {
|
|
535
|
-
context,
|
|
536
549
|
shell: false,
|
|
537
550
|
env: { SKIP: 'prepare-commit-msg' },
|
|
538
551
|
});
|
|
539
552
|
}
|
|
553
|
+
async maybeUpdateTranslations(branchRef) {
|
|
554
|
+
const { config, context: { stdout, stderr }, } = this;
|
|
555
|
+
try {
|
|
556
|
+
let hasUpdates = false;
|
|
557
|
+
// Helper to check and update translations for a specific type
|
|
558
|
+
const updateTranslationType = async (type, command) => {
|
|
559
|
+
stdout.write(` Checking ${type} translations...`);
|
|
560
|
+
const result = await this.executeWpCli(command, { silent: true });
|
|
561
|
+
if (result.exitCode === 0 && result.stdout) {
|
|
562
|
+
if (result.stdout.includes('Updated') || result.stdout.includes('updated')) {
|
|
563
|
+
hasUpdates = true;
|
|
564
|
+
stdout.write(ansis.green(' updated\n'));
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
stdout.write(ansis.dim(' up to date\n'));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
stdout.write(ansis.dim(' skipped (not available)\n'));
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
// Update different translation types
|
|
575
|
+
await updateTranslationType('core', ['language', 'core', 'update']);
|
|
576
|
+
await updateTranslationType('plugin', ['language', 'plugin', 'update', '--all']);
|
|
577
|
+
await updateTranslationType('theme', ['language', 'theme', 'update', '--all']);
|
|
578
|
+
// If we have translation updates, commit them
|
|
579
|
+
if (hasUpdates) {
|
|
580
|
+
const wpConfig = await config.loadWordPressConfig();
|
|
581
|
+
if (!wpConfig) {
|
|
582
|
+
stderr.write(ansis.red('Failed to load WordPress configuration\n'));
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
// Create or ensure we're on the update branch
|
|
586
|
+
await this.ensureBranchCreated(wpConfig, branchRef);
|
|
587
|
+
const gitCommand = await config.command('git');
|
|
588
|
+
// Add all language files that might have been updated
|
|
589
|
+
await execC(gitCommand, ['add', wpConfig.wpRoot]);
|
|
590
|
+
// Check if there are any changes to commit
|
|
591
|
+
const statusResult = await execC(gitCommand, ['diff', '--cached', '--exit-code'], {
|
|
592
|
+
reject: false,
|
|
593
|
+
});
|
|
594
|
+
if (statusResult.exitCode !== 0) {
|
|
595
|
+
// There are changes to commit
|
|
596
|
+
await execC(gitCommand, ['commit', '-m', 'Update translations'], {
|
|
597
|
+
shell: false,
|
|
598
|
+
env: { SKIP: 'prepare-commit-msg' },
|
|
599
|
+
});
|
|
600
|
+
stdout.write(ansis.green(' Committed translation updates\n'));
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
stdout.write(ansis.dim(' No translation files changed\n'));
|
|
604
|
+
}
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
stderr.write(ansis.red(`Error updating translations: ${error}\n`));
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
540
612
|
}
|
|
541
613
|
WPUpdateCommand.paths = [['wp', 'update']];
|
|
542
614
|
export class WPUpdateMergeCommand extends JoltCommand {
|
|
@@ -720,6 +792,9 @@ export class WPUpdateModifyCommand extends JoltCommand {
|
|
|
720
792
|
constructor() {
|
|
721
793
|
super(...arguments);
|
|
722
794
|
this.requiredCommands = ['git'];
|
|
795
|
+
this.autostash = Option.Boolean('--autostash', false, {
|
|
796
|
+
description: 'Automatically stash and unstash changes before and after the rebase',
|
|
797
|
+
});
|
|
723
798
|
}
|
|
724
799
|
async command() {
|
|
725
800
|
const { config, context, context: { stdout, stderr }, logo, } = this;
|
|
@@ -732,7 +807,7 @@ export class WPUpdateModifyCommand extends JoltCommand {
|
|
|
732
807
|
try {
|
|
733
808
|
const gitCommand = await config.command('git');
|
|
734
809
|
// Get current branch
|
|
735
|
-
const currentBranchResult = await execC(gitCommand, ['branch', '--show-current']
|
|
810
|
+
const currentBranchResult = await execC(gitCommand, ['branch', '--show-current']);
|
|
736
811
|
const currentBranch = String(currentBranchResult.stdout || '').trim();
|
|
737
812
|
if (!currentBranch.startsWith('joltWpUpdate/')) {
|
|
738
813
|
stderr.write(ansis.red('Not currently on a WordPress update branch\n'));
|
|
@@ -741,7 +816,6 @@ export class WPUpdateModifyCommand extends JoltCommand {
|
|
|
741
816
|
// Count commits since branching from main
|
|
742
817
|
const branchName = (await config.get('branch')) || 'master';
|
|
743
818
|
const commitCountResult = await execC(gitCommand, ['rev-list', '--count', `${branchName}..HEAD`], {
|
|
744
|
-
context,
|
|
745
819
|
reject: false,
|
|
746
820
|
});
|
|
747
821
|
if (commitCountResult.exitCode !== 0) {
|
|
@@ -755,7 +829,11 @@ export class WPUpdateModifyCommand extends JoltCommand {
|
|
|
755
829
|
}
|
|
756
830
|
stdout.write(ansis.cyan(`📋 Starting interactive rebase for ${commitCount} commits...\n`));
|
|
757
831
|
// Run interactive rebase
|
|
758
|
-
const
|
|
832
|
+
const rebaseArgs = ['rebase', '-i', `HEAD~${commitCount}`];
|
|
833
|
+
if (this.autostash) {
|
|
834
|
+
rebaseArgs.push('--autostash');
|
|
835
|
+
}
|
|
836
|
+
const rebaseResult = await execC(gitCommand, rebaseArgs, {
|
|
759
837
|
context,
|
|
760
838
|
reject: false,
|
|
761
839
|
});
|