Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ The required GitHub App permissions under `Repository permissions` are:
| `FILTER_AUTHORS` | False | `""` | A comma-separated list of GitHub usernames. When set, only PRs authored by these users will be analyzed for conflicts. Useful for incremental rollout to specific teams. Example: `alice,bob,charlie` |
| `FILTER_TEAMS` | False | `""` | A comma-separated list of GitHub teams (`org/team-slug`). Members are resolved at runtime and merged with `FILTER_AUTHORS`. Requires `read:org` scope. Example: `my-org/frontend,my-org/backend` |
| `ENABLE_PR_COMMENTS` | False | `false` | If set to `true`, the action will post comments on PRs about detected conflicts. Comments include conflicting files, line ranges, and links to the other PR. See [PR Comments](#pr-comments) for details. |
| `ENABLE_REPORT_ISSUES` | False | `true` | If set to `true`, the action will create/update conflict report issues in each repository. Set to `false` to disable issue creation while keeping PR comments and step summaries. |

\*One of `ORGANIZATION` or `REPOSITORY` must be set.

Expand Down
3 changes: 3 additions & 0 deletions env.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class EnvVars: # pylint: disable=too-many-instance-attributes
filter_authors: list[str]
filter_teams: list[str]
enable_pr_comments: bool
enable_report_issues: bool


def get_bool_env_var(env_var_name: str, default: bool = False) -> bool:
Expand Down Expand Up @@ -186,6 +187,7 @@ def get_env_vars(test: bool = False) -> EnvVars:
filter_teams.append(team)

enable_pr_comments = get_bool_env_var("ENABLE_PR_COMMENTS")
enable_report_issues = get_bool_env_var("ENABLE_REPORT_ISSUES", default=True)

return EnvVars(
gh_app_id=gh_app_id,
Expand All @@ -209,4 +211,5 @@ def get_env_vars(test: bool = False) -> EnvVars:
filter_authors=filter_authors,
filter_teams=filter_teams,
enable_pr_comments=enable_pr_comments,
enable_report_issues=enable_report_issues,
)
4 changes: 3 additions & 1 deletion pr_conflict_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ def main():
write_to_json(all_conflicts, output_file=json_output)

# Create/update issues in repos (all conflicts, not just new)
if not env_vars.dry_run:
if not env_vars.enable_report_issues:
print("Report issue creation disabled (ENABLE_REPORT_ISSUES=false)")
elif not env_vars.dry_run:
for repo_full_name, conflicts in all_conflicts.items():
owner, rname = repo_full_name.split("/")
repo_obj = github_connection.repository(owner, rname)
Expand Down
3 changes: 3 additions & 0 deletions test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_get_env_vars_with_org(self):
slack_channel="#alerts",
enable_github_actions_step_summary=False,
enable_pr_comments=False,
enable_report_issues=True,
filter_authors=[],
filter_teams=[],
)
Expand Down Expand Up @@ -115,6 +116,7 @@ def test_get_env_vars_with_repos(self):
filter_authors=[],
filter_teams=[],
enable_pr_comments=False,
enable_report_issues=True,
)
result = get_env_vars(True)
self.assertEqual(result, expected_result)
Expand Down Expand Up @@ -151,6 +153,7 @@ def test_get_env_vars_optional_values(self):
filter_authors=[],
filter_teams=[],
enable_pr_comments=False,
enable_report_issues=True,
)
result = get_env_vars(True)
self.assertEqual(result, expected_result)
Expand Down
81 changes: 79 additions & 2 deletions test_pr_conflict_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def _make_env_vars(**overrides):
"filter_authors": [],
"filter_teams": [],
"enable_pr_comments": False,
"enable_report_issues": True,
}
defaults.update(overrides)
return EnvVars(**defaults)
Expand Down Expand Up @@ -822,8 +823,84 @@ def test_same_author_conflicts_filtered(
self.assertEqual(written_conflicts["test-org/repo-a"][0], diff_author_conflict)


if __name__ == "__main__":
unittest.main()
@patch("pr_conflict_detector.deduplication", new=_mock_dedup_passthrough())
@patch("pr_conflict_detector.send_slack_notification")
@patch("pr_conflict_detector.create_or_update_issue")
@patch("pr_conflict_detector.write_to_json")
@patch("pr_conflict_detector.write_to_markdown")
@patch("pr_conflict_detector.detect_conflicts")
@patch("pr_conflict_detector.fetch_all_pr_data")
@patch("pr_conflict_detector.auth.auth_to_github")
@patch("pr_conflict_detector.env.get_env_vars")
class TestEnableReportIssues(unittest.TestCase):
"""Test the ENABLE_REPORT_ISSUES flag."""

def test_issues_not_created_when_disabled(
self,
mock_get_env,
mock_auth,
mock_fetch,
mock_detect,
mock_md,
mock_json,
mock_issue,
_mock_slack,
):
"""Verify issues are NOT created when ENABLE_REPORT_ISSUES is false."""
repo = _make_repo("test-org/repo-a")
env_vars = _make_env_vars(enable_report_issues=False)
mock_get_env.return_value = env_vars

gh = MagicMock()
mock_auth.return_value = gh
org_mock = MagicMock()
org_mock.repositories.return_value = [repo]
gh.organization.return_value = org_mock

pr1, pr2 = _make_pr(1), _make_pr(2)
mock_fetch.return_value = [pr1, pr2]
conflict = MagicMock()
mock_detect.return_value = [conflict]

main()

mock_md.assert_called_once()
mock_json.assert_called_once()
mock_issue.assert_not_called()

def test_issues_created_when_enabled(
self,
mock_get_env,
mock_auth,
mock_fetch,
mock_detect,
mock_md,
mock_json,
mock_issue,
_mock_slack,
):
"""Verify issues ARE created when ENABLE_REPORT_ISSUES is true (default)."""
repo = _make_repo("test-org/repo-a")
env_vars = _make_env_vars(enable_report_issues=True)
mock_get_env.return_value = env_vars

gh = MagicMock()
mock_auth.return_value = gh
org_mock = MagicMock()
org_mock.repositories.return_value = [repo]
gh.organization.return_value = org_mock

pr1, pr2 = _make_pr(1), _make_pr(2)
mock_fetch.return_value = [pr1, pr2]
conflict = MagicMock()
mock_detect.return_value = [conflict]
mock_issue.return_value = "https://github.com/test-org/repo-a/issues/99"

main()

mock_md.assert_called_once()
mock_json.assert_called_once()
mock_issue.assert_called_once()


if __name__ == "__main__":
Expand Down
Loading