8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Github、Bitbucketとのデプロイ連携するときのBottle用のテンプレート

Last updated at Posted at 2015-10-29

自分用のBottle用テンプレート。

Bitbucket、GithubのHook用APIは、pullした後、Upstartに登録してるAPIサーバー(gunicorn)を再起動してる。

Gitレポジトリの操作用に、GitPythonを入れてる。

時間周りの処理で、arrowも入れてる。

server.py
# -*- coding: utf-8 -*-

import commands
import os.path
import traceback
from decorator import decorator
import logging
import subprocess
import getpass

from bottle import get, post, put, delete, run, default_app, request, response, HTTPError, redirect, local, abort 
from bottle import static_file, route

import arrow

from git import Repo


# Decorator

@decorator
def check_db_connection(func, *args, **kwargs):
    """
    Peewee用。dbは、Peeweeのデータベースのインスタンス。
    """

    try:
        db.get_conn().ping(True)
    except:
        logging.error(traceback.format_exc())
    
    return func(*args, **kwargs)

@decorator
def check_login(func, *args, **kwargs):
    """
    認証処理を書いて、ログインしたユーザーのインスタンスをlocal.meとかに入れとく。
    """

    response_json = func(*args, **kwargs)
    return response_json

@decorator
def error_handling(func, *args, **kwargs):
    """
    エラーをJSON形式で返す。デバッグ用。本公開の時は、error_classとかerror_traceは消す。
    """

    try:
        return func(*args, **kwargs)
    except Exception as exception:
        if issubclass(exception.__class__, HTTPError):
            raise exception
        else:
            logging.error(traceback.format_exc())

            return {
                "error_class": type(exception).__name__,
                "error_trace": traceback.format_exc(),
            }

@decorator
def measurement(func, *args, **kwargs):
    """
    APIの処理時間を計測する。
    """

    start_time = arrow.now()

    result = func(*args, **kwargs)

    print "Transaction time: {0} secs".format(arrow.now().float_timestamp - start_time.float_timestamp)

    return result


# API


# Static files

@route('/')
@route('/<filepath:path>')
def server_static(filepath = None):
    if filepath is None:
        filepath = 'index.html'

    root_path = u"Webのルートパス"

    response = static_file(filepath, root = root_path)
    return response


# Pull from Bitbucket

@post('/__pull_from_bitbucket')
@error_handling
def pull_from_bitbucket():
    """
    Bitbucket連携用。
    IPで、このAPIへのアクセスをBitbucketからだけに絞っとく。
    """

    repository_path = "{0}/../../..".format(os.path.dirname(__file__))
    repository = Repo(repository_path)

    payload = request.json

    logging.info("payload: {0}".format(payload))
    branch = payload['push']['changes'][0]['new']['name']

    logging.info("Pull from Bitbucket: {0}: {1}".format(
        branch, repository.active_branch.path))

    if repository.active_branch.path.endswith(branch):
        repository.remotes[0].pull()

        reboot_gunicorn_command = ["/usr/bin/sudo", "/sbin/restart", "api-server"]
        output = subprocess.check_output(reboot_gunicorn_command)
        logging.info("Reboot API server: {0}: {1}".format(
            reboot_gunicorn_command, output))

    return {
    }


# Pull from GitHub

GITHUB_HOOK_SECRET = os.environ.get('GITHUB_HOOK_SECRET')

@post('/__pull_from_github')
@error_handling
def pull_from_github():
    """
    GitHub連携用。
    GitHub Hookのシークレットキーを、環境変数に入れとく。
    """

    sent_signature = request.headers.get('X-Hub-Signature')[5:]
    raw_payload = request.body.read()
    generated_signature = hmac.new(GITHUB_HOOK_SECRET, raw_payload, hashlib.sha1).hexdigest()

    if sent_signature == generated_signature:

        repository_path = "{0}/../../..".format(os.path.dirname(__file__))
        repository = Repo(repository_path)
    
        payload = request.json
    
        if payload['ref'] == repository.active_branch.path:
            logging.info("Pull from GitHub: {0}: {1}".format(payload['ref'], payload['head_commit']['id']))
            repository.remotes[0].pull()
    
            reboot_gunicorn_command = ["/bin/sudo", "/usr/bin/systemctl", "restart", "api_server"]
    
            logging.info("Reboot API server: {0}".format(reboot_gunicorn_command))
            return_code = subprocess.call(reboot_gunicorn_command)

    return {
    }




application = default_app()
if __name__ == '__main__':
    run(host = 'localhost', port = 8000, debug = True)
8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?