@bostonuniversity/buwp-local 0.6.3 → 0.7.1
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/buwp-local.js +9 -0
- package/docs/ARCHITECTURE.md +3 -56
- package/docs/CHANGELOG.md +18 -0
- package/docs/COMMANDS.md +40 -0
- package/docs/MIGRATION_FROM_VM.md +1 -4
- package/docs/ROADMAP.md +27 -10
- package/lib/commands/destroy.js +1 -1
- package/lib/commands/init.js +37 -35
- package/lib/commands/update.js +113 -0
- package/package.json +2 -2
- package/.buwp-local.json +0 -22
- package/MULTI_PROJECT_GUIDE.md +0 -929
- package/PROJECT_OVERVIEW.md +0 -307
- package/QUICK_REFERENCE.md +0 -234
- package/ROADMAP.md +0 -363
- package/USAGE.md +0 -324
- package/docker-compose.yml +0 -106
- package/docs/MULTI_PROJECT.md +0 -516
- package/feedback-from-0-6-1.md +0 -16
package/bin/buwp-local.js
CHANGED
|
@@ -24,6 +24,7 @@ const packageJson = JSON.parse(
|
|
|
24
24
|
import startCommand from '../lib/commands/start.js';
|
|
25
25
|
import stopCommand from '../lib/commands/stop.js';
|
|
26
26
|
import destroyCommand from '../lib/commands/destroy.js';
|
|
27
|
+
import updateCommand from '../lib/commands/update.js';
|
|
27
28
|
import logsCommand from '../lib/commands/logs.js';
|
|
28
29
|
import wpCommand from '../lib/commands/wp.js';
|
|
29
30
|
import shellCommand from '../lib/commands/shell.js';
|
|
@@ -60,6 +61,13 @@ program
|
|
|
60
61
|
.option('-f, --force', 'Skip confirmation prompt')
|
|
61
62
|
.action(destroyCommand);
|
|
62
63
|
|
|
64
|
+
// Update command
|
|
65
|
+
program
|
|
66
|
+
.command('update')
|
|
67
|
+
.description('Update Docker images and recreate containers')
|
|
68
|
+
.option('--all', 'Update all service images (default: WordPress only)')
|
|
69
|
+
.action(updateCommand);
|
|
70
|
+
|
|
63
71
|
// Logs command
|
|
64
72
|
program
|
|
65
73
|
.command('logs')
|
|
@@ -88,6 +96,7 @@ program
|
|
|
88
96
|
.option('--plugin', 'Non-interactive: initialize as plugin')
|
|
89
97
|
.option('--mu-plugin', 'Non-interactive: initialize as mu-plugin')
|
|
90
98
|
.option('--theme', 'Non-interactive: initialize as theme')
|
|
99
|
+
.option('--sandbox', 'Non-interactive: initialize as sandbox')
|
|
91
100
|
.option('-f, --force', 'Overwrite existing configuration')
|
|
92
101
|
.action(initCommand);
|
|
93
102
|
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -442,9 +442,9 @@ Docker's **volume mapping architecture** creates a clean separation:
|
|
|
442
442
|
│ └── wp-content/ │
|
|
443
443
|
│ └── plugins/ │
|
|
444
444
|
│ └── my-plugin/ ──┐ │ (mapped from Mac)
|
|
445
|
-
│
|
|
446
|
-
│ SEPARATED = No conflicts!
|
|
447
|
-
|
|
445
|
+
│ │ │
|
|
446
|
+
│ SEPARATED = No conflicts! │ │
|
|
447
|
+
└───────────────────────────────┴─┘
|
|
448
448
|
```
|
|
449
449
|
|
|
450
450
|
**Technical Benefits:**
|
|
@@ -459,47 +459,6 @@ Docker's **volume mapping architecture** creates a clean separation:
|
|
|
459
459
|
|
|
460
460
|
5. **Safe Testing** - Test breaking changes in WordPress without risk. If something goes wrong, recreate the container—your code was never in danger.
|
|
461
461
|
|
|
462
|
-
#### Workflow Comparison
|
|
463
|
-
|
|
464
|
-
**VM Sandbox Workflow:**
|
|
465
|
-
```
|
|
466
|
-
Week 1-3: Develop in VM
|
|
467
|
-
Week 4: Monthly rebuild
|
|
468
|
-
1. Backup your code manually
|
|
469
|
-
2. Coordinate with team
|
|
470
|
-
3. Wait for new VM image
|
|
471
|
-
4. Restore code manually
|
|
472
|
-
5. Re-test everything
|
|
473
|
-
6. Hope nothing broke
|
|
474
|
-
Time lost: 2-4 hours + coordination overhead
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
**buwp-local Workflow:**
|
|
478
|
-
```
|
|
479
|
-
Anytime: New WordPress version available
|
|
480
|
-
1. docker pull ghcr.io/bu-ist/buwp:latest
|
|
481
|
-
2. npx buwp-local start
|
|
482
|
-
3. Test (your code unchanged)
|
|
483
|
-
Time: 2 minutes
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
#### Real-World Example
|
|
487
|
-
|
|
488
|
-
**Scenario:** 6-week plugin development project. WordPress update lands in week 3.
|
|
489
|
-
|
|
490
|
-
**VM Approach:**
|
|
491
|
-
- Wait for scheduled monthly rebuild (week 4)
|
|
492
|
-
- Backup your work
|
|
493
|
-
- Rebuild overwrites everything
|
|
494
|
-
- Restore and re-test
|
|
495
|
-
- **Impact:** 2-4 hours lost, risk of data loss
|
|
496
|
-
|
|
497
|
-
**buwp-local Approach:**
|
|
498
|
-
- Pull new image when convenient (any time in week 3-6)
|
|
499
|
-
- Containers recreate with new WordPress version
|
|
500
|
-
- Your code untouched on local filesystem
|
|
501
|
-
- **Impact:** 2 minutes, zero risk
|
|
502
|
-
|
|
503
462
|
### Separation of Concerns
|
|
504
463
|
|
|
505
464
|
This architecture provides clean boundaries:
|
|
@@ -516,18 +475,6 @@ This architecture provides clean boundaries:
|
|
|
516
475
|
|
|
517
476
|
Updates to WordPress never touch your development code. Updates to your code never require rebuilding WordPress.
|
|
518
477
|
|
|
519
|
-
### Additional Architectural Benefits
|
|
520
|
-
|
|
521
|
-
1. **Live Reload** - File changes sync instantly via volume mappings. Save in your editor, refresh browser, see changes.
|
|
522
|
-
|
|
523
|
-
2. **IDE Integration** - Use any editor (VS Code, PHPStorm, Sublime) with full IDE features (autocomplete, debugging, git integration).
|
|
524
|
-
|
|
525
|
-
3. **Version Control** - Your code is already on the host filesystem where git lives. No special workflows to commit from inside VMs.
|
|
526
|
-
|
|
527
|
-
4. **Multiple Projects** - Run multiple projects simultaneously, each with isolated environments. No VM resource conflicts.
|
|
528
|
-
|
|
529
|
-
5. **Portable Configuration** - Commit `.buwp-local.json` to version control. Teammates get identical environments with one command.
|
|
530
|
-
|
|
531
478
|
For detailed migration guidance, see [MIGRATION_FROM_VM.md](MIGRATION_FROM_VM.md).
|
|
532
479
|
|
|
533
480
|
## Security Model
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to buwp-local will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.7.1]
|
|
9
|
+
|
|
10
|
+
Documentation only release.
|
|
11
|
+
|
|
12
|
+
## [0.7.0]
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`update` command** - Pull latest Docker images and recreate containers without losing data
|
|
16
|
+
- Pull WordPress image only by default (typical use case)
|
|
17
|
+
- `--all` flag to update all service images (Redis, S3 proxy, etc.)
|
|
18
|
+
- Safely applies security updates and WordPress core updates
|
|
19
|
+
- Data preserved: Database, WordPress files, volume mappings
|
|
20
|
+
|
|
21
|
+
- **Non-interactive sandbox initialization** - Add `--sandbox` flag to `init` command for scripted setup of sandbox-type projects
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- **`init` command** - Now supports `--sandbox` flag for non-interactive initialization
|
|
25
|
+
|
|
8
26
|
## [0.6.3]
|
|
9
27
|
|
|
10
28
|
### Added
|
package/docs/COMMANDS.md
CHANGED
|
@@ -115,6 +115,46 @@ npx buwp-local destroy --force
|
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
118
|
+
### `update`
|
|
119
|
+
|
|
120
|
+
Update Docker images and recreate containers without losing data.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx buwp-local update [options]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Options:**
|
|
127
|
+
- `--all` - Update all service images (default: WordPress image only)
|
|
128
|
+
|
|
129
|
+
**Examples:**
|
|
130
|
+
```bash
|
|
131
|
+
# Update WordPress image only (recommended)
|
|
132
|
+
npx buwp-local update
|
|
133
|
+
|
|
134
|
+
# Update all service images (Redis, S3 proxy, etc.)
|
|
135
|
+
npx buwp-local update --all
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**What it does:**
|
|
139
|
+
- Checks if environment exists and Docker is running
|
|
140
|
+
- Pulls latest Docker images from registry
|
|
141
|
+
- Recreates containers with new images using `--force-recreate`
|
|
142
|
+
- Loads credentials from Keychain and/or `.env.local`
|
|
143
|
+
- **Preserves volumes** - Database and WordPress files untouched
|
|
144
|
+
- Shows success message confirming what was preserved
|
|
145
|
+
|
|
146
|
+
**Use cases:**
|
|
147
|
+
- Pull latest WordPress updates without losing development work
|
|
148
|
+
- Update only WordPress image (typical use case) or all services
|
|
149
|
+
- Safe alternative to `destroy` when you only want to refresh images
|
|
150
|
+
|
|
151
|
+
**Key difference from `stop/start`:**
|
|
152
|
+
- `stop` → `start`: Reuses existing containers (no new images)
|
|
153
|
+
- `update`: Pulls new images and recreates containers (gets updates)
|
|
154
|
+
- `destroy`: Removes everything including volumes (fresh start)
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
118
158
|
### `logs`
|
|
119
159
|
|
|
120
160
|
View logs from Docker containers.
|
|
@@ -198,9 +198,6 @@ npx buwp-local start
|
|
|
198
198
|
```bash
|
|
199
199
|
# Check Docker Desktop is running
|
|
200
200
|
docker info
|
|
201
|
-
|
|
202
|
-
# Check port conflicts
|
|
203
|
-
npx buwp-local start --verbose
|
|
204
201
|
```
|
|
205
202
|
|
|
206
203
|
### Code changes not appearing
|
|
@@ -224,7 +221,7 @@ Check volume mappings in `.buwp-local.json`:
|
|
|
224
221
|
# Verify Keychain entries
|
|
225
222
|
npx buwp-local keychain list
|
|
226
223
|
|
|
227
|
-
# Or use .env.local fallback
|
|
224
|
+
# Or use .env.local fallback --- this is a nice idea, but the actual command does not yet exist
|
|
228
225
|
npx buwp-local keychain export > .env.local
|
|
229
226
|
```
|
|
230
227
|
|
package/docs/ROADMAP.md
CHANGED
|
@@ -102,7 +102,7 @@ hostile.remove('127.0.0.1', config.hostname);
|
|
|
102
102
|
---
|
|
103
103
|
|
|
104
104
|
## Incremental Functional Improvements: v0.6.x
|
|
105
|
-
**Status:**
|
|
105
|
+
**Status:** Shipped
|
|
106
106
|
**Focus:** Enhancements based on initial user experience
|
|
107
107
|
|
|
108
108
|
### Shipped in v0.6.1
|
|
@@ -115,7 +115,7 @@ hostile.remove('127.0.0.1', config.hostname);
|
|
|
115
115
|
- **Fix issues with spaces in paths**
|
|
116
116
|
- Fix issues with spaces in host paths causing Docker errors
|
|
117
117
|
|
|
118
|
-
###
|
|
118
|
+
### Shipped for v0.6.3
|
|
119
119
|
|
|
120
120
|
- **Basic docs on existing Xdebug features**
|
|
121
121
|
- Quickstart guide for enabling and using Xdebug in containers
|
|
@@ -123,10 +123,6 @@ hostile.remove('127.0.0.1', config.hostname);
|
|
|
123
123
|
- **Volume Mapping pattern guide**
|
|
124
124
|
- Documentation on different volume mapping strategies for various development workflows
|
|
125
125
|
|
|
126
|
-
### Shipped in v0.6.3
|
|
127
|
-
|
|
128
|
-
**Focus:** Documentation refinement based on real user patterns
|
|
129
|
-
|
|
130
126
|
**Key Deliverables:**
|
|
131
127
|
|
|
132
128
|
1. **Volume Mapping Patterns Guide** ✅
|
|
@@ -152,12 +148,24 @@ hostile.remove('127.0.0.1', config.hostname);
|
|
|
152
148
|
|
|
153
149
|
**Result:** Documentation now accurately reflects real-world development workflows, making it easier for new users to adopt appropriate patterns.
|
|
154
150
|
|
|
155
|
-
## Next Phase: v0.7.
|
|
151
|
+
## Next Phase: v0.7.x - Developer Experience
|
|
156
152
|
|
|
157
|
-
**Status:**
|
|
158
|
-
**Timeline:** After team onboarding feedback
|
|
153
|
+
**Status:** Ongoing
|
|
159
154
|
**Focus:** Ease of use and visibility
|
|
160
155
|
|
|
156
|
+
### Shipped in v0.7.0
|
|
157
|
+
- **Docker Image Update Command** 🎯 (Proposed for v0.7.0)
|
|
158
|
+
- **Problem:** Stopping and restarting containers reuses existing images; newer images aren't pulled
|
|
159
|
+
- **Solution:** Add `buwp-local update` command that:
|
|
160
|
+
- Pulls latest Docker images from registry
|
|
161
|
+
- Recreates containers with new images
|
|
162
|
+
- Preserves volumes (database, WordPress data)
|
|
163
|
+
- **Benefit:** Safe, explicit way to apply WordPress/service updates without `destroy`
|
|
164
|
+
- **Implementation:** Wrapper around `docker-compose pull && docker-compose up -d --force-recreate`
|
|
165
|
+
|
|
166
|
+
### Shipped in v0.7.1
|
|
167
|
+
- **Documentation Improvements**
|
|
168
|
+
|
|
161
169
|
### Potential Features
|
|
162
170
|
|
|
163
171
|
- **Database Security**
|
|
@@ -169,6 +177,10 @@ hostile.remove('127.0.0.1', config.hostname);
|
|
|
169
177
|
- Command to help generate Xdebug configuration for IDEs (VSCode, Zed)
|
|
170
178
|
- Documentation on usage patterns
|
|
171
179
|
|
|
180
|
+
- **Interactive setup assistant for adding volume mappings**
|
|
181
|
+
- Guided prompts to add common volume mappings post-initialization
|
|
182
|
+
- Suggestions based on detected project structure
|
|
183
|
+
|
|
172
184
|
- **Improved Windows and Linux support**
|
|
173
185
|
- Multiplatform /etc/hosts hostname guide
|
|
174
186
|
- Evaluate credential storage solutions for non-macOS platforms (https://www.npmjs.com/package/keytar)
|
|
@@ -195,6 +207,10 @@ hostile.remove('127.0.0.1', config.hostname);
|
|
|
195
207
|
- **Docker Volume management assistant**
|
|
196
208
|
- listing and cleanup of unused volumes
|
|
197
209
|
|
|
210
|
+
- **Unit tests**
|
|
211
|
+
- Core modules (config, keychain, docker-compose)
|
|
212
|
+
- Command tests (init, start, stop, destroy, wp)
|
|
213
|
+
|
|
198
214
|
### Prioritization
|
|
199
215
|
Will be informed by feedback from initial small group of users and actual pain points observed during rollout.
|
|
200
216
|
|
|
@@ -209,7 +225,8 @@ Will be informed by feedback from initial small group of users and actual pain p
|
|
|
209
225
|
|
|
210
226
|
- **Cross-Platform Support** - Windows WSL2 and Linux credential storage
|
|
211
227
|
- **SSL Certificate Generation** - Local HTTPS with mkcert
|
|
212
|
-
- **
|
|
228
|
+
- **Real support for running on ports other than 443**
|
|
229
|
+
- **Potential GUI from Electron or SwiftUI**
|
|
213
230
|
|
|
214
231
|
**Note:** Automatic `/etc/hosts` management deferred pending user feedback. See "Lessons Learned" section above for details on the `hostile` library approach.
|
|
215
232
|
|
package/lib/commands/destroy.js
CHANGED
|
@@ -85,7 +85,7 @@ function confirmDestroy(projectName) {
|
|
|
85
85
|
console.log(chalk.yellow(`This will destroy project: ${chalk.bold(projectName)}`));
|
|
86
86
|
console.log(chalk.yellow(' - Stop all containers'));
|
|
87
87
|
console.log(chalk.yellow(' - Remove all containers'));
|
|
88
|
-
console.log(chalk.yellow(' - Delete all volumes (including database data)
|
|
88
|
+
console.log(chalk.yellow(' - Delete all volumes (including database data)\n'));
|
|
89
89
|
|
|
90
90
|
rl.question(chalk.red('Are you sure you want to continue? (yes/no): '), (answer) => {
|
|
91
91
|
rl.close();
|
package/lib/commands/init.js
CHANGED
|
@@ -9,6 +9,17 @@ import fs from 'fs';
|
|
|
9
9
|
import os from 'os';
|
|
10
10
|
import { initConfig, CONFIG_FILE_NAME } from '../config.js';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Container path templates for project types
|
|
14
|
+
* Defines where each project type maps to in the WordPress container
|
|
15
|
+
*/
|
|
16
|
+
const MAPPING_TEMPLATES = {
|
|
17
|
+
'plugin': '/var/www/html/wp-content/plugins/{name}',
|
|
18
|
+
'mu-plugin': '/var/www/html/wp-content/mu-plugins/{name}',
|
|
19
|
+
'theme': '/var/www/html/wp-content/themes/{name}',
|
|
20
|
+
'sandbox': null // Sandbox has no default mapping
|
|
21
|
+
};
|
|
22
|
+
|
|
12
23
|
/**
|
|
13
24
|
* Detect project type from package.json or directory structure
|
|
14
25
|
* @param {string} projectPath - Path to project directory
|
|
@@ -84,6 +95,7 @@ async function initCommand(options) {
|
|
|
84
95
|
if (options.plugin) initOptions.plugin = true;
|
|
85
96
|
if (options.muPlugin) initOptions.muPlugin = true;
|
|
86
97
|
if (options.theme) initOptions.theme = true;
|
|
98
|
+
if (options.sandbox) initOptions.sandbox = true;
|
|
87
99
|
|
|
88
100
|
const configPath = initConfig(projectPath, initOptions);
|
|
89
101
|
console.log(chalk.green(`✅ Created configuration file: ${configPath}\n`));
|
|
@@ -101,11 +113,26 @@ async function initCommand(options) {
|
|
|
101
113
|
console.log(chalk.cyan(`ℹ️ Detected project type: ${detectedType}\n`));
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
// Define project type choices
|
|
117
|
+
const projectTypeChoices = [
|
|
118
|
+
{ title: 'Plugin', value: 'plugin', description: 'WordPress plugin development' },
|
|
119
|
+
{ title: 'MU Plugin', value: 'mu-plugin', description: 'Must-use plugin development' },
|
|
120
|
+
{ title: 'Theme', value: 'theme', description: 'WordPress theme development' },
|
|
121
|
+
{ title: 'Sandbox', value: 'sandbox', description: 'Base WordPress environment (add code mappings later)' }
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
// Determine default project type with priority: CLI flag > detected type > default
|
|
125
|
+
const typeFromFlag = options.plugin ? 'plugin'
|
|
126
|
+
: options.muPlugin ? 'mu-plugin'
|
|
127
|
+
: options.theme ? 'theme'
|
|
128
|
+
: options.sandbox ? 'sandbox'
|
|
129
|
+
: null;
|
|
130
|
+
|
|
131
|
+
const preferredType = typeFromFlag || detectedType || 'plugin';
|
|
132
|
+
|
|
133
|
+
const defaultTypeIndex = projectTypeChoices.findIndex(
|
|
134
|
+
choice => choice.value === preferredType
|
|
135
|
+
);
|
|
109
136
|
|
|
110
137
|
const questions = [
|
|
111
138
|
{
|
|
@@ -119,13 +146,7 @@ async function initCommand(options) {
|
|
|
119
146
|
type: 'select',
|
|
120
147
|
name: 'projectType',
|
|
121
148
|
message: 'Project type',
|
|
122
|
-
choices:
|
|
123
|
-
{ title: 'Plugin', value: 'plugin', description: 'WordPress plugin development' },
|
|
124
|
-
{ title: 'MU Plugin', value: 'mu-plugin', description: 'Must-use plugin development' },
|
|
125
|
-
{ title: 'Theme', value: 'theme', description: 'WordPress theme development' },
|
|
126
|
-
{ title: 'Sandbox', value: 'sandbox', description: 'Base WordPress environment (add code mappings later)' },
|
|
127
|
-
{ title: 'Custom', value: 'custom', description: 'Custom mapping configuration' }
|
|
128
|
-
],
|
|
149
|
+
choices: projectTypeChoices,
|
|
129
150
|
initial: defaultTypeIndex
|
|
130
151
|
},
|
|
131
152
|
{
|
|
@@ -245,31 +266,12 @@ async function initCommand(options) {
|
|
|
245
266
|
}
|
|
246
267
|
};
|
|
247
268
|
|
|
248
|
-
// Add mapping based on project type
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
local: './',
|
|
252
|
-
container: `/var/www/html/wp-content/plugins/${answers.projectName}`
|
|
253
|
-
});
|
|
254
|
-
} else if (answers.projectType === 'mu-plugin') {
|
|
255
|
-
config.mappings.push({
|
|
256
|
-
local: './',
|
|
257
|
-
container: `/var/www/html/wp-content/mu-plugins/${answers.projectName}`
|
|
258
|
-
});
|
|
259
|
-
} else if (answers.projectType === 'theme') {
|
|
260
|
-
config.mappings.push({
|
|
261
|
-
local: './',
|
|
262
|
-
container: `/var/www/html/wp-content/themes/${answers.projectName}`
|
|
263
|
-
});
|
|
264
|
-
} else if (answers.projectType === 'sandbox') {
|
|
265
|
-
// Sandbox type: no initial mappings
|
|
266
|
-
// User can add mappings manually to config.mappings array
|
|
267
|
-
} else {
|
|
268
|
-
// Custom type
|
|
269
|
+
// Add mapping based on project type using template
|
|
270
|
+
const template = MAPPING_TEMPLATES[answers.projectType];
|
|
271
|
+
if (template) {
|
|
269
272
|
config.mappings.push({
|
|
270
273
|
local: './',
|
|
271
|
-
container: '
|
|
272
|
-
comment: 'Customize this mapping for your project'
|
|
274
|
+
container: template.replace('{name}', answers.projectName)
|
|
273
275
|
});
|
|
274
276
|
}
|
|
275
277
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update command - Updates Docker images and recreates containers
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { loadConfig, loadKeychainCredentials, createSecureTempEnvFile, secureDeleteTempEnvFile, ENV_FILE_NAME } from '../config.js';
|
|
10
|
+
|
|
11
|
+
async function updateCommand(options = {}) {
|
|
12
|
+
console.log(chalk.blue('🔄 Updating Docker images...\n'));
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const projectPath = process.cwd();
|
|
16
|
+
const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
|
|
17
|
+
const composeDir = path.dirname(composePath);
|
|
18
|
+
const envFilePath = path.join(projectPath, ENV_FILE_NAME);
|
|
19
|
+
|
|
20
|
+
// Check if docker-compose.yml exists
|
|
21
|
+
if (!fs.existsSync(composePath)) {
|
|
22
|
+
console.log(chalk.yellow('⚠️ No environment found.'));
|
|
23
|
+
console.log(chalk.gray('Run "buwp-local start" to create an environment.\n'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Load config to get project name
|
|
28
|
+
const config = loadConfig(projectPath);
|
|
29
|
+
const projectName = config.projectName || 'buwp-local';
|
|
30
|
+
|
|
31
|
+
// Check if Docker is running
|
|
32
|
+
try {
|
|
33
|
+
execSync('docker info', { stdio: 'ignore' });
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error(chalk.red('❌ Docker is not running'));
|
|
36
|
+
console.log(chalk.gray('Please start Docker Desktop and try again.\n'));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Determine which services to pull
|
|
41
|
+
const pullAll = options.all || false;
|
|
42
|
+
const imageFilter = pullAll ? '' : 'wordpress';
|
|
43
|
+
|
|
44
|
+
// Step 1: Pull images (WordPress only by default, or all with --all flag)
|
|
45
|
+
console.log(chalk.cyan(pullAll ? '📥 Pulling all Docker images...' : '📥 Pulling WordPress image...'));
|
|
46
|
+
try {
|
|
47
|
+
execSync(
|
|
48
|
+
`docker compose -p ${projectName} -f "${composePath}" pull ${imageFilter}`,
|
|
49
|
+
{
|
|
50
|
+
cwd: composeDir,
|
|
51
|
+
stdio: 'inherit'
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error(chalk.red('\n❌ Failed to pull Docker images'));
|
|
56
|
+
console.log(chalk.gray('Check your Docker registry credentials and network connection.\n'));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Step 2: Recreate containers with new images (preserves volumes)
|
|
61
|
+
// Need to pass environment variables just like start command does
|
|
62
|
+
console.log(chalk.cyan('\n🔨 Recreating containers with new images...'));
|
|
63
|
+
|
|
64
|
+
// Load keychain credentials and create secure temp env file if available
|
|
65
|
+
let tempEnvPath = null;
|
|
66
|
+
const finalKeychainCredentials = loadKeychainCredentials();
|
|
67
|
+
const keychainCredCount = Object.keys(finalKeychainCredentials).length;
|
|
68
|
+
|
|
69
|
+
if (keychainCredCount > 0) {
|
|
70
|
+
try {
|
|
71
|
+
tempEnvPath = createSecureTempEnvFile(finalKeychainCredentials, projectName);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.warn(chalk.yellow(`⚠️ Could not load keychain credentials: ${err.message}`));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Build env-file flags
|
|
78
|
+
const envFileFlag = fs.existsSync(envFilePath) ? `--env-file ${envFilePath}` : '';
|
|
79
|
+
const tempEnvFileFlag = tempEnvPath ? `--env-file ${tempEnvPath}` : '';
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
execSync(
|
|
83
|
+
`docker compose -p ${projectName} ${tempEnvFileFlag} ${envFileFlag} -f "${composePath}" up -d --force-recreate`,
|
|
84
|
+
{
|
|
85
|
+
cwd: composeDir,
|
|
86
|
+
stdio: 'inherit'
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(chalk.red('\n❌ Failed to recreate containers'));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
} finally {
|
|
93
|
+
// Always clean up temp env file
|
|
94
|
+
if (tempEnvPath) {
|
|
95
|
+
secureDeleteTempEnvFile(tempEnvPath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Success message
|
|
100
|
+
console.log(chalk.green('\n✅ Update complete!\n'));
|
|
101
|
+
console.log(chalk.gray('Preserved:'));
|
|
102
|
+
console.log(chalk.gray(' ✓ Database and WordPress data'));
|
|
103
|
+
console.log(chalk.gray(' ✓ Volume mappings and configuration\n'));
|
|
104
|
+
console.log(chalk.cyan('Access your site at:'));
|
|
105
|
+
console.log(chalk.white(` https://${config.hostname}\n`));
|
|
106
|
+
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.error(chalk.red('\n❌ Error:'), err.message);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default updateCommand;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bostonuniversity/buwp-local",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Local WordPress development environment for Boston University projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"buwp-local": "
|
|
8
|
+
"buwp-local": "bin/buwp-local.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
package/.buwp-local.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"projectName": "buwp-local",
|
|
3
|
-
"image": "bu-wordpress:latest",
|
|
4
|
-
"hostname": "jaydub.local",
|
|
5
|
-
"multisite": true,
|
|
6
|
-
"services": {
|
|
7
|
-
"redis": true,
|
|
8
|
-
"s3proxy": true,
|
|
9
|
-
"shibboleth": true
|
|
10
|
-
},
|
|
11
|
-
"ports": {
|
|
12
|
-
"http": 80,
|
|
13
|
-
"https": 443,
|
|
14
|
-
"db": 3306,
|
|
15
|
-
"redis": 6379
|
|
16
|
-
},
|
|
17
|
-
"mappings": [],
|
|
18
|
-
"env": {
|
|
19
|
-
"WP_DEBUG": true,
|
|
20
|
-
"XDEBUG": false
|
|
21
|
-
}
|
|
22
|
-
}
|