Compare commits
21 Commits
2.0.0.post
...
2.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 227db21f8d | |||
|
|
48eacc4d69 | ||
|
|
807e564380 | ||
|
|
236efcc258 | ||
| 4c10ed1ecd | |||
|
|
e4df9f7d77 | ||
| e14e867205 | |||
|
|
418eec803d | ||
|
|
8a01ad04bb | ||
|
|
1be6751d5c | ||
|
|
407282f70e | ||
|
|
198337e877 | ||
|
|
d1a34fafe3 | ||
|
|
010145a0a8 | ||
|
|
1ed87d05f6 | ||
|
|
2d8d2f2a74 | ||
|
|
8d68edd4ab | ||
| b919b2e04b | |||
| 4deaa933ee | |||
| dd37858daa | |||
| b0a22af5c8 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -41,3 +41,5 @@ docs
|
||||
helpers-results
|
||||
.coverage
|
||||
/.mypy_cache/
|
||||
.coverage
|
||||
.mypy_cache
|
||||
77
Jenkinsfile
vendored
77
Jenkinsfile
vendored
@@ -26,7 +26,7 @@ def _bPreRelease = false
|
||||
def _bDraft = false
|
||||
// release content / changelog management
|
||||
def _bAutoChangelog = true //Not supported yet
|
||||
def _ReleaseContent_Title = "_CI/CD Automatic Release_"
|
||||
def _ReleaseContent_Title = "# _CI/CD Automatic Release_"
|
||||
def bPushMasterOnPypi = true
|
||||
// full rebuild toogle
|
||||
def _bFullRebuilt = true
|
||||
@@ -148,6 +148,7 @@ pipeline {
|
||||
PY_PROJECT_NAME = "__NOTSET__"
|
||||
PY_PROJECT_VERSION = "__NOTSET__"
|
||||
PY_PROJECT_VERSION_STRIPPED = "__NOTSET__"
|
||||
CHANGELOG = "__NOTSET__"
|
||||
}
|
||||
|
||||
stages {
|
||||
@@ -184,16 +185,14 @@ pipeline {
|
||||
|
||||
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade setuptools build pip copier jinja2-slug toml")
|
||||
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install simple_rest_client requests twine")
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install simple_rest_client requests twine packaging")
|
||||
|
||||
script {
|
||||
if(_PROJECT_NAME!="pygitversionhelper") {
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install pygitversionhelper")
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: need to install pygitversionhelper deps from a better way...
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install packaging")
|
||||
if(_PROJECT_NAME!="pychangelogfactory") {
|
||||
sh(". ~/TOOLS_ENV/bin/activate && pip install pychangelogfactory")
|
||||
}
|
||||
}
|
||||
sh("git config --global user.email $_MaintainerEmail")
|
||||
@@ -217,6 +216,32 @@ pipeline {
|
||||
withCredentials([usernamePassword(credentialsId: _SCMCredentials, passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
|
||||
sh("git remote set-url origin https://${GIT_USERNAME}:${GIT_PASSWORD}@chacha.ddns.net/gitea/${_PROJECT_USER_NAME}/${_PROJECT_NAME}.git")
|
||||
}
|
||||
|
||||
CHANGELOG = sh(script: """#!/bin/sh -
|
||||
|. ~/TOOLS_ENV/bin/activate
|
||||
|exec python - << '__EOWRAPPER__'
|
||||
|
|
||||
|import re
|
||||
|
|
||||
|try:
|
||||
| from pychangelogfactory import ChangelogFactory
|
||||
|except ImportError:
|
||||
| from src.pychangelogfactory import ChangelogFactory
|
||||
|
|
||||
|try:
|
||||
| from pygitversionhelper import gitversionhelper
|
||||
|except ImportError:
|
||||
| from src.pygitversionhelper import gitversionhelper
|
||||
|
|
||||
|
|
||||
|LastTag=gitversionhelper.tag.getLastTag(same_branch=True)
|
||||
|CommitHistory=gitversionhelper.commit.getMessagesSinceTag(LastTag, merged_output=True, ignore_merged=True)
|
||||
|Changelog = ChangelogFactory(CommitHistory).RenderFullChangelog(include_unknown=True)
|
||||
|print(Changelog.replace("\\n","\\n\\n"))
|
||||
|
|
||||
|__EOWRAPPER__
|
||||
""".stripMargin(),
|
||||
returnStdout: true).trim()
|
||||
|
||||
if(_GIT_BRANCH=="master") {
|
||||
if(sh(returnStdout: true, script: "git tag --points-at HEAD").trim().isEmpty()) {
|
||||
@@ -397,14 +422,23 @@ pipeline {
|
||||
}
|
||||
post {
|
||||
always {
|
||||
dir("gitrepo") {
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/quality_check",
|
||||
reportFiles: "report.html",
|
||||
reportName: "quality-report",
|
||||
allowMissing: false,
|
||||
alwaysLinkToLastBuild: true,
|
||||
keepAll: true])
|
||||
dir("gitrepo") {
|
||||
publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/types_check/cobertura.xml")]
|
||||
junit 'helpers-results/types_check/junit.xml'
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/quality_check",
|
||||
reportFiles: "report.html",
|
||||
reportName: "quality-report",
|
||||
allowMissing: false,
|
||||
alwaysLinkToLastBuild: true,
|
||||
keepAll: true])
|
||||
publishHTML([
|
||||
reportDir: "helpers-results/types_check",
|
||||
reportFiles: "index.html",
|
||||
reportName: "types_check",
|
||||
allowMissing: false,
|
||||
alwaysLinkToLastBuild: true,
|
||||
keepAll: true])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,12 +515,7 @@ pipeline {
|
||||
sz_full_rate = full_rate.setScale(2, RoundingMode.HALF_EVEN).toString()
|
||||
badge_coverage.setStatus(sz_full_rate)
|
||||
badge_coverage.setColor(getColorScale(full_rate))
|
||||
|
||||
//complexity = new BigDecimal( 10*GetCoverageValue_complexity(coverage_report_path))
|
||||
//sz_complexity = complexity.setScale(2, RoundingMode.HALF_EVEN).toString()
|
||||
//badge_complexity.setStatus(sz_complexity)
|
||||
//badge_quality.setColor(getColorScale_reversed(complexity))
|
||||
|
||||
|
||||
//badge_maintainability
|
||||
records = readCSV file: 'helpers-results/complexity_check/MI.csv'
|
||||
maintainability = records[1][1]
|
||||
@@ -569,6 +598,7 @@ pipeline {
|
||||
|from simple_rest_client.api import API
|
||||
|from simple_rest_client.resource import Resource
|
||||
|
|
||||
|
|
||||
|try:
|
||||
| from pygitversionhelper import gitversionhelper
|
||||
|except ImportError:
|
||||
@@ -615,6 +645,13 @@ pipeline {
|
||||
|ReleaseContent = "${_ReleaseContent_Title}" + "\\n" \\
|
||||
| + "\\n" \\
|
||||
| + "Reference documentation: [mkdocs page](https://chacha.ddns.net/mkdocs-web/${_PROJECT_USER_NAME}/${PY_PROJECT_NAME}/${_GIT_BRANCH}/${PY_PROJECT_VERSION_STRIPPED}/) "
|
||||
|
|
||||
|Changelog='''${CHANGELOG}'''
|
||||
|
|
||||
|ReleaseContent = ReleaseContent + "\\n"+ "\\n"+ "## Changelog:\\n" + Changelog
|
||||
|
|
||||
|if not Changelog:
|
||||
| ReleaseContent = ReleaseContent + "code/project maintainance"
|
||||
|
|
||||
|data={
|
||||
| "body": ReleaseContent,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||

|
||||
|
||||
# pyChangeLogFactory
|
||||
# pyChangelogFactory
|
||||
|
||||
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.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pychangelogfactory/helpers}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--complexity-check"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
|
||||
<mapEntry key="PATH" value="C:\Program Files\GTK3-Runtime Win64\bin"/>
|
||||
</mapAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pychangelogfactory/helpers}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--doc-gen --doc-gen-pdf"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pychangelogfactory/helpers}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--type-check --quality-check"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="2"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:pychangelogfactory/helpers}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/helpers"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--unit-test --coverage-check"/>
|
||||
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
|
||||
|
||||
@@ -42,7 +42,7 @@ From master git repository:
|
||||
|
||||
### Sample code
|
||||
``` py
|
||||
from pychangelogfactory import ChangeLogFactory
|
||||
from pychangelogfactory import ChangelogFactory
|
||||
|
||||
raw_changelog = (
|
||||
"feat: add a nice feature to the project\n"
|
||||
@@ -52,7 +52,7 @@ raw_changelog = (
|
||||
"improve core performances by reducing complexity\n"
|
||||
"some random changes in the text content\n"
|
||||
)
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(self.raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog()
|
||||
print(changelog)
|
||||
@@ -61,13 +61,13 @@ print(changelog)
|
||||
#### Or shorted version:
|
||||
|
||||
``` py
|
||||
hdlr = ChangeLogFactory(self.raw_changelog)
|
||||
hdlr = ChangelogFactory(self.raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog()
|
||||
```
|
||||
#### Or one-liner version:
|
||||
|
||||
``` py
|
||||
changelog = ChangeLogFactory(self.raw_changelog).RenderFullChangelog()
|
||||
changelog = ChangelogFactory(self.raw_changelog).RenderFullChangelog()
|
||||
```
|
||||
|
||||
### Output(Raw)
|
||||
@@ -97,7 +97,7 @@ changelog = ChangeLogFactory(self.raw_changelog).RenderFullChangelog()
|
||||
### Options
|
||||
#### Display unknown messages types
|
||||
``` py
|
||||
from pychangelogfactory import ChangeLogFormater
|
||||
from pychangelogfactory import ChangelogFormater
|
||||
|
||||
raw_changelog = (
|
||||
"feat: add a nice feature to the project\n"
|
||||
@@ -107,7 +107,7 @@ raw_changelog = (
|
||||
"improve core performances by reducing complexity\n"
|
||||
"some random changes in the text content\n"
|
||||
)
|
||||
changelog = ChangeLogFactory(self.raw_changelog).RenderFullChangelog(include_unknown=True)
|
||||
changelog = ChangelogFactory(self.raw_changelog).RenderFullChangelog(include_unknown=True)
|
||||
print(changelog)
|
||||
```
|
||||
### Output (rendered)
|
||||
@@ -125,34 +125,34 @@ print(changelog)
|
||||
|
||||
## Supported types
|
||||
|
||||
| Type/Tag | Priority | Keywords | Title |
|
||||
|-----------|----------|----------------------------------------|-------------------------------------------------------|
|
||||
| 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 | 10 | task, refactor, build, better, improve | Chore :building_construction: : |
|
||||
| perf | 15 | fast, perf | Performance Enhancements :rocket: : |
|
||||
| wip | 0 | temp | Work in progress changes :construction: : |
|
||||
| doc | 0 | doc, manual | Documentations :book: : |
|
||||
| style | 5 | beautify | Style :art: : |
|
||||
| refactor | 0 | | Refactorings :recycle: : |
|
||||
| ci | 0 | jenkins, git | Continuous Integration :cyclone: : |
|
||||
| test | -5 | unittest, check, testing | Testings :vertical_traffic_light: : |
|
||||
| build | 0 | compile, version | Builds :package: : |
|
||||
| revert | 0 | revert, fallback | Reverts :back: : |
|
||||
| other | -20 | | Others :question: : |
|
||||
| Type/Tag | Priority | Keywords | Title | Class Name |
|
||||
|-----------|----------|----------------------------------------|-------------------------------------------------------|-------------------------------|
|
||||
| break | 20 | break | :rotating_light: Breaking changes :rotating_light: : | `ChangelogFormater_break` |
|
||||
| feat | 20 | feat, new, create, add | Features :sparkles: : | `ChangelogFormater_feat` |
|
||||
| fix | 0 | fix, issue, problem | Fixes :wrench: : | `ChangelogFormater_fix` |
|
||||
| security | 20 | safe, leak | Security :shield: : | `ChangelogFormater_security` |
|
||||
| chore | 10 | task, refactor, build, better, improve | Chore :building_construction: : | `ChangelogFormater_chore` |
|
||||
| perf | 15 | fast, perf | Performance Enhancements :rocket: : | `ChangelogFormater_perf` |
|
||||
| wip | 0 | temp | Work in progress changes :construction: : | `ChangelogFormater_wip` |
|
||||
| doc | 0 | doc, manual | Documentations :book: : | `ChangelogFormater_wip` |
|
||||
| style | 5 | beautify | Style :art: : | `ChangelogFormater_style` |
|
||||
| refactor | 0 | | Refactorings :recycle: : | `ChangelogFormater_refactor` |
|
||||
| ci | 0 | jenkins, git | Continuous Integration :cyclone: : | `ChangelogFormater_ci` |
|
||||
| test | -5 | unittest, check, testing | Testings :vertical_traffic_light: : | `ChangelogFormater_test` |
|
||||
| build | 0 | compile, version | Builds :package: : | `ChangelogFormater_build` |
|
||||
| revert | 0 | revert, fallback | Reverts :back: : | `ChangelogFormater_revert` |
|
||||
| other | -20 | | Others :question: : | `ChangelogFormater_others` |
|
||||
|
||||
## Add new types
|
||||
|
||||
New formaters can be easily added by subclassing `ChangeLogFormater`:
|
||||
New formaters can be easily added by subclassing `ChangelogFormater`:
|
||||
|
||||
### Inject custom formater locally (prefered way)
|
||||
|
||||
``` py
|
||||
from pychangelogfactory import ChangeLogFormater,ChangeLogFactory
|
||||
from pychangelogfactory import ChangelogFormater,ChangelogFactory
|
||||
|
||||
class ChangeLogFormater_others(ChangeLogFormater):
|
||||
class ChangelogFormater_others(ChangelogFormater):
|
||||
"""My formater"""
|
||||
|
||||
prefix: str = "mytag"
|
||||
@@ -160,18 +160,18 @@ class ChangeLogFormater_others(ChangeLogFormater):
|
||||
keywords: list[str] = ["foo","42"]
|
||||
priority: int = 10
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr.RegisterFormater(ChangeLogFormater_others)
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.RegisterFormater(ChangelogFormater_others)
|
||||
...
|
||||
```
|
||||
|
||||
### Inject custom formater module-wide
|
||||
|
||||
``` py
|
||||
from pychangelogfactory import ChangeLogFormater,ChangelogFormaterRecordType
|
||||
from pychangelogfactory import ChangelogFormater,ChangelogFormaterRecordType
|
||||
|
||||
@ChangelogFormaterRecordType
|
||||
class ChangeLogFormater_others(ChangeLogFormater):
|
||||
class ChangelogFormater_others(ChangelogFormater):
|
||||
"""My formater"""
|
||||
|
||||
prefix: str = "mytag"
|
||||
@@ -179,7 +179,7 @@ class ChangeLogFormater_others(ChangeLogFormater):
|
||||
keywords: list[str] = ["foo","42"]
|
||||
priority: int = 10
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
...
|
||||
```
|
||||
|
||||
@@ -193,7 +193,7 @@ raw_changelog = ("mytag: add a nice feature to the project\n"
|
||||
"foo modification in my file\n"
|
||||
"need 42 coffee\n"
|
||||
)
|
||||
hdlr = ChangeLogFactory(raw_changelog)
|
||||
hdlr = ChangelogFactory(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
print(changelog)
|
||||
```
|
||||
@@ -207,24 +207,24 @@ print(changelog)
|
||||
> need 42 coffee
|
||||
|
||||
|
||||
### revert changes
|
||||
### Revert changes
|
||||
#### Reset to original list class-wise (all modules):
|
||||
``` py
|
||||
ChangeLogFactory.ResetFormaterList()
|
||||
ChangelogFactory.ResetBaseFormaterList()
|
||||
...
|
||||
```
|
||||
#### Reset to original list instance-wise:
|
||||
``` py
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ResetFormaterList()
|
||||
...
|
||||
```
|
||||
#### Removing a specific formater:
|
||||
``` py
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr.unRegisterFormater(ChangeLogFormater_others)
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.unRegisterFormater(ChangelogFormater_others)
|
||||
...
|
||||
```
|
||||
/// warning
|
||||
There is no way to remove a specific formater class-wise (all modules).
|
||||
There is no way to remove a specific formater class-wise (all modules) except using ResetFormaterList().
|
||||
///
|
||||
|
||||
@@ -22,7 +22,6 @@ if __package__ == "helpers":
|
||||
from .quality_check import quality_check
|
||||
from .unit_test import unit_test
|
||||
from .doc_gen import doc_gen
|
||||
from .changelog_gen import changelog_gen
|
||||
from .complexity_check import complexity_check
|
||||
else:
|
||||
# when calling the __main__.py file (from IDE)
|
||||
@@ -30,7 +29,6 @@ else:
|
||||
from helpers.quality_check import quality_check
|
||||
from helpers.unit_test import unit_test
|
||||
from helpers.doc_gen import doc_gen
|
||||
from helpers.changelog_gen import changelog_gen
|
||||
from helpers.complexity_check import complexity_check
|
||||
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
@@ -59,8 +57,6 @@ if __name__ == "__main__":
|
||||
"-pdf", "--doc-gen-pdf", dest="docgenpdf", action="store_true", help="enable pdf documentation export (requires doc-gen)"
|
||||
)
|
||||
|
||||
parser.add_argument("-clg", "--changelog-gen", dest="changeloggen", action="store_true", help="enable changelog generation")
|
||||
|
||||
parser.add_argument("-cpc", "--complexity-check", dest="complexitycheck", action="store_true", help="enable complexity check")
|
||||
|
||||
args = parser.parse_args()
|
||||
@@ -76,7 +72,6 @@ if __name__ == "__main__":
|
||||
# args.coveragecheck = True
|
||||
# args.docgen = True
|
||||
# args.docgenpdf = True
|
||||
# args.changeloggen = True
|
||||
# args.complexitycheck = True
|
||||
|
||||
helpers = []
|
||||
@@ -104,9 +99,6 @@ if __name__ == "__main__":
|
||||
else:
|
||||
raise RuntimeError("doc-gen is required to enable doc-gen-pdf")
|
||||
|
||||
if args.changeloggen == True:
|
||||
helpers.append(changelog_gen)
|
||||
|
||||
if args.complexitycheck == True:
|
||||
helpers.append(complexity_check)
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# 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 <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
# from pathlib import Path
|
||||
# import os
|
||||
# import datetime
|
||||
|
||||
|
||||
from .helper_base import helper_base
|
||||
|
||||
|
||||
class changelog_gen(helper_base):
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
pass
|
||||
@@ -50,6 +50,7 @@ class doc_gen(helper_withresults_base):
|
||||
reference_path = doc_path / "reference"
|
||||
cls._reset_dir(reference_path)
|
||||
|
||||
# create one .md per python module
|
||||
for path in sorted((cls.project_rootdir_path / "src").rglob("*.py")):
|
||||
module_path = path.relative_to(cls.project_rootdir_path / "src").with_suffix("")
|
||||
doc_path = path.relative_to(cls.project_rootdir_path / "src").with_suffix(".md")
|
||||
@@ -57,14 +58,12 @@ class doc_gen(helper_withresults_base):
|
||||
|
||||
parts = list(module_path.parts)
|
||||
|
||||
if parts[-1] == "__init__":
|
||||
parts = parts[:-1]
|
||||
elif parts[-1] == "__main__":
|
||||
if parts[-1] in ("__init__", "__main__"):
|
||||
continue
|
||||
|
||||
cls._reset_dir(os.path.dirname(full_doc_path))
|
||||
cls._create_dir(full_doc_path.parent.resolve())
|
||||
with open(full_doc_path, "w+") as fd:
|
||||
identifier = "src." + ".".join(parts)
|
||||
identifier = ".".join(parts)
|
||||
print("::: " + identifier, file=fd)
|
||||
|
||||
cmdopts = [f"{sys.executable}", "-m", "mkdocs", "-v", "build", "--site-dir", str(site_path), "--clean"]
|
||||
@@ -93,6 +92,7 @@ class doc_gen(helper_withresults_base):
|
||||
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))
|
||||
|
||||
print(" !! start doc generation")
|
||||
res = cls.run_cmd(cmdopts)
|
||||
print(res.decode())
|
||||
print(" !! done")
|
||||
|
||||
@@ -11,6 +11,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
@@ -34,11 +35,17 @@ class helper_base(ABC):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _reset_dir(dirpath: Path):
|
||||
def _create_dir(dirpath: Path):
|
||||
dirpath = Path(dirpath)
|
||||
if not os.path.exists(dirpath):
|
||||
os.makedirs(dirpath)
|
||||
[f.unlink() for f in Path(dirpath).glob("*") if f.is_file()]
|
||||
|
||||
@staticmethod
|
||||
def _reset_dir(dirpath: Path):
|
||||
dirpath = Path(dirpath)
|
||||
if os.path.exists(dirpath):
|
||||
shutil.rmtree(dirpath)
|
||||
os.makedirs(dirpath)
|
||||
|
||||
@classmethod
|
||||
def reset_result_dir(cls):
|
||||
@@ -57,10 +64,11 @@ class helper_base(ABC):
|
||||
return process.stdout
|
||||
|
||||
@classmethod
|
||||
def run_cmd(cls, cmdarray):
|
||||
def run_cmd(cls, cmdarray, silent: bool = False):
|
||||
p = subprocess.run(cmdarray, capture_output=True)
|
||||
print(p.stdout)
|
||||
print(p.stderr)
|
||||
if not silent:
|
||||
print(p.stdout.decode())
|
||||
print(p.stderr.decode())
|
||||
return p.stdout
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class quality_check(helper_withresults_base):
|
||||
def GetPylintMessageList(cls):
|
||||
Messagelist = dict()
|
||||
regex = r"^:([a-zA-Z-]+) \(([^\)]+)\)"
|
||||
for line in cls.run_cmd([sys.executable, "-m", "pylint", "--list-msgs"]).splitlines():
|
||||
for line in cls.run_cmd([sys.executable, "-m", "pylint", "--list-msgs"], True).splitlines():
|
||||
if res := re.search(regex, line.decode()):
|
||||
Messagelist[res.group(1)] = res.group(2)
|
||||
cls.PylintMessageList = Messagelist
|
||||
@@ -52,6 +52,7 @@ class quality_check(helper_withresults_base):
|
||||
@classmethod
|
||||
def do_job(cls):
|
||||
print("checking code quality ...")
|
||||
|
||||
cls.GetPylintMessageList()
|
||||
|
||||
RES_all = dict()
|
||||
@@ -62,7 +63,7 @@ class quality_check(helper_withresults_base):
|
||||
[
|
||||
"--load-plugins=pylint.extensions.mccabe",
|
||||
"--output-format=json,parseable",
|
||||
"--disable=invalid-name",
|
||||
"--disable=invalid-name,too-few-public-methods,too-many-arguments", # ignore
|
||||
"--ignore=_version.py",
|
||||
"--reports=y",
|
||||
"--score=yes",
|
||||
|
||||
@@ -24,22 +24,18 @@ class types_check(helper_withresults_base):
|
||||
print("checking code typing ...")
|
||||
result = api.run(
|
||||
[ # project path
|
||||
"-m",
|
||||
"src." + str(cls.pyproject["project"]["name"]),
|
||||
"-p",
|
||||
"src." + cls.pyproject["project"]["name"],
|
||||
# analysis configuration
|
||||
"--ignore-missing-imports",
|
||||
"--strict-equality",
|
||||
# "--show-traceback",
|
||||
"--explicit-package-bases",
|
||||
# "--strict-equality",
|
||||
# "--check-untyped-defs",
|
||||
# reports generation
|
||||
"--cobertura-xml-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--html-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--linecount-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--linecoverage-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--lineprecision-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--txt-report",
|
||||
str(cls.get_result_dir()),
|
||||
"--xml-report",
|
||||
@@ -52,6 +48,9 @@ class types_check(helper_withresults_base):
|
||||
if result[0]:
|
||||
print("\nType checking report:\n")
|
||||
print(result[0]) # stdout
|
||||
# converting the report using pylint_json2html (/!\ internal API, but as their is no leading '_' ...)
|
||||
with open(cls.get_result_dir() / "raw_eport.txt", "w+", encoding="utf-8") as Outfile:
|
||||
Outfile.write(result[0])
|
||||
|
||||
if result[1]:
|
||||
print("\nError report:\n")
|
||||
|
||||
14
mkdocs.yml
14
mkdocs.yml
@@ -15,11 +15,11 @@ theme:
|
||||
- navigation.tabs
|
||||
- navigation.tabs.sticky
|
||||
- navigation.footer
|
||||
- toc.integrate
|
||||
- navigation.path
|
||||
- navigation.top
|
||||
- navigation.section
|
||||
- content.code.annotate
|
||||
- navigation.prune
|
||||
- navigation.expand
|
||||
- toc.follow
|
||||
palette:
|
||||
- media: '(prefers-color-scheme: dark)'
|
||||
@@ -45,19 +45,23 @@ plugins:
|
||||
default_handler: python
|
||||
handlers:
|
||||
python:
|
||||
path:
|
||||
- src
|
||||
options:
|
||||
filters:
|
||||
- '!^_[^_]'
|
||||
inherited_members: true
|
||||
inherited_members: false
|
||||
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
|
||||
heading_level: 2
|
||||
docstring_section_style: spacy
|
||||
show_root_toc_entry: false
|
||||
- with-pdf:
|
||||
cover_subtitle: User Manual
|
||||
cover_logo: C:\Users\chacha\git\pychangelogfactory\docs-static\Library.jpg
|
||||
@@ -115,4 +119,4 @@ markdown_extensions:
|
||||
emoji_generator: !!python/name:materialx.emoji.to_svg
|
||||
extra:
|
||||
branch: master
|
||||
repository: pygitversionhelper
|
||||
repository: pychangelogfactory
|
||||
|
||||
@@ -47,6 +47,7 @@ where = ["src"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"pychangelogfactory.data" = ["*.*"]
|
||||
"pysimpleini" = ["py.typed"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://chacha.ddns.net/gitea/chacha/pychangelogfactory"
|
||||
|
||||
@@ -20,4 +20,4 @@ except PackageNotFoundError: # pragma: no cover
|
||||
warnings.warn("can not read __version__, assuming local test context, setting it to ?.?.?")
|
||||
__version__ = "?.?.?"
|
||||
|
||||
from .changelogfactory import ChangeLogFactory, ChangelogFormaterRecordType, ChangeLogFormater
|
||||
from .changelogfactory import ChangelogFactory, ChangelogFormaterRecordType, ChangelogFormater
|
||||
|
||||
@@ -15,36 +15,93 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from re import Match, search, compile as _compile, match
|
||||
from abc import ABC
|
||||
from copy import deepcopy
|
||||
|
||||
_savedFormaterList = set()
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing import Generic, TypeVar, cast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Optional, ClassVar, Type, Dict, List
|
||||
|
||||
T_ChangelogFormater = TypeVar("T_ChangelogFormater", bound="ChangelogFormater")
|
||||
|
||||
|
||||
def ChangelogFormaterRecordType(Klass: type) -> type:
|
||||
class _ChangelogFormatersCtx(Generic[T_ChangelogFormater]):
|
||||
"""Storage class that manage Formaters"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Storage class init method"""
|
||||
self._savedFormaterList: set[Type[T_ChangelogFormater]] = set()
|
||||
|
||||
def add(self, record: Type[T_ChangelogFormater]) -> None:
|
||||
"""Add a Formater to the storage class
|
||||
Args:
|
||||
record: the Formater class to be added
|
||||
"""
|
||||
self._savedFormaterList.add(record)
|
||||
|
||||
def remove(self, record: Type[T_ChangelogFormater]) -> None:
|
||||
"""Remove a Formater from the storage class
|
||||
Args:
|
||||
record: the Formater class to be removed
|
||||
"""
|
||||
self._savedFormaterList.remove(record)
|
||||
|
||||
def reset(self) -> None:
|
||||
"""Reset the storage class"""
|
||||
self._savedFormaterList = set()
|
||||
|
||||
def get(self) -> set[Type[T_ChangelogFormater]]:
|
||||
"""Get the storage data set
|
||||
Returns:
|
||||
The internal storage class (set)
|
||||
"""
|
||||
return self._savedFormaterList
|
||||
|
||||
def __copy__(self) -> _ChangelogFormatersCtx[T_ChangelogFormater]:
|
||||
"""Copy the class"""
|
||||
cls = self.__class__
|
||||
result = cls.__new__(cls)
|
||||
result._savedFormaterList = self._savedFormaterList
|
||||
return result
|
||||
|
||||
def __deepcopy__(self, memo: Dict[int, object]) -> _ChangelogFormatersCtx[T_ChangelogFormater]:
|
||||
"""Deep-Copy the class
|
||||
Args:
|
||||
memo: __deepcopy__ interface impl"""
|
||||
result = self.__copy__()
|
||||
memo[id(self)] = result
|
||||
result._savedFormaterList = self._savedFormaterList.copy()
|
||||
return result
|
||||
|
||||
|
||||
def ChangelogFormaterRecordType(Klass: Type[T_ChangelogFormater]) -> Type[T_ChangelogFormater]:
|
||||
"""Decorator function that registers formater implementation in factory
|
||||
Args:
|
||||
Klass: class to register in the factory
|
||||
Returns:
|
||||
untouched class"""
|
||||
ChangeLogFactory.ar_FormaterKlass.add(Klass)
|
||||
ChangelogFactory.RegisterBaseFormater(Klass)
|
||||
return Klass
|
||||
|
||||
|
||||
def _ChangelogFormaterRecordType(Klass: type) -> type:
|
||||
def _ChangelogFormaterRecordType(Klass: Type[T_ChangelogFormater]) -> Type[T_ChangelogFormater]:
|
||||
"""Internal decorator function that registers formater implementation in factory
|
||||
Args:
|
||||
Klass: class to register in the factory
|
||||
Returns:
|
||||
untouched class"""
|
||||
_savedFormaterList.add(Klass)
|
||||
cast(ChangelogFactory[ChangelogFormater], ChangelogFactory).ar_SavedFormaterKlass.add(Klass)
|
||||
return ChangelogFormaterRecordType(Klass)
|
||||
|
||||
|
||||
class ChangeLogFormater(ABC):
|
||||
"""ChangeLogFormater class
|
||||
class ChangelogFormater(ABC):
|
||||
"""ChangelogFormater class
|
||||
|
||||
This class is the base formater class.
|
||||
This class is the formater base class.
|
||||
|
||||
This class is for:
|
||||
|
||||
@@ -58,16 +115,15 @@ class ChangeLogFormater(ABC):
|
||||
///
|
||||
"""
|
||||
|
||||
prefix: None | str = None
|
||||
title: None | str = None
|
||||
keywords: None | list[str] = None
|
||||
priority: int = 0
|
||||
prefix: ClassVar[Optional[str]] = None
|
||||
title: ClassVar[Optional[str]] = None
|
||||
keywords: ClassVar[Optional[list[str]]] = None
|
||||
priority: ClassVar[int] = 0
|
||||
_lines: List[None | str] = []
|
||||
|
||||
_lines: list[str] = []
|
||||
|
||||
def __init__(self):
|
||||
"""ChangeLogFormater class constructor"""
|
||||
self._lines = []
|
||||
def __init__(self) -> None:
|
||||
"""ChangelogFormater class constructor"""
|
||||
self._lines: List[None | str] = []
|
||||
|
||||
def Clear(self) -> None:
|
||||
"""Clear the formater content"""
|
||||
@@ -103,7 +159,7 @@ class ChangeLogFormater(ABC):
|
||||
return full_lines
|
||||
|
||||
@classmethod
|
||||
def CheckLine(cls, content: str) -> re.Match:
|
||||
def CheckLine(cls, content: str) -> None | Match[str]:
|
||||
"""Check if a line match the current formater (lazy identification)
|
||||
|
||||
/// warning
|
||||
@@ -116,7 +172,7 @@ class ChangeLogFormater(ABC):
|
||||
Returns:
|
||||
match object
|
||||
"""
|
||||
regex = re.compile(r"^(?:-\s+)?(?:{0})(?:\((.*)\))?(?::)(?:\s*)([^\s].+)".format(cls.prefix))
|
||||
regex = _compile(rf"^(?:-\s+)?(?:{cls.prefix})(?:\((.*)\))?(?::)(?:\s*)([^\s].+)")
|
||||
_match = regex.match(content)
|
||||
return _match
|
||||
|
||||
@@ -132,55 +188,68 @@ class ChangeLogFormater(ABC):
|
||||
True if a keyword has matched, False otherwise
|
||||
"""
|
||||
keyword_list = cls.keywords
|
||||
for _keyword in keyword_list:
|
||||
if (_keyword != "") and re.search(_keyword, content):
|
||||
return True
|
||||
if keyword_list:
|
||||
for _keyword in keyword_list:
|
||||
if _keyword and search(_keyword, content):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class ChangeLogFactory:
|
||||
class ChangelogFactory(Generic[T_ChangelogFormater]):
|
||||
"""The main changelog class"""
|
||||
|
||||
ar_FormaterKlass: set[type[ChangeLogFormater]] = set()
|
||||
ar_Formater: None | dict[ChangeLogFormater] = None
|
||||
ar_SavedFormaterKlass: ClassVar[_ChangelogFormatersCtx[ChangelogFormater]] = _ChangelogFormatersCtx[ChangelogFormater]()
|
||||
ar_FormaterKlass: _ChangelogFormatersCtx[T_ChangelogFormater] = _ChangelogFormatersCtx[T_ChangelogFormater]()
|
||||
|
||||
ar_Formater: Dict[str, T_ChangelogFormater] = {}
|
||||
checkCommentPattern: str = r"^[ \t]*(?:\/\/|#)"
|
||||
|
||||
def __init__(self, ChangelogString: None | str = None):
|
||||
"""Main ChangeLogFormater class constructor
|
||||
def __init__(self, ChangelogString: Optional[str] = None) -> None:
|
||||
"""Main ChangelogFormater class constructor
|
||||
|
||||
Args:
|
||||
ChangelogString: optionnal input string to start with
|
||||
ChangelogString: optional input string to be processed
|
||||
"""
|
||||
self.ar_Formater = dict()
|
||||
self.ar_FormaterKlass = self.ar_FormaterKlass.copy()
|
||||
self.ar_Formater: Dict[str, T_ChangelogFormater] = {}
|
||||
self.ar_FormaterKlass = deepcopy(type(self).ar_FormaterKlass)
|
||||
|
||||
for FormaterKlass in self.ar_FormaterKlass:
|
||||
for FormaterKlass in self.ar_FormaterKlass.get():
|
||||
self.ar_Formater[FormaterKlass.__name__] = FormaterKlass()
|
||||
|
||||
# missing mypy coverage here because of internal bad isinstance() handling
|
||||
# could be fixed using 'type(ChangelogString) is str' but then quality check will bad
|
||||
# so let quality advise
|
||||
if isinstance(ChangelogString, str):
|
||||
self.ProcessFullChangelog(ChangelogString)
|
||||
|
||||
def ResetFormaterList(self=None) -> None | ChangeLogFactory:
|
||||
"""Reset the formater class list to original
|
||||
|
||||
This method can be call both from class or from instance.
|
||||
|
||||
> If call from class it will reset the whole list.
|
||||
|
||||
> If call from instance only the instance will be reseted.
|
||||
|
||||
def ResetFormaterList(self) -> ChangelogFactory[T_ChangelogFormater]:
|
||||
"""Reset the formater class list to original (Instance wise)
|
||||
Returns:
|
||||
self for convenience or None if call from class
|
||||
self for convenience
|
||||
"""
|
||||
if self is not None:
|
||||
self.ar_FormaterKlass = _savedFormaterList.copy()
|
||||
self.ar_Formater = {}
|
||||
for FormaterKlass in self.ar_FormaterKlass:
|
||||
self.ar_Formater[FormaterKlass.__name__] = FormaterKlass()
|
||||
ChangeLogFactory.ar_FormaterKlass = _savedFormaterList.copy()
|
||||
return None
|
||||
self.ar_FormaterKlass: T_ChangelogFormater = deepcopy(
|
||||
cast(_ChangelogFormatersCtx[T_ChangelogFormater], ChangelogFactory.ar_SavedFormaterKlass)
|
||||
)
|
||||
self.ar_Formater = {}
|
||||
for FormaterKlass in self.ar_FormaterKlass.get():
|
||||
self.ar_Formater[FormaterKlass.__name__] = FormaterKlass()
|
||||
return self
|
||||
|
||||
def RegisterFormater(self, FormaterKlass: ChangeLogFormater) -> None:
|
||||
@classmethod
|
||||
def RegisterBaseFormater(cls, FormaterKlass: Type[T_ChangelogFormater]) -> None:
|
||||
"""Register a new formater in the current instance
|
||||
|
||||
Args:
|
||||
FormaterKlass: class of the formater to be added
|
||||
"""
|
||||
cls.ar_FormaterKlass.add(FormaterKlass)
|
||||
|
||||
@classmethod
|
||||
def ResetBaseFormaterList(cls) -> None:
|
||||
"""Reset the formater class list to original (BaseClass wise)"""
|
||||
cls.ar_FormaterKlass = deepcopy(cls.ar_SavedFormaterKlass)
|
||||
|
||||
def RegisterFormater(self, FormaterKlass: Type[T_ChangelogFormater]) -> ChangelogFactory[T_ChangelogFormater]:
|
||||
"""Register a new formater in the current instance
|
||||
|
||||
Args:
|
||||
@@ -192,7 +261,7 @@ class ChangeLogFactory:
|
||||
self.ar_Formater[FormaterKlass.__name__] = FormaterKlass()
|
||||
return self
|
||||
|
||||
def unRegisterFormater(self, FormaterKlass: ChangeLogFormater) -> None:
|
||||
def unRegisterFormater(self, FormaterKlass: Type[T_ChangelogFormater]) -> ChangelogFactory[T_ChangelogFormater]:
|
||||
"""unRegister a new formater in the current instance
|
||||
|
||||
Args:
|
||||
@@ -204,7 +273,7 @@ class ChangeLogFactory:
|
||||
del self.ar_Formater[FormaterKlass.__name__]
|
||||
return self
|
||||
|
||||
def Clear(self) -> ChangeLogFactory:
|
||||
def Clear(self) -> ChangelogFactory[T_ChangelogFormater]:
|
||||
"""Clear internal memory
|
||||
Returns:
|
||||
self for convenience
|
||||
@@ -220,14 +289,16 @@ class ChangeLogFactory:
|
||||
If a matching formater is found, line is inserted.
|
||||
|
||||
Args:
|
||||
RawChangelogLine: line to parse
|
||||
RawChangelogLine: line to process
|
||||
Returns:
|
||||
True if successfully matched, False otherwise
|
||||
"""
|
||||
for formater in sorted(self.ar_Formater.values(), key=lambda x: x.priority):
|
||||
content = formater.CheckLine(RawChangelogLine)
|
||||
if content is not None:
|
||||
formater.PushLine(content.group(2))
|
||||
content: Optional[Match[str]] = formater.CheckLine(RawChangelogLine)
|
||||
# missing mypy coverage here because of internal bad isinstance() handling AND Match type
|
||||
if isinstance(content, Match) and (len(content.groups()) == 2):
|
||||
res: str = content.group(2)
|
||||
formater.PushLine(res)
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -239,7 +310,7 @@ class ChangeLogFactory:
|
||||
If a matching formater is found, line is inserted.
|
||||
|
||||
Args:
|
||||
RawChangelogLine: line to parse
|
||||
RawChangelogLine: line to process
|
||||
Returns:
|
||||
True if successfully matched, False otherwise
|
||||
"""
|
||||
@@ -248,22 +319,25 @@ class ChangeLogFactory:
|
||||
formater.PushLine(RawChangelogLine)
|
||||
return True
|
||||
|
||||
self.ar_Formater[ChangeLogFormater_others.__name__].PushLine(RawChangelogLine)
|
||||
self.ar_Formater[ChangelogFormater_others.__name__].PushLine(RawChangelogLine)
|
||||
return False
|
||||
|
||||
def ProcessFullChangelog(self, RawChangelogMessage: str) -> ChangeLogFactory:
|
||||
def ProcessFullChangelog(self, RawChangelogMessage: str) -> ChangelogFactory[T_ChangelogFormater]:
|
||||
"""Process all input lines
|
||||
|
||||
This function handles the main 2-round changes search algo.
|
||||
It 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 #
|
||||
|
||||
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)
|
||||
RawChangelogMessage: The full raw changelog to be processed
|
||||
Returns:
|
||||
self for convenience
|
||||
"""
|
||||
@@ -272,7 +346,7 @@ class ChangeLogFactory:
|
||||
|
||||
for line in RawChangelogMessage.split("\n"):
|
||||
lineWordsCount = len(line.split())
|
||||
if (lineWordsCount > 1) and (not re.match(self.checkCommentPattern, line)):
|
||||
if (lineWordsCount > 1) and (not match(self.checkCommentPattern, line)):
|
||||
if self._ProcessLineMain(line) is True:
|
||||
continue
|
||||
if lineWordsCount > 2:
|
||||
@@ -292,7 +366,8 @@ class ChangeLogFactory:
|
||||
"""
|
||||
full_changelog = ""
|
||||
for formater in sorted(self.ar_Formater.values(), key=lambda x: x.priority, reverse=True):
|
||||
if (include_unknown is False) and (isinstance(formater, ChangeLogFormater_others)):
|
||||
# missing mypy coverage here because of internal bad isinstance() handling
|
||||
if (include_unknown is False) and (isinstance(formater, ChangelogFormater_others)):
|
||||
continue
|
||||
full_changelog = full_changelog + formater.Render()
|
||||
|
||||
@@ -334,7 +409,7 @@ for RecordType, Config in {
|
||||
"Documentations :book: :",
|
||||
),
|
||||
"style": ( 5, ["beautify", ],
|
||||
"Style :art: :",
|
||||
"Style :art: :",
|
||||
),
|
||||
"refactor": ( 0, [],
|
||||
"Refactorings :recycle: :"
|
||||
@@ -351,10 +426,12 @@ for RecordType, Config in {
|
||||
# fmt: on
|
||||
}.items():
|
||||
# then we instantiate all of them
|
||||
_name = f"ChangeLogFormater_{RecordType}"
|
||||
_tmp = globals()[_name] = type(
|
||||
_name = f"ChangelogFormater_{RecordType}"
|
||||
|
||||
# can not change globals definition so mypy will keep complaining
|
||||
_tmp = type(
|
||||
_name,
|
||||
(ChangeLogFormater,),
|
||||
(ChangelogFormater,),
|
||||
{
|
||||
"prefix": RecordType,
|
||||
"title": Config[2],
|
||||
@@ -362,18 +439,19 @@ for RecordType, Config in {
|
||||
"priority": Config[0],
|
||||
},
|
||||
)
|
||||
ChangeLogFactory.ar_FormaterKlass.add(_tmp)
|
||||
_savedFormaterList.add(_tmp)
|
||||
globals()[_name] = _tmp
|
||||
cast(ChangelogFactory[ChangelogFormater], ChangelogFactory).RegisterBaseFormater(_tmp)
|
||||
cast(ChangelogFactory[ChangelogFormater], ChangelogFactory).ar_SavedFormaterKlass.add(_tmp)
|
||||
|
||||
|
||||
@_ChangelogFormaterRecordType
|
||||
class ChangeLogFormater_revert(ChangeLogFormater):
|
||||
class ChangelogFormater_revert(ChangelogFormater):
|
||||
"""Revert scope formater"""
|
||||
|
||||
prefix: str = "revert"
|
||||
title: str = "Reverts :back: :"
|
||||
keywords: list[str] = ["revert", "fallback"]
|
||||
priority: int = 0
|
||||
prefix: ClassVar[Optional[str]] = "revert"
|
||||
title: ClassVar[Optional[str]] = "Reverts :back: :"
|
||||
keywords: ClassVar[Optional[List[str]]] = ["revert", "fallback"]
|
||||
priority: ClassVar[int] = 0
|
||||
|
||||
def RenderLines(self) -> str:
|
||||
"""Render all lines
|
||||
@@ -387,10 +465,10 @@ class ChangeLogFormater_revert(ChangeLogFormater):
|
||||
|
||||
|
||||
@_ChangelogFormaterRecordType
|
||||
class ChangeLogFormater_others(ChangeLogFormater):
|
||||
class ChangelogFormater_others(ChangelogFormater):
|
||||
"""Others / unknown scope formater"""
|
||||
|
||||
prefix: str = "other"
|
||||
title: str = "Others :question: :"
|
||||
keywords: list[str] = [""]
|
||||
priority: int = -20
|
||||
prefix: ClassVar[Optional[str]] = "other"
|
||||
title: ClassVar[Optional[str]] = "Others :question: :"
|
||||
keywords: ClassVar[Optional[List[str]]] = [""]
|
||||
priority: ClassVar[int] = -20
|
||||
|
||||
1
src/pychangelogfactory/py.typed
Normal file
1
src/pychangelogfactory/py.typed
Normal file
@@ -0,0 +1 @@
|
||||
# PlaceHolder
|
||||
@@ -8,15 +8,15 @@
|
||||
|
||||
import unittest
|
||||
|
||||
from src.pychangelogfactory import ChangeLogFormater, ChangeLogFactory, ChangelogFormaterRecordType
|
||||
from src.pychangelogfactory import ChangelogFormater, ChangelogFactory, ChangelogFormaterRecordType
|
||||
|
||||
|
||||
class Testtest_module(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ChangeLogFactory.ResetFormaterList()
|
||||
ChangelogFactory.ResetBaseFormaterList()
|
||||
|
||||
def simplegeneration(self, inputstr, teststrs: list[str], withunknown: bool = False):
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(inputstr)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=withunknown)
|
||||
for test in teststrs:
|
||||
@@ -25,7 +25,7 @@ class Testtest_module(unittest.TestCase):
|
||||
def test_simplegeneration_ignored2(self):
|
||||
raw = "break: testbreak break" + "\n" + "#doc: testdoc doc" + "\n" + "#style: teststyle beautify" + "\n" + "//test: testtest check"
|
||||
|
||||
hdlr = ChangeLogFactory(raw)
|
||||
hdlr = ChangelogFactory(raw)
|
||||
changelog = hdlr.RenderFullChangelog()
|
||||
|
||||
self.assertIn("testbreak", changelog)
|
||||
@@ -36,7 +36,7 @@ class Testtest_module(unittest.TestCase):
|
||||
def test_simplegeneration_ignored(self):
|
||||
raw = "break: testbreak" + "\n" + "#doc: testdoc" + "\n" + "#style: teststyle" + "\n" + "//test: testtest"
|
||||
|
||||
hdlr = ChangeLogFactory(raw)
|
||||
hdlr = ChangelogFactory(raw)
|
||||
changelog = hdlr.RenderFullChangelog()
|
||||
self.assertIn("testbreak", changelog)
|
||||
self.assertNotIn("testdoc", changelog)
|
||||
@@ -45,7 +45,7 @@ class Testtest_module(unittest.TestCase):
|
||||
|
||||
def test_simplegeneration_order(self):
|
||||
raw = "break: testbreak" + "\n" + "doc: testdoc" + "\n" + "style: teststyle" + "\n" + "test: testtest"
|
||||
hdlr = ChangeLogFactory(raw)
|
||||
hdlr = ChangelogFactory(raw)
|
||||
changelog = hdlr.RenderFullChangelog().splitlines()
|
||||
self.assertIn("testbreak", changelog[1])
|
||||
self.assertIn("teststyle", changelog[3])
|
||||
@@ -156,22 +156,22 @@ class Testtest_module(unittest.TestCase):
|
||||
# fmt: on
|
||||
|
||||
def test_sample(self):
|
||||
hdlr = ChangeLogFactory(self.raw_changelog)
|
||||
hdlr = ChangelogFactory(self.raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, self.expected_formated)
|
||||
|
||||
def test_sample_aio(self):
|
||||
changelog = ChangeLogFactory(self.raw_changelog).RenderFullChangelog(include_unknown=True)
|
||||
changelog = ChangelogFactory(self.raw_changelog).RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, self.expected_formated)
|
||||
|
||||
def test_sample_exploded(self):
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(self.raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, self.expected_formated)
|
||||
|
||||
def test_sample_clear(self):
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(self.raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, self.expected_formated)
|
||||
@@ -182,7 +182,7 @@ class Testtest_module(unittest.TestCase):
|
||||
|
||||
class Testtest_module_othercontext(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ChangeLogFactory.ResetFormaterList()
|
||||
ChangelogFactory.ResetBaseFormaterList()
|
||||
|
||||
def test_custom(self):
|
||||
"""
|
||||
@@ -190,7 +190,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
"""
|
||||
|
||||
@ChangelogFormaterRecordType
|
||||
class ChangeLogFormater_TEST(ChangeLogFormater):
|
||||
class ChangelogFormater_TEST(ChangelogFormater):
|
||||
"""My formater"""
|
||||
|
||||
prefix: str = "mytag"
|
||||
@@ -211,7 +211,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
hdlr = ChangeLogFactory(raw_changelog)
|
||||
hdlr = ChangelogFactory(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, expected_formated_orig)
|
||||
|
||||
@@ -219,7 +219,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
2nd PART: cheking the custom formater is still here after new object creation
|
||||
"""
|
||||
|
||||
hdlr = ChangeLogFactory(raw_changelog)
|
||||
hdlr = ChangelogFactory(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, expected_formated_orig)
|
||||
|
||||
@@ -227,8 +227,8 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
3rd PART: removing the custom formater at runtime
|
||||
"""
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr.unRegisterFormater(ChangeLogFormater_TEST)
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.unRegisterFormater(ChangelogFormater_TEST)
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
|
||||
@@ -248,7 +248,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
4th PART: checking it is back when create new obj
|
||||
"""
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, expected_formated_orig)
|
||||
@@ -257,7 +257,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
3.1rd PART: removing the custom formater at runtime
|
||||
"""
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ResetFormaterList()
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
@@ -267,7 +267,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
4.1th PART: checking it is back when create new obj
|
||||
"""
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, expected_formated_orig)
|
||||
@@ -275,8 +275,8 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
"""
|
||||
5th PART: reseting class list globally
|
||||
"""
|
||||
ChangeLogFactory.ResetFormaterList()
|
||||
hdlr = ChangeLogFactory()
|
||||
ChangelogFactory.ResetBaseFormaterList()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, expected_formated)
|
||||
@@ -284,7 +284,7 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
"""
|
||||
6th PART: checking it is still not here
|
||||
"""
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
self.assertEqual(changelog, expected_formated)
|
||||
@@ -292,10 +292,10 @@ class Testtest_module_othercontext(unittest.TestCase):
|
||||
|
||||
class Testtest_module_othercontext2(unittest.TestCase):
|
||||
def setUp(self):
|
||||
ChangeLogFactory.ResetFormaterList()
|
||||
ChangelogFactory.ResetBaseFormaterList()
|
||||
|
||||
def test_custom2(self):
|
||||
class ChangeLogFormater_TEST2(ChangeLogFormater):
|
||||
class ChangelogFormater_TEST2(ChangelogFormater):
|
||||
"""My formater"""
|
||||
|
||||
prefix: str = "mytag"
|
||||
@@ -316,9 +316,9 @@ class Testtest_module_othercontext2(unittest.TestCase):
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
hdlr = ChangeLogFactory()
|
||||
hdlr = ChangelogFactory()
|
||||
|
||||
hdlr.RegisterFormater(ChangeLogFormater_TEST2)
|
||||
hdlr.RegisterFormater(ChangelogFormater_TEST2)
|
||||
|
||||
hdlr.ProcessFullChangelog(raw_changelog)
|
||||
changelog = hdlr.RenderFullChangelog(include_unknown=True)
|
||||
|
||||
Reference in New Issue
Block a user