@bostonuniversity/buwp-local 0.1.0 → 0.3.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/.eslintrc.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "env": {
3
+ "es2022": true,
4
+ "node": true
5
+ },
6
+ "extends": "eslint:recommended",
7
+ "parserOptions": {
8
+ "ecmaVersion": "latest",
9
+ "sourceType": "module"
10
+ },
11
+ "rules": {
12
+ "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
13
+ "no-console": "off"
14
+ }
15
+ }
package/USAGE.md CHANGED
@@ -5,7 +5,7 @@
5
5
  ### 1. Install in your project
6
6
 
7
7
  ```bash
8
- npm install --save-dev buwp-local
8
+ npm install --save-dev @bostonuniversity/buwp-local
9
9
  ```
10
10
 
11
11
  ### 2. Initialize configuration
@@ -14,6 +14,12 @@ npm install --save-dev buwp-local
14
14
  npx buwp-local config --init
15
15
  ```
16
16
 
17
+ ```bash
18
+ buwp-local config --init --plugin # For plugins
19
+ buwp-local config --init --mu-plugin # For mu-plugins
20
+ buwp-local config --init --theme # For themes
21
+ ```
22
+
17
23
  This creates `.buwp-local.json` in your project directory.
18
24
 
19
25
  ### 3. Edit configuration
@@ -250,6 +256,14 @@ See the resolved configuration (with masked secrets):
250
256
  npx buwp-local config --show
251
257
  ```
252
258
 
259
+ ## WP-CLI Command
260
+ ```bash
261
+ buwp-local wp user list
262
+ buwp-local wp post list --format=json
263
+ buwp-local wp plugin activate akismet
264
+ ```
265
+
266
+
253
267
  ## Next Steps
254
268
 
255
269
  - [ ] Phase 2: WP-CLI proxy command
package/bin/buwp-local.js CHANGED
@@ -5,16 +5,29 @@
5
5
  * Main entry point for the BU WordPress Local development environment tool
6
6
  */
7
7
 
8
- const { Command } = require('commander');
9
- const chalk = require('chalk');
10
- const packageJson = require('../package.json');
8
+ import { Command } from 'commander';
9
+ import chalk from 'chalk';
10
+ import { readFileSync } from 'fs';
11
+ import { fileURLToPath } from 'url';
12
+ import { dirname, join } from 'path';
13
+
14
+ // Get __dirname equivalent in ESM
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+
18
+ // Load package.json
19
+ const packageJson = JSON.parse(
20
+ readFileSync(join(__dirname, '../package.json'), 'utf8')
21
+ );
11
22
 
12
23
  // Import commands
13
- const startCommand = require('../lib/commands/start');
14
- const stopCommand = require('../lib/commands/stop');
15
- const destroyCommand = require('../lib/commands/destroy');
16
- const logsCommand = require('../lib/commands/logs');
17
- const configCommand = require('../lib/commands/config');
24
+ import startCommand from '../lib/commands/start.js';
25
+ import stopCommand from '../lib/commands/stop.js';
26
+ import destroyCommand from '../lib/commands/destroy.js';
27
+ import logsCommand from '../lib/commands/logs.js';
28
+ import wpCommand from '../lib/commands/wp.js';
29
+ import shellCommand from '../lib/commands/shell.js';
30
+ import configCommand from '../lib/commands/config.js';
18
31
 
19
32
  const program = new Command();
20
33
 
@@ -70,10 +83,13 @@ program
70
83
  .command('wp <args...>')
71
84
  .description('Run WP-CLI commands in the WordPress container')
72
85
  .allowUnknownOption()
73
- .action((args) => {
74
- console.log(chalk.yellow('WP-CLI proxy not yet implemented'));
75
- console.log('Would run:', args.join(' '));
76
- });
86
+ .action(wpCommand);
87
+
88
+ // Shell command
89
+ program
90
+ .command('shell')
91
+ .description('Open an interactive bash shell in the WordPress container')
92
+ .action(shellCommand);
77
93
 
78
94
  // Error handling
79
95
  program.exitOverride();
@@ -2,8 +2,9 @@
2
2
  * Config command - Configuration management
3
3
  */
4
4
 
5
- const chalk = require('chalk');
6
- const { loadConfig, validateConfig, initConfig, CONFIG_FILE_NAME } = require('../config');
5
+ import chalk from 'chalk';
6
+ import path from 'path';
7
+ import { loadConfig, validateConfig, initConfig, CONFIG_FILE_NAME } from '../config.js';
7
8
 
8
9
  async function configCommand(options) {
9
10
  try {
@@ -31,7 +32,6 @@ async function configCommand(options) {
31
32
  console.log(chalk.green(`✅ Created configuration file: ${configPath}\n`));
32
33
 
33
34
  if (initOptions.plugin || initOptions.muPlugin || initOptions.theme) {
34
- const path = require('path');
35
35
  const projectName = path.basename(projectPath);
36
36
  const type = initOptions.plugin ? 'plugin' : initOptions.muPlugin ? 'mu-plugin' : 'theme';
37
37
  console.log(chalk.cyan(`Auto-configured mapping for ${type}: ${projectName}`));
@@ -128,4 +128,4 @@ function maskSensitiveData(config) {
128
128
  return masked;
129
129
  }
130
130
 
131
- module.exports = configCommand;
131
+ export default configCommand;
@@ -2,12 +2,12 @@
2
2
  * Destroy command - Destroys the local WordPress environment (including volumes)
3
3
  */
4
4
 
5
- const chalk = require('chalk');
6
- const { execSync } = require('child_process');
7
- const path = require('path');
8
- const fs = require('fs');
9
- const readline = require('readline');
10
- const { loadConfig } = require('../config');
5
+ import chalk from 'chalk';
6
+ import { execSync } from 'child_process';
7
+ import path from 'path';
8
+ import fs from 'fs';
9
+ import readline from 'readline';
10
+ import { loadConfig } from '../config.js';
11
11
 
12
12
  async function destroyCommand(options) {
13
13
  console.log(chalk.red('⚠️ DESTROY BU WordPress local environment\n'));
@@ -48,6 +48,7 @@ async function destroyCommand(options) {
48
48
  const composeDir = path.dirname(composePath);
49
49
 
50
50
  try {
51
+ // This is the actual docker compose down command that removes everything
51
52
  execSync(
52
53
  `docker compose -p ${projectName} -f ${composePath} down -v`,
53
54
  {
@@ -93,4 +94,4 @@ function confirmDestroy(projectName) {
93
94
  });
94
95
  }
95
96
 
96
- module.exports = destroyCommand;
97
+ export default destroyCommand;
@@ -2,11 +2,11 @@
2
2
  * Logs command - View logs from the WordPress environment
3
3
  */
4
4
 
5
- const chalk = require('chalk');
6
- const { execSync } = require('child_process');
7
- const path = require('path');
8
- const fs = require('fs');
9
- const { loadConfig } = require('../config');
5
+ import chalk from 'chalk';
6
+ import { execSync } from 'child_process';
7
+ import path from 'path';
8
+ import fs from 'fs';
9
+ import { loadConfig } from '../config.js';
10
10
 
11
11
  async function logsCommand(options) {
12
12
  console.log(chalk.blue('📋 Viewing logs...\n'));
@@ -63,4 +63,4 @@ async function logsCommand(options) {
63
63
  }
64
64
  }
65
65
 
66
- module.exports = logsCommand;
66
+ export default logsCommand;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Shell command - Open an interactive bash shell in the WordPress container
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import { spawnSync } from 'child_process';
7
+ import path from 'path';
8
+ import fs from 'fs';
9
+ import { loadConfig } from '../config.js';
10
+
11
+ async function shellCommand(_options) {
12
+ console.log(chalk.blue('🐚 Opening interactive shell...\n'));
13
+
14
+ try {
15
+ const projectPath = process.cwd();
16
+ const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
17
+
18
+ // Check if docker-compose.yml exists
19
+ if (!fs.existsSync(composePath)) {
20
+ console.log(chalk.yellow('⚠️ No running environment found.'));
21
+ console.log(chalk.gray('Run "buwp-local start" to create an environment.\n'));
22
+ return;
23
+ }
24
+
25
+ // Load config to get project name
26
+ const config = loadConfig(projectPath);
27
+ const projectName = config.projectName || 'buwp-local';
28
+
29
+ // Check if Docker is running
30
+ try {
31
+ spawnSync('docker', ['info'], { stdio: 'ignore' });
32
+ } catch (err) {
33
+ console.error(chalk.red('❌ Docker is not running.'));
34
+ process.exit(1);
35
+ }
36
+
37
+ // Build docker compose exec command for interactive shell
38
+ const composeDir = path.dirname(composePath);
39
+
40
+ // Use spawnSync instead of execSync for proper TTY handling
41
+ const result = spawnSync(
42
+ 'docker',
43
+ [
44
+ 'compose',
45
+ '-p', projectName,
46
+ '-f', composePath,
47
+ 'exec',
48
+ 'wordpress',
49
+ '/bin/bash'
50
+ ],
51
+ {
52
+ cwd: composeDir,
53
+ stdio: 'inherit',
54
+ shell: false
55
+ }
56
+ );
57
+
58
+ // Only show exit message if shell exited with error
59
+ if (result.status !== 0 && result.status !== null) {
60
+ console.log(chalk.yellow(`\n⚠️ Shell exited with code ${result.status}\n`));
61
+ } else {
62
+ console.log(chalk.gray('\n👋 Shell closed.\n'));
63
+ }
64
+
65
+ } catch (err) {
66
+ console.error(chalk.red('\n❌ Error:'), err.message);
67
+ process.exit(1);
68
+ }
69
+ }
70
+
71
+ export default shellCommand;
@@ -2,11 +2,11 @@
2
2
  * Start command - Starts the local WordPress environment
3
3
  */
4
4
 
5
- const chalk = require('chalk');
6
- const { execSync } = require('child_process');
7
- const path = require('path');
8
- const { loadConfig, validateConfig } = require('../config');
9
- const { generateComposeFile } = require('../compose-generator');
5
+ import chalk from 'chalk';
6
+ import { execSync } from 'child_process';
7
+ import path from 'path';
8
+ import { loadConfig, validateConfig } from '../config.js';
9
+ import { generateComposeFile } from '../compose-generator.js';
10
10
 
11
11
  async function startCommand(options) {
12
12
  console.log(chalk.blue('🚀 Starting BU WordPress local environment...\n'));
@@ -95,4 +95,4 @@ async function startCommand(options) {
95
95
  }
96
96
  }
97
97
 
98
- module.exports = startCommand;
98
+ export default startCommand;
@@ -2,11 +2,11 @@
2
2
  * Stop command - Stops the local WordPress environment
3
3
  */
4
4
 
5
- const chalk = require('chalk');
6
- const { execSync } = require('child_process');
7
- const path = require('path');
8
- const fs = require('fs');
9
- const { loadConfig } = require('../config');
5
+ import chalk from 'chalk';
6
+ import { execSync } from 'child_process';
7
+ import path from 'path';
8
+ import fs from 'fs';
9
+ import { loadConfig } from '../config.js';
10
10
 
11
11
  async function stopCommand() {
12
12
  console.log(chalk.blue('🛑 Stopping BU WordPress local environment...\n'));
@@ -59,4 +59,4 @@ async function stopCommand() {
59
59
  }
60
60
  }
61
61
 
62
- module.exports = stopCommand;
62
+ export default stopCommand;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * WP-CLI proxy command - Execute WP-CLI commands in the WordPress container
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 } from '../config.js';
10
+
11
+ async function wpCommand(args, _options) {
12
+ try {
13
+ const projectPath = process.cwd();
14
+ const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
15
+
16
+ // Check if docker-compose.yml exists
17
+ if (!fs.existsSync(composePath)) {
18
+ console.log(chalk.yellow('⚠️ No running environment found.'));
19
+ console.log(chalk.gray('Run "buwp-local start" to create an environment.\n'));
20
+ return;
21
+ }
22
+
23
+ // Load config to get project name
24
+ const config = loadConfig(projectPath);
25
+ const projectName = config.projectName || 'buwp-local';
26
+
27
+ // Check if Docker is running
28
+ try {
29
+ execSync('docker info', { stdio: 'ignore' });
30
+ } catch (err) {
31
+ console.error(chalk.red('❌ Docker is not running.'));
32
+ process.exit(1);
33
+ }
34
+
35
+ // Build docker compose exec command for WP-CLI
36
+ const composeDir = path.dirname(composePath);
37
+ const wpArgs = args.join(' ');
38
+ const command = `docker compose -p ${projectName} -f ${composePath} exec wordpress wp ${wpArgs}`;
39
+
40
+ // Execute WP-CLI command
41
+ try {
42
+ execSync(command, {
43
+ cwd: composeDir,
44
+ stdio: 'inherit'
45
+ });
46
+ } catch (err) {
47
+ // WP-CLI may exit with error codes (e.g., failed import), don't exit harshly
48
+ // The error output is already shown via stdio: 'inherit'
49
+ }
50
+
51
+ } catch (err) {
52
+ console.error(chalk.red('\n❌ Error:'), err.message);
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ export default wpCommand;
@@ -3,10 +3,9 @@
3
3
  * Generates docker-compose.yml from configuration using js-yaml
4
4
  */
5
5
 
6
- const yaml = require('js-yaml');
7
- const fs = require('fs');
8
- const path = require('path');
9
- const os = require('os');
6
+ import yaml from 'js-yaml';
7
+ import fs from 'fs';
8
+ import path from 'path';
10
9
 
11
10
  /**
12
11
  * Generate docker-compose configuration from buwp-local config
@@ -272,7 +271,7 @@ function generateComposeFile(config, projectPath = process.cwd()) {
272
271
  return writeComposeFile(composeConfig, composePath);
273
272
  }
274
273
 
275
- module.exports = {
274
+ export {
276
275
  generateComposeConfig,
277
276
  generateComposeFile,
278
277
  writeComposeFile
package/lib/config.js CHANGED
@@ -3,9 +3,10 @@
3
3
  * Handles loading, validating, and merging configuration from various sources
4
4
  */
5
5
 
6
- const fs = require('fs');
7
- const path = require('path');
8
- const chalk = require('chalk');
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import chalk from 'chalk';
9
+ import dotenv from 'dotenv';
9
10
 
10
11
  const CONFIG_FILE_NAME = '.buwp-local.json';
11
12
  const ENV_FILE_NAME = '.env.local';
@@ -58,7 +59,7 @@ function loadConfig(projectPath = process.cwd()) {
58
59
  // Load .env.local if it exists
59
60
  if (fs.existsSync(envPath)) {
60
61
  try {
61
- require('dotenv').config({ path: envPath });
62
+ dotenv.config({ path: envPath });
62
63
  envVars = extractEnvVars();
63
64
  } catch (err) {
64
65
  console.warn(chalk.yellow(`Warning: Failed to load ${ENV_FILE_NAME}: ${err.message}`));
@@ -282,7 +283,7 @@ function sanitizeProjectName(name) {
282
283
  .replace(/^-+|-+$/g, ''); // Remove leading/trailing dashes
283
284
  }
284
285
 
285
- module.exports = {
286
+ export {
286
287
  loadConfig,
287
288
  validateConfig,
288
289
  initConfig,
package/lib/index.js CHANGED
@@ -3,21 +3,14 @@
3
3
  * Main library exports
4
4
  */
5
5
 
6
- const config = require('./config');
7
- const composeGenerator = require('./compose-generator');
6
+ import * as config from './config.js';
7
+ import * as composeGenerator from './compose-generator.js';
8
8
 
9
- module.exports = {
10
- // Configuration
11
- loadConfig: config.loadConfig,
12
- validateConfig: config.validateConfig,
13
- initConfig: config.initConfig,
14
-
15
- // Docker Compose generation
16
- generateComposeConfig: composeGenerator.generateComposeConfig,
17
- generateComposeFile: composeGenerator.generateComposeFile,
18
-
19
- // Constants
20
- CONFIG_FILE_NAME: config.CONFIG_FILE_NAME,
21
- ENV_FILE_NAME: config.ENV_FILE_NAME,
22
- DEFAULT_CONFIG: config.DEFAULT_CONFIG
23
- };
9
+ export const loadConfig = config.loadConfig;
10
+ export const validateConfig = config.validateConfig;
11
+ export const initConfig = config.initConfig;
12
+ export const generateComposeConfig = composeGenerator.generateComposeConfig;
13
+ export const generateComposeFile = composeGenerator.generateComposeFile;
14
+ export const CONFIG_FILE_NAME = config.CONFIG_FILE_NAME;
15
+ export const ENV_FILE_NAME = config.ENV_FILE_NAME;
16
+ export const DEFAULT_CONFIG = config.DEFAULT_CONFIG;
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@bostonuniversity/buwp-local",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Local WordPress development environment for Boston University projects",
5
+ "type": "module",
5
6
  "main": "lib/index.js",
6
7
  "bin": {
7
8
  "buwp-local": "./bin/buwp-local.js"
8
9
  },
9
10
  "scripts": {
10
11
  "test": "echo \"Error: no test specified\" && exit 1",
11
- "dev": "node bin/buwp-local.js",
12
+ "buwp-local": "node bin/buwp-local.js config --init --mu-plugin",
12
13
  "lint": "eslint ."
13
14
  },
14
15
  "keywords": [
@@ -21,7 +22,7 @@
21
22
  "author": "Boston University",
22
23
  "license": "ISC",
23
24
  "engines": {
24
- "node": ">=16.0.0"
25
+ "node": ">=18.0.0"
25
26
  },
26
27
  "dependencies": {
27
28
  "js-yaml": "^4.1.0",
package/.buwp-local.json DELETED
@@ -1,27 +0,0 @@
1
- {
2
- "image": "ghcr.io/bu-ist/bu-wp-docker-mod_shib:arm64-latest",
3
- "hostname": "jaydub.local",
4
- "multisite": true,
5
- "services": {
6
- "redis": true,
7
- "s3proxy": true,
8
- "shibboleth": true
9
- },
10
- "ports": {
11
- "http": 80,
12
- "https": 443,
13
- "db": 3306,
14
- "redis": 6379
15
- },
16
- "mappings": [
17
- {
18
- "local": "./",
19
- "container": "/var/www/html/wp-content/plugins/my-plugin",
20
- "comment": "Map current directory to a plugin location"
21
- }
22
- ],
23
- "env": {
24
- "WP_DEBUG": false,
25
- "XDEBUG": true
26
- }
27
- }