📆

GitコマンドとGithub APIで取得できるFour Keys

2022/12/18に公開

Four Keysとは?

デリバリーのパフォーマンスを示す4つの指標です。
GoogleのDevOps Research and Assesment (DORA) チームがAccelerate State of DevOps Report 2019で報告しました。

  • デプロイの頻度 - 組織による正常な本番環境へのリリースの頻度
  • 変更のリードタイム - commit から本番環境稼働までの所要時間
  • 変更障害率 - デプロイが原因で本番環境で障害が発生する割合(%)
  • サービス復元時間 - 組織が本番環境での障害から回復するのにかかる時間

cf. エリート DevOps チームであることを Four Keys プロジェクトで確認する | Google Cloud Blog

2022年の同レポートでは、これに運用のパフォーマンスを示す信頼性 (Reliability) を加えた5つの指標により組織のパフォーマンスを予測できると報告しています。

レポートの作成プロセスなど詳細は書籍『LeanとDevOpsの科学』で知ることができます。

考慮すべき事項

リリースフロー

それぞれの指標について何を取得すべきかはリリースフローに拠るところが大きいです。
プロダクトごとに検討し、取得可能なものを選択する必要があります。

サービス復元時間 (Time to restore)

いわゆるMTTRではありますが、MTTRには大量の意味があります。

一番メジャーな使われ方はMean time to repairです。


引用元: MTTR vs MTBF vs MTTF: A Simple Guide To Failure Metrics

一説によるとMean time to restoreはMean time to recoveryと同じ意味で使われるようです。
とはいえ、その計測対象自体はサプライヤーが定めるものとも。

では、Four Keysとして取得すべき時間はどの期間になるでしょうか。
アラートが鳴ってからhotfixのリリースまで?バグの紛れ込んだリリースからfixのリリースまで?解決に着手してから完全な解決を承認するまで?

AtlassianがいろいろなMTTRがそれぞれどの時間を指すか定義したものがあります。

  1. Mean time to recovery
  2. Mean time to repair
  3. Mean time to respond
  4. Mean time to resolve

についてどの部分に当たるか図解しています。


引用元: MTBF, MTTR, MTTA, and MTTF
(日本語版)

ここでは、Mean time to recoveryがDORAの示す指標だと記載されています。

とはいえ基本的に全て包含関係にあるのでパフォーマンスに比例するのは変わらなさそうです。
初期段階においては、計測を定常化するために、正確性よりも測りやすさを軸に計測対象を決定するのが良いと思います。

取得してみる

GitやGithubで使えそうな情報の取得方法を例示していきます。
取得対象のブランチを変えたり、コミットのSHAやPull RequestのIDをキーに紐づけることで各指標に対応する値が取れるかもしれません。

タグごとの日時情報

git for-each-ref --format '%(refname),%(authordate),%(committerdate),%(creatordate),%(taggerdate)' refs/tags --sort=taggerdate

git tagの際に注釈付き (-m) かどうかで取得できる取れる値が違ってきます。

タグのついたコミットの日時情報

_tags() {
    tags=($(git tag -l "v*" | sort -r))
    for tag in "${tags[@]}"; do
        git show --oneline --pretty=format:"${tag},%ai,%cd,%h" --date=unix --decorate-refs=tags ${tag}
    done
}

メッセージに特定の文字列を含むコミットの作成時間

git log --oneline --pretty=format:'%h,%cd,%s' --date=unix | grep hotfix

mainブランチにマージ済みPull Requestの作成時間, マージされた時間

_prs() {
    prs=($(gh api -X GET "repos/{owner}/{repo}/pulls" --paginate -F per_page=100 -F base=main -F state=closed | jq -r  '.[] | [.id, .number, .base.sha[:10], .head.sha[:10], .merge_commit_sha[:10], .created_at, .closed_at, .merged_at] | @csv'))
    for pr in "${prs[@]}"; do
        IFS=$','
        prc=($pr)
        if [ -n "${prc[7]}" ]; then
           echo ${prc[0]},${prc[1]},${prc[2]},${prc[3]},${prc[4]},${prc[5]},${prc[6]},${prc[7]}
        fi
    done
}

さらに、各PRに含まれるコミットが作成された時間

_commits() {
    prs=($(_prs))
    for pr in "${prs[@]}"; do
        IFS=$','
        prc=($pr)
        tmp="${prc[2]%\"}"
        base="${tmp#\"}"
        tmp="${prc[3]%\"}"
        head="${tmp#\"}"
        IFS=$'\n'
        commits=($(git log --oneline --pretty=format:'%h,%cd' --date=unix ${base}..${head}))
        for commit in "${commits[@]}"; do
            echo ${commit},${prc[0]}
        done
    done
}

gh apiコマンドを使えば特定がラベル付いたissueの作成日時やクローズ日時を取得できます。
cf. Github REST API

前回タグから最新タグまでのコミット回数, マージまでの時間統計

#!/bin/bash

tags=($(git tag -l "v*" | sort -r | head -2 | xargs))
echo "check ${tags[0]}...${tags[1]}"

IFS=$'\n'
commits=($(git log --oneline --pretty=format:'%h,%cd,%an,%D' --date=format:'%Y-%m-%d %H:%M:%S' --decorate-refs=tags ${tags[0]}...${tags[1]}))
merge_commits=($(git log --merges --oneline --pretty=format:'%h,%cd,%an,%D' --date=format:'%Y-%m-%d %H:%M:%S' --decorate-refs=tags ${tags[0]}...${tags[1]}))

IFS=$','
release_commit=(${commits[0]})
## for Linux
# release_date=$(date +%s --date '%Y-%m-%d %H:%M:%S' "${release_commit[1]}")
## for Mac
release_date=$(date -j -f "%Y-%m-%d %H:%M:%S" "${release_commit[1]}" +%s)

for c in "${commits[@]}"; do
    IFS=$','
    commit=($c)
    if ! [[ -n $(echo "${merge_commits[@]}" | grep "${commit[0]}") ]]; then
        ## for Linux
        # commit_date=$(date +%s --date '%Y-%m-%d %H:%M:%S' "${commit[1]}")
        ## for Mac
        commit_date=$(date -j -f "%Y-%m-%d %H:%M:%S" "${commit[1]}" +%s)
        durations+=($(($release_date - $commit_date)))
    fi
done

commit_count=${#durations[@]}

echo "commit count(merge): ${#merge_commits[@]}"
echo "commit count(no merge): ${commit_count}"

readable () {
    ((sec=${1}%60, min=(${1}%3600)/60, hour=${1}/3600))
    printf "%d:%02d:%02d" $hour $min $sec
}
echo "min: $(readable ${durations[0]})"
if [ $((${commit_count} % 2)) -eq 0 ]; then
    echo "mid: $(readable $(( (${durations[$((${commit_count} / 2))-1]} + ${durations[$((${commit_count} / 2))]}) / 2 )))"
else
    echo "mid: $(readable ${durations[$((${commit_count} / 2))]})"
fi
echo "max: $(readable ${durations[${commit_count}-1]})"
echo "avg: $(readable $(((${durations[@]/%/+}0)/${commit_count})))"

おまけ:公開されているツールではどうしてる?

ここまで自前で取得する方法を書いてきましたが、既にツールとして公開されたものが数多くあります。
どういった値を取得しているかはツールごとに様々です。

変更失敗率やMTTRの取得に関して、issueの作成タイミングで取っているものもあれば、gitのブランチやコミットメッセージをもとに算出しているものもあります。

最大限利用するには、プロダクトの開発フローをツールに合わせて変更していく必要があるでしょう。

  • Findy Teams

    • https://engineering-org.findy-teams.com/posts/engineering_org_devops_metrics/
      • 変更障害率 - 期間内にメインブランチにマージされたプルリクのうち、hotfixブランチからのプルリクが占める割合
      • 平均修復時間 - 期間内にメインブランチにマージされたプルリクのうち、hotfixブランチまたは、revertブランチに紐づくコミットの最初のコミットからメインブランチへのマージまでの平均時間
  • LinearB

    • https://linearb.helpdocs.io/article/y6ul0o0vz0-mttr
    • MTTR - Mean Time To Restore
      MTTR is a metric that represents the average time it takes to restore from a failure of the system or one of its components. LinearB calculates this metric based on the time between when a "production bug" is created in your project management tool, until the time this issue (ticket) is resolved.

    • CFR - Change Failure Rate
      CFR is a metric that represents the percentage of deployments causing a failure in production. LinearB calculates this metric based on the number of "production incidents" defined in your project management tool divided by the number of deployments.

    • Change Failure Rate
      Change Failure Rate can be improved by focusing on your Review Depth metric. Review depth measures the average number of comments per pull request review. This metric is an indication regarding the quality of the review and how thorough reviews are done.

  • GoogleCloudPlatform/fourkeys

  • thoughtworks/metrik

  • Trendyol/four-key

  • hmiyado/four-keys

    • (commitメッセージで判別)
    • (直前のリリース〜fix commitの時間)

おわりに

自社の成長を確認・評価する指標として、ぜひ気軽に見ることができると楽しそうですね。

Discussion