Skip to content

Commit

Permalink
feat: support pre and post processing regex substitution (#15)
Browse files Browse the repository at this point in the history
Also change to use more pydantic-settings instead of pyyaml.
  • Loading branch information
guangie88 authored Oct 7, 2024
1 parent aa2c45c commit 8e477ab
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 40 deletions.
12 changes: 12 additions & 0 deletions .clog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,15 @@ breaking_changes_heading: BREAKING CHANGES 💥

# Makes the Markdown bullet point neater with consistent capitalized first char
capitalize_title_first_char: true

# Pre and Post processing msg via regex to further amend the text
# Preprocessing occurs before all other steps
# Use Python Regex syntax for search and replace
# preprocessing:
# search: '.+'
# replace: '\g<0>'

# Postprocessing occurs after all other steps
postprocessing:
search: '(.+)\(#(\d+)\)'
replace: '\1[#\2](https://github.com/dsaidgovsg/cc-changelog-gen/pull/\2)'
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,11 @@ to auto-format the entire code base.
The parsing of the commit messages (in particular the titles) can be controlled via the values set
by `.clog.yaml` in the current working directory

If you prefer to have a different file name or path to it, or even want to access it via http/https
GET request, you can override this value:
If you prefer to have a different file name or path to it, you can override this value, e.g.

Example:

- `-c /path/to/.clog.yaml`
- `-c file:///path/to/.clog.yaml` (same effect as above)
- `-c http://domain.com/.clog.yaml`
- `-c https://domain.com/.clog.yaml`
```bash
cc-changelog-gen ... -c /path/to/.clog.yaml`
```

For the YAML specifications, as the parsing feature set is still growing and fairly unstable, there
will not be any specifications yet and do expect new / breaking changes to take place (though any
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ authors = [
]
dependencies = [
"GitPython~=3.1.32",
"PyYAML~=6.0.1",
"pydantic-settings~=2.5.2",
"semver~=3.0.1",
]

Expand Down
20 changes: 16 additions & 4 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --extra=dev --output-file=requirements.dev.txt
#
annotated-types==0.7.0
# via pydantic
black==23.7.0
# via cc-changelog-gen (pyproject.toml)
click==8.1.6
Expand All @@ -20,9 +22,19 @@ pathspec==0.11.2
# via black
platformdirs==3.10.0
# via black
pyyaml==6.0.1
pydantic==2.9.2
# via pydantic-settings
pydantic-core==2.23.4
# via pydantic
pydantic-settings==2.5.2
# via cc-changelog-gen (pyproject.toml)
python-dotenv==1.0.1
# via pydantic-settings
semver==3.0.2
# via cc-changelog-gen (pyproject.toml)
smmap==5.0.0
# via gitdb
tomli==2.0.1
# via black
typing-extensions==4.12.2
# via
# pydantic
# pydantic-core
18 changes: 16 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --output-file=requirements.txt
#
annotated-types==0.7.0
# via pydantic
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
# via cc-changelog-gen (pyproject.toml)
pyyaml==6.0.1
pydantic==2.9.2
# via pydantic-settings
pydantic-core==2.23.4
# via pydantic
pydantic-settings==2.5.2
# via cc-changelog-gen (pyproject.toml)
python-dotenv==1.0.1
# via pydantic-settings
semver==3.0.2
# via cc-changelog-gen (pyproject.toml)
smmap==5.0.0
# via gitdb
typing-extensions==4.12.2
# via
# pydantic
# pydantic-core
68 changes: 43 additions & 25 deletions src/cc_changelog_gen/app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
from argparse import ArgumentParser
from collections import OrderedDict
from dataclasses import dataclass, field
from enum import Enum, auto
from enum import Enum, StrEnum, auto
from git import Repo, TagReference
import os
import os.path
from pydantic import BaseModel
from pydantic_settings import (
BaseSettings,
PydanticBaseSettingsSource,
YamlConfigSettingsSource,
)
import re
import semver
import sys
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
import urllib.request
import yaml
from typing import Dict, List, Optional, Tuple, Type

ALLOWED_SCHEME = ["file", "http", "https"]

Expand All @@ -23,7 +26,7 @@ def __str__(self) -> str:
return f"Invalid scheme '{self.scheme}' to retrieve content from"


class Color:
class Color(StrEnum):
WARNING = "\033[93m"
ENDC = "\033[0m"

Expand All @@ -40,8 +43,12 @@ class Args:
repo: str


@dataclass
class Conf:
class Processing(BaseModel):
search: str
replace: str


class Conf(BaseSettings):
pre_captures: List[str] = field(default_factory=list)
pre_captures_after_trim: str = r"\s+"
type_captures: List[str] = field(default_factory=list)
Expand All @@ -56,6 +63,22 @@ class Conf:
others_heading: str = "Others"
breaking_changes_heading: str = "BREAKING CHANGES"
capitalize_title_first_char: bool = True
preprocessing: Optional[Processing] = None
postprocessing: Optional[Processing] = None

@classmethod
def settings_customise_sources(
cls,
settings_cls: Type[BaseSettings],
init_settings: PydanticBaseSettingsSource,
env_settings: PydanticBaseSettingsSource,
dotenv_settings: PydanticBaseSettingsSource,
file_secret_settings: PydanticBaseSettingsSource,
) -> Tuple[PydanticBaseSettingsSource, ...]:
# TODO: No better way to pass in runtime value until source changes:
# https://github.com/pydantic/pydantic-settings/issues/259
global YAML_FILE_PATH
return (YamlConfigSettingsSource(settings_cls, yaml_file=YAML_FILE_PATH),)


class TypeMatch(Enum):
Expand Down Expand Up @@ -94,19 +117,6 @@ def get_values(self, heading: str) -> List[str]:
return self.values[heading]


def load_conf(conf_path: str) -> Dict[str, Any]:
conf_url = urlparse(conf_path)

if conf_url.scheme and conf_url.scheme not in ALLOWED_SCHEME:
raise ValueError("Protocol of given file is invalid")

if not conf_url.scheme:
conf_url = urlparse(f"file://{os.path.abspath(conf_path)}")

f = urllib.request.urlopen(conf_url.geturl()).read()
return yaml.safe_load(f)


def args_parse() -> Args:
parser = ArgumentParser(
prog="Changelog Generator",
Expand Down Expand Up @@ -320,18 +330,20 @@ def process_breaking_change(

def main():
args = args_parse()
conf_dict = {}

try:
conf_dict = load_conf(args.conf)
global YAML_FILE_PATH
YAML_FILE_PATH = args.conf
if not os.path.isfile(YAML_FILE_PATH):
raise FileNotFoundError(YAML_FILE_PATH)
except OSError:
print_color(
Color.WARNING,
f"Missing '{args.conf}' config file, using default values...",
file=sys.stderr,
)

c = Conf(**conf_dict)
c = Conf()
repo = Repo(args.repo)

# Commit parsing to find nearest previous semver tag
Expand All @@ -346,6 +358,9 @@ def main():
messages = cm.message.split("\n")
title = messages[0]

if c.preprocessing:
title = re.sub(c.preprocessing.search, c.preprocessing.replace, title)

# Pre-capture logic
title = process_pre_capture(
title=title,
Expand All @@ -369,6 +384,9 @@ def main():

title = type_capture_output.title

if c.postprocessing:
title = re.sub(c.postprocessing.search, c.postprocessing.replace, title)

match type_capture_output.type_match:
case TypeMatch.SUPPORTED_TYPE:
heading = c.supported_types[type_capture_output.type_capture]
Expand Down

0 comments on commit 8e477ab

Please sign in to comment.