![]() |
But nowadays, we're blessed with a few deployment tools written in our language that enable deeper integration. One of these tools is Rocketeer, a tool that takes inspiration from Capistrano and the Laravel framework.
Rocketeer is a modern tool that brings a great approach for your deployment needs. That is to run tasks and manage your application across different environments and servers. On top of that, it also has some magic in it, like installing Composer dependencies if it detects a composer.json file. You get sane defaults and automation of common tasks for a modern PHP application. And you have the ability to customise and extend everything.
You could describe it as an SSH task runner that runs client-side. The commands execute on servers through an SSH connection. If you use a shared hosting provider with only FTP access, you're out of luck, unfortunately. What you also need is a remote repository where the tool can fetch your code from. There is support for Git and SVN by default. Need support for another version control system? Write your own implementation with the provided interfaces.
Installation
You can install Rocketeer in two different ways. Either you download the phar file and make it executable or you install it through Composer. I'm a supporter of the latter. Having it as a dependency allows for easy installation when cloning the repository. This can benefit anyone cloning the repository to get them up and running.
Installing with Composer:
- $ composer require anahkiasen/rocketeer --dev
Ignition
Let's get started! First you bootstrap the directories and files for configuration. You do this by running rocketeer ignite in the root of your project.
When your application ignites, the tool creates a .rocketeer folder in your project. The contents of the directory will look like this:
- | .rocketeer
- | -- config.php
- | -- hooks.php
- | -- paths.php
- | -- remote.php
- | -- scm.php
- | -- stages.php
- | -- strategies.php
Remote Folder Structure
It's important to understand how Rocketeer manages its folder structure on the server side, since it's a bit different to a regular setup. It uses a few directories for managing certain aspects of the deployment, so it can be effective at what it does. You specify a path to where you want to deploy your application on your server, and the tool will take care of the rest. That folder will look like this, if you have /var/www/app as your application directory.
- | /var/www/app
- | | -- current => /var/www/app/releases/20160103183754
- | | -- releases
- | | | -- 20160101161243
- | | | |-- uploads => /var/www/app/shared/uploads
- | | | -- 20160103183754
- | | | |-- uploads => /var/www/app/shared/uploads
- | | -- shared
- | | | -- uploads
- The tool creates a time-stamped folder in the releases directory.
- Completes all tasks to make a ready release.
- Updates the symbolic link current to the new release.
Some data should be persistent between your deployments. This can be file uploads, user sessions and logs, for example. Those files or folders go into the shared directory. The tool creates symbolic links inside each release for the ones you've configured.
Events
Events drive the tool, and all strategies and tasks fire a before and after event when they run. They also provide a special halt event when a task fails. This could be for example dependencies.halt, or deploy.halt for general failure. This allows us to hook into the process where we need to.
The default events that happen during a deployment are:
- deploy.before: before anything happens.
- create-release.before: before it creates a new release directory.
- create-release.after: after creating a new release directory.
- dependencies.before: before installing or updating dependencies.
- dependencies.after: after installing or updating dependencies. Perhaps make sure that binaries in your vendor folder are executable.
- test.before: before running tests.
- test.after: after running tests.
- migrate.before: before running database migrations. Maybe you want to do a backup of your database?
- migrate.after: after running database migrations.
- deploy.before-symlink: before symlinking the release as our current release.
- deploy.after: completed. You could notify people that everything was smooth sailing or otherwise.
Tasks
At the heart of Rocketeer, we find a concept called tasks. Most of what is happening under the hood are core tasks. The definition of a task could be a set of instructions to perform as a step in a deployment. If we look at some of the classes that the tool provides, we can get a general feel of what tasks are: classes such as Deploy, Setup, Migrate, Rollback, and Dependencies. When you deploy, the deploy command itself is a task with sub-tasks.
Types of Tasks
This is where you'll start to see how integrated the tool is with PHP, since you'll write tasks in the language. You can create your own tasks in three different ways:
Arbitrary terminal commands. These are one-liners that you want to run on your server. Can be useful for a lot of things, like running gulp build ---production for example.
Closures. If you need a bit more flexibility or complexity, you can write a task as a closure (anonymous function). Say you'd like to generate documentation for an API during your deployment.
- function($task) {
- return $task->runForCurrentRelease('apigen generate source src destination api');
- }
- namespace MyDeployableApp\Deploy\Tasks;
- class HelloWorld extends \Rocketeer\Abstracts\AbstractTask
- {
- /**
- * Description of the Task
- *
- * @var string
- */
- protected $description = 'Says hello to the world';
- /**
- * Executes the Task
- *
- * @return void
- */
- public function execute() {
- $this->explainer->line('Hello world!');
- return true;
- }
- }
- 'custom' => array('MyDeployableApp\Deploy\Tasks\HelloWorld',),
- Rocketeer::add('MyDeployableApp\Deploy\Tasks\HelloWorld');
- $ rocketeer hello:world
- staging/0 | HelloWorld (Says hello to the world)
- staging/0 |=> Hello world!
- Execution time: 0.004s
We discussed events first because we hook tasks in where we need them in the process. You can do this in a few ways. Go with the one you like and that meets requirements for your level of complexity.
The easiest way of defining your tasks is in the hooks.php file. It provides two arrays for this, specifying task execution before or after certain events.
- 'before' => [
- 'setup' => [],
- 'deploy' => ['hello:world'],
- 'cleanup' => [],
- ],
You might be able to tell already that the tasks provided are quite generic. Take Dependencies, for example. What kind of dependencies are we talking about and which package manager?
This is where strategies come into play. A strategy is a specific implementation of a task, such as running tests with Behat or using Gulp for building your front-end. Tasks have a default strategy with the option of running the other strategies through the CLI. We can list the strategies available like this:
![]() |
Say you're doing BDD With Behat for your application instead of TDD. Then you want to run your tests with Behat instead of PHPUnit. Since it is a test runner, there is already a strategy namespace for that, but no implementation. Create the directory .rocketeer/strategies/ and place your new BehatStrategy.php in there.
- namespace MyDeployableApp\Deploy\Strategies;
- use Rocketeer\Abstracts\Strategies\AbstractStrategy;use Rocketeer\Interfaces\Strategies\TestStrategyInterface;
- class BehatStrategy extends AbstractStrategy implements TestStrategyInterface
- {
- public function test() {
- return $this->binary('vendor/bin/behat')->runForCurrentRelease();
- }
- }
- 'test' => 'Behat',
It doesn't matter if you have an infrastructure in place or have one in mind. It doesn't matter if your application deploys to many environments across many servers. Rocketeer will be there for you. You can even have many varying locations on the same server. This is where the terms connections and stages enter.
A connection is a server where you deploy your application to. This is often called an environment, and production and staging are examples of this. Configuring these connections is a breeze in the tool. Either you do it through a nested array or by keeping separate files for each connection. Each connection can also have multiple servers in it.
Stages are like connections inside connections, a kind of "connectionception". You could set up a staging and a production environment on a single server with the use of stages. So instead of having two separate connections, you have one connection with two stages in it.
Plugins
A great feature is that we can extend our process using plugins. There are a few official ones for integration with Laravel, Slack, HipChat and Campfire. Then there are a few, but not that many, on Packagist. Installing plugins is an easy task through the CLI:
- $ rocketeer plugin:install rocketeers/rocketeer-slack
Written by Niklas Modess
If you found this post interesting, follow and support us.
Suggest for you:
Learn PHP 7 This Way to Rise Above & Beyond Competion!
PHP MySQL Database Connections
The Complete PHP with MySQL Developer Course (New)
Learn what's new in PHP 7
Modern Programming with PHP











