概要
- DangerとはPull Request(以下PR)の自動チェックを行えるツールです。
- 今回は
GitHubActions
を使って、PRを行ったときにDangerでそのPRの自動チェックを走らせてみます。

GitHub
- danger-js-demo
- PRの例は[WIP] 大きなファイルを10以上追加 #16を参照。
参考
- Danger-js公式
- Danger (JS) を GitHub Actions で導入する
- Dangerでpull requestレビューの指摘事項を減らす
- iOSにおけるコードレビューを一歩先へ進める
- ブランチ名の取得
// ブランチ名の取得例
warn("base: " + danger.github.pr.base.ref); // develop
warn("head: " + danger.github.pr.head.ref); // feature/hoge
- JSの動作確認用ページ(ローカルで.js用のエディタが無かったため)
-
secrets.GITHUB_TOKEN
の権限の話
導入例
- リポジトリに
./.github/workflows/actions.yml
を作成。 - GitHubActionsでPR時にDangerが走るように設定します。
- danger-js@xxxのバージョンは適宜置換します
name: Danger JS
on: [pull_request]
jobs:
build:
name: Danger JS
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Danger
uses: danger/danger-js@11.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DANGER_DISABLE_TRANSPILATION: true
- 続いてリポジトリ直下に
dangerfile.js
を作成します。 - 大半の設定はその他記事からの参考ですが、
checkBranchNames
の箇所は自分で書いてみました。jsは知らないので雰囲気ですが。
- messageは単純にコメントを書き込むDSL。定型文を返す時など。
- fail() を呼び出すと ci は失敗し、マージできないようになります。
- warn() の場合は警告を表示しますが、マージは可能です。
// ===== Functions =====
function checkBranchNames(head_branch, base_branch) {
// head(例: feature) -> base(例: develop)
const template_branches = ["release", "master", "main", "develop", "feature/", "revert/", "hotfix/"];
// ブランチ名が想定する名称かどうかの確認
is_valid_head_branch_name = false;
for (const template_branch of template_branches) {
if (head_branch.startsWith(template_branch)) {
is_valid_head_branch_name = true;
break;
}
}
if (!is_valid_head_branch_name) {
// warn(`ブランチ名が不正です: ${head_branch}\n次のいずれかの名称を使用してください: \n${template_branch_names.join(' ')}`);
fail(`ブランチ名が不正です: ${head_branch}\n次のいずれかの名称を使用してください: \n${template_branches.join(' ')}`);
}
// ブランチ名とマージの整合性確認
// 仮に誤ってdevelop -> featureとしてしまったときに検出させるとか。
// TODO...
}
// ===== Entry Point =====
let isAllCheckPassed = true;
// ===== Title =====
// PRのタイトルに[WIP]が含まれる場合は、作業中なのでfailさせる
if (danger.github.pr.title.includes('[WIP]')) {
fail("Should NOT inclued 'WIP' in your PR title");
}
// PRのタイトルに課題番号が含まれているかどうか(DEV_1-XXX)
const hasIssuesNumber = /DEV_1-[0-9]/.test(danger.github.pr.title);
if (!hasIssuesNumber) {
warn("Should include issues number in your PR title");
isAllCheckPassed = false;
}
// ===== Settings =====
// PRにレビュアーが指定されているかどうか
if (!danger.github.pr.reviews) {
warn("Should select PR reviewer");
isAllCheckPassed = false;
}
// PRにassigneesが指定されているかどうか
if (!danger.github.pr.assignee) {
warn("Should select PR assignees");
isAllCheckPassed = false;
}
// ===== Changing amount =====
// 500行以上の追加・削除の変更があったかどうか
const diffSize = Math.max(danger.github.pr.additions, danger.github.pr.deletions);
if (diffSize > 500) {
warn("Should reduce diffs less than 500");
isAllCheckPassed = false;
}
// 変更したファイルの数が10より多いかどうか
if (danger.github.pr.changed_files > 10 ) {
warn("Should reduce change files less than 10");
isAllCheckPassed = false;
}
// ===== Branch =====
checkBranchNames(danger.github.pr.head.ref, danger.github.pr.base.ref)
// ===== Result =====
if (isAllCheckPassed) {
markdown('## All checkes have passed :tada:');
}
- 以上の内容をmainブランチにプッシュしてPRを作ってやると、GitHubActionsによってDanger JSが動作しPRの自動チェックが走ってくれます。

- PRを更新して再度チェックする場合は以下をクリック(多分)

その他チェック項目の例
- Dangerで実現できることを把握したかったので、他の方の事例で行っているをいくつか抜粋しています。
Danger (JS) を GitHub Actions で導入する
- CHANGELOG.md が変更されていないと怒られるやつです。
dangerfile.js
const hasChangelog = danger.git.modified_files.includes('CHANGELOG.md')
const isTrivial = (danger.github.pr.body + danger.github.pr.title).includes(
'#trivial'
)
if (!hasChangelog && !isTrivial) {
warn('Please add a changelog entry for your changes.')
}
コードレビューの機械的な指摘はDangerに任せる
- また別リポジトリにあるDangerfileを参照することができる。
- 多分こういうことですね。
各リポジトリでDangerfileを用意してチェック項目を記述していますが、組織独自のルールなど共通する処理は専用リポジトリで管理して参照するようにしています。
例えば、danger-lclというリポジトリを用意して共通のチェック項目を記述したDangerfileを管理します。 そして別のリポジトリのDangerfileで下記を追加することで、そのリポジトリのDangerfileの内容を読み込むことができます。
# dangerfile.js内
# danger-lclを読み込み
danger.import_dangerfile(github: "XXX/danger-lcl")
dangerfile.js
# ===== Description =====
# 本文が1行以上書かれているか(10行以下の軽微な変更は考慮)
warn "作業内容について本文に1行以上の説明を記載してください。" if github.pr_body.length < 1 && git.lines_of_code > 10
...
# ===== Label =====
labels = github.pr_labels
# ラベルが付いていなかったら「wip」ラベルを付ける
add_label "wip", 'fbca04' if labels.empty?
Dangerで始めるPull Requestチェック自動化
- ライブラリの更新があった場合にテストを書くことをチェック
- ブランチの運用確認
dangerfile.js
has_lib_changes = !git.modified_files.grep(/^lib/).empty?
has_test_changes = !git.modified_files.grep(/^(features|spec)/).empty?
has_changelog_changes = git.modified_files.include?("CHANGELOG.md")
if has_lib_changes && !has_test_changes
warn("There are code changes, but no corresponding tests. "\
"Please include tests if this PR introduces any modifications in "\
"#{project_name}'s behavior.",
:sticky => false)
end
# --------------------
# base branch
# --------------------
is_to_master = github.branch_for_base == 'master'
is_to_release = !!github.branch_for_base.match(/release-[0-9]+\.[0-9]+\.[0-9]/)
is_from_release = !!github.branch_for_head.match(/release-[0-9]+\.[0-9]+\.[0-9]/)
if is_to_master && !is_from_release
warn('masterへmerge出来るのはrelease branchのみです。')
end
if is_to_release
warn('release branchに対してPRを向けないで下さい。develop branchに向けてPRを作成し、develop branchをrelease branchにmergeしてください。')
end
アプリ開発を支える10個のDangerレシピ
dangerfile.js
- githubの更新があった箇所のみ指摘する
github.dismiss_out_of_range_messages
- PR担当者を該当PRの起票者に割り当てたい
## assigneeが未割り当てかのチェック
if github.pr_json['assignee'] == nil
## github.api 経由で GitHubの操作可能
github.api.add_assignees(
github.pr_json['base']['repo']['full_name'],
github.pr_json['number'],
[github.pr_author] ## <- 起票者は github.pr_author
)
end
レシピ4:JIRAのリンクを掲載したい
git.commits.each do |commit|
# コミットメッセージからJIRAの番号を抜き出しています。"MIR-"の部分は自社でお使いのJIRA IDに置き換えてください。
match = commit.message.match /(MIR-\d+)/
if match
message(
":paperclip: <a href='https://xxx.atlassian.net/browse/#{match[1]}'>#{match[1]}</a>"
)
end
end
所感
- PRのメッセージのテンプレートを設定することに加えて、自動チェックを走らせられることでより快適にPR運用ができる。
- GitHubActions自体に言えることですが、リポジトリのプログラムとは独立して設定できるのは気楽で良いですね。
- Dangerfileの言語にはRuby,TypeScript,JavaScriptといろいろ使えるので、ネットで検索する際は混同しないように注意。
-
actions.yml
、dangerfile.js
の設定はデフォルトブランチのみ有効になります。- そのためDangerの設定でいろいろ試す際は別のリポジトリで試したり、(お行儀は良くないですが)mainブランチでrebaseしてコミット履歴をきれいにする、もしくはローカルでDangerを動かすといいかなと思っています。