diff --git a/.pydevproject b/.pydevproject
index 9452bc3..2c06e15 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -1,17 +1,20 @@
-
+
+
Default
-
+
+
python interpreter
-
+
+
- /${PROJECT_DIR_NAME}/src
/${PROJECT_DIR_NAME}
-
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
index 5e838b3..99f26c0 100644
--- a/.settings/org.eclipse.core.resources.prefs
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -1,3 +1,2 @@
eclipse.preferences.version=1
-encoding//src/pychangelogfactory/changelogfactory.py=utf-8
encoding/=UTF-8
diff --git a/README.md b/README.md
index 94685df..215c798 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,7 @@
# pyChangeLogHelper
-A simple changelog formater that consume merged commit message and produce nice pre-formated changelogs
+A simple changelog formater that consume raw changes list text and produce nice pre-formated changelogs.
+The input data mainly aim to be a merged commit report.
-Checkout [Latest Documentation](https://chacha.ddns.net/mkdocs-web/chacha/pychangelogfactory/master/latest/).
-
-## Features
+Checkout [Latest Documentation](https://chacha.ddns.net/mkdocs-web/chacha/pychangelogfactory/master/latest/).
\ No newline at end of file
diff --git a/RUN_changelog.launch b/RUN_changelog.launch
new file mode 100644
index 0000000..22d81bf
--- /dev/null
+++ b/RUN_changelog.launch
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RUN_complexity.launch b/RUN_complexity.launch
new file mode 100644
index 0000000..55ecc1c
--- /dev/null
+++ b/RUN_complexity.launch
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RUN_mkdocs.launch b/RUN_mkdocs.launch
new file mode 100644
index 0000000..7816ecf
--- /dev/null
+++ b/RUN_mkdocs.launch
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RUN_quality.launch b/RUN_quality.launch
new file mode 100644
index 0000000..689dcff
--- /dev/null
+++ b/RUN_quality.launch
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RUN_unittest.launch b/RUN_unittest.launch
new file mode 100644
index 0000000..98bd546
--- /dev/null
+++ b/RUN_unittest.launch
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs-static/usage.md b/docs-static/usage.md
index 06f0375..472d0d0 100644
--- a/docs-static/usage.md
+++ b/docs-static/usage.md
@@ -1,5 +1,28 @@
# Usage
+## Theory
+
+This lib will try to extract normalized changes from a given raw history.
+
+_It's up to the user to provide this merged history._
+
+To realize this job, parsing is done in two rounds:
+
+- first round extrats formal changes messages: e.g.: `(): `
+- secound round extracts lines from remaining ones, based on keywords dictionnaries
+
+/// warning | searching policy
+When formal search (1), _lines must contain at least 2 words_
+When keywords search (2), _lines must contain at least 3 words_
+///
+
+/// note | ignored lines
+lines with comment tags are ignored:
+
+- `[0..N space]//`
+- `[0..N space]#`
+///
+
## Installation
From pypi repository (prefered):
@@ -15,10 +38,34 @@ From master git repository:
python -m pip install git+https://chacha.ddns.net/gitea/chacha/pychangelogfactory.git@master
+## Use in your project
+### Sample code
+``` py
+from pychangelogfactory import ChangeLogFormater
-## Import in your project
+raw_changelog='''
+feat: add a nice feature to the project
+style: reindent the full Foo class
+security: fix a security leak on the Foo2 component
+'''
+ChangeLogFormater.FactoryProcessFullChangelog(raw_changelog)
+changelog = ChangeLogFormater.RenderFullChangelog()
+print(changelog)
+```
+### Output(Raw)
-Add this line on the top of your python script:
-
- from pychangelogfactory import ChangeLogFormater
+ #### Features :sparkles::
+ > add a nice feature to the project
+ #### Security :shield::
+ > fix a security leak on the Foo2 component
+ #### Style :art::
+ > reindent the full Foo class
+
+### Output (rendered)
+#### Features :sparkles::
+> add a nice feature to the project
+#### Security :shield::
+> fix a security leak on the Foo2 component
+#### Style :art::
+> reindent the full Foo class
\ No newline at end of file
diff --git a/helpers/doc_gen.py b/helpers/doc_gen.py
index 155db4d..232278e 100644
--- a/helpers/doc_gen.py
+++ b/helpers/doc_gen.py
@@ -72,9 +72,11 @@ class doc_gen(helper_withresults_base):
# little hack here, to enable / disable pdf generation using own class config
# => reason is mkdocs seems to try loading the plugin even if we disable it, so we need to
# manually process the configuration file.
- mkdocsCfg = None
with open(cls.project_rootdir_path / "mkdocs.yml", "r") as mkdocsCfgFile:
- mkdocsCfg = yaml.load(mkdocsCfgFile, Loader=yaml.SafeLoader)
+ mkdocsCfg = yaml.load(mkdocsCfgFile, Loader=yaml.Loader)
+
+ if "plugins" in mkdocsCfg:
+ mkdocsCfg["plugins"] = [_ for _ in mkdocsCfg["plugins"] if (not isinstance(_, dict) or "with-pdf" not in _.keys())]
if cls.enable_gen_pdf == True:
mkdocsCfg["plugins"].append(
@@ -83,19 +85,11 @@ class doc_gen(helper_withresults_base):
"cover_subtitle": "User Manual",
"cover_logo": str(cls.project_rootdir_path / "docs-static" / "Library.jpg"),
"verbose": False,
- "media_type": "print",
"exclude_pages": ["LICENSE"],
"output_path": str(site_path / "pdf" / "manual.pdf"),
}
}
)
- else:
- for subelem in mkdocsCfg["plugins"]:
- if isinstance(subelem, dict):
- if "with-pdf" in subelem.keys():
- mkdocsCfg["plugins"].remove(subelem)
- break
-
with open(cls.project_rootdir_path / "mkdocs.yml", "w") as mkdocsCfgFile:
mkdocsCfgFile.write(yaml.dump(mkdocsCfg, Dumper=Dumper, default_flow_style=False, sort_keys=False))
diff --git a/mkdocs.yml b/mkdocs.yml
index f8fa45d..b474ff2 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,92 +1,110 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
docs_dir: docs
site_name: pychangelogfactory
-site_url: https://chacha.ddns.net/mkdocs-web/chacha/pychangelogfactory/latest/
-site_description: A simple changelog builder that you can feed with your repository change history
+site_url: 'https://chacha.ddns.net/mkdocs-web/chacha/pychangelogfactory/latest/'
+site_description: 'A simple changelog builder that you can feed with your repository change history'
site_author: chacha
-repo_url: https://chacha.ddns.net/gitea/chacha/pychangelogfactory
+repo_url: 'https://chacha.ddns.net/gitea/chacha/pychangelogfactory'
use_directory_urls: false
-copyright: CC BY-NC-SA 4.0
+copyright: 'CC BY-NC-SA 4.0'
theme:
name: material
features:
- - navigation.instant
- - navigation.tracking
- - navigation.tabs
- - navigation.tabs.sticky
- - toc.integrate
- - navigation.top
+ - navigation.instant
+ - navigation.tracking
+ - navigation.tabs
+ - navigation.tabs.sticky
+ - navigation.footer
+ - toc.integrate
+ - navigation.top
+ - navigation.section
+ - content.code.annotate
+ - navigation.prune
+ - toc.follow
palette:
- - media: '(prefers-color-scheme: dark)'
- scheme: slate
- toggle:
- icon: material/brightness-4
- name: Switch to system preference
- - media: (prefers-color-scheme)
- toggle:
- icon: material/brightness-auto
- name: Switch to light mode
- - media: '(prefers-color-scheme: light)'
- scheme: default
- toggle:
- icon: material/brightness-7
- name: Switch to dark mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ toggle:
+ icon: material/brightness-4
+ name: Switch to system preference
+ - media: (prefers-color-scheme)
+ toggle:
+ icon: material/brightness-auto
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ toggle:
+ icon: material/brightness-7
+ name: Switch to dark mode
plugins:
- - search
- - markdownextradata
- - mermaid2
- - localsearch
- - autorefs
- - mkdocstrings:
- default_handler: python
- handlers:
- python:
- selection:
- filters:
- - '!^_(?!_init__)'
- inherited_members: true
- rendering:
- show_root_heading: false
- show_root_toc_entry: false
- show_root_full_path: false
- show_if_no_docstring: true
- show_signature_annotations: true
- show_source: false
- heading_level: 2
- group_by_category: true
- show_category_heading: true
+- search
+- markdownextradata
+- mermaid2
+- localsearch
+- mkdocstrings:
+ default_handler: python
+ handlers:
+ python:
+ options:
+ filters:
+ - '!^_[^_]'
+ inherited_members: true
+ show_if_no_docstring: true
+ show_signature_annotations: true
+ show_source: false
+ show_category_heading: true
+ group_by_category: true
+ docstring_section_style: spacy
+ show_root_full_path: false
+ merge_init_into_class: true
+ separate_signature: true
markdown_extensions:
- - def_list
- - tables
- - attr_list
- - abbr
- - pymdownx.betterem:
- smart_enable: all
- - pymdownx.caret
- - pymdownx.critic
- - pymdownx.details
- - pymdownx.inlinehilite
- - pymdownx.snippets
- - pymdownx.highlight:
- anchor_linenums: true
- line_spans: __span
- pygments_lang_class: true
- - pymdownx.keys
- - pymdownx.mark
- - pymdownx.progressbar
- - pymdownx.smartsymbols
- - pymdownx.tasklist:
- custom_checkbox: true
- - pymdownx.tilde
- - footnotes
-
+- def_list
+- tables
+- attr_list
+- abbr
+- pymdownx.blocks.admonition:
+ types:
+ - new
+ - settings
+ - note
+ - abstract
+ - info
+ - tip
+ - success
+ - question
+ - warning
+ - failure
+ - danger
+ - bug
+ - example
+ - quote
+- pymdownx.blocks.definition
+- pymdownx.blocks.details
+- pymdownx.blocks.tab
+- pymdownx.blocks.html
+- pymdownx.betterem:
+ smart_enable: all
+- pymdownx.caret
+- pymdownx.critic
+- pymdownx.details
+- pymdownx.inlinehilite
+- pymdownx.snippets
+- pymdownx.highlight:
+ anchor_linenums: true
+ line_spans: __span
+ pygments_lang_class: true
+- pymdownx.keys
+- pymdownx.mark
+- pymdownx.progressbar
+- pymdownx.smartsymbols
+- pymdownx.tasklist:
+ custom_checkbox: true
+- pymdownx.tilde
+- footnotes
+- pymdownx.superfences
+- pymdownx.emoji:
+ emoji_index: !!python/name:materialx.emoji.twemoji
+ emoji_generator: !!python/name:materialx.emoji.to_svg
extra:
branch: master
- repository: pygitversionhelper
\ No newline at end of file
+ repository: pygitversionhelper
diff --git a/pyproject.toml b/pyproject.toml
index f689a2b..2475436 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -59,7 +59,7 @@ coverage-check = ["coverage>=7.0"]
complexity-check = ["radon>=5.1"]
quality-check = ["pylint>=2.15","pylint-json2html>=0.4","pandas>=1.5"]
type-check = ["mypy[reports]>=0.99" ]
-doc-gen = ["mkdocs>=1.4.0", "mkdocs-material>=8.5", "mkdocs-localsearch>=0.9.0", "mkdocstrings[python]>=0.19", "mkdocs-with-pdf>=0.9.3","pyyaml>=6.0","pymdown-extensions>=9","mkdocs-markdownextradata-plugin","mkdocs-mermaid2-plugin"]
+doc-gen = ["mkdocs>=1.4.0", "mkdocs-material>=8.5","mkdocs-pymdownx-material-extras", "mkdocs-localsearch>=0.9.0", "mkdocstrings[python]>=0.19", "mkdocs-with-pdf>=0.9.3","pyyaml>=6.0","pymdown-extensions>=9","mkdocs-markdownextradata-plugin","mkdocs-mermaid2-plugin"]
#[project.scripts]
#my-script = "my_package.module:function"
diff --git a/src/pychangelogfactory/changelogfactory.py b/src/pychangelogfactory/changelogfactory.py
index 99ab8bb..e900e28 100644
--- a/src/pychangelogfactory/changelogfactory.py
+++ b/src/pychangelogfactory/changelogfactory.py
@@ -9,7 +9,7 @@
# You should have received a copy of the license along with this
# work. If not, see .
-""" A simple changelog formater that consume merged commit message and produce nice pre-formated changelogs
+"""A simple changelog formater that consume merged commit message and produce nice pre-formated changelogs.
"""
@@ -20,35 +20,60 @@ from abc import ABC
def ChangeLogFormaterRecordType(Klass: type) -> type:
- """decorator helper function to register interface implementation"""
+ """Decorator helper function to register interface implementation in factory
+ Args:
+ Klass: class to register in the factory
+ Returns:
+ untouched class"""
ChangeLogFormater.ar_Klass.append(Klass)
return Klass
class ChangeLogFormater(ABC):
- """the main changelog class that define nearly everythings.
+ """The main changelog class that define nearly everythings.
+
This was supposed to be a very shorty script this is why it is all-in-one...
- Factory and base-object are mixed.
+ /// warning
+ Factory and base-objects are mixed in the same class.
+ ///
"""
ar_Klass: list[ChangeLogFormater] = []
ar_LinesResult: list[ChangeLogFormater] = []
- prefix: str = ""
+ prefix: str = "^\s+"
title: str = "Others :"
+ checkCommentPattern: str = r"^[ \t]*(?:\/\/|#)"
keywords: list[str] = []
priority: int = 0
def __init__(self, scope: str | None, ChangelogString: str):
+ """Main ChangeLogFormater class constructor
+
+ This class contain both formater and factory.
+
+ /// warning
+ this class does not aim to be instantiated by user.
+ ///
+ Args:
+ scope: scope of the formater (tag)
+ ChangelogString: formater rendered title
+ """
self._scope = scope
self._ChangelogString = ChangelogString.strip()
def RenderLine(self):
- """return a rendered line"""
+ """Get a rendered line
+ Returns:
+ the rendered line
+ """
return self._ChangelogString.strip()
@classmethod
def RenderLines(cls) -> str:
- """render all lines"""
+ """Render all lines
+ Returns:
+ the rendered lines
+ """
changelog_category: str = ""
lines = cls.GetLines()
if len(lines) > 0:
@@ -61,24 +86,41 @@ class ChangeLogFormater(ABC):
return changelog_category
def GetScope(self) -> str:
- """return the current scope (category)"""
+ """Return the current scope (category)
+ Returns:
+ the current scope
+ """
return self._scope if self._scope is not None else ""
@classmethod
def Clear(cls) -> None:
- """clear internal memory"""
+ """Clear internal memory"""
ChangeLogFormater.ar_LinesResult = []
@classmethod
- def CheckLine(cls, content: str) -> bool:
- """check if a line is in the current scope (lazy identification)"""
+ def CheckLine(cls, content: str) -> re.Match:
+ """Check if a line is in the current scope (lazy identification)
+ only formal tags are parsed by this function
+ eg: ():
+ Args:
+ content: line to parse
+ Returns:
+ match object
+ """
regex = re.compile(r"^(?:-\s+)?(?:{0})(?:\((.*)\))?(?::)(?:\s*)([^\s].+)".format(cls.prefix))
_match = regex.match(content)
return _match
@classmethod
def CheckLine_keywords(cls, content: str) -> bool:
- """check if a line is in the current scope (deeper in-word identification)"""
+ """Check if a line is in the current scope (deeper in-word identification)
+ any word in the message can be used to categorize this message.
+ this function test only for the current category.
+ Args:
+ content: line to parse
+ Returns:
+ True if a keyword has matched
+ """
keyword_list = cls.keywords
for _keyword in keyword_list:
if (_keyword != "") and re.search(_keyword, content):
@@ -87,7 +129,14 @@ class ChangeLogFormater(ABC):
@classmethod
def FactoryProcessLineMain(cls, RawChangelogLine: str) -> ChangeLogFormater:
- """Process a line and look for identified ones"""
+ """Process a line and look for identified ones
+ this function will try to apply every available formater for the 1st search round: formal search
+ order of search is set according to formater's configuration
+ Args:
+ RawChangelogLine: line to parse
+ Returns:
+ a corresponding ChangeLogFormater_XXX() object, or a ChangeLogFormater_others()
+ """
for Klass in sorted(ChangeLogFormater.ar_Klass, key=lambda x: x.priority):
content = Klass.CheckLine(RawChangelogLine)
if content is not None:
@@ -96,7 +145,14 @@ class ChangeLogFormater(ABC):
@classmethod
def FactoryProcessLineSecond(cls, RawChangelogLine: str) -> ChangeLogFormater:
- """Process a line and look for non-identified ones"""
+ """Process a line and look for non-identified ones
+ this function will try to apply every available formater for the 2ns search round: any keyword
+ order of search is set according to formater's configuration
+ Args:
+ RawChangelogLine: line to parse
+ Returns:
+ a corresponding ChangeLogFormater_XXX() object, or a ChangeLogFormater_others()
+ """
for Klass in sorted(ChangeLogFormater.ar_Klass, key=lambda x: x.priority, reverse=True):
if Klass.CheckLine_keywords(RawChangelogLine):
return Klass(None, RawChangelogLine)
@@ -105,16 +161,29 @@ class ChangeLogFormater(ABC):
@classmethod
def FactoryProcessFullChangelog(cls, RawChangelogMessage: str) -> list[ChangeLogFormater]:
- """Process all input lines"""
+ """Process all input lines
+ This function handle the main 2-round changes search algo.
+ Tt takes care of search-order and automatically skip any non-relevants message line.
+ A non relevant line can be a commented one, or a to short one.
+ Available comment patterns are: // and #
+ A relevant commit line must contain:
+ - at least 2 words for formal
+ - at least 3 words for keywords
+ Args:
+ RawChangelogMessage: The full raw changelog (merged commit-history)
+ Returns:
+ a list of ChangeLogFormater_XXX() object
+ """
LinesResult = []
Lines2ndRound = []
for line in RawChangelogMessage.split("\n"):
- if line.strip() != "":
+ lineWordsCount = len(line.split())
+ if (lineWordsCount > 1) and (not re.match(cls.checkCommentPattern, line)):
res = cls.FactoryProcessLineMain(line)
- if res is not ChangeLogFormater_others:
+ if type(res) is not ChangeLogFormater_others:
LinesResult.append(res)
- else:
+ elif lineWordsCount > 2:
Lines2ndRound.append(line)
for line in Lines2ndRound:
@@ -125,76 +194,93 @@ class ChangeLogFormater(ABC):
@classmethod
def GetLinesOfType(cls, Klass: type) -> list[ChangeLogFormater]:
- """retrieve all lines of specified type"""
+ """Retrieve all lines of specified formater type
+ Args:
+ Klass: type of formater to get
+ Returns:
+ a list of ChangeLogFormater_XXX() object
+ """
return [_ for _ in ChangeLogFormater.ar_LinesResult if isinstance(_, Klass)]
@classmethod
def GetLines(cls) -> list[ChangeLogFormater]:
- """retrieve all lines for the current formater"""
+ """Retrieve all lines for the current formater
+ Returns:
+ a list of ChangeLogFormater_XXX() object
+ """
return ChangeLogFormater.GetLinesOfType(cls)
@classmethod
- def RenderFullChangelog(cls) -> str:
- """render the main changelog"""
+ def RenderFullChangelog(cls, include_unknown: bool = False) -> str:
+ """Render the main changelog
+ Args:
+ include_unknown: includes unknown lines in an Unknown category
+ Returns:
+ the final formated changelog
+ """
full_changelog = ""
for Klass in sorted(ChangeLogFormater.ar_Klass, key=lambda x: x.priority, reverse=True):
+ if (include_unknown is False) and (Klass == ChangeLogFormater_others):
+ continue
full_changelog = full_changelog + Klass.RenderLines()
return full_changelog
# to avoid writing class, they are initialized with the following structure:
-# creating category classes: '': (priority, ['',...], '')
+# creating category classes: '': ( priority, ['',...],
+# ''
+# )
+#
+# => priority is both for ordering categories in final changelog
+# and parsing commit to extract messages
+#
for RecordType, Config in {
- "break": (
- 20,
- [],
- ":rotating_light: Breaking changes :rotating_light::",
- ),
- "feat": (20, ["feat", "new", "create", "add"], "Features :sparkles::"),
- "fix": (10, ["issue", "problem"], "Fixes :wrench::"),
- "security": (20, ["safe", "leak"], "Security :shield::"),
- "chore": (
- 20,
- ["task", "refactor", "build", "better", "improve"],
- "Chore :building_construction::",
- ),
- "perf": (
- 0,
- [
- "fast",
- ],
- "Performance Enhancements :rocket::",
- ),
- "wip": (
- 0,
- [
- "temp",
- ],
- "Work in progress changes :construction::",
- ),
- "docs": (
- 0,
- [
- "doc",
- ],
- "Documentations :book::",
- ),
- "style": (
- 5,
- [
- "beautify",
- ],
- "Style :art::",
- ),
- "refactor": (0, [], "Refactorings :recycle::"),
- "ci": (0, ["jenkins", "git"], "Continuous Integration :cyclone::"),
- "test": (15, ["unittest", "check", r"^(?:\s)*test(?:\s)*$"], "Testings :vertical_traffic_light::"),
- "build": (0, ["compile", "version"], "Builds :package:"),
+ # fmt: off
+ "break": ( 20, ["break"],
+ ":rotating_light: Breaking changes :rotating_light::",
+ ),
+ "feat": ( 20, ["feat", "new", "create", "add"],
+ "Features :sparkles::"
+ ),
+ "fix": ( 0, ["fix","issue", "problem"],
+ "Fixes :wrench::"
+ ),
+ "security": ( 20, ["safe", "leak"],
+ "Security :shield::"
+ ),
+ "chore": ( 20, ["task", "refactor", "build", "better", "improve"],
+ "Chore :building_construction::",
+ ),
+ "perf": ( 0, ["fast", ],
+ "Performance Enhancements :rocket::",
+ ),
+ "wip": ( 0, ["temp", ],
+ "Work in progress changes :construction::",
+ ),
+ "docs": ( 0, [ "doc", ],
+ "Documentations :book::",
+ ),
+ "style": ( 5, ["beautify", ],
+ "Style :art::",
+ ),
+ "refactor": ( 0, [],
+ "Refactorings :recycle::"
+ ),
+ "ci": ( 0, ["jenkins", "git"],
+ "Continuous Integration :cyclone::"
+ ),
+ "test": ( -5, ["unittest", "check", r"^(?:\s)*test(?:\s)*$"],
+ "Testings :vertical_traffic_light::"
+ ),
+ "build": ( 0, ["compile", "version"],
+ "Builds :package:"
+ ),
+ # fmt: on
}.items():
# then we instantiate all of them
- name = f"ChangeLogFormater_{RecordType}"
- tmp = globals()[name] = type(
- name,
+ _name = f"ChangeLogFormater_{RecordType}"
+ _tmp = globals()[_name] = type(
+ _name,
(ChangeLogFormater,),
{
"prefix": RecordType,
@@ -203,12 +289,12 @@ for RecordType, Config in {
"priority": Config[0],
},
)
- ChangeLogFormater.ar_Klass.append(tmp)
+ ChangeLogFormater.ar_Klass.append(_tmp)
@ChangeLogFormaterRecordType
class ChangeLogFormater_revert(ChangeLogFormater):
- """revert scope formater"""
+ """Revert scope formater"""
prefix: str = "revert"
title: str = "Reverts :back::"
@@ -216,12 +302,16 @@ class ChangeLogFormater_revert(ChangeLogFormater):
priority: int = 0
def RenderLine(self) -> str:
+ """an overloaded RenderLine implementation that adds surrounding '~~'
+ Returns:
+ the rendered pattern
+ """
return "~~" + super().RenderLine() + "~~"
@ChangeLogFormaterRecordType
class ChangeLogFormater_others(ChangeLogFormater):
- """others / unknown scope formater"""
+ """Others / unknown scope formater"""
prefix: str = "other"
title: str = "Others :question::"
diff --git a/test/test_changelogfactory.py b/test/test_changelogfactory.py
index a9e1301..fcab973 100644
--- a/test/test_changelogfactory.py
+++ b/test/test_changelogfactory.py
@@ -18,82 +18,122 @@ class Testtest_module(unittest.TestCase):
for test in teststrs:
self.assertIn(test, changelog)
+ def test_simplegeneration_ignored2(self):
+ raw = "break: testbreak break" + "\n" + "#docs: testdoc doc" + "\n" + "#style: teststyle beautify" + "\n" + "//test: testtest check"
+
+ pychangelogfactory.ChangeLogFormater.FactoryProcessFullChangelog(raw)
+ changelog = pychangelogfactory.ChangeLogFormater.RenderFullChangelog()
+
+ self.assertIn("testbreak", changelog)
+ self.assertNotIn("testdoc", changelog)
+ self.assertNotIn("teststyle", changelog)
+ self.assertNotIn("testtest", changelog)
+
+ def test_simplegeneration_ignored(self):
+ raw = "break: testbreak" + "\n" + "#docs: testdoc" + "\n" + "#style: teststyle" + "\n" + "//test: testtest"
+
+ pychangelogfactory.ChangeLogFormater.FactoryProcessFullChangelog(raw)
+ changelog = pychangelogfactory.ChangeLogFormater.RenderFullChangelog()
+ self.assertIn("testbreak", changelog)
+ self.assertNotIn("testdoc", changelog)
+ self.assertNotIn("teststyle", changelog)
+ self.assertNotIn("testtest", changelog)
+
def test_simplegeneration_order(self):
raw = "break: testbreak" + "\n" + "docs: testdoc" + "\n" + "style: teststyle" + "\n" + "test: testtest"
pychangelogfactory.ChangeLogFormater.FactoryProcessFullChangelog(raw)
changelog = pychangelogfactory.ChangeLogFormater.RenderFullChangelog().splitlines()
self.assertIn("testbreak", changelog[1])
- self.assertIn("testtest", changelog[3])
- self.assertIn("teststyle", changelog[5])
- self.assertIn("testdoc", changelog[7])
+ self.assertIn("teststyle", changelog[3])
+ self.assertIn("testdoc", changelog[5])
+ self.assertIn("testtest", changelog[7])
def test_simplegeneration_multiple(self):
raw = "break: testbreak" + "\n" + "docs: testdoc" + "\n" + "style: teststyle"
-
self.simplegeneration(raw, ["testbreak", "testdoc", "teststyle"])
def test_simplegeneration_breaking(self):
self.simplegeneration("break: teststring", ["teststring"])
- self.simplegeneration("test break", ["test break"])
+ self.simplegeneration("test break dummy1 dummy2", ["test break"])
def test_simplegeneration_features(self):
self.simplegeneration("feat: teststring", ["teststring"])
- self.simplegeneration("test feat", ["test feat"])
- self.simplegeneration("test new", ["test new"])
- self.simplegeneration("test create", ["test create"])
- self.simplegeneration("test add", ["test add"])
+ self.simplegeneration("test feat dummy1 dummy2", ["test feat"])
+ self.simplegeneration("test new dummy1 dummy2", ["test new"])
+ self.simplegeneration("test create dummy1 dummy2", ["test create"])
+ self.simplegeneration("test add dummy1 dummy2", ["test add"])
def test_simplegeneration_fix(self):
self.simplegeneration("fix: teststring", ["teststring"])
- self.simplegeneration("test fix", ["test fix"])
- self.simplegeneration("test issue", ["test issue"])
- self.simplegeneration("test problem", ["test problem"])
+ self.simplegeneration("test fix dummy1 dummy2", ["test fix"])
+ self.simplegeneration("test issue dummy1 dummy2", ["test issue"])
+ self.simplegeneration("test problem dummy1 dummy2", ["test problem"])
def test_simplegeneration_security(self):
self.simplegeneration("security: teststring", ["teststring"])
- self.simplegeneration("test safe", ["test safe"])
- self.simplegeneration("test leak", ["test leak"])
+ self.simplegeneration("test safe dummy1 dummy2", ["test safe"])
+ self.simplegeneration("test leak dummy1 dummy2", ["test leak"])
- def test_simplegeneration_task(self):
- self.simplegeneration("task: teststring", ["teststring"])
- self.simplegeneration("test refactor", ["test refactor"])
- self.simplegeneration("test build", ["test build"])
- self.simplegeneration("test better", ["test better"])
- self.simplegeneration("test improve", ["test improve"])
+ def test_simplegeneration_chore(self):
+ self.simplegeneration("chore: teststring", ["teststring"])
+ self.simplegeneration("chore refactor dummy1 dummy2", ["chore refactor"])
+ self.simplegeneration("chore build dummy1 dummy2", ["chore build"])
+ self.simplegeneration("chore better dummy1 dummy2", ["chore better"])
+ self.simplegeneration("chore improve dummy1 dummy2", ["chore improve"])
def test_simplegeneration_perf(self):
self.simplegeneration("perf: teststring", ["teststring"])
- self.simplegeneration("test fast", ["test fast"])
+ self.simplegeneration("test fast dummy1 dummy2", ["test fast"])
def test_simplegeneration_wip(self):
self.simplegeneration("wip: teststring", ["teststring"])
- self.simplegeneration("test temp", ["test temp"])
+ self.simplegeneration("test temp dummy1 dummy2", ["test temp"])
def test_simplegeneration_docs(self):
self.simplegeneration("docs: teststring", ["teststring"])
- self.simplegeneration("test doc", ["test doc"])
+ self.simplegeneration("test doc dummy1 dummy2", ["test doc"])
def test_simplegeneration_style(self):
self.simplegeneration("style: teststring", ["teststring"])
- self.simplegeneration("test beautify", ["test beautify"])
+ self.simplegeneration("test beautify dummy1 dummy2", ["test beautify"])
def test_simplegeneration_refactor(self):
self.simplegeneration("refactor: teststring", ["teststring"])
def test_simplegeneration_ci(self):
self.simplegeneration("ci: teststring", ["teststring"])
- self.simplegeneration("test jenkins", ["test jenkins"])
- self.simplegeneration("test git", ["test git"])
+ self.simplegeneration("test jenkins dummy1 dummy2", ["test jenkins"])
+ self.simplegeneration("test git dummy1 dummy2", ["test git"])
def test_simplegeneration_test(self):
self.simplegeneration("test: teststring", ["teststring"])
- self.simplegeneration("test unittest", ["test unittest"])
- self.simplegeneration("test check", ["test check"])
+ self.simplegeneration("test unittest dummy1 dummy2", ["test unittest"])
+ self.simplegeneration("test check dummy1 dummy2", ["test check"])
def test_simplegeneration_build(self):
self.simplegeneration("build: teststring", ["teststring"])
- self.simplegeneration("test compile", ["test compile"])
- self.simplegeneration("test version", ["test version"])
+ self.simplegeneration("test compile dummy1 dummy2", ["test compile"])
+ self.simplegeneration("test version dummy1 dummy2", ["test version"])
def test_simplegeneration_revert(self):
self.simplegeneration("revert: teststring", ["~~teststring~~"])
+
+ def test_sample(self):
+ raw_changelog = (
+ "feat: add a nice feature to the project\n"
+ "style: reindent the full Foo class\n"
+ "security: fix a security leak on the Foo2 component"
+ )
+ pychangelogfactory.ChangeLogFormater.FactoryProcessFullChangelog(raw_changelog)
+ changelog = pychangelogfactory.ChangeLogFormater.RenderFullChangelog()
+
+ expected_formated = (
+ "#### Features :sparkles::\n"
+ "> add a nice feature to the project\n"
+ "#### Security :shield::\n"
+ "> fix a security leak on the Foo2 component\n"
+ "#### Style :art::\n"
+ "> reindent the full Foo class\n"
+ )
+
+ self.assertEqual(changelog, expected_formated)