rhiza 0.5.2__py3-none-any.whl → 0.5.4__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.
rhiza/__init__.py CHANGED
@@ -1,7 +1,65 @@
1
- """Utility tools and command-line helpers for the Rhiza project.
1
+ """Rhiza Manage reusable configuration templates for Python projects.
2
2
 
3
- This package groups small, user-facing utilities that can be invoked from
4
- the command line or other automation scripts.
3
+ Rhiza is a command‑line interface (CLI) that helps you maintain consistent
4
+ configuration across multiple Python projects using templates stored in a
5
+ central repository. It can initialize projects with standard configuration,
6
+ materialize (inject) template files into a target repository, and validate the
7
+ template configuration.
8
+
9
+ ## Key features
10
+
11
+ - Template initialization for new or existing projects.
12
+ - Template materialization with selective include/exclude support.
13
+ - Configuration validation (syntax and basic semantics).
14
+ - Multi‑host support (GitHub and GitLab).
15
+ - Non‑destructive updates by default, with an explicit `--force` flag.
16
+
17
+ ## Quick start
18
+
19
+ Initialize a project with Rhiza templates:
20
+
21
+ ```bash
22
+ cd your-project
23
+ rhiza init
24
+ ```
25
+
26
+ Validate your configuration:
27
+
28
+ ```bash
29
+ rhiza validate
30
+ ```
31
+
32
+ Customize `.github/template.yml`, then materialize templates into your project:
33
+
34
+ ```bash
35
+ rhiza materialize
36
+ ```
37
+
38
+ ## Main modules
39
+
40
+ - `rhiza.commands` — Core command implementations (init, materialize, validate).
41
+ - `rhiza.models` — Data models and schemas for template configuration.
42
+
43
+ ## Documentation
44
+
45
+ For an overview and usage guides, see the repository files:
46
+
47
+ - [README.md](https://github.com/jebel-quant/rhiza-cli/blob/main/README.md) —
48
+ Project overview and installation instructions.
49
+ - [USAGE.md](https://github.com/jebel-quant/rhiza-cli/blob/main/USAGE.md) —
50
+ Practical examples, workflows, and best practices.
51
+ - [CLI.md](https://github.com/jebel-quant/rhiza-cli/blob/main/CLI.md) —
52
+ Command reference with examples.
53
+
54
+ Latest version and updates: https://github.com/jebel-quant/rhiza-cli
5
55
  """
6
56
 
57
+ from importlib.metadata import PackageNotFoundError, version
58
+
59
+ try:
60
+ __version__ = version("rhiza")
61
+ except PackageNotFoundError:
62
+ # Package is not installed, use a fallback version
63
+ __version__ = "0.0.0+dev"
64
+
7
65
  __all__ = ["commands", "models"]
rhiza/cli.py CHANGED
@@ -8,16 +8,58 @@ from pathlib import Path
8
8
 
9
9
  import typer
10
10
 
11
+ from rhiza import __version__
11
12
  from rhiza.commands import init as init_cmd
12
13
  from rhiza.commands import materialize as materialize_cmd
13
14
  from rhiza.commands import validate as validate_cmd
14
15
 
15
16
  app = typer.Typer(
16
- help="Rhiza - Manage reusable configuration templates for Python projects",
17
+ help=(
18
+ """
19
+ Rhiza - Manage reusable configuration templates for Python projects
20
+
21
+ \x1b]8;;https://jebel-quant.github.io/rhiza-cli/\x1b\\https://jebel-quant.github.io/rhiza-cli/\x1b]8;;\x1b\\
22
+ """
23
+ ),
17
24
  add_completion=True,
18
25
  )
19
26
 
20
27
 
28
+ def version_callback(value: bool):
29
+ """Print version information and exit.
30
+
31
+ Args:
32
+ value: Whether the --version flag was provided.
33
+
34
+ Raises:
35
+ typer.Exit: Always exits after printing version.
36
+ """
37
+ if value:
38
+ typer.echo(f"rhiza version {__version__}")
39
+ raise typer.Exit()
40
+
41
+
42
+ @app.callback()
43
+ def main(
44
+ version: bool = typer.Option(
45
+ False,
46
+ "--version",
47
+ "-v",
48
+ help="Show version and exit",
49
+ callback=version_callback,
50
+ is_eager=True,
51
+ ),
52
+ ):
53
+ """Rhiza CLI main callback.
54
+
55
+ This callback is executed before any command. It handles global options
56
+ like --version.
57
+
58
+ Args:
59
+ version: Version flag (handled by callback).
60
+ """
61
+
62
+
21
63
  @app.command()
22
64
  def init(
23
65
  target: Path = typer.Argument(
@@ -28,11 +70,13 @@ def init(
28
70
  help="Target directory (defaults to current directory)",
29
71
  ),
30
72
  ):
31
- """Initialize or validate .github/template.yml.
73
+ r"""Initialize or validate .github/template.yml.
32
74
 
33
- Creates a default .github/template.yml configuration file if one doesn't
34
- exist, or validates the existing configuration.
75
+ \b
76
+ Creates a default `.github/template.yml` configuration file if one
77
+ doesn't exist, or validates the existing configuration.
35
78
 
79
+ \b
36
80
  The default template includes common Python project files:
37
81
  - .github (workflows, actions, etc.)
38
82
  - .editorconfig
@@ -41,10 +85,11 @@ def init(
41
85
  - Makefile
42
86
  - pytest.ini
43
87
 
88
+ \b
44
89
  Examples:
45
- rhiza init
46
- rhiza init /path/to/project
47
- rhiza init ..
90
+ rhiza init
91
+ rhiza init /path/to/project
92
+ rhiza init ..
48
93
  """
49
94
  init_cmd(target)
50
95
 
@@ -59,27 +104,36 @@ def materialize(
59
104
  help="Target git repository (defaults to current directory)",
60
105
  ),
61
106
  branch: str = typer.Option("main", "--branch", "-b", help="Rhiza branch to use"),
107
+ target_branch: str = typer.Option(
108
+ None,
109
+ "--target-branch",
110
+ "--checkout-branch",
111
+ help="Create and checkout a new branch in the target repository for changes",
112
+ ),
62
113
  force: bool = typer.Option(False, "--force", "-y", help="Overwrite existing files"),
63
114
  ):
64
- """Inject Rhiza configuration templates into a target repository.
115
+ r"""Inject Rhiza configuration templates into a target repository.
65
116
 
117
+ \b
66
118
  Materializes configuration files from the template repository specified
67
119
  in .github/template.yml into your project. This command:
68
120
 
69
- 1. Reads .github/template.yml configuration
70
- 2. Performs a sparse clone of the template repository
71
- 3. Copies specified files/directories to your project
72
- 4. Respects exclusion patterns defined in the configuration
73
-
74
- Files that already exist will NOT be overwritten unless --force is used.
121
+ \b
122
+ - Reads .github/template.yml configuration
123
+ - Performs a sparse clone of the template repository
124
+ - Copies specified files/directories to your project
125
+ - Respects exclusion patterns defined in the configuration
126
+ - Files that already exist will NOT be overwritten unless --force is used.
75
127
 
128
+ \b
76
129
  Examples:
77
130
  rhiza materialize
78
131
  rhiza materialize --branch develop
79
132
  rhiza materialize --force
133
+ rhiza materialize --target-branch feature/update-templates
80
134
  rhiza materialize /path/to/project -b v2.0 -y
81
135
  """
82
- materialize_cmd(target, branch, force)
136
+ materialize_cmd(target, branch, target_branch, force)
83
137
 
84
138
 
85
139
  @app.command()
@@ -92,11 +146,13 @@ def validate(
92
146
  help="Target git repository (defaults to current directory)",
93
147
  ),
94
148
  ):
95
- """Validate Rhiza template configuration.
149
+ r"""Validate Rhiza template configuration.
96
150
 
97
151
  Validates the .github/template.yml file to ensure it is syntactically
98
- correct and semantically valid. Performs comprehensive validation:
152
+ correct and semantically valid.
99
153
 
154
+ \b
155
+ Performs comprehensive validation:
100
156
  - Checks if template.yml exists
101
157
  - Validates YAML syntax
102
158
  - Verifies required fields are present (template-repository, include)
@@ -104,8 +160,10 @@ def validate(
104
160
  - Ensures repository name follows owner/repo format
105
161
  - Confirms include paths are not empty
106
162
 
163
+
107
164
  Returns exit code 0 on success, 1 on validation failure.
108
165
 
166
+ \b
109
167
  Examples:
110
168
  rhiza validate
111
169
  rhiza validate /path/to/project
@@ -1,7 +1,53 @@
1
1
  """Command implementations for the Rhiza CLI.
2
2
 
3
- This package contains the functions that back Typer commands exposed by
4
- `rhiza.cli`, such as `hello` and `inject`.
3
+ This package contains the core implementation functions that back the Typer
4
+ commands exposed by `rhiza.cli`. These commands help you manage reusable
5
+ configuration templates for Python projects.
6
+
7
+ ## Available Commands
8
+
9
+ ### init
10
+
11
+ Initialize or validate `.github/template.yml` in a target directory.
12
+
13
+ Creates a default configuration file if it doesn't exist, or validates
14
+ an existing one. The default configuration includes common Python project
15
+ files like `.github`, `.editorconfig`, `.gitignore`,
16
+ `.pre-commit-config.yaml`, `Makefile`, and `pytest.ini`.
17
+
18
+ ### materialize
19
+
20
+ Inject Rhiza configuration templates into a target repository.
21
+
22
+ Materializes template files from the configured template repository into
23
+ your target project by performing a sparse clone of the template repository,
24
+ copying specified files/directories, and respecting exclusion patterns.
25
+ Files that already exist will not be overwritten unless the `--force` flag
26
+ is used.
27
+
28
+ ### validate
29
+
30
+ Validate Rhiza template configuration.
31
+
32
+ Validates the `.github/template.yml` file to ensure it is syntactically
33
+ correct and semantically valid. Performs comprehensive validation including
34
+ YAML syntax checking, required field verification, field type validation,
35
+ and repository format verification.
36
+
37
+ ## Usage Example
38
+
39
+ These functions are typically invoked through the CLI:
40
+
41
+ ```bash
42
+ $ rhiza init # Initialize configuration
43
+
44
+ $ rhiza materialize # Apply templates to project
45
+
46
+ $ rhiza validate # Validate template configuration
47
+ ```
48
+
49
+ For more detailed usage examples and workflows, see the USAGE.md guide
50
+ or try rhiza <command> --help
5
51
  """
6
52
 
7
53
  from .init import init # noqa: F401
rhiza/commands/init.py CHANGED
@@ -61,4 +61,4 @@ Next steps:
61
61
  """)
62
62
 
63
63
  # the template file exists, so validate it
64
- validate(target)
64
+ return validate(target)
@@ -1,5 +1,14 @@
1
+ """Command for materializing Rhiza template files into a repository.
2
+
3
+ This module implements the `materialize` command. It performs a sparse
4
+ checkout of the configured template repository, copies the selected files
5
+ into the target Git repository, and records managed files in
6
+ `.rhiza.history`. Use this to take a one-shot snapshot of template files.
7
+ """
8
+
1
9
  import shutil
2
10
  import subprocess
11
+ import sys
3
12
  import tempfile
4
13
  from pathlib import Path
5
14
 
@@ -28,28 +37,78 @@ def expand_paths(base_dir: Path, paths: list[str]) -> list[Path]:
28
37
  return all_files
29
38
 
30
39
 
31
- def materialize(target: Path, branch: str, force: bool) -> None:
40
+ def materialize(target: Path, branch: str, target_branch: str | None, force: bool) -> None:
32
41
  """Materialize Rhiza templates into the target repository.
33
42
 
34
43
  This performs a sparse checkout of the template repository and copies
35
44
  the selected files into the target repository, recording all files
36
45
  under template control in `.rhiza.history`.
46
+
47
+ Parameters
48
+ ----------
49
+ target:
50
+ Path to the target repository.
51
+ branch:
52
+ The Rhiza template branch to use.
53
+ target_branch:
54
+ Optional branch name to create/checkout in target repository.
55
+ force:
56
+ Whether to overwrite existing files.
37
57
  """
38
58
  target = target.resolve()
39
59
 
40
60
  logger.info(f"Target repository: {target}")
41
61
  logger.info(f"Rhiza branch: {branch}")
42
62
 
63
+ # -----------------------
64
+ # Handle target branch creation/checkout if specified
65
+ # -----------------------
66
+ if target_branch:
67
+ logger.info(f"Creating/checking out target branch: {target_branch}")
68
+ try:
69
+ # Check if branch already exists
70
+ result = subprocess.run(
71
+ ["git", "rev-parse", "--verify", target_branch],
72
+ cwd=target,
73
+ capture_output=True,
74
+ text=True,
75
+ )
76
+
77
+ if result.returncode == 0:
78
+ # Branch exists, checkout
79
+ logger.info(f"Branch '{target_branch}' exists, checking out...")
80
+ subprocess.run(
81
+ ["git", "checkout", target_branch],
82
+ cwd=target,
83
+ check=True,
84
+ )
85
+ else:
86
+ # Branch doesn't exist, create and checkout
87
+ logger.info(f"Creating new branch '{target_branch}'...")
88
+ subprocess.run(
89
+ ["git", "checkout", "-b", target_branch],
90
+ cwd=target,
91
+ check=True,
92
+ )
93
+ except subprocess.CalledProcessError as e:
94
+ logger.error(f"Failed to create/checkout branch '{target_branch}': {e}")
95
+ sys.exit(1)
96
+
43
97
  # -----------------------
44
98
  # Ensure Rhiza is initialized
45
99
  # -----------------------
46
- init(target)
100
+ valid = init(target)
101
+
102
+ if not valid:
103
+ logger.error(f"Rhiza template is invalid. {target}")
104
+ sys.exit(1)
47
105
 
48
106
  template_file = target / ".github" / "template.yml"
49
107
  template = RhizaTemplate.from_yaml(template_file)
50
108
 
51
109
  rhiza_repo = template.template_repository
52
110
  rhiza_branch = template.template_branch or branch
111
+ rhiza_host = template.template_host or "github"
53
112
  include_paths = template.include
54
113
  excluded_paths = template.exclude
55
114
 
@@ -60,24 +119,36 @@ def materialize(target: Path, branch: str, force: bool) -> None:
60
119
  for p in include_paths:
61
120
  logger.info(f" - {p}")
62
121
 
122
+ # -----------------------
123
+ # Construct git clone URL based on host
124
+ # -----------------------
125
+ if rhiza_host == "gitlab":
126
+ git_url = f"https://gitlab.com/{rhiza_repo}.git"
127
+ elif rhiza_host == "github":
128
+ git_url = f"https://github.com/{rhiza_repo}.git"
129
+ else:
130
+ raise ValueError(f"Unsupported template-host: {rhiza_host}. Must be 'github' or 'gitlab'.")
131
+
63
132
  # -----------------------
64
133
  # Sparse clone template repo
65
134
  # -----------------------
66
135
  tmp_dir = Path(tempfile.mkdtemp())
67
136
  materialized_files: list[Path] = []
68
137
 
69
- logger.info(f"Cloning {rhiza_repo}@{rhiza_branch} into temporary directory")
138
+ logger.info(f"Cloning {rhiza_repo}@{rhiza_branch} from {rhiza_host} into temporary directory")
70
139
 
71
140
  try:
72
141
  subprocess.run(
73
142
  [
74
143
  "git",
75
144
  "clone",
76
- "--depth", "1",
145
+ "--depth",
146
+ "1",
77
147
  "--filter=blob:none",
78
148
  "--sparse",
79
- "--branch", rhiza_branch,
80
- f"https://github.com/{rhiza_repo}.git",
149
+ "--branch",
150
+ rhiza_branch,
151
+ git_url,
81
152
  str(tmp_dir),
82
153
  ],
83
154
  check=True,
@@ -101,15 +172,9 @@ def materialize(target: Path, branch: str, force: bool) -> None:
101
172
  # -----------------------
102
173
  all_files = expand_paths(tmp_dir, include_paths)
103
174
 
104
- excluded_files = {
105
- f.resolve()
106
- for f in expand_paths(tmp_dir, excluded_paths)
107
- }
175
+ excluded_files = {f.resolve() for f in expand_paths(tmp_dir, excluded_paths)}
108
176
 
109
- files_to_copy = [
110
- f for f in all_files
111
- if f.resolve() not in excluded_files
112
- ]
177
+ files_to_copy = [f for f in all_files if f.resolve() not in excluded_files]
113
178
 
114
179
  # -----------------------
115
180
  # Copy files into target repo
@@ -121,9 +186,7 @@ def materialize(target: Path, branch: str, force: bool) -> None:
121
186
  materialized_files.append(relative_path)
122
187
 
123
188
  if dst_file.exists() and not force:
124
- logger.warning(
125
- f"{relative_path} already exists — use --force to overwrite"
126
- )
189
+ logger.warning(f"{relative_path} already exists — use --force to overwrite")
127
190
  continue
128
191
 
129
192
  dst_file.parent.mkdir(parents=True, exist_ok=True)
@@ -136,10 +199,7 @@ def materialize(target: Path, branch: str, force: bool) -> None:
136
199
  # -----------------------
137
200
  # Warn about workflow files
138
201
  # -----------------------
139
- workflow_files = [
140
- p for p in materialized_files
141
- if p.parts[:2] == (".github", "workflows")
142
- ]
202
+ workflow_files = [p for p in materialized_files if p.parts[:2] == (".github", "workflows")]
143
203
 
144
204
  if workflow_files:
145
205
  logger.warning(
@@ -161,10 +221,7 @@ def materialize(target: Path, branch: str, force: bool) -> None:
161
221
  for file_path in sorted(materialized_files):
162
222
  f.write(f"{file_path}\n")
163
223
 
164
- logger.info(
165
- f"Created {history_file.relative_to(target)} "
166
- f"with {len(materialized_files)} files"
167
- )
224
+ logger.info(f"Created {history_file.relative_to(target)} with {len(materialized_files)} files")
168
225
 
169
226
  logger.success("Rhiza templates materialized successfully")
170
227
 
@@ -39,7 +39,7 @@ def validate(target: Path) -> bool:
39
39
  template_file = target / ".github" / "template.yml"
40
40
  if not template_file.exists():
41
41
  logger.error(f"Template file not found: {template_file}")
42
- logger.info("Run 'rhiza materialize' or 'rhiza inject' to create a default template.yml")
42
+ logger.info("Run 'rhiza init' to create a default template.yml")
43
43
  return False
44
44
 
45
45
  logger.success(f"Found template file: {template_file}")
@@ -115,6 +115,15 @@ def validate(target: Path) -> bool:
115
115
  else:
116
116
  logger.success(f"template-branch is valid: {branch}")
117
117
 
118
+ if "template-host" in config:
119
+ host = config["template-host"]
120
+ if not isinstance(host, str):
121
+ logger.warning(f"template-host should be a string, got {type(host).__name__}: {host}")
122
+ elif host not in ("github", "gitlab"):
123
+ logger.warning(f"template-host should be 'github' or 'gitlab', got: {host}")
124
+ else:
125
+ logger.success(f"template-host is valid: {host}")
126
+
118
127
  if "exclude" in config:
119
128
  exclude = config["exclude"]
120
129
  if not isinstance(exclude, list):
@@ -133,4 +142,5 @@ def validate(target: Path) -> bool:
133
142
  return True
134
143
  else:
135
144
  logger.error("✗ Validation failed: template.yml has errors")
145
+ # raise AssertionError("Invalid template.yml")
136
146
  return False
rhiza/models.py CHANGED
@@ -16,16 +16,19 @@ class RhizaTemplate:
16
16
  """Represents the structure of .github/template.yml.
17
17
 
18
18
  Attributes:
19
- template_repository: The GitHub repository containing templates (e.g., "jebel-quant/rhiza").
19
+ template_repository: The GitHub or GitLab repository containing templates (e.g., "jebel-quant/rhiza").
20
20
  Can be None if not specified in the template file.
21
21
  template_branch: The branch to use from the template repository.
22
22
  Can be None if not specified in the template file (defaults to "main" when creating).
23
+ template_host: The git hosting platform ("github" or "gitlab").
24
+ Defaults to "github" if not specified in the template file.
23
25
  include: List of paths to include from the template repository.
24
26
  exclude: List of paths to exclude from the template repository (default: empty list).
25
27
  """
26
28
 
27
29
  template_repository: str | None = None
28
30
  template_branch: str | None = None
31
+ template_host: str = "github"
29
32
  include: list[str] = field(default_factory=list)
30
33
  exclude: list[str] = field(default_factory=list)
31
34
 
@@ -53,6 +56,7 @@ class RhizaTemplate:
53
56
  return cls(
54
57
  template_repository=config.get("template-repository"),
55
58
  template_branch=config.get("template-branch"),
59
+ template_host=config.get("template-host", "github"),
56
60
  include=config.get("include", []),
57
61
  exclude=config.get("exclude", []),
58
62
  )
@@ -77,6 +81,10 @@ class RhizaTemplate:
77
81
  if self.template_branch:
78
82
  config["template-branch"] = self.template_branch
79
83
 
84
+ # Only include template-host if it's not the default "github"
85
+ if self.template_host and self.template_host != "github":
86
+ config["template-host"] = self.template_host
87
+
80
88
  # Include is always present as it's a required field for the config to be useful
81
89
  config["include"] = self.include
82
90
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rhiza
3
- Version: 0.5.2
3
+ Version: 0.5.4
4
4
  Summary: Reusable configuration templates for modern Python projects
5
5
  Project-URL: Homepage, https://github.com/jebel-quant/rhiza-cli
6
6
  Project-URL: Repository, https://github.com/jebel-quant/rhiza-cli
@@ -370,9 +370,12 @@ Rhiza uses a `.github/template.yml` file to define template sources and what to
370
370
  The `template.yml` file uses YAML format with the following structure:
371
371
 
372
372
  ```yaml
373
- # Required: GitHub repository containing templates (format: owner/repo)
373
+ # Required: GitHub or GitLab repository containing templates (format: owner/repo)
374
374
  template-repository: jebel-quant/rhiza
375
375
 
376
+ # Optional: Git hosting platform (default: github)
377
+ template-host: github
378
+
376
379
  # Optional: Branch to use from template repository (default: main)
377
380
  template-branch: main
378
381
 
@@ -398,8 +401,16 @@ exclude:
398
401
 
399
402
  - **Type:** String
400
403
  - **Format:** `owner/repository`
401
- - **Description:** GitHub repository containing your configuration templates
402
- - **Example:** `jebel-quant/rhiza`, `myorg/python-templates`
404
+ - **Description:** GitHub or GitLab repository containing your configuration templates
405
+ - **Example:** `jebel-quant/rhiza`, `myorg/python-templates`, `mygroup/gitlab-templates`
406
+
407
+ #### `template-host` (optional)
408
+
409
+ - **Type:** String
410
+ - **Default:** `github`
411
+ - **Options:** `github`, `gitlab`
412
+ - **Description:** Git hosting platform where the template repository is hosted
413
+ - **Example:** `github`, `gitlab`
403
414
 
404
415
  #### `template-branch` (optional)
405
416
 
@@ -443,6 +454,7 @@ exclude:
443
454
 
444
455
  ### Complete Configuration Example
445
456
 
457
+ #### GitHub Example
446
458
  ```yaml
447
459
  template-repository: jebel-quant/rhiza
448
460
  template-branch: main
@@ -461,6 +473,21 @@ exclude:
461
473
  - .github/CODEOWNERS
462
474
  ```
463
475
 
476
+ #### GitLab Example
477
+ ```yaml
478
+ template-repository: mygroup/python-templates
479
+ template-host: gitlab
480
+ template-branch: main
481
+ include:
482
+ - .gitlab-ci.yml
483
+ - .editorconfig
484
+ - .gitignore
485
+ - Makefile
486
+ - pytest.ini
487
+ exclude:
488
+ - .gitlab-ci.yml
489
+ ```
490
+
464
491
  ## Examples
465
492
 
466
493
  ### Example 1: Setting up a new Python project
@@ -532,7 +559,29 @@ Then materialize:
532
559
  rhiza materialize --force
533
560
  ```
534
561
 
535
- ### Example 4: Validating before CI/CD
562
+ ### Example 4: Using a GitLab template repository
563
+
564
+ Edit `.github/template.yml`:
565
+
566
+ ```yaml
567
+ template-repository: mygroup/python-templates
568
+ template-host: gitlab
569
+ template-branch: main
570
+ include:
571
+ - .gitlab-ci.yml
572
+ - .editorconfig
573
+ - .gitignore
574
+ - Makefile
575
+ - pytest.ini
576
+ ```
577
+
578
+ Then materialize:
579
+
580
+ ```bash
581
+ rhiza materialize --force
582
+ ```
583
+
584
+ ### Example 5: Validating before CI/CD
536
585
 
537
586
  Add to your CI pipeline:
538
587
 
@@ -736,8 +785,9 @@ Run `rhiza validate` for detailed error messages.
736
785
  Ensure:
737
786
  1. The template repository exists and is accessible
738
787
  2. The specified branch exists
739
- 3. You have network connectivity to GitHub
788
+ 3. You have network connectivity to GitHub or GitLab
740
789
  4. The repository is public (or you have appropriate credentials configured)
790
+ 5. The `template-host` field matches your repository's hosting platform (defaults to "github")
741
791
 
742
792
  ### Files not being copied
743
793
 
@@ -755,7 +805,18 @@ A: Yes, as long as you have Git credentials configured that allow access to the
755
805
 
756
806
  **Q: Does Rhiza support template repositories hosted outside GitHub?**
757
807
 
758
- A: Currently, Rhiza is designed for GitHub repositories. Support for other Git hosting services could be added in the future.
808
+ A: Yes! Rhiza supports both GitHub and GitLab repositories. Use the `template-host` field in your `.github/template.yml` to specify "github" (default) or "gitlab".
809
+
810
+ **Q: How do I use a GitLab repository as a template source?**
811
+
812
+ A: Add `template-host: gitlab` to your `.github/template.yml` file. For example:
813
+ ```yaml
814
+ template-repository: mygroup/myproject
815
+ template-host: gitlab
816
+ include:
817
+ - .gitlab-ci.yml
818
+ - Makefile
819
+ ```
759
820
 
760
821
  **Q: Can I materialize templates from multiple repositories?**
761
822
 
@@ -0,0 +1,13 @@
1
+ rhiza/__init__.py,sha256=1jfkGAONm7dH4KwYjvNEyuxrQ-1m2YncxREYCJnTrHA,1933
2
+ rhiza/__main__.py,sha256=Lx0GqVZo6ymm0f18_uYB6E7_SOWwJNYjb73Vr31oLoM,236
3
+ rhiza/cli.py,sha256=orVHOn569qHm-TffRLpSoJlF5x59dNfQsC2pX7VppYA,4721
4
+ rhiza/models.py,sha256=R2nu_bf-j-U0kPfQXg6u-MSykrdGO9ixOzZoWy8mLCc,3448
5
+ rhiza/commands/__init__.py,sha256=lIkN15MIat-wn9CB1cgUjTzTUQB95LBBAKFK1sGHdCc,1836
6
+ rhiza/commands/init.py,sha256=QsOV_VBnRfSPebydH-fMe3haadboNIAYlOpAIYHtgUs,1936
7
+ rhiza/commands/materialize.py,sha256=PcJT7Cq1eXoUZjAe_X1TXn4yUXt1Kft7rCedEe2P-44,7921
8
+ rhiza/commands/validate.py,sha256=_0t9kfylMncm9JmKULn5e7V71XcQdFjlrtuOqZeshPM,5282
9
+ rhiza-0.5.4.dist-info/METADATA,sha256=2Dh1FhzIIHbDvGu2FSPGHJCG8PQonP9rcZvO4D3MH-M,21278
10
+ rhiza-0.5.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
11
+ rhiza-0.5.4.dist-info/entry_points.txt,sha256=NAwZUpbXvfKv50a_Qq-PxMHl3lcjAyZO63IBeuUNgfY,45
12
+ rhiza-0.5.4.dist-info/licenses/LICENSE,sha256=4m5X7LhqX-6D0Ks79Ys8CLpmza8cxDG34g4S9XSNAGY,1077
13
+ rhiza-0.5.4.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- rhiza/__init__.py,sha256=1AECbLiERqRhdcFkVxHk3vEK4KPWll-D05CTAHZDI2A,224
2
- rhiza/__main__.py,sha256=Lx0GqVZo6ymm0f18_uYB6E7_SOWwJNYjb73Vr31oLoM,236
3
- rhiza/cli.py,sha256=v7VaGUEnfuGRMOGh8I7Luh-QiUHj0to7tsSXVFuUyts,3458
4
- rhiza/models.py,sha256=-n5eyPcU35IVsbvy7F-kyKR343TkOrx25kooLCF9whg,3001
5
- rhiza/commands/__init__.py,sha256=KcoFX52xQ1NFdgVeGsAkIaqmJrRso1GOq0vFL0WEB44,300
6
- rhiza/commands/init.py,sha256=K8NN9x_gMWeoD1gx9PCDkGUCN3luxZgp7tVD2jCqT94,1929
7
- rhiza/commands/materialize.py,sha256=6dE5uG41HkSERFqupS29PaHh32lveHRvbxEttaCfBpk,5525
8
- rhiza/commands/validate.py,sha256=itcLg44GiuZ7hZ67Bscj1RavdERlWgq40rJDaYOp2zM,4829
9
- rhiza-0.5.2.dist-info/METADATA,sha256=3X4vrQOv-eb1Znj_VAq8J5OmHAPI3V6vgM4dNTSasaw,19938
10
- rhiza-0.5.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
11
- rhiza-0.5.2.dist-info/entry_points.txt,sha256=NAwZUpbXvfKv50a_Qq-PxMHl3lcjAyZO63IBeuUNgfY,45
12
- rhiza-0.5.2.dist-info/licenses/LICENSE,sha256=4m5X7LhqX-6D0Ks79Ys8CLpmza8cxDG34g4S9XSNAGY,1077
13
- rhiza-0.5.2.dist-info/RECORD,,
File without changes