Bitbucket hook server node.js로 구현하기

December 17, 2019

Devops에서의 필요성

github 또는 bitbucket 등의 형상관리 솔루션을 사용하는 경우, 팀내 개발 운영에 있어서 단일 솔루션만 쓰기에는 여러가지 불편한 점이 많습니다. 내 PR을 다른사람이 확인할 수 있는 부분은 메일밖에 없고, 승인을 한 경우 또는 PR에 대한 코드리뷰 코멘트를 남기는 경우에도 메일 외에는 알림을 받기 어려운 경우가 많습니다.

이렇게 알림을 받기 어려운 경우를 수정하기 위해서, 이전에는 chrome extension을 이용하여 API내 수신되는 데이터를 캐치하여, 액션에 따라 버튼을 배치하여 slack으로 연동하거나, 각 솔루션별 플러그인에 슬랙 등의 메신저를 연결하여 사용했으나, 이러한 경우 커스터마이징이 어려운 단점들이 있었습니다.

제가 속한 팀에도 이러한 문제를 해결하기 위해서, 자체적으로 Chrome extension을 만들어 PR을 올리고, 각 채널에 PR을 올렸다는 내용을 메신저 API를 통해 전송하거나, Approve 한 경우에 대한 내용을 PR 생성자에게 DM을 보내는 등의 유틸리티를 만들어 해결하곤 했습니다.

Chrome extension의 한계점

이렇게 Chrome extension을 이용해서 만들면 어느정도는 custom 하게 사용할 수 있으나, 실제 bitbucket에서 지원하는 내용이 없다보니, 개발 운영에 있어서 한계점은 존재합니다. github의 경우 github action 플랫폼이 11월중 릴리즈되어, workflow를 통한 이벤트 트리거링이 가능해 졌고, 이를 통해서 CI/CD 환경을 구축할 수 있게 되었습니다. (관련 내용은 이후에 포스팅 하겠습니다. :))

bitbucket에는 REST API를 전송할 수 있는 webhook 기능이 각 레포지토리의 설정 (settings) 내에 존재하고 있어, 이를 이용하여 각 이벤트에 대한 내용을 설정할 수 있습니다.

이번 포스트는 이 webhook의 내용을 nodejs를 이용하여 POST Method의 API를 이용하여 이벤트에 대한 데이터를 받는 것 까지의 구현 내용을 정리하고자 합니다.

구조

개략적인 구조를 이미지로 먼저 보여드리고, 세부 내용을 설명하는 것이 나을것 같습니다. :)

bitbucket hook server 구조

bitbucket내에서 개발자들이 Pull Request, Push, 코드리뷰 후 코멘트 등 bitbucket에서 미리 설정한 이벤트들이 트리거되면, 관련된 data를 미리 생성한 Hook server에 POST Method를 이용하여 관련된 data를 전송합니다.

전송된 data는 Hook server에서 설정한 라우터를 통해 들어온 이벤트 데이터는 request 객체 내 body data를 통해서 해당 이벤트에 대한 로직을 처리할 수 있도록 되어 있습니다.

bitbucket에서 Webhook을 이용하여 data를 전송할 수 있는 이벤트는 다음과 같습니다.

Repository

  • Push
  • Fork
  • Updated
  • Commit comment created
  • Build status created
  • Build status Updated

Issue

  • Created
  • Updated
  • Comment created

Pull Request

  • Created
  • Updated
  • Approved
  • Approval removed
  • Merged
  • Declined
  • Comment created
  • Commend updated
  • Comment deleted

위의 이벤트들을 설정하면, Hook server에서 API 형태로 이벤트 내용을 받을 수 있게 됩니다.

Hook Server 만들기

저는 Node.js를 이용해서, Hook Server를 개발하겠습니다. 서버 개발을 위한 package.json 을 생성하고, express 를 이용하여 API 서버를 개발하려고 합니다. 또한, applicaiton/json Content-type을 가진 request body안의 데이터를 받기 위해서, body-parser 플러그인도 같이 추가합니다.

// package.json 생성
npm init

// express, body-parser install
npm i express body-parser

body-parser middleware를 express내에 삽입하고, router를 설정합니다. Hook 데이터를 받기 위해서, /hook 이라는 URL을 POST 형태로 받을 수 있도록 설정하고자 합니다.

'use strict';

const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());

app.post('/hook', (req, res) => {
  const { body } = req;
  console.log('req.body ====>', body);
  res.status(200).send({ msg: 'success' });
});

app.listen(80, () => {
  console.log('Hook server listen in port 80');
});

위의 코드는 간단하게 /hook 라우터를 post type으로 설정하고, bitbucket에서 이벤트가 발생하여, /hook 라우터로 POST Method를 전송하여 bitbucket 관련 데이터의 내용을 req.body에서 확인하여 console로 출력하도록 개발되어 있습니다.

Bitbucket hook 설정하기

이제, 서버도 개발되었으니 실제로 Bitbucket 플랫폼에서 Webhook을 이용하여 hook server에 연결하는 작업이 필요할 것 같습니다. 사용하는 Bitbucket repository에서, Settings > Webhooks 메뉴로 진입합니다.

bitbucket webhooks

webhooks 페이지에 진입하면, 연결되어 있는 webhook 관련 리스트들이 보입니다. (hook-server-test의 경우 위의 코드로 연결한 aws 주소입니다.) Add webhook 버튼을 눌러 server를 세팅합니다.

bitbucket add webhook 화면

각 메뉴의 내용은 다음과 같습니다.

  • Title: webhook을 설정할 URL의 대표 타이틀을 설정합니다.
  • URL: webhook을 설정할 POST Method API URL을 설정합니다.
  • Status : 활성화 / 비활성화 상태를 체크합니다.
  • SSL/TLS: SSL 설정 관련된 유효성 검사를 실시합니다.
  • Request History: 설정된 URL의 Request에 관련된 History를 활성화합니다. 활성화하면, view history 메뉴를 통해서 호출한 내역 및 데이터를 확인할 수 잇습니다.
  • Triggers: 트리거링할 이벤트를 설정합니다. 이벤트 트리거링의 경우 위에 설명했던 이벤트를 기반으로 트리거를 설정할 수 있습니다.

우리가 만든 내용은 {APIURL}/hook 주소로 세팅했기 때문에, URL 항목에서는 /hook이 포함된 url로 설정합니다. 개인적으로 설정한 내용은 Pull Request에 대한 전반적인 이벤트를 모두 설정했습니다. 설정한 이후에는 Webhooks 리스트에 표시됩니다.

테스트하기

Pull Request 이벤트를 테스트하기 위해서, 소스하나를 수정해서 Commit을 하고, Pull Request를 생성합니다. 생성한 Pull Request에서 comment 및 Approve, UnApprove 등의 버튼을 클릭해봅니다.

이후, Settings > Webhooks 메뉴에서 설정한 리스트의 오른쪽에 Actions 컬럼에 있는 View requests를 클릭합니다.

View requests 화면

View requests 화면에 진입하면, 트리거링된 이벤트를 확인할 수 있습니다. 다시 테이블의 오른쪽 Actions 항목에서 View details를 클릭합니다.

view detail

View detail 화면입니다. 실제로 hook을 통해 전송한 Header 정보 및 밑으로 보시면 request body까지 확인이 가능합니다.

마치며

지금까지, Node.js를 이용한 POST Hook API를 구축하고, Bitbucket 내에 Webhook을 통해 이벤트 발생시 API URL로 데이터를 전송하는 것까지 구현하였습니다. 이후에는, 이 API 서버와 Chrome extension을 이용하여 Bitbucket에서 개발 운영에 필요한 환경을 구축하는 내용을 다루고자 합니다.

...