Skip to content

Commit

Permalink
feat(config): Add -ch / --config-file option to specify custom co…
Browse files Browse the repository at this point in the history
…nfig location
  • Loading branch information
sandzhaj committed Nov 25, 2023
1 parent d4b5d5c commit 04285c0
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 112 deletions.
10 changes: 9 additions & 1 deletion commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ def __call__(
"name": ["-n", "--name"],
"help": "use the given commitizen (default: cz_conventional_commits)",
},
{
"name": ["-cf", "--config-file"],
"help": "configuration file path",
},
{
"name": ["-nr", "--no-raise"],
"type": str,
Expand Down Expand Up @@ -505,7 +509,6 @@ def parse_no_raise(comma_separated_no_raise: str) -> list[int]:


def main():
conf = config.read_cfg()
parser = cli(data)

argcomplete.autocomplete(parser)
Expand Down Expand Up @@ -547,6 +550,11 @@ def main():
extra_args = " ".join(unknown_args[1:])
arguments["extra_cli_args"] = extra_args

if args.config_file:
conf = config.read_cfg(cfg_path=Path(args.config_file))
else:
conf = config.read_cfg()

if args.name:
conf.update({"name": args.name})
elif not args.name and not conf.path:
Expand Down
111 changes: 94 additions & 17 deletions commitizen/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,73 @@
from pathlib import Path

from commitizen import defaults, git
from commitizen.exceptions import InvalidConfigurationError

from .base_config import BaseConfig
from .json_config import JsonConfig
from .toml_config import TomlConfig
from .yaml_config import YAMLConfig


def read_cfg() -> BaseConfig:
def read_cfg(
cfg_path: Path | None = None,
) -> BaseConfig | TomlConfig | JsonConfig | YAMLConfig:
"""
Read and load a configuration based on the provided path or defaults.
Args:
cfg_path (Path | None): The path to the configuration file passed from CLI args,
or None if no specific path is provided. Defaults to None.
Returns:
BaseConfig: An instance of `BaseConfig` (included TomlConfig | JsonConfig | YAMLConfig)
containing the loaded configuration.
Raises:
InvalidConfigurationError: If the specified configuration file path does not exist.
InvalidConfigurationError: If the loaded configuration is empty, indicating that
the file does not contain any valid configuration data.
Note:
If `cfg_path` is provided, the function attempts to load the configuration from
that path. If the path does not exist or the configuration is empty, an exception
is raised. If `cfg_path` is not provided, the function searches for a configuration
in default locations using `_find_config_from_defaults()`.
"""
conf = BaseConfig()

if cfg_path:
if not cfg_path.exists():
raise InvalidConfigurationError(f"File {cfg_path} not exists.")
_conf = _load_config_from_file(cfg_path)
if _conf.is_empty_config:
raise InvalidConfigurationError(
f"File {cfg_path} doesn't contain any configuration. "
f"Fill it or don't use --config-file option."
)
else:
_conf = _find_config_from_defaults()

if _conf:
conf = _conf

return conf


def _find_config_from_defaults():
"""
Find and load a configuration from default search paths.
This function looks for configuration files in default locations and loads the first
non-empty configuration it encounters. If no suitable configuration is found, it returns None.
Returns:
TomlConfig | JsonConfig | YAMLConfig | None
"""
git_project_root = git.find_git_project_root()
cfg_search_paths = [Path(".")]
if git_project_root:
cfg_search_paths.append(git_project_root)

cfg_paths = (
path / Path(filename)
for path in cfg_search_paths
Expand All @@ -26,23 +78,48 @@ def read_cfg() -> BaseConfig:
for filename in cfg_paths:
if not filename.exists():
continue
_conf = _load_config_from_file(path=filename)
if not _conf.is_empty_config:
return _conf
return None

_conf: TomlConfig | JsonConfig | YAMLConfig

with open(filename, "rb") as f:
data: bytes = f.read()
def _load_config_from_file(path: Path) -> TomlConfig | JsonConfig | YAMLConfig:
"""
Load configuration data from a file based on its extension.
if "toml" in filename.suffix:
_conf = TomlConfig(data=data, path=filename)
elif "json" in filename.suffix:
_conf = JsonConfig(data=data, path=filename)
elif "yaml" in filename.suffix:
_conf = YAMLConfig(data=data, path=filename)
Args:
path (Path): The path to the configuration file.
if _conf.is_empty_config:
continue
else:
conf = _conf
break
Returns:
TomlConfig | JsonConfig | YAMLConfig: An instance of a configuration class
corresponding to the file's extension (TomlConfig for .toml, JsonConfig for .json,
or YAMLConfig for .yaml).
return conf
Raises:
ValueError: If the file extension is not one of the expected formats (toml, json, yaml).
Note:
We expect that any object in defaults.py -> config_files
definitely falls under the conditions above. Therefore,
this error may occur when using an arbitrary configuration file path.
"""
_conf: TomlConfig | JsonConfig | YAMLConfig

with open(path, "rb") as f:
data: bytes = f.read()

if "toml" in path.suffix:
_conf = TomlConfig(data=data, path=path)
elif "json" in path.suffix:
_conf = JsonConfig(data=data, path=path)
elif "yaml" in path.suffix:
_conf = YAMLConfig(data=data, path=path)
else:
# We expect that any object in defaults.py -> config_files
# definitely falls under the conditions above. Therefore,
# this error may occur when using an arbitrary configuration file path.
raise InvalidConfigurationError(
"Config file should have a valid extension: toml, yaml or json"
)
return _conf
4 changes: 3 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Read more in the section [Getting Started](./getting_started.md).

```sh
$ czp --help
usage: czp [-h] [--debug] [-n NAME] [-nr NO_RAISE] {init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version} ...
usage: czp [-h] [--debug] [-n NAME] [-cf CONFIG_FILE] [-nr NO_RAISE] {init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version} ...

Commitizen is a cli tool to generate conventional commits.
For more information about the topic go to https://conventionalcommits.org/
Expand All @@ -109,6 +109,8 @@ optional arguments:
-h, --help show this help message and exit
--debug use debug mode
-n NAME, --name NAME use the given commitizen (default: cz_conventional_commits)
-cf CONFIG_FILE, --config-file CONFIG_FILE
configuration file path
-nr NO_RAISE, --no-raise NO_RAISE
comma separated error codes that won't rise error, e.g: czp -nr 1,2,3 bump. See codes at https://commitizen-
tools.github.io/commitizen/exit_codes/
Expand Down
193 changes: 100 additions & 93 deletions docs/config.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,105 @@
# Configuration

## Configuration file

### pyproject.toml or .cz.toml

Default and recommended configuration format for a project.
For a **python** project, we recommend adding an entry to your `pyproject.toml`.
You can also create a `.cz.toml` file at the root of your project folder.

Example configuration:

```toml
[tool.commitizen]
name = "cz_conventional_commits"
version = "0.1.0"
version_files = [
"src/__version__.py",
"pyproject.toml:version"
]
update_changelog_on_bump = true
style = [
["qmark", "fg:#ff9d00 bold"],
["question", "bold"],
["answer", "fg:#ff9d00 bold"],
["pointer", "fg:#ff9d00 bold"],
["highlighted", "fg:#ff9d00 bold"],
["selected", "fg:#cc5454"],
["separator", "fg:#cc5454"],
["instruction", ""],
["text", ""],
["disabled", "fg:#858585 italic"]
]
```

### .cz.json or cz.json

Commitizen has support for JSON configuration. Recommended for `NodeJS` projects.

```json
{
"commitizen": {
"name": "cz_conventional_commits",
"version": "0.1.0",
"version_files": ["src/__version__.py", "pyproject.toml:version"],
"style": [
["qmark", "fg:#ff9d00 bold"],
["question", "bold"],
["answer", "fg:#ff9d00 bold"],
["pointer", "fg:#ff9d00 bold"],
["highlighted", "fg:#ff9d00 bold"],
["selected", "fg:#cc5454"],
["separator", "fg:#cc5454"],
["instruction", ""],
["text", ""],
["disabled", "fg:#858585 italic"]
]
}
}
```

### .cz.yaml or cz.yaml

YAML configuration is supported by Commitizen. Recommended for `Go`, `ansible`, or even `helm` charts projects.

```yaml
commitizen:
name: cz_conventional_commits
version: 0.1.0
version_files:
- src/__version__.py
- pyproject.toml:version
style:
- - qmark
- fg:#ff9d00 bold
- - question
- bold
- - answer
- fg:#ff9d00 bold
- - pointer
- fg:#ff9d00 bold
- - highlighted
- fg:#ff9d00 bold
- - selected
- fg:#cc5454
- - separator
- fg:#cc5454
- - instruction
- ""
- - text
- ""
- - disabled
- fg:#858585 italic
```
### Custom file path
It is possible to specify custom path to the config file by using `-cf`/`--config-file` argument.
```cz -cf mics/cz.yaml```

Note: file should have a valid extension (toml/json/yaml).

## Settings

### `name`
Expand Down Expand Up @@ -216,99 +316,6 @@ Default: `{}`

Provide extra variables to the changelog template. [Read more][template-customization]

## Configuration file

### pyproject.toml or .cz.toml

Default and recommended configuration format for a project.
For a **python** project, we recommend adding an entry to your `pyproject.toml`.
You can also create a `.cz.toml` file at the root of your project folder.

Example configuration:

```toml
[tool.commitizen]
name = "cz_conventional_commits"
version = "0.1.0"
version_files = [
"src/__version__.py",
"pyproject.toml:version"
]
update_changelog_on_bump = true
style = [
["qmark", "fg:#ff9d00 bold"],
["question", "bold"],
["answer", "fg:#ff9d00 bold"],
["pointer", "fg:#ff9d00 bold"],
["highlighted", "fg:#ff9d00 bold"],
["selected", "fg:#cc5454"],
["separator", "fg:#cc5454"],
["instruction", ""],
["text", ""],
["disabled", "fg:#858585 italic"]
]
```

### .cz.json or cz.json

Commitizen has support for JSON configuration. Recommended for `NodeJS` projects.

```json
{
"commitizen": {
"name": "cz_conventional_commits",
"version": "0.1.0",
"version_files": ["src/__version__.py", "pyproject.toml:version"],
"style": [
["qmark", "fg:#ff9d00 bold"],
["question", "bold"],
["answer", "fg:#ff9d00 bold"],
["pointer", "fg:#ff9d00 bold"],
["highlighted", "fg:#ff9d00 bold"],
["selected", "fg:#cc5454"],
["separator", "fg:#cc5454"],
["instruction", ""],
["text", ""],
["disabled", "fg:#858585 italic"]
]
}
}
```

### .cz.yaml or cz.yaml

YAML configuration is supported by Commitizen. Recommended for `Go`, `ansible`, or even `helm` charts projects.

```yaml
commitizen:
name: cz_conventional_commits
version: 0.1.0
version_files:
- src/__version__.py
- pyproject.toml:version
style:
- - qmark
- fg:#ff9d00 bold
- - question
- bold
- - answer
- fg:#ff9d00 bold
- - pointer
- fg:#ff9d00 bold
- - highlighted
- fg:#ff9d00 bold
- - selected
- fg:#cc5454
- - separator
- fg:#cc5454
- - instruction
- ""
- - text
- ""
- - disabled
- fg:#858585 italic
```
## Version providers

Commitizen can read and write version from different sources.
Expand Down
Loading

0 comments on commit 04285c0

Please sign in to comment.