RepoAuditor 0.2.27__tar.gz → 0.2.28__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. {repoauditor-0.2.27 → repoauditor-0.2.28}/PKG-INFO +1 -1
  2. {repoauditor-0.2.27 → repoauditor-0.2.28}/pyproject.toml +1 -1
  3. repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Impl/EnableRulesetRequirementImpl.py +83 -0
  4. repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Module.py +26 -0
  5. repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequirePullRequests.py +25 -0
  6. repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequireSignedCommits.py +25 -0
  7. repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequireStatusChecks.py +25 -0
  8. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubRulesets/RulesetQuery.py +24 -3
  9. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRuleset.py → repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesetsPlugin.py +2 -2
  10. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/__init__.py +1 -1
  11. repoauditor-0.2.28/src/RepoAuditor/py.typed +0 -0
  12. repoauditor-0.2.28/tests/Plugins/GitHubRuleset_EndToEndTest.py +73 -0
  13. repoauditor-0.2.28/tests/Plugins/GitHubRuleset_UnitTest.py +190 -0
  14. repoauditor-0.2.28/tests/Plugins/__snapshots__/GitHubRuleset_EndToEndTest.ambr +133 -0
  15. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Module.py +0 -49
  16. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequirePullRequests.py +0 -47
  17. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequireSignedCommits.py +0 -47
  18. repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements/RequireStatusChecks.py +0 -47
  19. repoauditor-0.2.27/tests/Plugins/GitHubRuleset_UnitTest.py +0 -213
  20. {repoauditor-0.2.27 → repoauditor-0.2.28}/.copier-answers.yml +0 -0
  21. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/CODEOWNERS +0 -0
  22. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  23. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  24. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/ISSUE_TEMPLATE/custom.md +0 -0
  25. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  26. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/actions/release_impl/action.yml +0 -0
  27. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/pull_request_template.md +0 -0
  28. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/release_sources.yaml +0 -0
  29. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/workflows/CICD.yml +0 -0
  30. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/workflows/CICD_impl.yml +0 -0
  31. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/workflows/EndToEnd.yml +0 -0
  32. {repoauditor-0.2.27 → repoauditor-0.2.28}/.github/workflows/codeql.yml +0 -0
  33. {repoauditor-0.2.27 → repoauditor-0.2.28}/.gitignore +0 -0
  34. {repoauditor-0.2.27 → repoauditor-0.2.28}/.pre-commit-config.yaml +0 -0
  35. {repoauditor-0.2.27 → repoauditor-0.2.28}/.python-version +0 -0
  36. {repoauditor-0.2.27 → repoauditor-0.2.28}/CODE_OF_CONDUCT.md +0 -0
  37. {repoauditor-0.2.27 → repoauditor-0.2.28}/CONTRIBUTING.md +0 -0
  38. {repoauditor-0.2.27 → repoauditor-0.2.28}/DEVELOPMENT.md +0 -0
  39. {repoauditor-0.2.27 → repoauditor-0.2.28}/GOVERNANCE.md +0 -0
  40. {repoauditor-0.2.27 → repoauditor-0.2.28}/LICENSE +0 -0
  41. {repoauditor-0.2.27 → repoauditor-0.2.28}/MAINTAINERS.md +0 -0
  42. {repoauditor-0.2.27 → repoauditor-0.2.28}/README.md +0 -0
  43. {repoauditor-0.2.27 → repoauditor-0.2.28}/SECURITY.md +0 -0
  44. {repoauditor-0.2.27 → repoauditor-0.2.28}/minisign_key.pub +0 -0
  45. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/AutoGitSemVer.yaml +0 -0
  46. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/CommandLineProcessor.py +0 -0
  47. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Display.py +0 -0
  48. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/EntryPoint.py +0 -0
  49. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/ExecuteModules.py +0 -0
  50. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Impl/ParallelSequentialProcessor.py +0 -0
  51. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Impl/__init__.py +0 -0
  52. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Module.py +0 -0
  53. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugin.py +0 -0
  54. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionQuery.py +0 -0
  55. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/AllowDeletions.py +0 -0
  56. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/AllowForcePushes.py +0 -0
  57. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/DismissStalePullRequestApprovals.py +0 -0
  58. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/DoNotAllowBypassSettings.py +0 -0
  59. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/EnsureStatusChecks.py +0 -0
  60. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/ClassicEnableRequirementImpl.py +0 -0
  61. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/ClassicValueRequirementImpl.py +0 -0
  62. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/Impl/__init__.py +0 -0
  63. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireApprovalMostRecentPush.py +0 -0
  64. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireApprovals.py +0 -0
  65. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireCodeOwnerReview.py +0 -0
  66. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireConversationResolution.py +0 -0
  67. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireLinearHistory.py +0 -0
  68. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequirePullRequests.py +0 -0
  69. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireSignedCommits.py +0 -0
  70. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireStatusChecksToPass.py +0 -0
  71. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/RequireUpToDateBranches.py +0 -0
  72. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/ClassicBranchProtectionRequirements/__init__.py +0 -0
  73. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQuery.py +0 -0
  74. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQueryRequirements/Protected.py +0 -0
  75. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/DefaultBranchQueryRequirements/__init__.py +0 -0
  76. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/Impl/Common.py +0 -0
  77. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/Impl/EnableRequirementImpl.py +0 -0
  78. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/Impl/ValueRequirementImpl.py +0 -0
  79. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/Impl/__init__.py +0 -0
  80. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/Module.py +0 -0
  81. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQuery.py +0 -0
  82. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/AutoMerge.py +0 -0
  83. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DefaultBranch.py +0 -0
  84. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DeleteHeadBranches.py +0 -0
  85. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/DependabotSecurityUpdates.py +0 -0
  86. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Description.py +0 -0
  87. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/StandardEnableRequirementImpl.py +0 -0
  88. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/StandardValueRequirementImpl.py +0 -0
  89. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Impl/__init__.py +0 -0
  90. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/License.py +0 -0
  91. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/MergeCommit.py +0 -0
  92. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/MergeCommitMessage.py +0 -0
  93. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/Private.py +0 -0
  94. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/RebaseMergeCommit.py +0 -0
  95. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SecretScanning.py +0 -0
  96. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SecretScanningPushProtection.py +0 -0
  97. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SquashCommitMerge.py +0 -0
  98. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SquashMergeCommitMessage.py +0 -0
  99. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SuggestUpdatingPullRequestBranches.py +0 -0
  100. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportDiscussions.py +0 -0
  101. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportIssues.py +0 -0
  102. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportProjects.py +0 -0
  103. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/SupportWikis.py +0 -0
  104. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/TemplateRepository.py +0 -0
  105. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/WebCommitSignoff.py +0 -0
  106. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/StandardQueryRequirements/__init__.py +0 -0
  107. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHub/__init__.py +0 -0
  108. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubBase/Module.py +0 -0
  109. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubBase/__init__.py +0 -0
  110. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/CustomizationQuery.py +0 -0
  111. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Impl/ExistsRequirementImpl.py +0 -0
  112. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Impl/__init__.py +0 -0
  113. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Module.py +0 -0
  114. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/CodeOwners.py +0 -0
  115. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/Contributing.py +0 -0
  116. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/IssueTemplates.py +0 -0
  117. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/PullRequestTemplates.py +0 -0
  118. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/SecurityPolicy.py +0 -0
  119. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/Requirements/__init__.py +0 -0
  120. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomization/__init__.py +0 -0
  121. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubCustomizationPlugin.py +0 -0
  122. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Plugins/GitHubPlugin.py +0 -0
  123. {repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets/Requirements → repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Impl}/__init__.py +0 -0
  124. {repoauditor-0.2.27/src/RepoAuditor/Plugins/GitHubRulesets → repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets/Requirements}/__init__.py +0 -0
  125. {repoauditor-0.2.27/src/RepoAuditor/Plugins → repoauditor-0.2.28/src/RepoAuditor/Plugins/GitHubRulesets}/__init__.py +0 -0
  126. /repoauditor-0.2.27/src/RepoAuditor/py.typed → /repoauditor-0.2.28/src/RepoAuditor/Plugins/__init__.py +0 -0
  127. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Query.py +0 -0
  128. {repoauditor-0.2.27 → repoauditor-0.2.28}/src/RepoAuditor/Requirement.py +0 -0
  129. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/CommandLineProcessor_UnitTest.py +0 -0
  130. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/EntryPoint_UnitTest.py +0 -0
  131. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/ExecuteModules_UnitTest.py +0 -0
  132. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Module_UnitTest.py +0 -0
  133. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugin_UnitTest.py +0 -0
  134. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/GitHubCustomization_EndToEndTest.py +0 -0
  135. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/GitHubCustomization_UnitTest.py +0 -0
  136. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/GitHubModule_UnitTest.py +0 -0
  137. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/GitHub_EndToEndTest.py +0 -0
  138. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/__snapshots__/GitHubCustomization_EndToEndTest.ambr +0 -0
  139. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/__snapshots__/GitHub_EndToEndTest.ambr +0 -0
  140. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Plugins/utilities.py +0 -0
  141. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Query_UnitTest.py +0 -0
  142. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/Requirement_UnitTest.py +0 -0
  143. {repoauditor-0.2.27 → repoauditor-0.2.28}/tests/__snapshots__/ExecuteModules_UnitTest.ambr +0 -0
  144. {repoauditor-0.2.27 → repoauditor-0.2.28}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RepoAuditor
3
- Version: 0.2.27
3
+ Version: 0.2.28
4
4
  Summary: Add your description here
5
5
  Project-URL: Homepage, https://github.com/gt-sse-center/RepoAuditor
6
6
  Project-URL: Documentation, https://github.com/gt-sse-center/RepoAuditor
@@ -39,7 +39,7 @@ repo_auditor = "RepoAuditor:EntryPoint.app"
39
39
  [project.entry-points.RepoAuditor]
40
40
  GitHubPlugin = "RepoAuditor.Plugins.GitHubPlugin"
41
41
  GitHubCustomizationPlugin = "RepoAuditor.Plugins.GitHubCustomizationPlugin"
42
- GitHubRulesetPlugin="RepoAuditor.Plugins.GitHubRuleset"
42
+ GitHubRulesetPlugin="RepoAuditor.Plugins.GitHubRulesetsPlugin"
43
43
 
44
44
  [build-system]
45
45
  requires = ["hatchling"]
@@ -0,0 +1,83 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the EnableRequirementImpl object."""
8
+
9
+ from typing import Any, Optional
10
+ from collections.abc import Callable
11
+
12
+ from dbrownell_Common.Types import override # type: ignore[import-untyped]
13
+
14
+ from RepoAuditor.Requirement import EvaluateResult, Requirement
15
+ from RepoAuditor.Plugins.GitHub.Impl.EnableRequirementImpl import EnableRequirementImpl
16
+
17
+
18
+ # ----------------------------------------------------------------------
19
+ class EnableRulesetRequirementImpl(EnableRequirementImpl):
20
+ """Object that implements ruleset settings that can be enabled/disabled."""
21
+
22
+ # ----------------------------------------------------------------------
23
+ def __init__(
24
+ self,
25
+ name: str,
26
+ default_value: bool, # noqa: FBT001
27
+ dynamic_arg_name: str,
28
+ github_ruleset_type: str,
29
+ github_ruleset_value: str,
30
+ get_configuration_value_func: Callable[[dict[str, Any]], Optional[bool]],
31
+ resolution: str,
32
+ rationale: str,
33
+ subject: Optional[str] = None,
34
+ *,
35
+ requires_explicit_include: bool = False,
36
+ unset_set_terminology: tuple[str, str] = ("unchecked", "checked"),
37
+ missing_value_is_warning: bool = True,
38
+ ) -> None:
39
+ super().__init__(
40
+ name=name,
41
+ default_value=default_value,
42
+ dynamic_arg_name=dynamic_arg_name,
43
+ github_settings_value=github_ruleset_value,
44
+ get_configuration_value_func=get_configuration_value_func,
45
+ resolution=resolution,
46
+ rationale=rationale,
47
+ subject=subject,
48
+ requires_explicit_include=requires_explicit_include,
49
+ unset_set_terminology=unset_set_terminology,
50
+ missing_value_is_warning=missing_value_is_warning,
51
+ )
52
+
53
+ self.github_ruleset_type = github_ruleset_type
54
+
55
+ # ----------------------------------------------------------------------
56
+ @override
57
+ def _EvaluateImpl(
58
+ self,
59
+ query_data: dict[str, Any],
60
+ requirement_args: dict[str, Any],
61
+ ) -> Requirement.EvaluateImplResult:
62
+ if requirement_args[self.dynamic_arg_name]:
63
+ # Get the rules for the specified branch
64
+ rules = query_data.get("rules", [])
65
+
66
+ for rule in rules:
67
+ if self.get_configuration_value_func(rule):
68
+ # Get the ruleset associated with the rule
69
+ ruleset = rule["ruleset"]
70
+ return self.EvaluateImplResult(
71
+ EvaluateResult.Success,
72
+ f"Ruleset '{ruleset['name']}' enforces {self.github_ruleset_type}",
73
+ )
74
+
75
+ return self.EvaluateImplResult(
76
+ EvaluateResult.Error,
77
+ f"No active branch ruleset requiring {self.github_ruleset_type} found",
78
+ provide_resolution=True,
79
+ provide_rationale=True,
80
+ )
81
+
82
+ # Requirement flag not set so DoesNotApply
83
+ return Requirement.EvaluateImplResult(EvaluateResult.DoesNotApply, None)
@@ -0,0 +1,26 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the GitHubRulesetModule object."""
8
+
9
+ from RepoAuditor.Module import ExecutionStyle
10
+ from RepoAuditor.Plugins.GitHubBase.Module import GitHubBaseModule
11
+ from RepoAuditor.Plugins.GitHubRulesets.RulesetQuery import RulesetQuery
12
+
13
+
14
+ class GitHubRulesetsModule(GitHubBaseModule):
15
+ """Module that validates GitHub repository rulesets."""
16
+
17
+ def __init__(self) -> None:
18
+ super().__init__(
19
+ "GitHubRulesets",
20
+ "Validates GitHub repository rulesets.",
21
+ ExecutionStyle.Parallel,
22
+ [
23
+ RulesetQuery(),
24
+ ],
25
+ requires_explicit_include=True,
26
+ )
@@ -0,0 +1,25 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RequirePullRequests object."""
8
+
9
+ from RepoAuditor.Plugins.GitHubRulesets.Impl.EnableRulesetRequirementImpl import EnableRulesetRequirementImpl
10
+
11
+
12
+ class RequirePullRequests(EnableRulesetRequirementImpl):
13
+ """Require pull requests before merging to default branch."""
14
+
15
+ def __init__(self) -> None:
16
+ super().__init__(
17
+ name="RequirePullRequests",
18
+ default_value=False,
19
+ dynamic_arg_name="true",
20
+ github_ruleset_type="Pull Requests",
21
+ github_ruleset_value="pull_request",
22
+ get_configuration_value_func=lambda rule: rule.get("type", "") == "pull_request",
23
+ resolution="Enable pull request requirements in repository rulesets",
24
+ rationale="Pull request reviews help maintain code quality and collaboration",
25
+ )
@@ -0,0 +1,25 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RequireSignedCommits object."""
8
+
9
+ from RepoAuditor.Plugins.GitHubRulesets.Impl.EnableRulesetRequirementImpl import EnableRulesetRequirementImpl
10
+
11
+
12
+ class RequireSignedCommits(EnableRulesetRequirementImpl):
13
+ """Require signed commits."""
14
+
15
+ def __init__(self) -> None:
16
+ super().__init__(
17
+ name="RequireSignedCommits",
18
+ default_value=False,
19
+ dynamic_arg_name="true",
20
+ github_ruleset_type="Signed Commits",
21
+ github_ruleset_value="required_signatures",
22
+ get_configuration_value_func=lambda rule: rule.get("type", "") == "required_signatures",
23
+ resolution="Enable commit signing requirement in repository rulesets",
24
+ rationale="Signed commits ensure commit authenticity",
25
+ )
@@ -0,0 +1,25 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Contains the RequireStatusChecks object."""
8
+
9
+ from RepoAuditor.Plugins.GitHubRulesets.Impl.EnableRulesetRequirementImpl import EnableRulesetRequirementImpl
10
+
11
+
12
+ class RequireStatusChecks(EnableRulesetRequirementImpl):
13
+ """Require status checks to pass before merging."""
14
+
15
+ def __init__(self) -> None:
16
+ super().__init__(
17
+ name="RequireStatusChecks",
18
+ default_value=False,
19
+ dynamic_arg_name="true",
20
+ github_ruleset_type="Status Checks",
21
+ github_ruleset_value="required_status_checks",
22
+ get_configuration_value_func=lambda rule: rule.get("type", "") == "required_status_checks",
23
+ resolution="Configure required status checks in repository rulesets",
24
+ rationale="Status checks ensure code quality and compatibility",
25
+ )
@@ -45,9 +45,30 @@ class RulesetQuery(Query):
45
45
  data, or None if an error occurs.
46
46
 
47
47
  """
48
- # Fetch ruleset data from the GitHub API
49
- ruleset_data = module_data["session"].get("rulesets")
48
+ branch = module_data.get("branch")
49
+ if branch is None:
50
+ # Get the default branch name
51
+ response = module_data["session"].get("")
52
+
53
+ response.raise_for_status()
54
+ response = response.json()
55
+
56
+ branch = response["default_branch"]
57
+
58
+ # Fetch ruleset data for a specific branch.
59
+ # This only returns active rules on the branch
60
+ rules_response = module_data["session"].get(f"rules/branches/{branch}")
61
+
62
+ rules_response.raise_for_status()
50
63
 
51
64
  # Add ruleset data to module_data
52
- module_data["ruleset_data"] = ruleset_data
65
+ module_data["rules"] = rules_response.json()
66
+
67
+ # Also get the associated ruleset for each rule
68
+ for rule in module_data["rules"]:
69
+ ruleset_respone = module_data["session"].get(f"rulesets/{rule['ruleset_id']}")
70
+ ruleset_respone.raise_for_status()
71
+ ruleset = ruleset_respone.json()
72
+ rule["ruleset"] = ruleset
73
+
53
74
  return module_data
@@ -11,10 +11,10 @@ import pluggy
11
11
  from RepoAuditor import APP_NAME
12
12
  from RepoAuditor.Module import Module
13
13
 
14
- from RepoAuditor.Plugins.GitHubRulesets.Module import GitHubRulesetModule
14
+ from RepoAuditor.Plugins.GitHubRulesets.Module import GitHubRulesetsModule
15
15
 
16
16
 
17
17
  @pluggy.HookimplMarker(APP_NAME)
18
18
  def GetModule() -> Module:
19
19
  """Return GitHubRulesetModule Module."""
20
- return GitHubRulesetModule()
20
+ return GitHubRulesetsModule()
@@ -3,4 +3,4 @@ APP_NAME = "RepoAuditor"
3
3
  # Note that this value will be overwritten by calls to `python ../../Build.py update_version` based
4
4
  # on changes observed in the git repository. The default value below will be used until the value
5
5
  # here is explicitly updated by the Continuous Integration system.
6
- __version__ = "0.2.27"
6
+ __version__ = "0.2.28"
File without changes
@@ -0,0 +1,73 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """End-to-end tests for the GitHubRulesets plugin."""
8
+
9
+ from pathlib import Path
10
+ import pytest
11
+
12
+ from dbrownell_Common.TestHelpers.StreamTestHelpers import (
13
+ InitializeStreamCapabilities,
14
+ )
15
+ from typer.testing import CliRunner
16
+
17
+ from RepoAuditor.EntryPoint import app
18
+
19
+ from utilities import ScrubDurationGithuburlAndSpaces, GetGithubUrl, CheckPATFileExists
20
+
21
+ # ----------------------------------------------------------------------
22
+ pytest.fixture(InitializeStreamCapabilities(), scope="session", autouse=True)
23
+
24
+
25
+ # ----------------------------------------------------------------------
26
+ class TestGitHubRuleset:
27
+ """End-to-end tests for rulesets in a GitHub repository."""
28
+
29
+ def test_RequireStatusChecks(self, pat_args, snapshot):
30
+ """Test for Status Checks not required ruleset"""
31
+ result = CliRunner().invoke(app, pat_args + ["--GitHubRulesets-RequireStatusChecks-true"])
32
+
33
+ assert result.exit_code == -1, result.output
34
+ assert ScrubDurationGithuburlAndSpaces(result.stdout) == snapshot
35
+
36
+ def test_RequirePullRequests(self, pat_args, snapshot):
37
+ """Test for Pull Requests required ruleset"""
38
+ result = CliRunner().invoke(app, pat_args + ["--GitHubRulesets-RequirePullRequests-true"])
39
+
40
+ assert result.exit_code == -1, result.output
41
+ assert ScrubDurationGithuburlAndSpaces(result.stdout) == snapshot
42
+
43
+ def test_RequireSignedCommits(self, pat_args, snapshot):
44
+ """Test for Signed Commits required ruleset"""
45
+ result = CliRunner().invoke(app, pat_args + ["--GitHubRulesets-RequireSignedCommits-true"])
46
+
47
+ assert result.exit_code == -1, result.output
48
+ assert ScrubDurationGithuburlAndSpaces(result.stdout) == snapshot
49
+
50
+
51
+ # ----------------------------------------------------------------------
52
+ # ----------------------------------------------------------------------
53
+ # ----------------------------------------------------------------------
54
+ @pytest.fixture
55
+ def args() -> list[str]:
56
+ return [
57
+ "--include",
58
+ "GitHubRulesets",
59
+ "--GitHubRulesets-url",
60
+ GetGithubUrl(),
61
+ ]
62
+
63
+
64
+ # ----------------------------------------------------------------------
65
+ @pytest.fixture
66
+ def pat_args(args) -> list[str]:
67
+ _github_pat_filename = (Path(__file__).parent / "github_pat.txt").resolve()
68
+ CheckPATFileExists(_github_pat_filename)
69
+
70
+ with _github_pat_filename.open() as f:
71
+ pat_value = f.read().strip()
72
+
73
+ return args + ["--GitHubRulesets-pat", pat_value]
@@ -0,0 +1,190 @@
1
+ # -------------------------------------------------------------------------------
2
+ # |
3
+ # | Copyright (c) 2024 Scientific Software Engineering Center at Georgia Tech
4
+ # | Distributed under the MIT License.
5
+ # |
6
+ # -------------------------------------------------------------------------------
7
+ """Unit tests for the GitHub Rulesets Plugin"""
8
+
9
+ from typing import Any
10
+
11
+ from RepoAuditor.Requirement import EvaluateResult
12
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequirePullRequests import RequirePullRequests
13
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequireStatusChecks import RequireStatusChecks
14
+ from RepoAuditor.Plugins.GitHubRulesets.Requirements.RequireSignedCommits import (
15
+ RequireSignedCommits,
16
+ )
17
+
18
+
19
+ def create_rule(name: str, rule_type: str, ruleset_name: str, parameters: dict[str, Any]):
20
+ """Helper function to create rule structure"""
21
+ return {
22
+ "name": name,
23
+ "type": rule_type,
24
+ "ruleset": {"name": ruleset_name},
25
+ "parameters": parameters,
26
+ }
27
+
28
+
29
+ # ----------------------------------------------------------------------
30
+ class TestRequirePullRequests:
31
+ """Unit tests for the RequirePullRequests requirement."""
32
+
33
+ def test_Enabled(self):
34
+ """Test if the rule is enabled on the main branch."""
35
+ requirement = RequirePullRequests()
36
+ context = {
37
+ "rules": [
38
+ create_rule(
39
+ name="PR Rules",
40
+ rule_type="pull_request",
41
+ ruleset_name="Ruleset Main",
42
+ parameters={},
43
+ )
44
+ ]
45
+ }
46
+ result = requirement.Evaluate(context, {"true": True})
47
+ assert result.result == EvaluateResult.Success
48
+ assert "enforces Pull Requests" in result.context
49
+
50
+ def test_Disabled(self):
51
+ """Test if the required rule is disabled on the main branch
52
+ by providing the wrong rule type.
53
+ """
54
+ requirement = RequirePullRequests()
55
+ context = {
56
+ "rules": [
57
+ create_rule(
58
+ name="Inactive PR Rules",
59
+ # Wrong rule type
60
+ rule_type="",
61
+ ruleset_name="Ruleset Main",
62
+ parameters={},
63
+ )
64
+ ]
65
+ }
66
+ result = requirement.Evaluate(context, {"true": True})
67
+ assert result.result == EvaluateResult.Error
68
+
69
+ def test_WrongTarget(self):
70
+ """Test if rules are applied on the wrong branch."""
71
+ requirement = RequirePullRequests()
72
+ context = {
73
+ "rules": [
74
+ # GitHub behavior is to always give enforced rules on the specified target target.
75
+ # Hence the rules here will be empty.
76
+ ]
77
+ }
78
+ result = requirement.Evaluate(context, {"true": True})
79
+ assert result.result == EvaluateResult.Error
80
+
81
+ def test_NoRulesets(self):
82
+ """Test if no rules are applied on the main branch."""
83
+ requirement = RequirePullRequests()
84
+ context = {"rules": []}
85
+ result = requirement.Evaluate(context, {"true": True})
86
+ assert result.result == EvaluateResult.Error
87
+ assert "No active branch ruleset requiring Pull Requests found" in result.context
88
+
89
+
90
+ # ----------------------------------------------------------------------
91
+ class TestRequireSignedCommits:
92
+ """Unit tests for the RequireSignedCommits requirement."""
93
+
94
+ def test_Enabled(self):
95
+ """Test if the rule is enabled on the main branch."""
96
+ requirement = RequireSignedCommits()
97
+ context = {
98
+ "rules": [
99
+ create_rule(
100
+ name="Signing Rules",
101
+ rule_type="required_signatures",
102
+ ruleset_name="Ruleset Main",
103
+ parameters={},
104
+ )
105
+ ]
106
+ }
107
+ result = requirement.Evaluate(context, {"true": True})
108
+ assert result.result == EvaluateResult.Success
109
+ assert "enforces Signed Commits" in result.context
110
+
111
+ def test_Disabled(self):
112
+ """Test if the required rule is disabled on the main branch
113
+ by providing the wrong rule type.
114
+ """
115
+ requirement = RequireSignedCommits()
116
+ context = {
117
+ "rules": [
118
+ create_rule(
119
+ name="Signing Rules",
120
+ # Wrong rule type
121
+ rule_type="pull_request",
122
+ ruleset_name="Ruleset Main",
123
+ parameters={},
124
+ )
125
+ ]
126
+ }
127
+ result = requirement.Evaluate(context, {"true": True})
128
+ assert result.result == EvaluateResult.Error
129
+
130
+ def test_PartialConfig(self):
131
+ """Test for rules that are not actively enforced."""
132
+ requirement = RequireSignedCommits()
133
+ context = {
134
+ "rules": [
135
+ # GitHub only returns rules that are actively enforced
136
+ ]
137
+ }
138
+ result = requirement.Evaluate(context, {"true": True})
139
+ assert result.result == EvaluateResult.Error
140
+
141
+ def test_NoRulesets(self):
142
+ """Test if no rules are applied on the main branch."""
143
+ requirement = RequireSignedCommits()
144
+ context = {"rules": []}
145
+ result = requirement.Evaluate(context, {"true": True})
146
+ assert result.result == EvaluateResult.Error
147
+ assert "No active branch ruleset requiring Signed Commits found" in result.context
148
+
149
+
150
+ # ----------------------------------------------------------------------
151
+ class TestRequireStatusChecks:
152
+ """Unit tests for the RequireStatusChecks requirement."""
153
+
154
+ def test_Enabled(self):
155
+ """Test if the rule is enabled on the main branch."""
156
+ requirement = RequireStatusChecks()
157
+ context = {
158
+ "rules": [
159
+ create_rule(
160
+ name="CI Checks",
161
+ rule_type="required_status_checks",
162
+ ruleset_name="Ruleset Main",
163
+ parameters={},
164
+ )
165
+ ]
166
+ }
167
+ result = requirement.Evaluate(context, {"true": True})
168
+ assert result.result == EvaluateResult.Success
169
+ assert "enforces Status Checks" in result.context
170
+
171
+ def test_EmptyChecks(self):
172
+ """Test for Status Check rules which don't have an associated CI check."""
173
+ requirement = RequireStatusChecks()
174
+ context = {
175
+ "rules": [
176
+ # GitHub won't allow active status check rules
177
+ # which don't have associated CI checks.
178
+ # Hence empty.
179
+ ]
180
+ }
181
+ result = requirement.Evaluate(context, {"true": True})
182
+ assert result.result == EvaluateResult.Error
183
+
184
+ def test_NoRulesets(self):
185
+ """Test if no rules are applied on the main branch."""
186
+ requirement = RequireStatusChecks()
187
+ context = {"rules": []}
188
+ result = requirement.Evaluate(context, {"true": True})
189
+ assert result.result == EvaluateResult.Error
190
+ assert "No active branch ruleset requiring Status Checks found" in result.context