Skip to content

Commit

Permalink
New CLI works with docker now -- commands will run on the local host …
Browse files Browse the repository at this point in the history
…unless specified to the dev container, like build-image
  • Loading branch information
kraftbj committed Jan 9, 2025
1 parent 67296ba commit 4391224
Show file tree
Hide file tree
Showing 18 changed files with 299 additions and 23 deletions.
13 changes: 11 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions projects/js-packages/jetpack-cli/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Files not needed to be distributed in the package.
.gitattributes export-ignore
node_modules export-ignore

# Files to exclude from the mirror repo
/changelog/** production-exclude
2 changes: 2 additions & 0 deletions projects/js-packages/jetpack-cli/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
vendor/
node_modules/
7 changes: 7 additions & 0 deletions projects/js-packages/jetpack-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

18 changes: 18 additions & 0 deletions projects/js-packages/jetpack-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Jetpack


## How to install Jetpack plugin on your site
### Installation From Git Repo

## Contribute

## Get Help

## Security

Need to report a security vulnerability? Go to [https://automattic.com/security/](https://automattic.com/security/) or directly to our security bug bounty site [https://hackerone.com/automattic](https://hackerone.com/automattic).

## License

Licensed under [GNU General Public License v2 (or later)](./LICENSE.txt).

162 changes: 149 additions & 13 deletions projects/js-packages/jetpack-cli/bin/jp.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#!/usr/bin/env node

import { spawnSync } from 'child_process';
import fs from 'fs';
import fs, { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import process from 'process';
import { fileURLToPath } from 'url';
import chalk from 'chalk';
import dotenv from 'dotenv';
import prompts from 'prompts';

// Get package.json path relative to this file
const __dirname = dirname( fileURLToPath( import.meta.url ) );
const packageJson = JSON.parse( readFileSync( resolve( __dirname, '../package.json' ), 'utf8' ) );

/**
* Check if a directory is the monorepo root.
*
Expand Down Expand Up @@ -45,7 +51,6 @@ const findMonorepoRoot = startDir => {
* @throws {Error} If clone fails
*/
const cloneMonorepo = async targetDir => {
// eslint-disable-next-line no-console
console.log( chalk.blue( 'Cloning Jetpack monorepo...' ) );
const result = spawnSync(
'git',
Expand Down Expand Up @@ -83,15 +88,15 @@ const initJetpack = async () => {

try {
await cloneMonorepo( targetDir );
// eslint-disable-next-line no-console

console.log( chalk.green( '\nJetpack monorepo has been cloned successfully!' ) );
// eslint-disable-next-line no-console

console.log( '\nNext steps:' );
// eslint-disable-next-line no-console

console.log( '1. cd', response.directory );
// eslint-disable-next-line no-console

console.log( '2. jp docker up' );
// eslint-disable-next-line no-console

console.log( '3. jp docker install' );
} catch ( error ) {
throw new Error( `Failed to initialize Jetpack: ${ error.message }` );
Expand All @@ -103,6 +108,12 @@ const main = async () => {
try {
const args = process.argv.slice( 2 );

// Handle version flag
if ( args[ 0 ] === '--version' || args[ 0 ] === '-v' ) {
console.log( chalk.green( packageJson.version ) );
return;
}

// Handle 'init' command specially
if ( args[ 0 ] === 'init' ) {
await initJetpack();
Expand All @@ -113,19 +124,145 @@ const main = async () => {
const monorepoRoot = findMonorepoRoot( process.cwd() );

if ( ! monorepoRoot ) {
// eslint-disable-next-line no-console
console.error( chalk.red( 'Could not find Jetpack monorepo.' ) );
// eslint-disable-next-line no-console

console.log( '\nTo get started:' );
// eslint-disable-next-line no-console

console.log( '1. Run', chalk.blue( 'jp init' ), 'to clone the repository' );
// eslint-disable-next-line no-console

console.log( ' OR' );
// eslint-disable-next-line no-console

console.log( '2. Navigate to an existing Jetpack monorepo directory' );
throw new Error( 'Monorepo not found' );
}

// Handle docker commands on the host
if ( args[ 0 ] === 'docker' ) {
// Commands that should run in the container
const containerCommands = [ 'build-image', 'install' ];
if ( containerCommands.includes( args[ 1 ] ) ) {
const result = spawnSync(
resolve( monorepoRoot, 'tools/docker/bin/monorepo' ),
[ 'pnpm', 'jetpack', ...args ],
{
stdio: 'inherit',
shell: true,
cwd: monorepoRoot,
}
);

if ( result.status !== 0 ) {
throw new Error( `Command failed with status ${ result.status }` );
}
return;
}

// Run config generation first if this is an 'up' command
if ( args[ 1 ] === 'up' ) {
// Create required directories
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/data/jetpack_dev_mysql' ), {
recursive: true,
} );
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/data/ssh.keys' ), { recursive: true } );
fs.mkdirSync( resolve( monorepoRoot, 'tools/docker/wordpress' ), { recursive: true } );

const images = [
{ name: 'mariadb:lts' },
{ name: 'automattic/jetpack-wordpress-dev:latest' },
{ name: 'phpmyadmin/phpmyadmin:latest', platform: 'linux/amd64' },
{ name: 'maildev/maildev', platform: 'linux/amd64' },
{ name: 'atmoz/sftp', platform: 'linux/amd64' },
];

for ( const image of images ) {
const inspect = spawnSync( 'docker', [ 'image', 'inspect', image.name ], {
stdio: 'ignore',
} );
if ( inspect.status !== 0 ) {
console.log( chalk.blue( `Pulling ${ image.name }...` ) );
const pullArgs = [ 'pull', image.name ];
if ( image.platform ) {
pullArgs.splice( 1, 0, '--platform', image.platform );
}
const pull = spawnSync( 'docker', pullArgs, { stdio: 'inherit' } );
if ( pull.status !== 0 ) {
throw new Error( `Failed to pull ${ image.name }` );
}
}
}

const configResult = spawnSync(
resolve( monorepoRoot, 'tools/docker/bin/monorepo' ),
[ 'pnpm', 'jetpack', 'docker', 'config' ],
{
stdio: 'inherit',
shell: true,
cwd: monorepoRoot,
}
);

if ( configResult.status !== 0 ) {
throw new Error( 'Failed to generate Docker config' );
}
}

// Get project name (from docker.js)
const projectName = args.includes( '--type=e2e' ) ? 'jetpack_e2e' : 'jetpack_dev';

// Load versions from .github/versions.sh
const versionsPath = resolve( monorepoRoot, '.github/versions.sh' );
const versions = fs.readFileSync( versionsPath, 'utf8' );
const versionVars = {};
versions.split( '\n' ).forEach( line => {
const match = line.match( /^([A-Z_]+)=(.+)$/ );
if ( match ) {
versionVars[ match[ 1 ] ] = match[ 2 ].replace( /['"]/g, '' );
}
} );

// Build environment variables (from docker.js)
const envVars = {
...process.env,
// Load from default.env
...( fs.existsSync( resolve( monorepoRoot, 'tools/docker/default.env' ) )
? dotenv.parse( fs.readFileSync( resolve( monorepoRoot, 'tools/docker/default.env' ) ) )
: {} ),
// Load from .env if it exists
...( fs.existsSync( resolve( monorepoRoot, 'tools/docker/.env' ) )
? dotenv.parse( fs.readFileSync( resolve( monorepoRoot, 'tools/docker/.env' ) ) )
: {} ),
HOST_CWD: monorepoRoot,
PHP_VERSION: versionVars.PHP_VERSION,
COMPOSER_VERSION: versionVars.COMPOSER_VERSION,
NODE_VERSION: versionVars.NODE_VERSION,
PNPM_VERSION: versionVars.PNPM_VERSION,
COMPOSE_PROJECT_NAME: projectName,
PORT_WORDPRESS: args.includes( '--type=e2e' ) ? '8889' : '80',
};

// Build the list of compose files to use
const composeFiles = [
'-f',
resolve( monorepoRoot, 'tools/docker/docker-compose.yml' ),
'-f',
resolve( monorepoRoot, 'tools/docker/compose-mappings.built.yml' ),
'-f',
resolve( monorepoRoot, 'tools/docker/compose-extras.built.yml' ),
];

const result = spawnSync( 'docker', [ 'compose', ...composeFiles, ...args.slice( 1 ) ], {
stdio: 'inherit',
shell: true,
cwd: resolve( monorepoRoot, 'tools/docker' ),
env: envVars,
} );

if ( result.status !== 0 ) {
throw new Error( `Docker command failed with status ${ result.status }` );
}
return;
}

// Run the monorepo script with the original arguments
const result = spawnSync(
resolve( monorepoRoot, 'tools/docker/bin/monorepo' ),
Expand All @@ -141,7 +278,6 @@ const main = async () => {
throw new Error( `Command failed with status ${ result.status }` );
}
} catch ( error ) {
// eslint-disable-next-line no-console
console.error( chalk.red( error.message ) );
process.exitCode = 1;
}
Expand Down
Empty file.
4 changes: 4 additions & 0 deletions projects/js-packages/jetpack-cli/changelog/initial-version
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Initial version.
37 changes: 37 additions & 0 deletions projects/js-packages/jetpack-cli/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "automattic/jetpack-cli",
"description": "Development tools for the Jetpack monorepo",
"type": "library",
"license": "GPL-2.0-or-later",
"require": {},
"require-dev": {
"automattic/jetpack-changelogger": "@dev"
},
"autoload": {
"classmap": [
"src/"
]
},
"scripts": {
"phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit --coverage-php \"$COVERAGE_DIR/php.cov\""
],
"test-php": [
"@composer phpunit"
]
},
"repositories": [
{
"type": "path",
"url": "../../packages/*",
"options": {
"monorepo": true
}
}
],
"minimum-stability": "dev",
"prefer-stable": true
}
11 changes: 11 additions & 0 deletions projects/js-packages/jetpack-cli/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import makeBaseConfig from 'jetpack-js-tools/eslintrc/base.mjs';

export default [
...makeBaseConfig( import.meta.url, { envs: [ 'node' ] } ),
{
rules: {
'no-console': 'off',
'n/no-process-exit': 'off',
},
},
];
5 changes: 3 additions & 2 deletions projects/js-packages/jetpack-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@automattic/jetpack-cli",
"version": "0.1.0-beta.1",
"version": "0.1.0-alpha",
"description": "Docker-based CLI for Jetpack development",
"bin": {
"jp": "bin/jp.js"
Expand All @@ -10,7 +10,8 @@
],
"type": "module",
"dependencies": {
"chalk": "^4.1.2",
"chalk": "^5.4.1",
"dotenv": "^16.3.1",
"prompts": "^2.4.2"
},
"publishConfig": {
Expand Down
2 changes: 2 additions & 0 deletions projects/js-packages/jetpack-cli/src/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Put your code in this `src/` folder!
// Feel free to delete or rename this file.
7 changes: 7 additions & 0 deletions projects/js-packages/jetpack-cli/tests/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// We recommend using `jest` for testing. If you're testing React code, we recommend `@testing-library/react` and related packages.
// Please match the versions used elsewhere in the monorepo.
//
// Please don't add new uses of `mocha`, `chai`, `sinon`, `enzyme`, and so on. We're trying to standardize on one testing framework.
//
// The default setup is to have files named like "name.test.js" (or .jsx, .ts, or .tsx) in this `tests/` directory.
// But you could instead put them in `src/`, or put files like "name.js" (or .jsx, .ts, or .tsx) in `test` or `__tests__` directories somewhere.
7 changes: 7 additions & 0 deletions projects/js-packages/jetpack-cli/tests/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const path = require( 'path' );
const baseConfig = require( 'jetpack-js-tools/jest/config.base.js' );

module.exports = {
...baseConfig,
rootDir: path.join( __dirname, '..' ),
};
Loading

0 comments on commit 4391224

Please sign in to comment.