@@ -173,38 +173,43 @@ def base_repo_name(pr: dict):
173
173
return pr ["base" ]["repo" ]["name" ]
174
174
175
175
176
- _BRANCH_PROTECTION_CACHE = defaultdict (dict )
176
+ def get_branch_protection (
177
+ gh : GitHubAPI , repo : str , branch_name : str , cache : dict
178
+ ) -> dict :
179
+ if branch_name not in cache [repo ]:
180
+ cache [repo ][branch_name ] = gh .get_branch_protection (repo , branch_name )
177
181
182
+ return cache [repo ][branch_name ]
178
183
179
- def get_branch_protection (gh : GitHubAPI , repo : str , branch_name : str ) -> dict :
180
- if branch_name not in _BRANCH_PROTECTION_CACHE [repo ]:
181
- _BRANCH_PROTECTION_CACHE [repo ][branch_name ] = gh .get_branch_protection (
182
- repo , branch_name
183
- )
184
-
185
- return _BRANCH_PROTECTION_CACHE [repo ][branch_name ]
186
184
187
-
188
- def get_min_required_approvals (gh : GitHubAPI , pr : dict ) -> int :
185
+ def get_min_required_approvals (
186
+ gh : GitHubAPI , pr : dict , branch_protection_cache : dict
187
+ ) -> int :
189
188
repo = base_repo_name (pr )
190
189
branch_name = pr ["base" ]["ref" ]
191
190
192
191
try :
193
- branch_protection_rules = get_branch_protection (gh , repo , branch_name )
192
+ branch_protection_rules = get_branch_protection (
193
+ gh , repo , branch_name , branch_protection_cache
194
+ )
194
195
except HTTPError as e :
195
196
# If the base branch does not have protection rules, the request
196
197
# above will 404. In that case, fall back to the rules for `main`
197
198
# as a safe default.
198
199
if e .response is not None and e .response .status_code == 404 :
199
- branch_protection_rules = get_branch_protection (gh , repo , "main" )
200
+ branch_protection_rules = get_branch_protection (
201
+ gh , repo , "main" , branch_protection_cache
202
+ )
200
203
else :
201
204
raise e
202
205
203
206
if "required_pull_request_reviews" not in branch_protection_rules :
204
207
# This can happen in the rare case where a PR is multiple branches deep,
205
208
# e.g. it depends on a branch which depends on a branch which depends on main.
206
209
# In that case, default to the rules for `main` as a safe default.
207
- branch_protection_rules = get_branch_protection (gh , repo , "main" )
210
+ branch_protection_rules = get_branch_protection (
211
+ gh , repo , "main" , branch_protection_cache
212
+ )
208
213
209
214
return branch_protection_rules ["required_pull_request_reviews" ][
210
215
"required_approving_review_count"
@@ -214,6 +219,12 @@ def get_min_required_approvals(gh: GitHubAPI, pr: dict) -> int:
214
219
@task (task_id = "pr_review_reminder_operator" )
215
220
def post_reminders (maintainers : set [str ], github_pat : str , dry_run : bool ):
216
221
gh = GitHubAPI (github_pat )
222
+ # Build a new cache for each DAG run so that changes to repository branch settings
223
+ # are reflected "by the next DAG run". Caching them at the run level also ensures
224
+ # that all evaluations for pings happen with the same settings, preventing changes
225
+ # during a run from causing PRs to receive different treatment, which could
226
+ # produce confusing results we might interpret as a bug rather than just a delay.
227
+ branch_protection_cache = defaultdict (dict )
217
228
218
229
open_prs = []
219
230
for repo in REPOSITORIES :
@@ -267,7 +278,9 @@ def post_reminders(maintainers: set[str], github_pat: str, dry_run: bool):
267
278
existing_reviews = gh .get_pull_reviews (base_repo_name (pr ), pr ["number" ])
268
279
269
280
approved_reviews = [r for r in existing_reviews if r ["state" ] == "APPROVED" ]
270
- if len (approved_reviews ) >= get_min_required_approvals (gh , pr ):
281
+ if len (approved_reviews ) >= get_min_required_approvals (
282
+ gh , pr , branch_protection_cache
283
+ ):
271
284
# if PR already has sufficient reviews to be merged, do not ping
272
285
# the requested reviewers.
273
286
continue
0 commit comments