alemol
alemol

Reputation: 8642

How to get push notifications from a remote git repository in real time?

I have a remote repository (bitbucket), a server repository (linux) and many local repositories (developers).

I want the server to be notified if some developer changes a branch in the remote.

Until now i tried using a bash script declared in cron in the server but the minimal resolution is 1 minute, so to adapt it for real-time seems to be very tricky. However, my approach is this:

path=/some/dir/

# something new in remote
if git fetch origin && [ `git rev-list HEAD...origin/master --count` != 0 ]
then
    echo 'Remote repository has changed. Pull needed' &>>$path/git-backup.log
    echo $d >> $path/git-backup.log
    git merge origin/master &>>$path/git-backup.log
fi

Upvotes: 4

Views: 2842

Answers (1)

alemol
alemol

Reputation: 8642

Finally I solved it

In bitbucket side

All you need is to declare a Webhook pointing to the server.

enter image description here

In the server side

You need a mechanism listening some port all the time. This is the content of celery_listengit.py which is running all the time:

import subprocess
import threading
from tasks import git_pull
from flask import *

app = Flask(__name__)


@app.route("/", methods=['GET', 'POST'])
def listen_git4pull():

    # Range of bitbucket IP Addresses that we know.
    trusted = ['131.103.20', '165.254.145', '04.192.143']

    incoming = '.'.join(str(request.remote_addr).split('.')[:-1])
    if incoming in trusted:
        git_pull.delay()
        # OK
        resp = Response(status=200, mimetype='application/json')
    else:
        # HTTP not authorized
        resp = Response(status=403, mimetype='application/json')

    return resp


class CeleryThread(threading.Thread):
    def run(self):
        error_message = ('Something went wrong when trying to '
                         'start celery. Make sure it is '
                         'accessible to this script')
        command = ['celery',
                   '-A',
                   'tasks',
                   'worker',
                   '--loglevel=info']
        try:
            _ = subprocess.check_output(command)
        except Exception:
            raise Exception(error_message)


if __name__ == '__main__':
    celery_thread = CeleryThread()
    celery_thread.start()
    app.run(host='0.0.0.0')

And this is the contents of tasks, where git_pull() function is declared. This have to be delayed because git.pull() could take a lot of time, so it must run after server responds with HTPP OK status:

from git import *
from celery.app.base import Celery


app = Celery('tasks',
             backend='amqp://guest@localhost//',
             broker='amqp://guest@localhost//')

app.conf.update(
    CELERY_ACCEPT_CONTENT=['json'],
    CELERY_TASK_SERIALIZER='json',
    CELERY_RESULT_SERIALIZER='json',)

@app.task
def git_pull():
    repo = Repo('.')
    o = repo.remotes.origin
    o.fetch()
    o.pull()

Upvotes: 3

Related Questions