pyrig 2.2.6__py3-none-any.whl

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 (102) hide show
  1. pyrig/__init__.py +1 -0
  2. pyrig/dev/__init__.py +6 -0
  3. pyrig/dev/builders/__init__.py +1 -0
  4. pyrig/dev/builders/base/__init__.py +5 -0
  5. pyrig/dev/builders/base/base.py +256 -0
  6. pyrig/dev/builders/pyinstaller.py +229 -0
  7. pyrig/dev/cli/__init__.py +5 -0
  8. pyrig/dev/cli/cli.py +95 -0
  9. pyrig/dev/cli/commands/__init__.py +1 -0
  10. pyrig/dev/cli/commands/build_artifacts.py +16 -0
  11. pyrig/dev/cli/commands/create_root.py +25 -0
  12. pyrig/dev/cli/commands/create_tests.py +244 -0
  13. pyrig/dev/cli/commands/init_project.py +160 -0
  14. pyrig/dev/cli/commands/make_inits.py +27 -0
  15. pyrig/dev/cli/commands/protect_repo.py +145 -0
  16. pyrig/dev/cli/shared_subcommands.py +20 -0
  17. pyrig/dev/cli/subcommands.py +73 -0
  18. pyrig/dev/configs/__init__.py +1 -0
  19. pyrig/dev/configs/base/__init__.py +5 -0
  20. pyrig/dev/configs/base/base.py +826 -0
  21. pyrig/dev/configs/containers/__init__.py +1 -0
  22. pyrig/dev/configs/containers/container_file.py +111 -0
  23. pyrig/dev/configs/dot_env.py +95 -0
  24. pyrig/dev/configs/dot_python_version.py +88 -0
  25. pyrig/dev/configs/git/__init__.py +5 -0
  26. pyrig/dev/configs/git/gitignore.py +181 -0
  27. pyrig/dev/configs/git/pre_commit.py +170 -0
  28. pyrig/dev/configs/licence.py +112 -0
  29. pyrig/dev/configs/markdown/__init__.py +1 -0
  30. pyrig/dev/configs/markdown/docs/__init__.py +1 -0
  31. pyrig/dev/configs/markdown/docs/index.py +38 -0
  32. pyrig/dev/configs/markdown/readme.py +132 -0
  33. pyrig/dev/configs/py_typed.py +28 -0
  34. pyrig/dev/configs/pyproject.py +436 -0
  35. pyrig/dev/configs/python/__init__.py +5 -0
  36. pyrig/dev/configs/python/builders_init.py +27 -0
  37. pyrig/dev/configs/python/configs_init.py +28 -0
  38. pyrig/dev/configs/python/dot_experiment.py +46 -0
  39. pyrig/dev/configs/python/main.py +59 -0
  40. pyrig/dev/configs/python/resources_init.py +27 -0
  41. pyrig/dev/configs/python/shared_subcommands.py +29 -0
  42. pyrig/dev/configs/python/src_init.py +27 -0
  43. pyrig/dev/configs/python/subcommands.py +27 -0
  44. pyrig/dev/configs/testing/__init__.py +5 -0
  45. pyrig/dev/configs/testing/conftest.py +64 -0
  46. pyrig/dev/configs/testing/fixtures_init.py +27 -0
  47. pyrig/dev/configs/testing/main_test.py +74 -0
  48. pyrig/dev/configs/testing/zero_test.py +43 -0
  49. pyrig/dev/configs/workflows/__init__.py +5 -0
  50. pyrig/dev/configs/workflows/base/__init__.py +5 -0
  51. pyrig/dev/configs/workflows/base/base.py +1662 -0
  52. pyrig/dev/configs/workflows/build.py +106 -0
  53. pyrig/dev/configs/workflows/health_check.py +133 -0
  54. pyrig/dev/configs/workflows/publish.py +68 -0
  55. pyrig/dev/configs/workflows/release.py +90 -0
  56. pyrig/dev/tests/__init__.py +5 -0
  57. pyrig/dev/tests/conftest.py +40 -0
  58. pyrig/dev/tests/fixtures/__init__.py +1 -0
  59. pyrig/dev/tests/fixtures/assertions.py +147 -0
  60. pyrig/dev/tests/fixtures/autouse/__init__.py +5 -0
  61. pyrig/dev/tests/fixtures/autouse/class_.py +42 -0
  62. pyrig/dev/tests/fixtures/autouse/module.py +40 -0
  63. pyrig/dev/tests/fixtures/autouse/session.py +589 -0
  64. pyrig/dev/tests/fixtures/factories.py +118 -0
  65. pyrig/dev/utils/__init__.py +1 -0
  66. pyrig/dev/utils/cli.py +17 -0
  67. pyrig/dev/utils/git.py +312 -0
  68. pyrig/dev/utils/packages.py +93 -0
  69. pyrig/dev/utils/resources.py +77 -0
  70. pyrig/dev/utils/testing.py +66 -0
  71. pyrig/dev/utils/versions.py +268 -0
  72. pyrig/main.py +9 -0
  73. pyrig/py.typed +0 -0
  74. pyrig/resources/GITIGNORE +216 -0
  75. pyrig/resources/LATEST_PYTHON_VERSION +1 -0
  76. pyrig/resources/MIT_LICENSE_TEMPLATE +21 -0
  77. pyrig/resources/__init__.py +1 -0
  78. pyrig/src/__init__.py +1 -0
  79. pyrig/src/git/__init__.py +6 -0
  80. pyrig/src/git/git.py +146 -0
  81. pyrig/src/graph.py +255 -0
  82. pyrig/src/iterate.py +107 -0
  83. pyrig/src/modules/__init__.py +22 -0
  84. pyrig/src/modules/class_.py +369 -0
  85. pyrig/src/modules/function.py +189 -0
  86. pyrig/src/modules/inspection.py +148 -0
  87. pyrig/src/modules/module.py +658 -0
  88. pyrig/src/modules/package.py +452 -0
  89. pyrig/src/os/__init__.py +6 -0
  90. pyrig/src/os/os.py +121 -0
  91. pyrig/src/project/__init__.py +5 -0
  92. pyrig/src/project/mgt.py +83 -0
  93. pyrig/src/resource.py +58 -0
  94. pyrig/src/string.py +100 -0
  95. pyrig/src/testing/__init__.py +6 -0
  96. pyrig/src/testing/assertions.py +66 -0
  97. pyrig/src/testing/convention.py +203 -0
  98. pyrig-2.2.6.dist-info/METADATA +174 -0
  99. pyrig-2.2.6.dist-info/RECORD +102 -0
  100. pyrig-2.2.6.dist-info/WHEEL +4 -0
  101. pyrig-2.2.6.dist-info/entry_points.txt +3 -0
  102. pyrig-2.2.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,244 @@
1
+ """Utilities for automatically creating test files for the project.
2
+
3
+ This module provides functions to generate test files for all modules and classes
4
+ in the project, ensuring that every function and method has a corresponding test.
5
+ It creates the basic test structure and generates skeleton test functions with
6
+ NotImplementedError to indicate tests that need to be written.
7
+ """
8
+
9
+ from types import ModuleType
10
+
11
+ from pyrig.dev.utils.packages import get_src_package
12
+ from pyrig.src.modules.class_ import (
13
+ get_all_cls_from_module,
14
+ get_all_methods_from_cls,
15
+ )
16
+ from pyrig.src.modules.function import get_all_functions_from_module
17
+ from pyrig.src.modules.inspection import get_qualname_of_obj
18
+ from pyrig.src.modules.module import (
19
+ create_module,
20
+ get_isolated_obj_name,
21
+ get_module_content_as_str,
22
+ to_path,
23
+ )
24
+ from pyrig.src.modules.package import (
25
+ walk_package,
26
+ )
27
+ from pyrig.src.testing.convention import (
28
+ get_test_obj_from_obj,
29
+ make_test_obj_importpath_from_obj,
30
+ make_test_obj_name,
31
+ )
32
+
33
+
34
+ def make_test_skeletons() -> None:
35
+ """Create all test files for the project.
36
+
37
+ This function orchestrates the test creation process by first setting up the base
38
+ test structure and then creating test files for all source packages.
39
+ """
40
+ create_tests_for_package(get_src_package())
41
+
42
+
43
+ def create_tests_for_package(package: ModuleType) -> None:
44
+ """Create test files for all modules in the source package.
45
+
46
+ This function walks through the source package hierarchy and creates corresponding
47
+ test packages and modules for each package and module found in the source.
48
+ """
49
+ for pkg, modules in walk_package(package):
50
+ create_test_package(pkg)
51
+ for module in modules:
52
+ create_test_module(module)
53
+
54
+
55
+ def create_test_package(package: ModuleType) -> None:
56
+ """Create a test package for a source package.
57
+
58
+ Args:
59
+ package: The source package module to create a test package for
60
+
61
+ This function creates a test package with the appropriate naming convention
62
+ if it doesn't already exist.
63
+
64
+ """
65
+ test_package_name = make_test_obj_importpath_from_obj(package)
66
+ # create package if it doesn't exist
67
+ create_module(test_package_name, is_package=True)
68
+
69
+
70
+ def create_test_module(module: ModuleType) -> None:
71
+ """Create a test module for a source module.
72
+
73
+ Args:
74
+ module: The source module to create a test module for
75
+
76
+ This function:
77
+ 1. Creates a test module with the appropriate naming convention
78
+ 2. Generates the test module content with skeleton test functions
79
+ 3. Writes the content to the test module file
80
+
81
+ """
82
+ test_module_name = make_test_obj_importpath_from_obj(module)
83
+ test_module = create_module(test_module_name, is_package=False)
84
+ test_module_path = to_path(test_module, is_package=False)
85
+ test_module_path.write_text(get_test_module_content(module))
86
+
87
+
88
+ def get_test_module_content(module: ModuleType) -> str:
89
+ """Generate the content for a test module.
90
+
91
+ Args:
92
+ module: The source module to generate test content for
93
+
94
+ Returns:
95
+ The generated test module content as a string
96
+
97
+ This function:
98
+ 1. Gets the existing test module content if it exists
99
+ 2. Adds test functions for all functions in the source module
100
+ 3. Adds test classes for all classes in the source module
101
+
102
+ """
103
+ test_module = get_test_obj_from_obj(module)
104
+ test_module_content = get_module_content_as_str(test_module)
105
+
106
+ test_module_content = get_test_functions_content(
107
+ module, test_module, test_module_content
108
+ )
109
+
110
+ return get_test_classes_content(module, test_module, test_module_content)
111
+
112
+
113
+ def get_test_functions_content(
114
+ module: ModuleType,
115
+ test_module: ModuleType,
116
+ test_module_content: str,
117
+ ) -> str:
118
+ """Generate test function content for a module.
119
+
120
+ Args:
121
+ module: The source module containing functions to test
122
+ test_module: The test module to add function tests to
123
+ test_module_content: The current content of the test module
124
+
125
+ Returns:
126
+ The updated test module content with function tests added
127
+
128
+ This function:
129
+ 1. Identifies all functions in the source module
130
+ 2. Determines which functions don't have corresponding tests
131
+ 3. Generates skeleton test functions for untested functions
132
+
133
+ """
134
+ funcs = get_all_functions_from_module(module)
135
+ test_functions = get_all_functions_from_module(test_module)
136
+ supposed_test_funcs_names = [make_test_obj_name(f) for f in funcs]
137
+
138
+ test_funcs_names = [get_qualname_of_obj(f) for f in test_functions]
139
+
140
+ untested_funcs_names = [
141
+ f for f in supposed_test_funcs_names if f not in test_funcs_names
142
+ ]
143
+
144
+ for test_func_name in untested_funcs_names:
145
+ test_module_content += f"""
146
+
147
+ def {test_func_name}() -> None:
148
+ \"\"\"Test function.\"\"\"
149
+ raise {NotImplementedError.__name__}
150
+ """
151
+
152
+ return test_module_content
153
+
154
+
155
+ def get_test_classes_content(
156
+ module: ModuleType,
157
+ test_module: ModuleType,
158
+ test_module_content: str,
159
+ ) -> str:
160
+ """Generate test class content for a module.
161
+
162
+ Args:
163
+ module: The source module containing classes to test
164
+ test_module: The test module to add class tests to
165
+ test_module_content: The current content of the test module
166
+
167
+ Returns:
168
+ The updated test module content with class tests added
169
+
170
+ This function:
171
+ 1. Identifies all classes in the source module
172
+ 2. Determines which classes and methods don't have corresponding tests
173
+ 3. Generates skeleton test classes and methods for untested classes and methods
174
+ 4. Inserts the new test classes into the existing content
175
+ if the class already exists
176
+
177
+ Raises:
178
+ ValueError: If a test class declaration appears multiple
179
+ times in the test module
180
+
181
+ """
182
+ classes = get_all_cls_from_module(module)
183
+ test_classes = get_all_cls_from_module(test_module)
184
+
185
+ class_to_methods = {
186
+ c: get_all_methods_from_cls(c, exclude_parent_methods=True) for c in classes
187
+ }
188
+ test_class_to_methods = {
189
+ tc: get_all_methods_from_cls(tc, exclude_parent_methods=True)
190
+ for tc in test_classes
191
+ }
192
+
193
+ supposed_test_class_to_methods_names = {
194
+ make_test_obj_name(c): [make_test_obj_name(m) for m in ms]
195
+ for c, ms in class_to_methods.items()
196
+ }
197
+ test_class_to_methods_names = {
198
+ get_isolated_obj_name(tc): [get_isolated_obj_name(tm) for tm in tms]
199
+ for tc, tms in test_class_to_methods.items()
200
+ }
201
+
202
+ untested_test_class_to_methods_names: dict[str, list[str]] = {}
203
+ for (
204
+ test_class_name,
205
+ supposed_test_methods_names,
206
+ ) in supposed_test_class_to_methods_names.items():
207
+ test_methods_names = test_class_to_methods_names.get(test_class_name, [])
208
+ untested_methods_names = [
209
+ tmn for tmn in supposed_test_methods_names if tmn not in test_methods_names
210
+ ]
211
+ if (
212
+ not supposed_test_methods_names
213
+ and test_class_name not in test_class_to_methods_names
214
+ ):
215
+ untested_test_class_to_methods_names[test_class_name] = []
216
+ if untested_methods_names:
217
+ untested_test_class_to_methods_names[test_class_name] = (
218
+ untested_methods_names
219
+ )
220
+
221
+ for (
222
+ test_class_name,
223
+ untested_methods_names,
224
+ ) in untested_test_class_to_methods_names.items():
225
+ test_class_declaration = f"""
226
+ class {test_class_name}:
227
+ \"\"\"Test class.\"\"\"
228
+ """
229
+ test_class_content = test_class_declaration
230
+ for untested_method_name in untested_methods_names:
231
+ test_class_content += f"""
232
+ def {untested_method_name}(self) -> None:
233
+ \"\"\"Test method.\"\"\"
234
+ raise {NotImplementedError.__name__}
235
+ """
236
+ parts = test_module_content.split(test_class_declaration)
237
+ expected_parts = 2
238
+ if len(parts) > expected_parts:
239
+ msg = f"Found {len(parts)} parts, expected 2"
240
+ raise ValueError(msg)
241
+ parts.insert(1, test_class_content)
242
+ test_module_content = "".join(parts)
243
+
244
+ return test_module_content
@@ -0,0 +1,160 @@
1
+ """Project initialization orchestration.
2
+
3
+ This module provides the main initialization flow for pyrig projects.
4
+ The `init()` function runs a series of setup steps to fully configure
5
+ a new project, including:
6
+
7
+ 1. Writing priority config files (pyproject.toml with dev dependencies)
8
+ 2. Installing dependencies with uv
9
+ 3. Creating project structure (source and test directories)
10
+ 4. Running pre-commit hooks for initial formatting
11
+ 5. Running tests to verify setup
12
+ 6. Re-installing to activate CLI entry points
13
+
14
+ The initialization process is idempotent and can be re-run safely.
15
+
16
+ Example:
17
+ Run from command line:
18
+ $ uv run pyrig init
19
+
20
+ Or programmatically:
21
+ >>> from pyrig.src.project.init import init
22
+ >>> init()
23
+ """
24
+
25
+ import logging
26
+ from collections.abc import Callable
27
+ from typing import Any
28
+
29
+ import pyrig
30
+ from pyrig.src.os.os import run_subprocess
31
+ from pyrig.src.project.mgt import PROJECT_MGT, get_pyrig_cli_cmd_args
32
+ from pyrig.src.string import make_name_from_obj
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ STANDARD_DEV_DEPS: list[str] = ["pyrig-dev"]
38
+
39
+
40
+ def adding_dev_dependencies() -> None:
41
+ """Install development dependencies.
42
+
43
+ This installs the dev dependencies listed in pyproject.toml.
44
+ """
45
+ run_subprocess([PROJECT_MGT, "add", "--group", "dev", *STANDARD_DEV_DEPS])
46
+
47
+
48
+ def creating_priority_config_files() -> None:
49
+ """Create priority config files.
50
+
51
+ This creates the priority config files that are required for
52
+ the other setup steps.
53
+ """
54
+ from pyrig.dev.configs.base.base import ConfigFile # noqa: PLC0415
55
+
56
+ ConfigFile.init_priority_config_files()
57
+
58
+
59
+ def syncing_venv() -> None:
60
+ """Sync the virtual environment.
61
+
62
+ This installs the dependencies listed in pyproject.toml.
63
+ """
64
+ run_subprocess([PROJECT_MGT, "sync"])
65
+
66
+
67
+ def creating_project_root() -> None:
68
+ """Execute the create-root CLI command via subprocess.
69
+
70
+ Invokes `uv run pyrig create-root` to generate all config files
71
+ and the project directory structure.
72
+ """
73
+ from pyrig.dev.cli.subcommands import mkroot # noqa: PLC0415
74
+
75
+ run_subprocess(get_pyrig_cli_cmd_args(mkroot))
76
+
77
+
78
+ def creating_test_files() -> None:
79
+ """Execute the create-tests CLI command via subprocess.
80
+
81
+ Invokes `uv run pyrig create-tests` to generate test skeleton
82
+ files that mirror the source code structure.
83
+ """
84
+ from pyrig.dev.cli.subcommands import mktests # noqa: PLC0415
85
+
86
+ run_subprocess(get_pyrig_cli_cmd_args(mktests))
87
+
88
+
89
+ def running_pre_commit_hooks() -> None:
90
+ """Run all pre-commit hooks.
91
+
92
+ This runs all pre-commit hooks to ensure the codebase is
93
+ in a clean, linted, and formatted state.
94
+ """
95
+ from pyrig.dev.configs.git.pre_commit import ( # noqa: PLC0415
96
+ PreCommitConfigConfigFile,
97
+ )
98
+
99
+ PreCommitConfigConfigFile.run_hooks(add_before_commit=True)
100
+
101
+
102
+ def running_tests() -> None:
103
+ """Run the test suite.
104
+
105
+ This executes the test suite to verify that everything is
106
+ working correctly after initialization.
107
+ """
108
+ from pyrig.dev.configs.testing.conftest import ConftestConfigFile # noqa: PLC0415
109
+
110
+ ConftestConfigFile.run_tests()
111
+
112
+
113
+ def committing_initial_changes() -> None:
114
+ """Commit all initial changes.
115
+
116
+ This commits all changes made during initialization in a single commit.
117
+ """
118
+ # changes were added by the run pre-commit hooks step
119
+ run_subprocess(
120
+ ["git", "commit", "--no-verify", "-m", f"{pyrig.__name__}: Initial commit"]
121
+ )
122
+
123
+
124
+ SETUP_STEPS: list[Callable[..., Any]] = [
125
+ adding_dev_dependencies,
126
+ syncing_venv,
127
+ creating_priority_config_files,
128
+ syncing_venv,
129
+ creating_project_root,
130
+ creating_test_files,
131
+ running_pre_commit_hooks,
132
+ running_tests,
133
+ committing_initial_changes,
134
+ ]
135
+
136
+
137
+ def init_project() -> None:
138
+ """Initialize a pyrig project by running all setup steps.
139
+
140
+ Executes each step in `SETUP_STEPS` sequentially, logging progress.
141
+ This is the main entry point for the `pyrig init` command.
142
+
143
+ The steps include:
144
+ 1. Write priority config files (pyproject.toml)
145
+ 2. Install dependencies
146
+ 3. Update dependencies to latest
147
+ 4. Create project structure
148
+ 5. Generate test skeletons
149
+ 6. Run pre-commit hooks
150
+ 7. Run tests
151
+ 8. Re-install to activate CLI
152
+ """
153
+ # for init set log level to info
154
+ logging.basicConfig(level=logging.INFO)
155
+
156
+ for step in SETUP_STEPS:
157
+ step_name = make_name_from_obj(step, join_on=" ")
158
+ logger.info(step_name)
159
+ step()
160
+ logger.info("Setup complete!")
@@ -0,0 +1,27 @@
1
+ """A func that creates __init__.py files for all packages and modules."""
2
+
3
+ from pyrig.dev.utils.packages import find_packages
4
+ from pyrig.src.modules.module import make_init_module, to_path
5
+ from pyrig.src.modules.package import DOCS_DIR_NAME
6
+
7
+
8
+ def get_namespace_packages() -> list[str]:
9
+ """Get all namespace packages."""
10
+ packages = find_packages(depth=None)
11
+ namespace_packages = find_packages(depth=None, include_namespace_packages=True)
12
+ namespace_packages = [
13
+ p for p in namespace_packages if not p.startswith(DOCS_DIR_NAME)
14
+ ]
15
+ return list(set(namespace_packages) - set(packages))
16
+
17
+
18
+ def make_init_files() -> None:
19
+ """Create __init__.py files for all packages and modules.
20
+
21
+ Will not overwrite existing files.
22
+ """
23
+ any_namespace_packages = get_namespace_packages()
24
+ if any_namespace_packages:
25
+ # make init files for all namespace packages
26
+ for package in any_namespace_packages:
27
+ make_init_module(to_path(package, is_package=True))
@@ -0,0 +1,145 @@
1
+ """Repository protection and security configuration.
2
+
3
+ This module provides functions to configure secure repository settings and
4
+ branch protection rulesets on GitHub. It implements pyrig's opinionated
5
+ security defaults, including required reviews, status checks, and merge
6
+ restrictions.
7
+
8
+ The protection rules enforce:
9
+ - Required pull request reviews with code owner approval
10
+ - Required status checks (health check workflow must pass)
11
+ - Linear commit history (no merge commits)
12
+ - Signed commits
13
+ - No force pushes or deletions
14
+
15
+ Example:
16
+ >>> from pyrig.src.git.github.repo.protect import protect_repository
17
+ >>> protect_repository() # Applies all protection rules
18
+ """
19
+
20
+ from typing import Any
21
+
22
+ from pyrig.dev.configs.pyproject import PyprojectConfigFile
23
+ from pyrig.dev.utils.git import (
24
+ DEFAULT_BRANCH,
25
+ DEFAULT_RULESET_NAME,
26
+ create_or_update_ruleset,
27
+ get_github_repo_token,
28
+ get_repo,
29
+ get_rules_payload,
30
+ )
31
+ from pyrig.src.git.git import (
32
+ get_repo_owner_and_name_from_git,
33
+ )
34
+
35
+
36
+ def protect_repository() -> None:
37
+ """Apply all security protections to the repository.
38
+
39
+ Configures both repository-level settings and branch protection
40
+ rulesets. This is the main entry point for securing a repository.
41
+ """
42
+ set_secure_repo_settings()
43
+ create_or_update_default_branch_ruleset()
44
+
45
+
46
+ def set_secure_repo_settings() -> None:
47
+ """Configure repository-level settings for security and consistency.
48
+
49
+ Sets the following repository settings:
50
+ - Description from pyproject.toml
51
+ - Default branch to 'main'
52
+ - Delete branches on merge
53
+ - Allow update branch button
54
+ - Disable merge commits (squash and rebase only)
55
+ """
56
+ owner, repo_name = get_repo_owner_and_name_from_git()
57
+ token = get_github_repo_token()
58
+ repo = get_repo(token, owner, repo_name)
59
+
60
+ toml_description = PyprojectConfigFile.get_project_description()
61
+
62
+ repo.edit(
63
+ name=repo_name,
64
+ description=toml_description,
65
+ default_branch=DEFAULT_BRANCH,
66
+ delete_branch_on_merge=True,
67
+ allow_update_branch=True,
68
+ allow_merge_commit=False,
69
+ allow_rebase_merge=True,
70
+ allow_squash_merge=True,
71
+ )
72
+
73
+
74
+ def create_or_update_default_branch_ruleset() -> None:
75
+ """Create or update the default branch protection ruleset.
76
+
77
+ Applies pyrig's standard protection rules to the default branch (main).
78
+ If a ruleset with the same name already exists, it is updated.
79
+ """
80
+ create_or_update_ruleset(
81
+ **get_default_ruleset_params(),
82
+ )
83
+
84
+
85
+ def get_default_ruleset_params() -> dict[str, Any]:
86
+ """Build the parameter dictionary for the default branch ruleset.
87
+
88
+ Constructs the complete ruleset configuration including:
89
+ - Branch targeting (default branch only)
90
+ - Bypass permissions for repository admins
91
+ - All protection rules (reviews, status checks, etc.)
92
+
93
+ Returns:
94
+ A dictionary of parameters suitable for `create_or_update_ruleset()`.
95
+ """
96
+ from pyrig.dev.configs.workflows.health_check import ( # noqa: PLC0415
97
+ HealthCheckWorkflow, # avoid circular import
98
+ )
99
+
100
+ owner, repo_name = get_repo_owner_and_name_from_git()
101
+ token = get_github_repo_token()
102
+
103
+ rules = get_rules_payload(
104
+ deletion={},
105
+ non_fast_forward={},
106
+ creation={},
107
+ update={},
108
+ pull_request={
109
+ "required_approving_review_count": 1,
110
+ "dismiss_stale_reviews_on_push": True,
111
+ "require_code_owner_review": True,
112
+ "require_last_push_approval": True,
113
+ "required_review_thread_resolution": True,
114
+ "allowed_merge_methods": ["squash", "rebase"],
115
+ },
116
+ required_linear_history={},
117
+ required_signatures={},
118
+ required_status_checks={
119
+ "strict_required_status_checks_policy": True,
120
+ "do_not_enforce_on_create": False,
121
+ "required_status_checks": [
122
+ {
123
+ "context": HealthCheckWorkflow.get_filename(),
124
+ }
125
+ ],
126
+ },
127
+ )
128
+
129
+ return {
130
+ "owner": owner,
131
+ "token": token,
132
+ "repo_name": repo_name,
133
+ "ruleset_name": DEFAULT_RULESET_NAME,
134
+ "enforcement": "active",
135
+ "bypass_actors": [
136
+ {
137
+ "actor_id": 5,
138
+ "actor_type": "RepositoryRole",
139
+ "bypass_mode": "always",
140
+ }
141
+ ],
142
+ "target": "branch",
143
+ "conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH"], "exclude": []}},
144
+ "rules": rules,
145
+ }
@@ -0,0 +1,20 @@
1
+ """Shared commands for the CLI.
2
+
3
+ This module provides shared CLI commands that can be used by multiple
4
+ packages in a multi-package architecture. These commands are automatically
5
+ discovered and added to the CLI by pyrig.
6
+ Example is version command that is available in all packages.
7
+ uv run my-awesome-project version will return my-awesome-project version 0.1.0
8
+ """
9
+
10
+ from importlib.metadata import version as get_version
11
+
12
+ import typer
13
+
14
+ from pyrig.dev.utils.cli import get_project_name_from_argv
15
+
16
+
17
+ def version() -> None:
18
+ """Display the version information."""
19
+ project_name = get_project_name_from_argv()
20
+ typer.echo(f"{project_name} version {get_version(project_name)}")
@@ -0,0 +1,73 @@
1
+ """Subcommands for the CLI.
2
+
3
+ They will be automatically imported and added to the CLI
4
+ IMPORTANT: All funcs in this file will be added as subcommands.
5
+ So best to define the logic elsewhere and just call it here in a wrapper.
6
+ """
7
+
8
+
9
+ def mkroot() -> None:
10
+ """Creates the root of the project.
11
+
12
+ This inits all ConfigFiles and creates __init__.py files for the src
13
+ and tests package where they are missing. It does not overwrite any
14
+ existing files.
15
+ """
16
+ from pyrig.dev.cli.commands.create_root import make_project_root # noqa: PLC0415
17
+
18
+ make_project_root()
19
+
20
+
21
+ def mktests() -> None:
22
+ """Create all test files for the project.
23
+
24
+ This generates test skeletons for all functions and classes in the src
25
+ package. It does not overwrite any existing tests.
26
+ Tests are also automatically generated when missing by running pytest.
27
+ """
28
+ from pyrig.dev.cli.commands.create_tests import make_test_skeletons # noqa: PLC0415
29
+
30
+ make_test_skeletons()
31
+
32
+
33
+ def mkinits() -> None:
34
+ """Create all __init__.py files for the project.
35
+
36
+ This creates __init__.py files for all packages and modules
37
+ that are missing them. It does not overwrite any existing files.
38
+ """
39
+ from pyrig.dev.cli.commands.make_inits import make_init_files # noqa: PLC0415
40
+
41
+ make_init_files()
42
+
43
+
44
+ def init() -> None:
45
+ """Set up the project.
46
+
47
+ This is the setup command when you created the project from scratch.
48
+ It will init all config files, create the root, create tests, and run
49
+ all pre-commit hooks and tests.
50
+ """
51
+ from pyrig.dev.cli.commands.init_project import init_project # noqa: PLC0415
52
+
53
+ init_project()
54
+
55
+
56
+ def build() -> None:
57
+ """Build all artifacts.
58
+
59
+ Invokes every subclass of Builder in the builder package.
60
+ """
61
+ from pyrig.dev.cli.commands.build_artifacts import build_artifacts # noqa: PLC0415
62
+
63
+ build_artifacts()
64
+
65
+
66
+ def protect_repo() -> None:
67
+ """Protect the repository.
68
+
69
+ This will set secure repo settings and add a branch protection rulesets.
70
+ """
71
+ from pyrig.dev.cli.commands.protect_repo import protect_repository # noqa: PLC0415
72
+
73
+ protect_repository()
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1,5 @@
1
+ """Base classes for configuration file management.
2
+
3
+ This package provides the abstract ConfigFile base class and format-specific
4
+ subclasses (YAML, TOML, Python, Text) for managing project configuration.
5
+ """