Skip to content

feat(config): CI が空のとき成功扱いにする設定を追加#73

Merged
HappyOnigiri merged 7 commits intomainfrom
feat/ci-empty-as-success-config
Mar 12, 2026
Merged

feat(config): CI が空のとき成功扱いにする設定を追加#73
HappyOnigiri merged 7 commits intomainfrom
feat/ci-empty-as-success-config

Conversation

@HappyOnigiri
Copy link
Owner

@HappyOnigiri HappyOnigiri commented Mar 12, 2026

概要 / Summary

CI チェックが空の PR を成功扱いにする設定を追加。最後のコミットから一定時間経過後に「CI なし」と判断し、refix:done と自動マージを許可する。

変更内容 / Changes

  • .refix.yamlci_empty_as_success(デフォルト true)と ci_empty_grace_minutes(デフォルト 5)を追加
  • ci_empty_as_success: true かつ check_runs が空のとき、head コミットの日時を取得し、経過が ci_empty_grace_minutes 分以上なら成功扱い
  • ci_empty_as_success: false のときは従来どおり空を常に unavailable 扱い
  • _are_all_ci_checks_successful に新パラメータを追加し、process_repo_process_single_pr_update_done_label_if_completed へ伝播
  • TestAreAllCiChecksSuccessful を追加(ci_empty_as_success false / 経過時間による判定のテスト)

テスト / Testing

  • make ci で全テストパス

関連 issues / Related issues

なし / none

Summary by CodeRabbit

  • 新機能

    • CI チェックが空の場合の挙動を設定可能にしました:ci_empty_as_success(デフォルト: true)と ci_empty_grace_minutes(デフォルト: 5)。一定期間をグレースとして扱い、ラベル更新やマージ判断を遅延させます。
  • バグ修正

    • CI ステータス取得時の不正な JSON を安全に扱い、想定外の構造での例外を防止します。
  • テスト

    • 空の CI とグレース期間の振る舞いを検証するテストを追加・更新しました。

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 82381d58-399e-4c29-bd65-bf8522b6f2ce

📥 Commits

Reviewing files that changed from the base of the PR and between dfca575 and 3693878.

📒 Files selected for processing (1)
  • src/auto_fixer.py

📝 Walkthrough

Walkthrough

トップレベル設定に ci_empty_as_success(bool)と ci_empty_grace_minutes(int)を追加し、空のCIチェックに対するグレース期間ロジックを導入。これに伴い関数シグネチャと戻り値、設定読み込み、テスト、CIステータスパースのガードが更新されました。

Changes

Cohort / File(s) Summary
設定ファイル
./.refix.yaml.sample
トップレベルに ci_empty_as_success(bool, default: true)と ci_empty_grace_minutes(int, default: 5)を追加。インラインコメントで挙動を説明。
コア処理(CIグレース導入)
src/auto_fixer.py
ランタイム設定へ ci_empty_as_success / ci_empty_grace_minutes を追加・検証。_are_all_ci_checks_successful がこれらを受け取り、空CIの扱い(成功/グレース/失敗)をコミット年齢で判定するよう拡張。_update_done_label_if_completed_process_single_pr のシグネチャと戻り値を更新し、ci_grace_pending フラグを伝搬。設定キー一覧(ALLOWED_CONFIG等)とデフォルトを更新。
PRステータス取得
src/pr_reviewer.py
_fetch_classic_statuses_via_rest にて JSON パース後の型チェックを追加し、非辞書の場合は空リストを返すガードを導入(.get 呼び出し回避)。
テスト
tests/test_auto_fixer.py
_are_all_ci_checks_successful の空CIとグレース判定を対象としたテストを追加。_update_done_label_if_completed の戻り値がタプル化した点に合わせてモック/期待値を更新。設定読み込みテストに新キーを追加検証。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45分

Possibly related PRs

Suggested labels

refix:done

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed タイトルは PR の主な変更内容(CI が空のときの成功設定)を明確に反映しており、簡潔で具体的です。
Description check ✅ Passed テンプレートの必須セクション(概要、変更内容、テスト、関連 issues)をすべて記載しており、実装詳細も具体的に説明されています。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ci-empty-as-success-config
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@HappyOnigiri HappyOnigiri added the refix:running Refix is currently processing review fixes. label Mar 12, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/auto_fixer.py`:
- Around line 2051-2104: The new "grace" time check (using
ci_empty_grace_minutes, head_sha, commit_dt, elapsed) can flip a PR from
False->True purely by time, but process_repo()'s skip uses only the cached
updatedAt so a PR handled once during the grace window will be cached and never
retried when the grace expires; fix by excluding the grace-only path from being
treated as a final skip: either (A) do not update/cache updatedAt when you
return False due solely to the grace check (i.e. when elapsed <
timedelta(minutes=ci_empty_grace_minutes)), or (B) change the function to return
a retry timestamp (next_retry = commit_dt +
timedelta(minutes=ci_empty_grace_minutes)) alongside the False result and have
process_repo() respect that retry time instead of treating the PR as fully
processed; locate the logic around ci_empty_as_success, head_result/head_sha,
commit_result/date_str and the elapsed calculation to implement this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fafec0e9-72c3-470a-92f9-34812fda8dbe

📥 Commits

Reviewing files that changed from the base of the PR and between ed2b1d0 and 9a5a62c.

📒 Files selected for processing (3)
  • .refix.yaml.sample
  • src/auto_fixer.py
  • tests/test_auto_fixer.py

_are_all_ci_checks_successful がグレース期間中に None を返すよう変更し、
_update_done_label_if_completed が (label_updated, ci_grace_pending) の
タプルを返すよう変更。ci_grace_pending が True の場合、呼び出し元の
_process_single_pr が cacheable=False を設定するため、次回実行時に
updatedAt が変わっていなくても PR が再チェックされる。
@HappyOnigiri
Copy link
Owner Author

HappyOnigiri commented Mar 12, 2026

🤖 Refix Status

対応済みレビュー一覧
Comment ID 処理日時
r3939343607 2026-03-13 05:06:38 JST
discussion_r2927024074 2026-03-13 05:06:38 JST
r3939481347 2026-03-13 05:37:12 JST
discussion_r2927141907 2026-03-13 05:37:13 JST
discussion_r2927141912 2026-03-13 05:37:13 JST
r3939591452 2026-03-13 05:46:09 JST
discussion_r2927239140 2026-03-13 05:46:09 JST
実行レポート

CI 修正

2026-03-12 21:00:00 UTC src/pr_reviewer.py / tests/test_auto_fixer.py 原因調査

4 テストすべて TestAreAllCiChecksSuccessful クラスで失敗。根本原因は 2 点:

  1. src/pr_reviewer.py:107 (_fetch_classic_statuses_via_rest) で json.loads の結果が dict 以外(list や str)の場合に data.get("statuses")AttributeError が発生する。
    • テストで subprocess.runstdout="[]" を返すと json.loads("[]") = [](list)となり .get() が失敗する。
  2. tests/test_auto_fixer.py のテストモックが古い関数設計(gh pr checks 1 回呼び出し)に基づいており、現行の REST API 呼び出し順序(head SHA → check-runs → classic statuses → [commit date])に対応していない。
    • test_empty_checks_ci_empty_as_success_false_returns_false: assert_called_once() だが実際は 3 回呼ばれる
    • test_empty_checks_commit_old_treats_as_success / test_empty_checks_commit_recent_returns_false: mock が 3 つだが 4 回呼ばれる
    • test_non_empty_checks_all_success_returns_true: return_value でまとめているが 3 回呼ばれる

修正方針:

  • pr_reviewer.py: isinstance(data, dict) チェックを追加して非 dict 時は [] を返す
  • test_auto_fixer.py: 4 テストのモック設定と呼び出し回数アサーションを現行のコール順序に合わせて更新

2026-03-12 21:05:00 UTC src/pr_reviewer.py / tests/test_auto_fixer.py 修正完了・push

変更内容:

  1. src/pr_reviewer.py:107 (_fetch_classic_statuses_via_rest): json.loads 結果が dict でない場合(list/str 等)に [] を返す早期リターンを追加
    if not isinstance(data, dict):
        return []
  2. tests/test_auto_fixer.py (TestAreAllCiChecksSuccessful 全 4 テスト): モック設定を現行の呼び出し順序(head SHA → check-runs → classic statuses → [commit date])に更新し、call_count アサーションも修正

結果: 182 passed で全テスト通過。push 完了 (dfca575)。

レビュー修正

2026-03-12 20:45:21 UTC src/auto_fixer.py レビューコメント確認開始

コードの現状を確認した結果:

  • r3939591452 (1): ci_empty_grace_minutes バリデーション (行484-506): コミット a735524 で既修正済み ✅
  • r3939591452 (2): head SHA 取得失敗時に None を返す (行2039-2044): コミット 7bc8a95 で既修正済み ✅
  • r3939591452 (3): commit date 取得失敗時に None を返す (行2093-2099): コミット 7bc8a95 で既修正済み ✅
  • discussion_r2927239140: テストの side_effect 修正 (test_auto_fixer.py 行2538-2601): コミット dfca575 で既修正済み ✅

未修正の箇所 (要対応):

  • 行2057: check-runs fetch 失敗時に False を返している → None に変更すべき
  • 行2065: check-runs JSON parse 失敗時に False を返している → None に変更すべき
  • 行2120: commit date parse 失敗時に False を返している → None に変更すべき

2026-03-12 20:46:00 UTC src/auto_fixer.py check-runs 失敗時の return None 修正

修正内容

r3939591452 の残課題として、以下3箇所を FalseNone に変更:

  • 行2057: check-runs API 呼び出し失敗 (returncode != 0)
  • 行2065: check-runs JSON parse 失敗 (JSONDecodeError)
  • 行2120: commit date parse 失敗 (ValueError/TypeError)

コミット: 3693878

既修正の確認

他の指摘 (head SHA 取得失敗, ci_empty_grace_minutes バリデーション, テストの side_effect 修正) は以前のコミットで対応済みだった。

@HappyOnigiri HappyOnigiri marked this pull request as draft March 12, 2026 20:09
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/auto_fixer.py`:
- Around line 2057-2109: The code currently treats transient GitHub API failures
as permanent by returning False in the head sha and commit date retrieval
blocks; update the handlers around head_result and commit_result in
auto_fixer.py (the blocks that print "CI checks unavailable for PR #{pr_number};
skip refix:done labeling.") to return None instead of False so callers treat
these as transient (retryable) and do not cache updatedAt; leave the existing
None return used for the recent-commit grace period (elapsed <
timedelta(minutes=ci_empty_grace_minutes)) unchanged.
- Around line 483-505: The ci_empty_grace_minutes parsing currently uses int()
which silently truncates floats; change the validation in the
ci_empty_grace_minutes handling block so only true integers are accepted: reject
float types and strings with decimal points, accept ints (but not bool), or
digit-only strings (e.g. using str.isdigit() or an integer regex) and then
convert to int into grace_int, preserving the negative check and the error
messages; ensure you still set config["ci_empty_grace_minutes"] = grace_int only
after this stricter validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 35b1d350-8765-4deb-ba6c-f355e18b245f

📥 Commits

Reviewing files that changed from the base of the PR and between 9a5a62c and ab8dbad.

📒 Files selected for processing (2)
  • src/auto_fixer.py
  • tests/test_auto_fixer.py

@HappyOnigiri HappyOnigiri marked this pull request as ready for review March 12, 2026 20:26
Combine PR #73's ci_empty_as_success/ci_empty_grace_minutes params and
grace-period logic with origin/main's REST API (Fine-grained PAT)
refactor. The empty-CI grace period block is now placed after REST API
check runs are fetched, reusing the already-computed head_sha.
GitHub API の一時失敗時に False を返すと updatedAt キャッシュに登録され
次の PR 更新まで refix:done 再判定が止まる問題を修正。
head_result と commit_result のハンドラーを None (再試行) に変更。
int() が小数を黙って切り捨てる問題を修正。
float 型と小数点を含む文字列を明示的に reject し、
真の整数 (bool 除外) または数字のみの文字列のみ受け付けるよう検証を厳格化。
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/auto_fixer.py (2)

2039-2044: ⚠️ Potential issue | 🟠 Major

一時的な CI 取得失敗を False に潰すと再試行不能になります

ここで False を返すと、呼び出し側で updatedAt がキャッシュされ、同一更新の PR が再判定されません。head SHA 取得失敗・check-runs 取得失敗・commit date 取得/parse 失敗は、再試行可能状態として None を返すべきです。

🛠 修正例(再試行可能エラーは `None`)
     if head_result.returncode != 0 or not (
         head_sha := (head_result.stdout or "").strip()
     ):
         print(f"CI checks unavailable for PR #{pr_number}; skip refix:done labeling.")
-        return False
+        return None
@@
     if result.returncode != 0:
         print(f"CI checks unavailable for PR #{pr_number}; skip refix:done labeling.")
-        return False
+        return None
@@
         if commit_result.returncode != 0 or not (
             date_str := (commit_result.stdout or "").strip()
         ):
             print(
                 f"CI checks unavailable for PR #{pr_number}; skip refix:done labeling."
             )
-            return False
+            return None
@@
         except (ValueError, TypeError):
             print(
                 f"CI checks unavailable for PR #{pr_number}; skip refix:done labeling."
             )
-            return False
+            return None

Also applies to: 2053-2056, 2093-2099, 2114-2118

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/auto_fixer.py` around lines 2039 - 2044, The code currently returns False
on transient CI/commit-data failures (e.g., when head_result.returncode != 0 or
head_sha is empty around the head_result/ head_sha check referencing head_result
and pr_number), which prevents retries; change these failure-return paths to
return None instead of False so the caller treats them as retryable. Apply the
same change to the other similar blocks mentioned (the check-runs retrieval
block referencing check_runs/check_results, the commit date retrieval/parse
block referencing commit_date/commit_result, and the later blocks around
2053-2056 and 2093-2099/2114-2118) so any temporary failures yield None; ensure
callers still distinguish None (retryable) from False (definitively handled).

484-506: ⚠️ Potential issue | 🟠 Major

ci_empty_grace_minutes が小数値を切り捨て受理しています

int() 変換により 0.5 -> 0, "2.9" -> 2 が通るため、grace 設定が意図より短くなります。ここは整数のみを受け付けるべきです。

🛠 修正例(整数のみ受理)
     ci_empty_grace_minutes = parsed.get("ci_empty_grace_minutes")
     if ci_empty_grace_minutes is not None:
-        if isinstance(ci_empty_grace_minutes, bool):
+        if isinstance(ci_empty_grace_minutes, bool):
             print(
                 "Error: ci_empty_grace_minutes must be a non-negative integer.",
                 file=sys.stderr,
             )
             sys.exit(1)
-        try:
-            grace_int = int(ci_empty_grace_minutes)
-        except (TypeError, ValueError):
+        if isinstance(ci_empty_grace_minutes, int):
+            grace_int = ci_empty_grace_minutes
+        elif (
+            isinstance(ci_empty_grace_minutes, str)
+            and ci_empty_grace_minutes.strip().isdigit()
+        ):
+            grace_int = int(ci_empty_grace_minutes.strip())
+        else:
             print(
                 "Error: ci_empty_grace_minutes must be a non-negative integer.",
                 file=sys.stderr,
             )
             sys.exit(1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/auto_fixer.py` around lines 484 - 506, The current parsing accepts floats
because it uses int() which truncates; change validation around
ci_empty_grace_minutes so only true integers are accepted: if
ci_empty_grace_minutes is an int (but not bool) accept it; reject booleans and
floats (e.g., isinstance(..., float)); if it's a string, only accept strings
that match an integer pattern (e.g., only digits, no decimal point or sign) and
then convert to int; otherwise print the same error and exit; finally set
config["ci_empty_grace_minutes"] = int_value. Ensure you update the checks
around the parsed variable name ci_empty_grace_minutes and the assignment to
config["ci_empty_grace_minutes"] accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_auto_fixer.py`:
- Around line 2538-2601: テストのモックは関数 _are_all_ci_checks_successful の実際の gh api
呼び出し順(head SHA → check-runs → commit date)と合っていないため壊れています。対象は
TestAreAllCiChecksSuccessful クラスの各テストで、mocking を mock_run.return_value のままにせず
subprocess.run を side_effect にして呼び出し毎の戻り値を順序通り設定し、最終的に呼び出し回数のアサーションを
assert_called_once() から mock_run.call_count == N へ修正するか、個別の side_effect
配列に合わせて期待値を検証してください。該当シンボル: _are_all_ci_checks_successful,
TestAreAllCiChecksSuccessful, subprocess.run, mock_run.side_effect を使って gh pr
checks / gh api head sha / gh api commit date の順で戻り値を返すように修正してください。

---

Duplicate comments:
In `@src/auto_fixer.py`:
- Around line 2039-2044: The code currently returns False on transient
CI/commit-data failures (e.g., when head_result.returncode != 0 or head_sha is
empty around the head_result/ head_sha check referencing head_result and
pr_number), which prevents retries; change these failure-return paths to return
None instead of False so the caller treats them as retryable. Apply the same
change to the other similar blocks mentioned (the check-runs retrieval block
referencing check_runs/check_results, the commit date retrieval/parse block
referencing commit_date/commit_result, and the later blocks around 2053-2056 and
2093-2099/2114-2118) so any temporary failures yield None; ensure callers still
distinguish None (retryable) from False (definitively handled).
- Around line 484-506: The current parsing accepts floats because it uses int()
which truncates; change validation around ci_empty_grace_minutes so only true
integers are accepted: if ci_empty_grace_minutes is an int (but not bool) accept
it; reject booleans and floats (e.g., isinstance(..., float)); if it's a string,
only accept strings that match an integer pattern (e.g., only digits, no decimal
point or sign) and then convert to int; otherwise print the same error and exit;
finally set config["ci_empty_grace_minutes"] = int_value. Ensure you update the
checks around the parsed variable name ci_empty_grace_minutes and the assignment
to config["ci_empty_grace_minutes"] accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 761c2ef6-86f6-49e3-a7b4-49b8a0415d08

📥 Commits

Reviewing files that changed from the base of the PR and between ab8dbad and e93aa1b.

📒 Files selected for processing (2)
  • src/auto_fixer.py
  • tests/test_auto_fixer.py

…クを現行 REST API 呼び出し順序に修正

- pr_reviewer.py: json.loads 結果が dict 以外の場合に AttributeError が発生していたため isinstance(data, dict) ガードを追加
- test_auto_fixer.py: TestAreAllCiChecksSuccessful の 4 テストを head SHA → check-runs → classic statuses → [commit date] の呼び出し順序に合わせてモックと call_count アサーションを更新
check-runs の API 呼び出し失敗 (returncode != 0) および JSON parse 失敗は
再試行可能な一時障害であるため、False ではなく None を返すよう修正する。
呼び出し側が updatedAt をキャッシュして同一PRの再判定が行われない問題を解消する。
@HappyOnigiri HappyOnigiri added the refix:done Refix finished review checks/fixes for now. label Mar 12, 2026
@HappyOnigiri HappyOnigiri merged commit c3056e7 into main Mar 12, 2026
2 checks passed
@HappyOnigiri HappyOnigiri deleted the feat/ci-empty-as-success-config branch March 12, 2026 20:50
@HappyOnigiri HappyOnigiri added refix:auto-merge-requested Refix has requested auto-merge for this PR. refix:merged PR has been merged after Refix auto-merge. and removed refix:running Refix is currently processing review fixes. refix:auto-merge-requested Refix has requested auto-merge for this PR. labels Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refix:done Refix finished review checks/fixes for now. refix:merged PR has been merged after Refix auto-merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant