Skip to content

Commit

Permalink
Merge pull request #208 from stellarwp/feature/slicrc
Browse files Browse the repository at this point in the history
Support project-level auto-config
  • Loading branch information
borkweb authored Jan 20, 2025
2 parents fceb236 + 7ad46e6 commit 2104b7a
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 18 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The slic (**S**tellarWP **L**ocal **I**nteractive **C**ontainers) CLI command pr
* [Adding tests](#adding-tests)
* [Running tests](#running-tests)
* [Advanced topics](#advanced-topics)
* [Defaults for your project with `slic.json`](/docs/slicjson.md)
* [Making composer installs faster](#making-composer-installs-faster)
* [Changing your composer version](#changing-your-composer-version)
* [Customizing `slic`'s `.env` file](#customizing-slics-env-file)
Expand Down
8 changes: 6 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ 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).

# [1.9.0] - 2025-01-20
- Added - Allow for projects to declare their desired PHP version for slic via `slic.json` (`phpVersion`) or `composer.json` (`config.platform.php`).
- Added - Support for auto-setup of appropriate PHP containers when running `slic use`.

# [1.8.1] - 2024-12-30
- Updated the ARM64 Chrome container image to version 4.20.0-20240427 from 4.1.2-20220227.
- Updated the x86 Chrome container image to version 4.27.0-20241225 from 3.141.59.
Expand Down Expand Up @@ -38,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Fixed - `.bat` file now uses the correct path to the `slic` executable on Windows.

# [1.6.0] - 2024-04-10
* Added - The `slic update-dump` command to update a dump file for the current project, with an optional WordPress version update, e.g. `slic update-dump tests/_data/dump.sql latest`.
* Added - The `slic update-dump` command to update a dump file for the current project, with an optional WordPress version update, e.g. `slic update-dump tests/_data/dump.sql latest`.

# [1.5.4] - 2024-04-08
* Change - Disable WordPress's automatic updating in slic containers via docker compose `WORDPRESS_CONFIG_EXTRA` defines. See comments in `.env.slic` to customize this behavior.
Expand All @@ -47,7 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Change - Build `linux/arm64` images for the `slic` and `wordpress` containers to avoid issues when running `slic` on ARM machines.

# [1.5.2] - 2024-04-04
* Change - Remove `version` property from docker compose .yml files as it's obsolete since v2.25. https://github.com/docker/compose/issues/11628
* Change - Remove `version` property from docker compose .yml files as it's obsolete since v2.25. https://github.com/docker/compose/issues/11628

# [1.5.1] - 2024-01-05
* Change - Update the `npm` version to `18.13.0`
Expand Down
15 changes: 15 additions & 0 deletions docs/slicjson.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Using a `slic.json` file

You can add a `slic.json` file to your project root to ensure that slic is setup correctly when you `slic use` your project.

Here's an example `slic.json` file:

```json
{
"phpVersion": "8.2"
}
```

## `phpVersion`

When you specify a `phpVersion` in your `slic.json` file, slic will automatically switch to that PHP version when you run `slic use` in your project if that isn't the current PHP version in slic.
4 changes: 2 additions & 2 deletions slic.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
] );

$cli_name = 'slic';
const CLI_VERSION = '1.8.1';
const CLI_VERSION = '1.9.0';

// If the run-time option `-q`, for "quiet", is specified, then do not print the header.
if ( in_array( '-q', $argv, true ) || ( in_array( 'exec', $argv, true ) && ! in_array( 'help', $argv, true ) ) ) {
Expand Down Expand Up @@ -114,7 +114,7 @@
<light_cyan>up</light_cyan> Starts containers in the stack; alias of `start`.
<light_cyan>update</light_cyan> Updates the tool and the images used in its services.
<light_cyan>upgrade</light_cyan> Upgrades the {$cli_name} repo.
<light_cyan>update-dump</light_cyan> Updates a SQL dump file. Optionally, installs a specific WordPress version..
<light_cyan>update-dump</light_cyan> Updates a SQL dump file. Optionally, installs a specific WordPress version..
HELP;

$help_message = colorize( $help_message_template );
Expand Down
17 changes: 3 additions & 14 deletions src/commands/php-version.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
$command = $args( '...' );
$sub_command = $command[0] ?? null;
$skip_rebuild = in_array( '--skip-rebuild', $command, true );
$confirm = in_array( '-y', $command, true );

if ( in_array( $sub_command, [ 'set', 'reset' ] ) ) {
switch ( $sub_command ) {
Expand All @@ -50,20 +51,8 @@
echo magenta( "Error: set-version requires a PHP version number with a single dot, e.g. 8.1" . PHP_EOL );
exit( 1 );
}
$run_settings_file = root( '/.env.slic.run' );
write_env_file( $run_settings_file, [ 'SLIC_PHP_VERSION' => $version ], true );
echo colorize( "PHP version set to $version" . PHP_EOL );

if ( ! $skip_rebuild ) {
$confirm = ask("Do you want to restart the stack now? ", 'yes');

if ( $confirm ) {
rebuild_stack();
update_stack_images();
load_env_file( root() . '/.env.slic.run' );
restart_php_services( true );
}
}

slic_set_php_version( $version, ! $confirm, $skip_rebuild );

exit( 0 );
case 'reset':
Expand Down
2 changes: 2 additions & 0 deletions src/commands/use.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@
}

echo light_cyan( "Using {$target}" . PHP_EOL );

project_apply_config( get_target_relative_path( $target ) );
158 changes: 158 additions & 0 deletions src/project.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,161 @@ function get_project_container_path() {
return '/var/www/html';
}
}

/**
* Returns the .slicrc file as an array.
*
* @param string $project_root_path The path to the project root.
*
* @return array<string,mixed> The .slicrc file as an array.
*/
function project_get_slic_json( $project_root_path ) {
if ( ! $project_root_path ) {
return [];
}

if ( ! file_exists( $project_root_path . '/slic.json' ) ) {
return [];
}

$slic_json = file_get_contents( $project_root_path . '/slic.json' );
$slic_json = json_decode( $slic_json, true, 512, JSON_THROW_ON_ERROR );

return $slic_json;
}

/**
* Applies the .slicrc and/or composer.json file to the current environment.
*
* @param string $project_root_path The path to the project root.
*/
function project_apply_config( $project_root_path ) {
if ( ! $project_root_path ) {
return;
}

$has_error = false;

$slic_env_local = '';
if ( file_exists( $project_root_path . '/.env.slic.local' ) ) {
$slic_env_local = file_get_contents( $project_root_path . '/.env.slic.local' );
}

try {
$slic_json = project_get_slic_json( $project_root_path );
} catch ( \Exception $e ) {
$has_error = true;
echo colorize( PHP_EOL .
sprintf(
"❌ <red>Error parsing slic.json file in %s: %s</red>",
$project_root_path,
$e->getMessage()
) . PHP_EOL );
}

try {
$composer_json = project_get_composer( $project_root_path );
} catch ( \Exception $e ) {
$has_error = true;
echo colorize( PHP_EOL .
sprintf(
"❌ <red>Error parsing composer.json file in %s: %s</red>",
$project_root_path,
$e->getMessage()
) . PHP_EOL );
}

if ( $has_error ) {
echo colorize( PHP_EOL .
sprintf(
"<red>Could not properly read your project's PHP requirements. Resolve the errors and try again.</red>",
$project_root_path
) . PHP_EOL );
return;
}

project_apply_php_version( $slic_env_local, $slic_json, $composer_json );
}

/**
* Returns the composer.json file as an array.
*
* @param string $project_root_path The path to the project root.
*
* @return array<string,mixed> The composer.json file as an array.
*/
function project_get_composer( $project_root_path ) {
if ( ! file_exists( $project_root_path . '/composer.json' ) ) {
return null;
}

$composer_json = file_get_contents( $project_root_path . '/composer.json' );
$composer_json = json_decode( $composer_json, true, 512, JSON_THROW_ON_ERROR );

return $composer_json;
}

/**
* Returns a slic-usable PHP version from the composer.json file.
*
* The PHP version is grabbed from config.platform.php if present and converted to a x.y format
* if it is not already. If the PHP version is less than 7.4, then null is returned.
*
* @param array<string,mixed> $composer_json The composer.json file as an array.
*
* @return string|null The PHP version specified in the composer.json file or null if not found.
*/
function project_get_composer_php_version( $composer_json ) {
if ( ! $composer_json ) {
return null;
}

if ( empty( $composer_json['config']['platform']['php'] ) ) {
return null;
}

$php_version = $composer_json['config']['platform']['php'];
$php_version = preg_replace( '/^(\d\.\d)\..+/', '$1', $php_version );
if ( strpos( $php_version, '.' ) === false ) {
$php_version .= '.0';
}

if ( version_compare( $php_version, '7.4', '<' ) ) {
return null;
}

return $php_version;
}

/**
* Applies the PHP version specified in the .slicrc or composer.json file to the current environment.
*
* @param string $slic_env_local The .env.slic.local file as a string.
* @param array<string,mixed> $slic_json The .slic.json file as an array.
* @param array<string,mixed> $composer_json The composer.json file as an array.
*/
function project_apply_php_version( $slic_env_local, $slic_json, $composer_json ) {
$current_php_version = getenv( 'SLIC_PHP_VERSION' );
$project_php_version = $slic_json['phpVersion'] ?? project_get_composer_php_version( $composer_json );

$slic_env_php_version = $project_php_version;

if (
$slic_env_local
&& preg_match( '/SLIC_PHP_VERSION=([^\n]+)/m', $slic_env_local, $matches )
) {
$slic_env_php_version = trim( $matches[1] );
}

if ( $project_php_version && $project_php_version !== $current_php_version ) {
slic_set_php_version( $project_php_version, false );
}

if ( $slic_env_php_version !== $project_php_version ) {
echo colorize(
PHP_EOL .
"<red>Your .env.slic.local file's PHP version is different than either your slic.json or composer.json file. This will cause your project to rebuild the PHP containers any time you type `slic use`.</red>" .
PHP_EOL
);
}
}
32 changes: 32 additions & 0 deletions src/slic.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,38 @@ function setup_slic_env( $root_dir, $reset = false ) {
remove_time_limit();
}

/**
* Sets the PHP version for the current environment.
*
* @param string $version The PHP version to set.
* @param bool $require_confirm Whether to require confirmation before restarting the stack.
* @param bool $skip_rebuild Whether to skip rebuilding the stack.
*/
function slic_set_php_version( $version, $require_confirm = false, $skip_rebuild = false ) {
$run_settings_file = root( '/.env.slic.run' );
write_env_file( $run_settings_file, [ 'SLIC_PHP_VERSION' => $version ], true );
echo colorize( "PHP version set to $version" . PHP_EOL );

$confirm = true;

if ( ! $skip_rebuild && $require_confirm ) {
$confirm = ask("Do you want to restart the stack now? ", 'yes');
}

if ( ! $confirm ) {
return;
}

if ( $skip_rebuild ) {
return;
}

rebuild_stack();
update_stack_images();
load_env_file( root() . '/.env.slic.run' );
restart_php_services( true );
}

/**
* Returns the current `use` target.
*
Expand Down

0 comments on commit 2104b7a

Please sign in to comment.