I want to note that I am not the author of this method. This is a collective code from different tutorials around the internet. Some of them are already dead...

Firstly you need to install few things:

Assuming that all necessary dependencies are installed lets create simple bash script which will do our deployment. Mostly it based on request data from BitBucket.

#!/bin/sh
# -*- coding: utf-8 -*-

echo "Content-type:text/plain\n"

if
    [ -n "$HTTP_X_HOOK_UUID" ] &&
    [ -n "$HTTP_X_REQUEST_UUID" ] &&
    [ "$HTTP_X_EVENT_KEY" = "pullrequest:fulfilled" ] &&
    [ "$HTTP_CONTENT_TYPE" = "application/json" ] &&
    [ "$REQUEST_METHOD" = "POST" ]
then
    echo Deploy Start: `date +'%F %T'`

    _IS_REQUEST_BODY_OK=`jq '.pullrequest.destination.branch.name == "master"'`

    if 
        [ "$_IS_REQUEST_BODY_OK" = true ]
    then
        cd '/var/www/shipment-date-updater'

        # GIT_SSH_COMMAND='ssh -i /var/deploy/.ssh/id_rsa -o UserKnownHostsFile=/var/deploy/.ssh/known_hosts'

        git reset --hard
        git pull origin master

        # git submodule init
        # git submodule update --remote
        # git submodule foreach git checkout master

        echo '"GIT" actions completed'

        TODAY=`date '+%Y_%m_%d__%H_%M_%S'`;

        LOG_FILE_NAME="/var/deploy/logs/shipment-date-updater_$TODAY.log"

        (composer install && php artisan migrate && npm i && npm run production) > $LOG_FILE_NAME 2>&1 &

        echo "\"composer\" & \"npm\" in progress. Check log $LOG_FILE_NAME"
    else
        echo "Body data check failed"
    fi

    echo Deploy End: `date +'%F %T'`
else
    echo "Wrong request"
fi

Save it as /var/deploy/run.sh and also create forlder /var/deploy/logs with write permissions.

Also you need to pay attention to 2 things:

  • First is how do you connect to BitBucket. You can specify GIT_SSH_COMMAND to use your own SSH key, but in my case it caused a lot of pain with permissions. Other, more simpler way, is to create other SSH key specifically for www-data user from which Nginx is running by default. And also dont forget to add (bitbucket.org)[bitbucket.org] host to known_hosts file
$ sudo -u www-data ssh-keygen -t rsa
$ sudo su - www-data -s /bin/bash -c 'ssh-keyscan -t rsa bitbucket.org >> /var/www/.ssh/known_hosts'
  • Second thing is response time for BibBucket. Yes, it waits some time and either gives you timeout error or prints whatever you give to him. So I'm suggestion to run your deployment stuff in background with custom log and give response to BitBucket immediately like this:
(composer install && php artisan migrate && npm i && npm run production) > $LOG_FILE_NAME 2>&1 &

Now we can config Nginx for our request. Dont forget to change the port for some random number and path.

server {
    listen 8081;
    listen [::]:8081;

    location /pull-merge {
        gzip off;

        include /etc/nginx/fastcgi_params;

        fastcgi_pass unix:/var/run/fcgiwrap.socket;
        fastcgi_param SCRIPT_FILENAME /var/deploy/run.sh;
    }

    error_log /var/deploy/logs/error.log;
    access_log /var/deploy/logs/access.log;
}

Now you need to go to your repo and create webhook which will call our specific url by which Nginx will start our script.

Thats all. Current scrip is mate specifically to run on pull request merge and deploy Laravel project. Fill free to edit it for your own needs.