Skip to content

Commit

Permalink
Merge pull request #35 from humanmade/altis-dev-tools-346/add-devcont…
Browse files Browse the repository at this point in the history
…ainer-bootstrap-command

Add template and bootstrap command for Codespaces dev container
  • Loading branch information
shadyvb authored Jun 15, 2022
2 parents 5642c5b + 8d80b85 commit 88560ae
Show file tree
Hide file tree
Showing 4 changed files with 372 additions and 1 deletion.
72 changes: 71 additions & 1 deletion inc/command/class-command.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected function configure() {
$this->setName( 'dev-tools' );
$this->setDescription( 'Developer tools' );
$this->setDefinition( [
new InputArgument( 'subcommand', InputArgument::REQUIRED, 'phpunit | codecept' ),
new InputArgument( 'subcommand', InputArgument::REQUIRED, 'phpunit | codecept | bootstrap' ),
new InputOption( 'chassis', null, null, 'Run commands in the Local Chassis environment' ),
new InputOption( 'path', 'p', InputArgument::OPTIONAL, 'Use a custom path for tests folder.', 'tests' ),
new InputOption( 'output', 'o', InputArgument::OPTIONAL, 'Use a custom path for output folder.', '' ),
Expand All @@ -50,6 +50,10 @@ protected function configure() {
Use -o to specify the output folder.
Use -a to continue executing all suites even if one fails.
Use `--` to send arguments to Codeception.
To Bootstrap configuration files:
bootstrap <config> [--] [options]
<config> is the type of config to bootstrap, eg: codespaces
EOT
);
}
Expand All @@ -68,6 +72,8 @@ protected function execute( InputInterface $input, OutputInterface $output ) {
return $this->phpunit( $input, $output );
case 'codecept':
return $this->codecept( $input, $output );
case 'bootstrap':
return $this->bootstrap( $input, $output );

default:
throw new CommandNotFoundException( sprintf( 'Subcommand "%s" is not defined.', $subcommand ) );
Expand Down Expand Up @@ -445,6 +451,70 @@ protected function codecept( InputInterface $input, OutputInterface $output ) {
return $return;
}

/**
* Bootstraps configuration files.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function bootstrap( InputInterface $input, OutputInterface $output ) : int {
$configs = [ 'codespaces' ];

$options = $input->getArgument( 'options' );
$subsubcommand = $options[0] ?? null;

if ( empty( $subsubcommand ) ) {
$output->writeln( '<warning>You need to select a configuration set to bootstrap/generate.</warning>' );
$output->writeln( sprintf( 'Available configuration sets are: %s.', implode( ', ', $configs ) ) );
$output->writeln( 'eg: composer dev-tools bootstrap codespaces' );

return 1;
}

if ( ! in_array( $subsubcommand, $configs, true ) ) {
$output->writeln( sprintf( '<error>Could not find the target configuration set generator for "%s".</error>', $subsubcommand ) );
return 1;
}

call_user_func( [ $this, 'bootstrap_' . $subsubcommand ], $input, $output );

return 0;
}

/**
* Bootstraps Codespaces devcontainer configuration files.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function bootstrap_codespaces( InputInterface $input, OutputInterface $output ) : int {
$target_folder = getcwd() . '/.devcontainer';
$template_folder = realpath( __DIR__ . '/../../templates/.devcontainer' );

if ( file_exists( $target_folder ) ) {
$output->writeln( '<error>Codespaces devcontainer configuration exists already at <root>/.devcontainer, aborting.</error>' );
return 1;
}

$base_command = sprintf( 'cp -r "%s" "%s" &> /dev/null', $template_folder, $target_folder );
passthru( $base_command, $return_var );

if ( $return_var ) {
$output->writeln( '<error>Could not generate Codespaces devcontainer configuration, aborting.</error>' );
return 1;
}

$output->writeln( '<info>Files have been copied to the root of your project in .devcontainer folder.</info>' );
$output->writeln( '<info>Feel free to edit the generated config files to install system packages or editor extensions as needed.</info>' );
$output->writeln( '<info>Once ready, visit https://github.com/codespaces/new to create a new Codespace for your project repo.</info>' );

return 0;
}

/**
* Run the passed command on either the local-server or local-chassis environment.
*
Expand Down
23 changes: 23 additions & 0 deletions templates/.devcontainer/DockerFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/main/containers/php/.devcontainer/base.Dockerfile

# [Choice] PHP version: 8, 8.0, 7, 7.4, 7.3
ARG PHP_VERSION="8.0"
FROM mcr.microsoft.com/vscode/devcontainers/php:${PHP_VERSION}

# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

# Set up Docker
COPY library-scripts/docker-in-docker-debian.sh /tmp/library-scripts/
RUN apt-get update && /bin/bash /tmp/library-scripts/docker-in-docker-debian.sh
ENTRYPOINT ["/usr/local/share/docker-init.sh"]
VOLUME [ "/var/lib/docker" ]
CMD ["sleep", "infinity"]
47 changes: 47 additions & 0 deletions templates/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/php
{
"name": "PHP",
"build": {
"dockerfile": "Dockerfile",
"args": {
"PHP_VERSION": "8",
"NODE_VERSION": "lts/*"
}
},
"mounts": [
"source=dind-var-lib-docker,target=/var/lib/docker,type=volume"
],
"runArgs": [
"--init",
"--privileged"
],
"overrideCommand": false,

// Set *default* container specific settings.json values on container create.
"settings": {
"php.validate.executablePath": "/usr/local/bin/php"
},

// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"felixfbecker.php-debug",
"bmewburn.vscode-intelephense-client",
"mrmlnc.vscode-apache"
],

// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
80,
8080,
],
"otherPortsAttributes": {
"onAutoForward": "ignore"
},

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html"

// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}
Loading

0 comments on commit 88560ae

Please sign in to comment.