LoginSignup
0
2

More than 1 year has passed since last update.

Code CommitにpushされたらコミットのリンクをBacklogに記載を自動化

Last updated at Posted at 2021-08-24

はじめに

Backlogのgitではなく、Code Commitでソースを管理している場合にどのチケットに関するコミットか?分からなくなる
そこでBacklogにコミットのリンクを自動で記載する仕組みを構築したのでその備忘録を残す

全体構成

自動的にコミットハッシュをBacklogチケット(Backlog的にはissue)に紐づけるロジックとしては、
コミットメッセージから正規表現でコミットハッシュを紐づけるべきBacklogのissueを探すキーワードを抽出し、そのキーワードをissueの件名に含むものを探し出しそのissueにコミットハッシュを紐づける
具体的には、

  1. 開発者のCode CommitへのpushをCloud Watch Eventで捕捉しLambda関数を呼び出す
  2. Cloud Watch EventのEventオブジェクトの内容にはコミットメッセージがないので、AWS SDK(今回はJavaScript)でCode Commitからコミットメッセージを取得
  3. BacklogのWeb APIでBacklog上のissueをある条件で絞り込み、コミットメッセージに含まれるキーワードで検索する対象になるissueを取得する
  4. 取得したissueの中からコミットメッセージのissueとの紐づきを探すためのキーワードが件名に含まれるissueを特定する
  5. 該当のissueにコミットハッシュを書き込む

image.png

Backlogにコメントを記載するLambdaを作成

Lambdaをローカルでもテスト可能に

lambda-localというパッケージを使うと簡単

Cloud Watch Eventから渡ってくるEventオブジェクトの中身を把握する

Code Commitへのpushの際には、Cloud Watch EventsのreferenceUpdatedというタイプのイベントが発火する
そのEventオブジェクトの中身としては以下

{
  "version": "0",
  "id": "xxxxxxxxxxxxxxxxxxxxxx",
  "detail-type": "CodeCommit Repository State Change",
  "source": "aws.codecommit",
  "account": "xxxxxxxxxx",
  "time": "2021-08-18T07:09:12Z",
  "region": "ap-northeast-1",
  "resources": [
    "arn:aws:codecommit:ap-northeast-1:xxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxx"
  ],
  "detail": {
    "callerUserArn": "arn:aws:iam::xxxxxxxxxx:user/xxxxxxxxxx",
    "commitId": "xxxxxxxxxxxxxxxxxxxxxx",
    "event": "referenceUpdated",
    "oldCommitId": "xxxxxxxxxxxxxxxxxxxxxx",
    "referenceFullName": "refs/heads/main",
    "referenceName": "main",
    "referenceType": "branch",
    "repositoryId": "xxxxxxxxxxxxxxxxxxxxxx",
    "repositoryName": "xxxxxxxxxxxxxxxxxxxxxx"
  }
}

・参考:referenceUpdated イベント

Code Commitからコミットメッセージを取得

AWS SDK for JavaScript v3を使う(正確にはその中の@aws-sdk/client-codecommitを使う)
@aws-sdk/client-codecommitにはGetCommitCommandがあり、これを使うとcommitIdrepositoryNameからコミット情報が取得できる

基本的にAWS SDKを使う際には、認証が必要になりそれはAWS.configに色々設定をする必要があるが、環境変数にCredentialとなるもの(AWS access key ID、AWS secret access keyなど)を定義しておけば勝手に読み込んでくれるのでその方式を採用する
※Lambdaにdeployした後はLambdaのIAMロール Lambda実行時のAWS_ACCESS_KEY_IDとかは何になる?に書いたように、実行ロールが関係してくるのでそこはまた設定する必要はあるが、今時点では気にしないでOK

・参考:SDK バージョン 3 開発者ガイド 環境変数から Node.js への認証情報のロード

AWS.config の Key 環境変数の Key 説明
accessKeyId AWS_ACCESS_KEY_ID your AWS access key ID
secretAccessKey AWS_SECRET_ACCESS_KEY your AWS secret access key
sessionToken AWS_SESSION_TOKEN (AWS.Credentials) the optional AWS session token to sign requests with

コミットハッシュを記載するissueを特定する

Backlogの構成として、

  • スペース(spaceId):プロジェクト(projectId)=1:N
  • プロジェクト(projectId):課題(issue)=1:N

というような構成になっている
どのプロジェクトのどの課題とCode Commitのコミットハッシュが紐づくのか?が分かっている場合と分かっていない場合とを想定して以下のような実装にする

環境変数BACKLOG_PJ_IDで対象のプロジェクトの指定を可能に

BACKLOG_PJ_ID

  • 指定:指定されたプロジェクトのみをコミットハッシュ書き込み対象のissueを検索する対象とする
  • 未指定:スペース内の全てのプロジェクトをコミットハッシュ書き込み対象のissueを検索する対象とする

実装としては以下

let pjIds = [];
if (process.env.BACKLOG_PJ_ID) pjIds.push(process.env.BACKLOG_PJ_ID);
else {
   const pjs = await axios.get(`/projects?apiKey=${process.env.BACKLOG_API_KEY}`, config);
   pjs.data.forEach(pj => pjIds.push(pj.id));
}

・参考:プロジェクト一覧の取得

環境変数BACKLOG_ISSUE_TYPE_NAMEで対象のissue typeを指定可能に

次に、環境変数BACKLOG_PJ_IDで対象のプロジェクトの指定を可能にで取得したプロジェクトIDを使ってそのプロジェクトにある課題(issue)を取得する
が、この時、BACKLOG_ISSUE_TYPE_NAME

  • 指定:指定された課題種別のみのissueをコミットハッシュ書き込み対象のissueを検索する対象とする
  • 未指定:プロジェクト内の全てのissueをコミットハッシュ書き込み対象のissueを検索する対象とする image.png

実装としては以下

let issues = [];
for (const pjId of pjIds) {
   const fectedIssues = await axios.get(`/issues?apiKey=${process.env.BACKLOG_API_KEY}&projectId[]=${pjId}`, config);
   if (process.env.BACKLOG_ISSUE_TYPE_NAME) {
      fectedIssues.data
         .filter(issue => issue.issueType.name === process.env.BACKLOG_ISSUE_TYPE_NAME)
         .map(issue => reObj(issue))
         .forEach(issue => issues.push(issue));
   } else fectedIssues.data.map(issue => reObj(issue)).forEach(issue => issues.push(issue));
}

※今回for-ofを使っているがそれは、forEachは同期関数を期待するから
ちなみに、forEach の中身はwhileになっている

・参考:課題一覧の取得

コミットハッシュ書き込み対象のissueを特定

Backlogのissueの件名にあるキーワードが含まれているか?でissueを特定すればいいので、実装としては以下

const issueIds = issues
   .filter(issue => issue.summary.includes(ticketSearchKey))
   .map(issue => issue.id);

コミットハッシュをBacklogのissueに書き込む

複数のissueがヒットする事ももしかしたらBacklogの運用上あり得るかもしれないので実装は以下のようにした

const message = "Commit Message";
const hash = "Code Commit CommitHash";
const link = `[${input.commitId}](https://${process.env.AWS_REGION}.console.aws.amazon.com/codesuite/codecommit/repositories/${input.repositoryName}/commit/${input.commitId}?region=${process.env.AWS_REGION})`;
const data = querystring.stringify({
   content: `## ${message}\n${commitMsg}\n## ${hash}\n${link}`
});

let resultMap = {};
for (const [index, issueId] of issueIds.entries()) {
   const result = await axios.post(`/issues/${issueId}/comments?apiKey=${process.env.BACKLOG_API_KEY}`, data, config);
   resultMap["index"] = index;
   resultMap["result"] = {
      status: result.status,
      statusText: result.statusText,
      id: result.data.id,
      content: result.data.content
      }
}

・参考:課題コメントの追加

まとめると・・・

はじめにのGitHubのリンクのようなソースコードになる
実行結果としては以下のような感じ
image.png

おまけ

Cloud Watch Eventの設定方法

以下のように設定する
※「一致したイベントの一部」でJSONPath形式(ex $.detail)でEventオブジェクトの中身の一部のみをLambdaに渡すとかもできるが、今回はやっていない
image.png

0
2
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
0
2