Last active
January 6, 2021 23:32
-
-
Save namikingsoft/b8d553c64c9a0ff7409dd4db206d68f2 to your computer and use it in GitHub Desktop.
Post reports of webpack-bundle-analyzer to GitHub statuses on CircleCI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh -eu | |
# ## Post bundle analyzer to github statuses | |
# | |
# ### Environment Variables | |
# | |
# - `REPORT_JSON_PATH`: By webpack-bundle-analyzer | |
# - `REPORT_HTML_PATH`: By webpack-bundle-analyzer | |
# - `GITHUB_TOKEN`: GitHub Access Token | |
# - `CIRCLE_SHA1`: Defined by CircleCI | |
# - `CIRCLE_BUILD_NUM`: Defined by CircleCI | |
# - `CIRCLE_PROJECT_USERNAME`: Defined by CircleCI | |
# - `CIRCLE_PROJECT_REPONAME`: Defined by CircleCI | |
# - `CIRCLE_PULL_REQUEST`: Defined by CircleCI on pull request build | |
# ポーリング系を待つ秒数: ベースブランチと同時にビルドが走ると Artifact がなかったりするため | |
TIMEOUT_UNIXTIME="$(($(date +%s)+300))" # 5 分間 | |
# GitHub Pull Request 番号を抽出 | |
PR_NUMBER="$(echo "$CIRCLE_PULL_REQUEST" | sed -e 's@^.*/@@')" | |
# GitHub Pull Request からベースブランチのコミットハッシュを取得 | |
base_branch_sha1() { | |
if [ "${PR_NUMBER:-undef}" != "undef" ]; then | |
branch="pull/${PR_NUMBER}/merge" | |
git fetch origin "${branch}:${branch}" > /dev/null | |
git log "${branch}" --oneline | head -n1 | sed -e 's/^.* into //' | |
else | |
git rev-list origin/master | head -n1 | |
fi | |
} | |
# GitHub Statuses に添付する Bundle Analyzer の url を取得 | |
report_html_url="$( | |
curl \ | |
-X GET "https://circleci.com/api/v2/project/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BUILD_NUM}/artifacts" \ | |
-H "Circle-Token: $CIRCLE_PERSONAL_TOKEN" \ | |
| jq -r ".items | map(select(.url | endswith(\"${REPORT_HTML_PATH}\"))) | .[0].url" | |
)" | |
# GitHub Statuses に Bundle Analyzer の url を POST | |
curl \ | |
-X POST "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/statuses/${CIRCLE_SHA1}" \ | |
-H "Authorization: token $GITHUB_TOKEN" \ | |
-H "Accept: application/vnd.github.v3+json" \ | |
-d "$(cat << EOS | |
{ | |
"state": "success", | |
"description": "From CircleCI Job: ${CIRCLE_BUILD_NUM}", | |
"target_url": "${report_html_url}", | |
"context": "Bundle Analyzer" | |
} | |
EOS | |
)" | |
# ベースブランチの GitHub Statuses Description から CircleCI Job 番号を抽出 | |
while [ "$(date +%s)" -lt "$TIMEOUT_UNIXTIME" ]; do # ベースブランチとの同時ビルド対策 | |
description="$( | |
curl \ | |
-X GET "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commits/$(base_branch_sha1)/statuses" \ | |
-H "Authorization: token $GITHUB_TOKEN" \ | |
-H "Accept: application/vnd.github.v3+json" \ | |
| jq -r '. | map(select(.context == "Bundle Analyzer")) | if length > 0 then .[0].description else "" end' | |
)" | |
base_build_num="$(echo "$description" | sed -E 's/^.* Job: (.*)$/\1/')" | |
if [ "${base_build_num:-none}" != "none" ]; then | |
break | |
fi | |
sleep 10 # sec | |
done | |
if [ "${base_build_num:-none}" = "none" ]; then | |
echo "Not found size-compare info from base branch" | |
exit 0 | |
fi | |
# ベースブランチの Bundle Analyzer json を Artifact から取得 | |
base_report_json_url="$( | |
curl \ | |
-X GET "https://circleci.com/api/v2/project/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/${base_build_num}/artifacts" \ | |
-H "Circle-Token: $CIRCLE_PERSONAL_TOKEN" \ | |
| jq -r '.items | map(select(.url | endswith("report.json"))) | .[0].url' | |
)" | |
curl -Lo /tmp/report-base.json "$base_report_json_url?circle-token=${CIRCLE_PERSONAL_TOKEN}" | |
cp "${REPORT_JSON_PATH}" /tmp/report-head.json | |
# Size compare を集計しやすいように json を整形 | |
< /tmp/report-head.json jq 'map( . | { label: .label | sub("\\.[a-z0-9]{20,32}\\.";"."), gzipSize: .gzipSize })' > /tmp/report-headmod.json | |
< /tmp/report-base.json jq 'map( . | { label: .label | sub("\\.[a-z0-9]{20,32}\\.";"."), gzipSize: - .gzipSize })' > /tmp/report-basemod.json | |
# 前後の Bundle Analyzer json から Size compare 情報を集計 | |
jq -s ' | |
add | |
| group_by(.label) | |
| map({ | |
label: .[0].label, | |
gzipSize: (.[0].gzipSize | fabs), | |
gzipSizeDiff: ((.[0].gzipSize // 0) + (.[1].gzipSize // 0)), | |
gzipSizePercent: (((.[0].gzipSize // 0) + (.[1].gzipSize // 0)) / (.[0].gzipSize | fabs) * 100), | |
}) | |
| map(select(.gzipSizeDiff != 0)) | |
' /tmp/report-headmod.json /tmp/report-basemod.json > /tmp/bundle-analyzer/size-compare.json # スクリプト外で store_artifact される TODO: 蜜 | |
# Total, Entry の Gzip サイズ差分を集計 | |
total_gzip_size_diff="$(< /tmp/bundle-analyzer/size-compare.json jq 'map(.gzipSizeDiff) | add // 0')" | |
entry_gzip_size_diff="$( | |
< /tmp/bundle-analyzer/size-compare.json jq ' | |
map( | |
select(.label | contains("index.") or contains("startup.")) | |
| .gzipSizeDiff | |
) | |
| add // 0 | |
')" | |
# 明示的に `+` をつける & 三桁カンマ区切り refs. https://pooh.gr.jp/?p=9768 | |
total_gzip_size_diff="$(perl -e "print '+' if $total_gzip_size_diff > 0")$(echo "${total_gzip_size_diff}" | awk '{printf"%\047d\n",$1}') B" # Byte | |
entry_gzip_size_diff="$(perl -e "print '+' if $entry_gzip_size_diff > 0")$(echo "${entry_gzip_size_diff}" | awk '{printf"%\047d\n",$1}') B" # Byte | |
# 他の Artifact url のファイル部を size-compare.json に書き換えて、流用する | |
# まだ store_artifact されていないため、API から直接 url が取得できない | |
size_compare_json_url="$(echo "$report_html_url" | sed -E 's|^(.+)/[^/]+$|\1/size-compare.json|')" | |
# Size compare 情報を GitHub Statuses に POST | |
curl \ | |
-X POST "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/statuses/${CIRCLE_SHA1}" \ | |
-H "Authorization: token $GITHUB_TOKEN" \ | |
-H "Accept: application/vnd.github.v3+json" \ | |
-d "$(cat << EOS | |
{ | |
"state": "success", | |
"description": "Entry: ${entry_gzip_size_diff} / Total: ${total_gzip_size_diff} (gzip)", | |
"target_url": "$size_compare_json_url", | |
"context": "Bundle Compare" | |
} | |
EOS | |
)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment