Articles

How to Automatically Deploy a Git Repo from Bitbucket

This article shows you how to automatically deploy your app from a git repo hosted at Bitbucket. That is, whenever you push your master branch to Bitbucket, Bitbucket will POST to a URL on your server, which will then pull and deploy the repo.

The code in this article is based on this tutorial.

Configuration

  1. In ServerPilot, create an app. We'll use APPNAME to refer to the name you chose for this app.
  2. SSH into the server as your app's system user; we use the serverpilot user in this tutorial.
  3. Run ssh-keygen to generate an SSH key. Don't assign it a password.
  4. Add the public key to your Bitbucket account's SSH keys.
  5. cd ~/apps/APPNAME
  6. git clone --mirror git@bitbucket.org:USERNAME/REPONAME.git repo, which checks out the repo to a directory called repo.
  7. Do an initial deployment from the command line by running:
    cd repo
    GIT_WORK_TREE=/srv/users/serverpilot/apps/APPNAME/public git checkout -f master
  8. Create the file ~/apps/APPNAME/public/bitbucket-deploy.php with the following contents (be sure to replace APPNAME with the name of your app):
    <?php
    $repo_dir = '/srv/users/serverpilot/apps/APPNAME/repo';
    $web_root_dir = '/srv/users/serverpilot/apps/APPNAME/public';
    
    // Full path to git binary is required if git is not in your PHP user's path. Otherwise just use 'git'.
    $git_bin_path = 'git';
    
    $update = false;
    
    // Parse data from Bitbucket hook payload
    $payload = json_decode($_POST['payload']);
    
    if (empty($payload->commits)){
      // When merging and pushing to bitbucket, the commits array will be empty.
      // In this case there is no way to know what branch was pushed to, so we will do an update.
      $update = true;
    } else {
      foreach ($payload->commits as $commit) {
        $branch = $commit->branch;
        if ($branch === 'master' || isset($commit->branches) && in_array('master', $commit->branches)) {
          $update = true;
          break;
        }
      }
    }
    
    if ($update) {
      // Do a git checkout to the web root
      exec('cd ' . $repo_dir . ' && ' . $git_bin_path  . ' fetch');
      exec('cd ' . $repo_dir . ' && GIT_WORK_TREE=' . $web_root_dir . ' ' . $git_bin_path  . ' checkout -f');
    
      // Log the deployment
      $commit_hash = shell_exec('cd ' . $repo_dir . ' && ' . $git_bin_path  . ' rev-parse --short HEAD');
      file_put_contents('deploy.log', date('m/d/Y h:i:s a') . " Deployed branch: " .  $branch . " Commit: " . $commit_hash . "\n", FILE_APPEND);
    }
    ?>
    
  9. Add a POST hook for the repo in Bitbucket with the URL http://YOURDOMAIN/bitbucket-deploy.php.
  10. Make changes, commit them to the "master" branch, and push.
  11. The files were now deployed to ~/apps/APPNAME/public as intended.
  12. For additional security, change the name of bitbucket-deploy.php to something containing random characters, such as bitbucket-deploy-23d98th98y.php. If you do that, don't forget to update the URL you configured in Bitbucket.

For debugging, the script in that blog post creates a log file at ~/apps/APPNAME/public/deploy.log. You can also check your app's nginx logs if you aren't sure Bitbucket made the request.