Fork me on GitHub

Prologue

Versioning Scheme

ProjectCLI follows Semantic Versioning.

Contribution Guide

TBD


Getting Started

Prerequisites

  • PHP CLI 7.2 or newer (incl. extensions: zlib, json, intl, xml, curl)

Homebrew

brew install php@7.2

Ubuntu

Make sure the available version meets the requirements:

apt show php

If not, add the following repository:

add-apt-repository -y ppa:ondrej/php \
    && apt-get update

Install the PHP CLI and extensions:

apt install php-cli php-xml php-curl php-zip php-intl php-json

Installation

After you've installed all dependencies, get the latest ProjectCLI release here and move it to /usr/local/bin/project or /usr/bin/project, depending on your system. The project command will be available after you restart your terminal session.

Update

Manually update ProjectCLI:

project self-update

Uninstall

rm -rf $HOME/.project $(which project)

Usage

Directory Structure

It's mandatory, that the project has the according directory structure and files in order for ProjectCLI to work properly.

root
  ├── commands
  │   - Contains project specific commands (see 'project make:command')
  ├── conf
  │   - Add configuration files for project components (like nginx, PHP, crontab, supervisor, etc)
  ├── scripts
  │   - Can contain scripts for deployment, HTTP requests or other complex tasks
  ├── src
  │   - Contains the application source
  └── temp
      - Temp directory for docker-compose service mounts

Project Configuration

The following configuration properties are available:

# project name including the vendor name (mandatory)
name: vendor/name-of-the-project
# the actual project version (mandatory)
version: v1.0.0
# specify multiple plugins required for this project
require:
- projectcli/laravel

Commands

ProjectCLI gives you the ability to write project specific commands, which can be used to translate complex tasks into a single command. For example, to completely setup a project, there need to be run many specific commands. So, instead of letting contributors execute command after command after command, there's just one command to rule them all.

If you clone a project via the clone command and the project provides a setup or install command, ProjectCLI will automatically ask, if those commands should be executed. So it's best practice to use the clone command to start setting up the project.

Writing Commands

First, let's create the command via:

project make:command SetupCommand

You'll then find the appropriate command in ./commands/SetupCommand.php

If you are in a PHP project with Composer support, you can require the ProjectCLI dev package, which provides all necessary interfaces for your IDE:

project composer require --dev chriha/project-cli-dev
Components

Since ProjectCLI is based on the Symfony Console, commands are defined in classes, extending \Chriha\ProjectCLI\Commands\Command. Every command consists of 4 components: The name, description, configuration and the handling.

This $defaultName variable specifies the argument of how the command will be called.

    /** @var string */
protected static $defaultName = 'setup';

The $description gives a short, but exact description for the command.

    /** @var string */
protected $description = 'Set up the project.';
Configure the command
public function configure() : void
{
    $this
        // the full command description shown when running the command with
        // via "project help COMMAND" option
        ->setHelp('This command allows you to create a user...')
        // specify command arguments via:
        ->addArgument($name, $mode = null, $description = '', $default = null)
        // specify command options via:
        ->addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
}

Consult the Symfony documentation for further instructions on how to use arguments and options.

Command handler

The handle method is where all the magic happens. If you, for example, would like to create a setup command for your project, let's do the following:

public function handle() : void
{
    // check if there's already an env file to use for Docker
    if ( ! file_exists(Helpers::projectPath('.env'))) {
        copy(Helpers::projectPath('.env.example'), Helpers::projectPath('.env'));
    }

    // same goes for application env variables
    if ( ! file_exists(Helpers::projectPath('src/.env'))) {
        copy(Helpers::projectPath('src/.env.example'), Helpers::projectPath('src/.env'));
    }

    // install all necessary composer packages
    $this->call('composer', ['install']);
    // generate application key
    $this->call('artisan', ['key:generate']);
    // run all database migrations
    $this->call('artisan', ['migrate:fresh']);
    // install all necessary Node packages
    $this->call('npm', ['install']);
    // compile static files
    $this->call('npm', ['run', 'dev']);
    // print a success message for the user
    $this->info('Project successfully installed');
}

For the artisan command, the projectcli/laravel plugin is required.

For all available helpers, see Helpers.php.


Plugins

Where commands are specific to and only available in each project, plugins are basically global commands.

Find Plugins

There are two ways to search for plugins. Via the console:

project plugins:search YOUR_QUERY

Install Plugins

Installing a plugin is as easy as:

project plugins:install VENDOR/NAME

You will also find the command to install a plugin on every plugin page, e.g. projectcli/laravel.

Update Plugins

project plugins:update VENDOR/NAME

Uninstall Plugins

project plugins:uninstall VENDOR/NAME

Require Plugins

If a certain plugin is required for the project, you can specify that in the project's configuration file project.yml:

name: vendor/project-name
version: v1.0.4
require:
- projectcli/laravel

In this case, ProjectCLI will notify the user every time, a command is executed inside the project.

****************************************************
*                 Required plugins                 *
****************************************************
- projectcli/laravel

All missing, but required plugins can be installed easily via:

project plugins:install

Writing Plugins

project plugins:uninstall VENDOR/NAME

Easily create the boilerplate via the following command:

project make:plugin

During the process, you can specify your vendor as well as the plugin name. ProjectCLI will tell you the according path to the plugin, whenever the plugin was successfully created.

The commands each plugin holds have the exact same structure as project specific commands. So head over to the writing commands chapter, if you're curious on how to write commands.

Additionally to normal commands, plugin commands have an extra method, which you can use to enable and disable the according command. Let's see an example from the projectcli/laravel package:

public static function isActive() : bool
{
    // via the constant, check if the command should only be available
    // inside a project and if the artisan file exists
    return PROJECT_IS_INSIDE
        && file_exists(Helpers::projectPath('src/artisan'));
}
Make Commands available

Plugin commands are not automatically loaded and available. Require the PHP file for each command in the ./plugin.php and specify the Namespace in the plugins ./project.yml:

name: projectcli/laravel
description: Laravel specific commands
version: v1.0.0
commands:
- \ProjectCLI\Laravel\Commands\ArtisanCommand

Composer packages inside plugins are not supported.

Publishing Plugins

For easy installation in the future or for other users to be able to use your plugin via the plugins:install command, you have to create a public Github repository and create a tag for every new version. After that, you can submit your plugin as an issue to the registry.