LoginSignup
1
3

More than 5 years have passed since last update.

LambdaとAPIGatewayを使ってgitbucketでのcommitをbacklogに送る方法

Last updated at Posted at 2017-06-23

Backlogでチケットを管理していて、Gitbucketをリポジトリとして使っている場合に
GitbucketへのcommitをBacklogのチケットに反映する方法

@colorrabbitさんのこの記事の焼き直しです
Backlog APIのv2に対応させています

必要な手順

  1. backlog apiを使う為のapi keyを取得
  2. LambdaとAPI Gatewayを設置
  3. gitbucket側のwebhookにbacklogを追加
  4. コミットメッセージにbacklogのチケットIDを含める

backlog apiを使う為のapi keyを取得

backlogに入り、個人設定 -> APIを開く

適当なAPIのメモを入力し「登録」をするとAPIキーが発行されるのでメモしておく

Kobito.QEgVEb.png

LambdaとAPI Gatewayを設置

Lambda設定

gitbucketのwebhook -> lambda -> backlog となるようにlambdaを構成。

まずaws consoleからLambdaに入り、Node.jsの6.10を選択、Blank Functionを選択

Kobito.XZSrgA.png

トリガーはとりあえず作らないで次へ

Kobito.FgA1X1.png

コードをバリバリ書く。

基本はgitbucketからcommit/push等でhookされた情報を受取り、
いい感じに加工してbacklogのチケットのコメントとして追加してやればOK。

なお、環境変数は以下の感じに定義している

Kobito.HlyOhr.png

書きなぐりのコードだけれど参考までに貼っておきます

console.log('--- Gitbucket to Backlog api start');

const response = {
    statusCode: 200,
    headers: {},
    body: ""
};

const querystring = require('querystring');
const http = require('https');
const url = require('url');

const backlog_endpoint = process.env.BACKLOG_ENDPOINT;
const backlog_api_key = process.env.BACKLOG_API_KEY;
const project_id = process.env.PROJECT_ID;

const makePushMessage = (json) => {
    return `''Git Push通知''\n\n ${pushMessage(json)}`;
};

const pushMessage = (json) => {
    return `
Pushed Repository
|~Repository|${json.repository.full_name}|
|~Branch|${json.ref}|
|~Compare|[[view:${json.compare}]]|
`;
};

const makeCommitMessage = (commit) => {
    return `\n${commitMessage(json)}`;
};


const commitMessage = (commit) => {
    return `
|~Commit ID|${commit.id}|
|~Commit Message|${commit.message.replace(/\r?\n/g,"")}|
|~Commiter|${commit.committer.name}|
|~Source|[[view:${commit.url}]]|
`;
};

const getTicketId = (message) => {
  const filtered = message.split(' ').filter((element, index, array) => {
    return (element.includes(project_id));
  });
  return filtered[0];
};

const isFix = (message) => {
    return (
        message.includes('#fix') ||
        message.includes('#fixes') ||
        message.includes('#fixed')
    );
};

const isClose = (message) => {
    return (
        message.includes('#close') ||
        message.includes('#closes') ||
        message.includes('#closed')
    );
};

const makeCommitInfo = (commit) => {
    return {
        ticketId: getTicketId(commit.message),
        isFix: isFix(commit.message),
        isClose: isClose(commit.message),
        commitMessage: commitMessage(commit)
    };
};


const postComment = (ticketId, content) => {
    return new Promise((resolve, reject) => {
        const endpoint = backlog_endpoint + '/issues/' + ticketId + '/comments' + '?apiKey=' + backlog_api_key;

        const req_opts = url.parse(endpoint);
        req_opts.method = 'POST';
        req_opts.headers = {'Content-Type': 'application/x-www-form-urlencoded'};

        const req =
            http.request(
                req_opts,
                (res) => {
                    if (res.statusCode === 200 || res.statusCode === 201) {
                        return resolve();
                    } else {
                        console.log('error, status: ' + res.statusCode);
                        res.on('data', (chunk) => {
                            console.log('BODY: ' + chunk);
                        });
                        return resolve();
                    }

                }
            )
        ;

        req.on('error', (error) => {
          console.log('probrem with request: ' + error.message);
          return resolve();
        });

        const postData = querystring.stringify({
            content: content,
            notifiedUserId: [],
            attachmentId: []
        });

        req.write(postData);
        req.end();

    });
};


exports.handler = (event, context, callback) => {

    const pushMessage = makePushMessage(event);

    const commits = ((event) => {
        if (!event.commits) return undefined;
        return event.commits.map((commit, index, array) => {
           return  makeCommitInfo(commit);
        });
    })(event);

    if (!commits) return;

    // sequential execute
    commits.reduce((current, args) => {
        return current.then(() => {
            return postComment.apply(null, [args.ticketId, pushMessage + args.commitMessage]);
        });
    }, Promise.resolve());


    callback(null, response);
};

なお、gitbucketのsettings -> webhookで適当にtestしてみるとgitbucketからの
payloadが表示されるのでそれをテストデータにしてLambdaを動かしていくと早い

API Gateway

以前の記事を参考に立てればOK

今のところgitbucket側からいい感じに認証キーを送る方法がわからなくて
API Gateway側は無認証で動かしている(良くないので対処検討中)

gitbucket側のwebhookにbacklogを追加

gitbucket -> 対象のリポジトリ -> Settings -> Service Hooks

を開き、Add webhookをクリック

payload URLにapi gatewayで作成したurlを指定

Kobito.uPVlk7.png

コミットメッセージにbacklogのチケットIDを含める

以下のようにしてcommit/pushすればbacklog側にコメントが飛ぶ

git commit -m 'add readme [backlogのチケットID]'

TODO

  • 今はcommitだけを拾ったが、issueとかpull requestとかも拾っていきたい
  • gitbucket -> API Gatewayの認証(最悪IPで絞る)
  • ちゃんとPromiseの非同期していないので対処したい(array分逐次実行にしないと)
1
3
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
1
3