Deploy local build with Deployer7


Deployer is a great tool to deploy your PHP Project.

Deployer executes a set of commands on the target server to build your project and enable the newly built version. A typical deployment process with Deployer involves SSHing into the target machine, where it performs a Git checkout of the project, installs dependencies via Composer, runs build commands, and possibly triggers some database migrations. When everything is successful, it will symlink the webroot to the new release.

On some servers, however, there are limitations that make this process unfeasible. For instance, you can’t install Composer, Git isn’t available, the CLI PHP version is different and can’t be changed, or certain asset-building processes aren’t possible because Node.js isn’t installed. This is often the case with shared hosting.

The strategy, therefore, is to build the project locally and upload it to the target machine.
In Deployer 6 there was a buildIn mechanism for building your project on the local host.
However with Deployer version 7 this has been removed and building your project locally has become a bit more fiddly.

With Deployer 6 you could just use the local() method on a task and set the deploy_path to a local dir.

task('build', function () {
    set('deploy_path', __DIR__ . '/.build');
    invoke('deploy:prepare');
    invoke('deploy:release');
    invoke('deploy:update_code');
    invoke('deploy:vendors');
    invoke('deploy:clear_paths');
    invoke('deploy:symlink');
})->local();Code language: PHP (php)

Then you could combine this with an upload task in a deploy task an you are done.

task('upload', function () {
     upload(__DIR__ . "/.build/current/", '{{release_path}}', ['--links']);
 });

 task('deploy', [
     'build',
     'upload',
     'cleanup',
     'success'
 ]);Code language: PHP (php)

See here for the docs of Deployer 6:
https://deployer.org/docs/6.x/advanced/deploy-strategies#build-server

Since Deployer 7, however, the local() method was removed. Instead, there is now a localhost() method, which defines a host for local builds. Additionally, you still need to define the remote host as the target destination for the upload.
However, you cannot specify a single task to run on a specific host, and therefore you cannot combine tasks for localhost and the remote host within a single task.

To build the project, we now need two separate tasks.
I managed to make it work with two tasks and two hosts: one for local build and one that takes the fresh local build and uploads it to the remote host.

localhost('local')->set('deploy_path', __DIR__ . '/.build');

host('remote')
    ->setHostname('server-host.com')
    ->set('remote_user', 'user')
    ->set('deploy_path', '/www/blog')
    ->set('http_user', 'user');
....

task('build', function () {
    // build it
})->once();

task('upload', function () {
    upload(__DIR__ . "/.build/current/", '{{deploy_path}}', ['--links']);
});Code language: PHP (php)

Then I simply run two separate commands: one for building on the local host and one for uploading to the remote host.

vendor/bin/dep build local
vendor/bin/dep upload remote

Not as convenient as previously but it works. :)

See this issue for context: https://github.com/deployphp/deployer/issues/2838