Posted at

CircleCIで何をデプロイしたかをわかるGitタグを作成

CircleCIの設定の話よりも、Gitタグ名の運用をメインに記していきます:santa:

CircleCIでGitタグをイベントにCIを回していく記事はありますが、じゃあ実際にどういうタグ名にするか

という記事は見かけなかった為、実際にタグを運用してみての話をしていきたいと思います:santa:


対象読者


  • CircleCIを使用している

  • CircleCIの環境内でshellを使う

  • Gitタグにブランチ名を使用したいと思っている


Gitタグ運用の背景

自分の場合、Gitタグを生成する目的は、Gitタグを使用してGitタグ生成時までロールバックするのが目的でした:santa:

なのでタグ名の詳細は特に細かいことを考えず、当初は下記のようなタグを生成していました:fish:


NOW=$(date +'%Y_%m%d'); # echo $NOW => "2018_0830"
TAG_NAME=${CIRCLE_BRANCH}_$NOW

# echo $TAG_NAME => master_2018_0830

その時は、いつなんのブランチのjobが実行完了したかを把握すればいいやという感覚で下記のようなタグ名にしていたのですが


master_2018_0830


  • マージやデプロイされる度にタグ名がどんどん増えていく(当たり前)

  • 何をいつデプロイしたのか忘れる→いつ時点までロールバックすれば良いのかコミット内容全て見返すハメに

  • デプロイ待ちを可視化したい

ロールバックをするという事態は起きていないのですが、より意味のあるGitタグを生成したい思いタグ名を見直す事にしました:santa:


CircleCIの流れ

まずは自分のCIの流れを簡単に紹介しておくと


masterブランチへプルリク成功後


  1. ビルド


  2. テスト


  3. Gitタグを生成


"master_2018_0830" #こんな名称


prod、devブランチへマージ成功後


  1. デプロイ


  2. Gitタグを生成


"prod_2018_0830" #こんな名称
"dev_2018_0830" #devの場合はこんな名称

そしてmaster→prod、stagingへマージするタイミングは人間の判断でしたい時とかあったので手動でmaster→prod、stgにマージしたタイミングです:santa:


それ以外のブランチは、プッシュの度に


  1. ビルド


  2. テスト

が走ります

CicleCIのconfigの内容がメインではないので、config.yml設定内容は最後に置いておきました!


結果

ともかく、まずは結果から


変更前


# masterブランチにマージ成功後
master_2018_0830

# prodブランチにマージ成功後

prod_2018_0830

# stgブランチにマージ成功後

stg_2018_0830


上記のように運用してみてわかった弱点


  • マージやデプロイされる度にタグ名がかさばっていく

  • 何をいつデプロイしたのか忘れる

  • デプロイされていないものがわからない

上記を解決するため下記のようにタグ名を変更しました:santa:


変更後


# masterブランチにマージ成功後
"master←←←issues/#100-hogehoge_2018_0928" というGitタグを作成
"#100_prod_no_deploy" も新たにタグ生成
"#100_stg_no_deploy" も新たにタグ生成

# productionブランチにマージ成功後
prod←←←issues/#100_2018_0928

"#100_prod_no_deploy" を削除

# stagingブランチにマージ成功後
stg←←←issues/#100_2018_0928

"#100_stg_no_deploy" を削除


変更のポイント


  1. " / "を入れると、GitHubのGUI上でフォルダ形式になってくれる

  2. どういうissueがいつどのブランチにマージされたかがわかる

  3. masterにプルリクがマージ後にno_deployを生成して何のissueがデプロイされていないかわかる

画像を使用して説明すると、GitKrakenSourceTreeなどをGitのGUIを使用しているわかる機能ですが

スクリーンショット 2018-12-09 23.27.28.png

上が"/"が入っていないタグで、どんどんリストが多くなっていきます

下がタグ名に"/"が入っているタグで、"/"から切れた状態でフォルダ化されます

タグ名をクリックして展開すると下記のようになります:santa:

スクリーンショット 2018-12-09 23.27.36.png


CircleCI上でマージしたissue名を抽出するには

さて、ここが結構苦悩したというか、自分の経験のなさ故にハマった場所なのですが、どうやったらCircleCIでマージされたブランチ名を取得しようか模索したのですが

結論からいうとgit logコマンドで取得することがわかりました:santa:

ツイッターでどうやってマージされたブランチ名を取得するんじゃーって悩んでいたら、公式のCircleCIのアカウントの方からアドバイスをいただいたのでそれを参考にしました:santa:

この場を借りて感謝申し上げます:santa:

本当にありがとうございます!

下記がmasterブランチにマージ後、CircleCIのdockerで実行するシェルになります(わかりにくいですね💦)


create-mastertag.sh

#!/bin/bash

# want to create git tag ex. 「 pr_name←←←issues/#100-hogehoge_2018_0928 」 and 「 #100_no_deploy 」
NOW=$(date +'%Y_%m%d'); # echo $NOW => "2018_0830"
pr_repo_name=$( git log --oneline --merges | awk '{print $7}' | head -1 ); # echo $pr_repo_name => CyberAgent/issues/#100-hogehoge
pr_name=${pr_repo_name#*/}; # echo $pr_name => issues/#100-hogehoge
issue_no=$( echo $pr_name | (sed 's/.*\(#[0-9]\{1,100\}\).*/\1/') ); # echo $issue_no => #100
tag_name="master←←←${pr_name}_${NOW}"; # echo $tag_name => master←←←issues/#100-hogehoge_2018_0928
dev_no_deploy_tag="${issue_no}_dev_no_deploy"; # echo $no_deploy_tag => #100_dev_no_deploy
prod_no_deploy_tag="${issue_no}_prod_no_deploy"; # echo $no_deploy_tag => #100_prod_no_deploy

git tag $tag_name && git tag $dev_no_deploy_tag && git tag $prod_no_deploy_tag && git push origin --tags;


変数の中身のサンプルをコメント化しているのであらかた見当はつくと思いますが

マージされた直後のブランチ名を取得しているのは5行目の箇所です


pr_repo_name=$( git log --oneline --merges | awk '{print $7}' | head -1 ); # echo $pr_repo_name => CyberAgent/issues/#100-hogehoge



  1. git logコマンドでマージのみのlogを取得


  2. awkコマンドで空白で区切られた7番目のlogだけにする


  3. head -1でマージ直前のブランチ名のみのラインを取得

CircleCIの${TAG_NAME}を使用するだとか、いろんな方法を試しましたが、うまく行かず上記の取得方法に落ち着きました:santa:

その後、下記がprod(or dev)ブランチにマージ後、CircleCIのdockerで実行するシェルになります


#!/bin/bash

# create gittag ex. dev←←←issues/#100,#101,#102,_2018_0928
NOW=$(date +'%Y_%m%d')

# no_deployを含むタグの#numberだけを連結
for nodeploytag in $(git tag -l '*dev_no_deploy'); do # nodeploytag => #100_dev_no_deploy
tagnumber=$( echo $nodeploytag | (sed 's/.*\(#[0-9]\{1,100\}\).*/\1/') ); # tagnumber => #100
tagnumbers+="$tagnumber"; # tagnumbers => #100,#101・・・
git tag -d "${nodeploytag}"; # #100_dev_no_deployのタグをローカルで削除
git push --delete origin "${nodeploytag}"; # #100_dev_no_deployのタグを削除
done;

tag_name="dev←←←issues/${tagnumbers}_${NOW}"; # echo $tag_name => dev←←←issues/#100,#101,#102,_2018_0928

git tag $tag_name && git push origin --tags

デプロイ待ちのブランチが複数あることを想定して、forでnodeploytagを連結していってます

devはprodをdevに置換するだけです。プロセスは全く同じです:santa:


最終的に

GitKrakenではこういう風にタグが可視化されました(SourceTreeも同じようになるはず)

スクリーンショット 2018-12-10 0.37.15.png

いつ何がmasterにマージされて、何がdevやprodにマージされていないのかが可視化され、かつタグがかさばらないようになりました:santa:

*no_deproyは本来あるべきではないので、"/"で区切らなくても良いと思いました:fish:


参考までにCircleCIの設定


config.yml

version: 2.1

executors:
container:
working_directory: ~/hogehoge
docker:
- image: circleci/node:8.11-browsers
environment:
TZ: Asia/Tokyo
TERM: xterm

jobs:
install-and-build:
executor:
name: container
steps:
- checkout
- restore_cache:
name: Restore Yarn Package Cache
key: dependency-cache-{{ checksum "yarn.lock" }}{{ .Branch }}
- run: yarn install
- run: yarn build:prod
- save_cache:
name: Save Yarn Package Cache
key: dependency-cache-{{ checksum "yarn.lock" }}{{ .Branch }}
paths:
- ~/.cache
- ./node_modules
- persist_to_workspace:
root: .
paths:
- .

test:
executor:
name: container
steps:
- attach_workspace:
at: .
- run:
command: yarn serve
background: true
- run:
command: yarn cypress:install
- run:
command: yarn test:wait

master-jobs:
executor:
name: container
steps:
- checkout
- attach_workspace:
at: .
- run: ./scripts/create-mastertag.sh

production-jobs:
executor:
name: container
steps:
- checkout
- attach_workspace:
at: .
- run: ./scripts/deploy-prod.sh

staging-jobs:
executor:
name: container
steps:
- checkout
- attach_workspace:
at: .
- run: ./scripts/deploy-dev.sh

workflows:
build-and-test:
jobs:
- install-and-build
- test:
requires:
- install-and-build
requires:
- test
- master-jobs:
requires:
- test
filters:
branches:
only: master
- production-jobs:
filters:
branches:
only: production
- staging-jobs:
filters:
branches:
only: staging