Compare commits

...

54 Commits

Author SHA1 Message Date
fc32bafee8 Merge pull request 'Update Jenkinsfile' (#18) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/18
new-tag:0.4
2024-10-12 16:36:45 +02:00
79fb84f2bc Update Jenkinsfile 2024-10-12 16:33:30 +02:00
8c2f0f2e4f Update Jenkinsfile 2024-10-12 16:33:05 +02:00
e440880243 Merge pull request 'dev' (#17) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/17
new-tag:0.3.7
2023-11-28 13:34:31 +01:00
aa22e534be fix import and quality warnings 2023-11-28 12:30:04 +00:00
d3f5587e16 fix embedded helper import (tomli) 2023-11-28 12:19:19 +00:00
e8dca96b59 update way of importing tomli / tomllib for legacy compatibility
remove unused RUN_xx.launch script
2023-11-28 12:15:09 +00:00
31105cde3b implement installdeps feature 2023-11-28 12:03:36 +00:00
63c881c318 Merge pull request 'dev' (#16) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/16
new-tag:0.3.6
2023-11-06 16:24:49 +01:00
cclecle
16c653e388 update from last project template 2023-11-06 15:15:39 +00:00
cclecle
a5f4664d0a split quality & types .launch scripts 2023-11-06 15:13:55 +00:00
fe65553f7c Merge pull request 'fix wrong Coverage configuration (now in project specific .toml)' (#15) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/15
new-tag:0.3.5
2023-11-06 14:40:17 +01:00
cclecle
aeccb8b813 fix wrong Coverage configuration (now in project specific .toml) 2023-11-06 13:35:55 +00:00
d7fe379563 Merge pull request 'dev' (#14) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/14
new-tag:0.3.4
2023-11-06 14:33:31 +01:00
cclecle
f5f17be805 clean-up CoverageProcess (not used anymore) 2023-11-06 13:29:43 +00:00
cclecle
b91708491a revert coverage cmd order
add Process subclass to handle Process in coverage context (unittest)
2023-11-06 11:58:48 +00:00
c3f1fe224d Merge pull request 'fix coverage: swap save and combine' (#13) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/13
new-tag:0.3.3
2023-11-06 12:15:51 +01:00
cclecle
8868f77ef3 fix coverage: swap save and combine 2023-11-06 11:13:16 +00:00
cdf43418fd Merge pull request 'enable coverage config_file usage (hopefully .toml)' (#12) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/12
new-tag:0.3.2
2023-11-06 11:55:11 +01:00
cclecle
0594c29334 enable coverage config_file usage (hopefully .toml) 2023-11-06 10:51:39 +00:00
575ace2f94 Merge pull request 'update coverage: add cov.combine()' (#11) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/11
new-tag:0.3.1
2023-11-06 11:04:35 +01:00
cclecle
0fa9f8d779 update coverage: add cov.combine() 2023-11-06 10:01:01 +00:00
f612a58cff Merge pull request 'dev' (#10) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/10
new-tag:0.3
2023-10-14 22:25:07 +02:00
cclecle
6fcc465d58 fix: debian distro 2023-10-14 21:19:40 +01:00
cclecle
01aa492d99 feat: add python 3.10 and 3.11 compatibility
fix: add missing tomli dep (for python 3.11+)
2023-10-14 21:15:46 +01:00
cclecle
f1252f2bd9 add missing tomli dependency 2023-10-14 14:19:04 +01:00
589be8e375 Merge pull request 'fix: put right pylint version also for this package CICD deps' (#9) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/9
new-tag:0.2.4
2023-10-04 16:33:01 +02:00
cclecle
021ac25f22 fix: put right pylint version also for this package CICD deps 2023-10-04 15:27:34 +01:00
48afb560ae Merge pull request 'chore: limit pylint to < 3 to avoid incompatibilities' (#8) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/8
new-tag:0.2.3
2023-10-04 16:23:32 +02:00
cclecle
1778d10685 chore: limit pylint to < 3 to avoid incompatibilities 2023-10-04 15:20:08 +01:00
4263bfc299 Merge pull request 'fix doc gen' (#7) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/7
new-tag:0.2.2
2023-09-30 01:51:05 +02:00
cclecle
d4b09d5d7a fix doc gen 2023-09-30 00:48:15 +01:00
ad32aa256d Merge pull request 'dev' (#6) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/6
new-tag:0.2.1
2023-09-30 01:34:01 +02:00
cclecle
4608fe637e update usage 2023-09-30 00:31:17 +01:00
cclecle
be511c366d fix (readme): doc link to master
chore (readme): repository to fixed (real) one
2023-09-30 00:24:19 +01:00
a1447c9f0c Merge pull request 'preparing pypi publishing' (#5) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/5
new-tag:0.2.0
2023-09-30 00:29:50 +02:00
cclecle
dbb16a07e7 preparing pypi publishing 2023-09-29 23:26:52 +01:00
687b5ae39d Merge pull request 'dev' (#4) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/4
new-tag:0.1.3
2023-09-29 00:46:03 +02:00
cclecle
d662247473 ignore temp test directory from git 2023-09-28 23:39:09 +01:00
cclecle
7f10031e6d fix project path 2023-09-28 00:18:06 +01:00
cclecle
019dfed113 try to fix wrong directory 2023-09-28 00:07:31 +01:00
07035023a5 Merge pull request 'fix arg naming convention' (#3) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/3
new-tag:0.1.2
2023-09-28 00:48:53 +02:00
cclecle
67478c0fa2 fix arg naming convention 2023-09-27 23:46:22 +01:00
9c7624d068 Merge pull request 'fix argument default value' (#2) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/2
new-tag:0.1.1
2023-09-28 00:32:21 +02:00
cclecle
05141eeb3f fix argument default value 2023-09-27 23:29:14 +01:00
22213d32ed Merge pull request 'dev' (#1) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/pulls/1
new-tag:0.1.0
2023-09-28 00:11:30 +02:00
cclecle
529a3e9922 fix unit-test and new quality issues 2023-09-27 22:45:56 +01:00
cclecle
f5b7931ed7 fix unit tests 2023-09-27 22:39:52 +01:00
cclecle
6a7be051bb chore: fix all quality issues 2023-09-27 22:32:47 +01:00
cclecle
3363792810 chore: fix more quality issues 2023-09-27 21:10:36 +01:00
cclecle
00df364a45 chore: apply quality improvements 2023-09-27 20:53:05 +01:00
cclecle
60aeac2040 chore: update copyright 2023-09-27 20:41:53 +01:00
cclecle
a44b344e0d chore: switch to Tap rather than argparse 2023-09-27 20:32:58 +01:00
cclecle
7aa3856d40 fix: add missing comma in pyproject.toml 2023-09-27 20:27:40 +01:00
22 changed files with 434 additions and 262 deletions

1
.gitignore vendored
View File

@@ -41,5 +41,6 @@ docs
helpers-results
.coverage
/.mypy_cache/
test/tmp
.coverage
.mypy_cache

View File

@@ -6,13 +6,9 @@
# 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 debian:bullseye-slim
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update
RUN apt install -y python3.9 python3-virtualenv python3-pip git python3.9-venv weasyprint
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install --upgrade virtualenv
RUN python3 -m pip install --upgrade setuptools wheel build
RUN apt install -y python3.11 python3-virtualenv python3-pip git python3-venv weasyprint

18
Jenkinsfile vendored
View File

@@ -27,7 +27,7 @@ def _bDraft = false
// release content / changelog management
def _bAutoChangelog = true //Not supported yet
def _ReleaseContent_Title = "# _CI/CD Automatic Release_"
def bPushMasterOnPypi = false
def bPushMasterOnPypi = true
// full rebuild toogle
def _bFullRebuilt = true
def _MkDocsWebURL = "dabauto--mkdocs-web.dmz.chacha.home/mkdocs-web/"
@@ -184,7 +184,7 @@ pipeline {
sh("virtualenv --pip=embed --setuptools=embed --wheel=embed --no-periodic-update --activators bash,python TOOLS_ENV")
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade setuptools build pip")
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade 'copier==8.*' jinja2-slug toml")
sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade 'copier==9.*' jinja2-slug toml")
sh(". ~/TOOLS_ENV/bin/activate && pip install simple_rest_client requests twine packaging")
@@ -424,8 +424,16 @@ pipeline {
post {
always {
dir("gitrepo") {
publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/types_check/cobertura.xml")]
junit 'helpers-results/types_check/junit.xml'
//publish coverage
recordCoverage( sourceDirectories: [[path: 'src']],
tools: [[parser: 'COBERTURA', pattern: 'helpers-results/types_check/cobertura.xml']],
id: 'COBERTURA', name: 'COBERTURA Coverage',
sourceCodeRetention: 'EVERY_BUILD',)
//add type check to junit result set
junit 'helpers-results/types_check/junit.xml'
//publish html reports files
publishHTML([
reportDir: "helpers-results/quality_check",
reportFiles: "report.html",
@@ -535,7 +543,7 @@ pipeline {
dir("gitrepo") {
junit 'helpers-results/unit_test/*.xml'
// using cobertura format (= coverage xml format)
publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/unit_test_coverage/test_coverage.xml")]
recordCoverage(tools: [[parser: 'COBERTURA', pattern: 'helpers-results/cl_unit_test_coverage/test_coverage.xml']])
publishHTML([
reportDir: "helpers-results/unit_test_coverage",
reportFiles: "index.html",

View File

@@ -1,53 +1,13 @@
![](https://chacha.ddns.net/jenkins/buildStatus/icon?subject=status&status=active&color=seagreen)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?subject=doc&status=MkDocs&color=blue)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?subject=jenkins-unittest&job={{repository}}-{{branch}})
![](https://chacha.ddns.net/jenkins/buildStatus/icon?job={{repository}}-{{branch}}&build=0&config=coverage)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?job={{repository}}-{{branch}}&build=0&config=maintainability)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?job={{repository}}-{{branch}}&build=0&config=quality)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?subject=jenkins-unittest&job=chacha_cicd_helper-{{branch}})
![](https://chacha.ddns.net/jenkins/buildStatus/icon?job=chacha_cicd_helper-{{branch}}&build=0&config=coverage)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?job=chacha_cicd_helper-{{branch}}&build=0&config=maintainability)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?job=chacha_cicd_helper-{{branch}}&build=0&config=quality)
![](https://chacha.ddns.net/jenkins/buildStatus/icon?subject=licence&status=CC%20BY-NC-SA%204.0&color=teal)
![](docs-static/Library.jpg)
# Python project template
A set of tool to help continuous integration.
A nice template to start blank python projets.
This template automate a lot of handy things and allow CI/CD automatic releases generation.
It is also collectings data to feed Jenkins build.
Checkout [Latest Documentation](https://chacha.ddns.net/mkdocs-web/chacha/{{repository}}/{{branch}}/latest/).
## Features
### Generic pipeline skeleton:
- Prepare
- GetCode
- BuildPackage
- Install
- CheckCode
- PlotMetrics
- RunUnitTests
- GenDOC
- PostRelease
### CI/CD Environment
- Jenkins
- Gitea (with patch for dynamic Readme variables: https://chacha.ddns.net/gitea/chacha/GiteaMarkupVariable)
- Docker
- MkDocsWeb
### CI/CD Helper libs
- VirtualEnv
- Changelog generation based on commits
- copier
- pylint + pylint_json2html
- mypy
- unittest + xmlrunner + junitparser + junit2htmlreport
- mkdocs
### Python project
- Full .toml implementation
- .whl automatic generation
- dynamic versionning using git repository
- embedded unit-test
Checkout [Latest Documentation](https://chacha.ddns.net/mkdocs-web/chacha/chacha_cicd_helper/master/latest/).

View File

@@ -9,7 +9,7 @@
</listAttribute>
<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.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--quality-check"/>
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="chacha_cicd_helper"/>
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>

View File

@@ -9,7 +9,7 @@
</listAttribute>
<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="--changelog-gen"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--type-check"/>
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="chacha_cicd_helper"/>
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>

View File

@@ -1,16 +1,45 @@
# Usage
## Pulvinar dolor
Donec dapibus est fermentum justo volutpat condimentum. Integer quis nunc neque. Donec dictum vehicula justo, in facilisis ex tincidunt in.
Vivamus sollicitudin sem dui, id mollis orci facilisis ut. Proin sed pulvinar dolor. Donec volutpat commodo urna imperdiet pulvinar. Fusce eget aliquam risus.
Vivamus viverra luctus ex, in finibus mi. Nullam elementum dapibus mollis. Ut suscipit volutpat ex, quis feugiat lacus consectetur eu.
/// note
This helper aim to be used by pychachadummyproject template instantiation.
///
## Condimentum faucibus
Quisque auctor egestas sem, luctus suscipit ex maximus vitae. Duis facilisis augue et condimentum faucibus.
Donec cursus, enim a sagittis egestas, lectus lorem eleifend libero, at tincidunt leo magna at libero.
Nunc eros velit, suscipit luctus tempor vel, finibus et est. Curabitur efficitur pretium pulvinar.
Donec urna lectus, vulputate quis turpis sed, placerat congue urna. Phasellus aliquet fermentum quam, non auctor elit porta nec. Morbi eu ligula at nisl ultricies condimentum vitae id ante.
```console
/> <python_bin> -m chacha_cicd_helper -h
usage: chacha-cicd-helper [-pp PROJECTPATH] [-tc] [-ut] [-cc] [-qc] [-dg] [-pdf] [-cpc] [-h]
## Aliquam lacinia
In volutpat lorem ex, et fringilla nibh faucibus quis. Mauris et arcu elementum, auctor dui vitae, egestas arcu. Duis sit amet aliquam quam.
Phasellus a odio turpis. Etiam tristique mi eu enim varius, eget facilisis est vestibulum. Aliquam lacinia nec purus sed luctus. Cras at laoreet erat.
A bundle of cicd helper tools
optional arguments:
-pp PROJECTPATH, --projectpath PROJECTPATH
path of the python project to process
-tc, --typecheck enable static typing check
-ut, --unittest enable unit-test
-cc, --coveragecheck enable unit-test coverage check (requires unit-test)
-qc, --qualitycheck enable code quality check
-dg, --docgen enable documentation generation using MkDoc
-pdf, --docgenpdf enable pdf documentation export (requires doc-gen)
-cpc, --complexitycheck
enable complexity check
-h, --help show this help message and exit
```
Calling those commands will create a directory called `helpers-results` in `<PROJECTPATH>` (or in the current directory).
This directory will contain some of the following subdirectory, depending on what enabled:
| Directory | Content |
|-----------------------|---------------------------------------------|
| cl_complexity_check | code complexity measurement report |
| cl_doc_gen | mkdocs documentation output (html + pdf) |
| cl_quality_check | quality check reports |
| cl_quality_check | quality check reports |
| cl_types_check | type check reports |
| cl_unit_test | unit test reports |
| cl_unit_test_coverage | unit test coverage reports |
| cl_unit_test_full | full unitest report (merged) |
/// warning
<docgen> needs a docs-static directory in the target project root. Then one can put any .md file inside.
///

View File

@@ -10,11 +10,17 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from pathlib import Path
import tomli
b_use_tomli=False
try:
import tomllib
except ImportError:
import tomli
b_use_tomli=True
import argparse
import os
import logging
import sys
if __package__ == "helpers":
# when calling the module from: > python -m helpers
@@ -37,7 +43,10 @@ if __name__ == "__main__":
project_rootdir_path = Path(__file__).parent.parent.absolute()
with open(project_rootdir_path / "pyproject.toml", mode="rb") as fp:
pyproject = tomli.load(fp)
if b_use_tomli:
pyproject = tomli.load(fp)
else:
pyproject = tomllib.load(fp)
parser = argparse.ArgumentParser(
prog="continuous-integration-helper", description="A tiny set of scripts to help continous integration on python"

View File

@@ -64,6 +64,7 @@ class quality_check(helper_withresults_base):
"--load-plugins=pylint.extensions.mccabe",
"--output-format=json,parseable",
"--disable=invalid-name,too-few-public-methods,too-many-arguments", # ignore
"--extension-pkg-whitelist=mypy",
"--ignore=_version.py",
"--reports=y",
"--score=yes",

View File

@@ -1,11 +1,11 @@
docs_dir: docs
site_name: 'chacha_cicd_helper'
site_url: 'https://chacha.ddns.net/mkdocs-web/chacha/chacha_cicd_helper/latest/'
site_description: 'A bundle of cicd helper tools'
site_author: 'chacha'
repo_url: 'https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper'
site_name: chacha_cicd_helper
site_url: https://chacha.ddns.net/mkdocs-web/chacha/chacha_cicd_helper/latest/
site_description: A bundle of cicd helper tools
site_author: chacha
repo_url: https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper
use_directory_urls: false
copyright: 'CC BY-NC-SA 4.0'
copyright: CC BY-NC-SA 4.0
theme:
name: material
features:
@@ -59,6 +59,13 @@ plugins:
heading_level: 2
docstring_section_style: spacy
show_root_toc_entry: false
- with-pdf:
cover_subtitle: User Manual
cover_logo: C:\Users\chacha\git\chacha_cicd_helper\docs-static\Library.jpg
verbose: false
exclude_pages:
- LICENSE
output_path: C:\Users\chacha\git\chacha_cicd_helper\helpers-results\doc_gen\site\pdf\manual.pdf
markdown_extensions:
- def_list
- tables

View File

@@ -31,18 +31,21 @@ classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
dependencies = [
'importlib-metadata; python_version<"3.9"',
'typed-argument-parser==1.*'
'typed-argument-parser==1.*',
'packaging',
'tomli; python_version<"3.11"',
"junitparser>=2.8",
"junit2html>=30.1",
"xmlrunner>=1.7",
"mypy>=0.99",
"coverage>=7.0",
"radon>=5.1",
"pylint>=2.15",
"pylint>=2.15,<3",
"pylint-json2html>=0.4",
"pandas>=1.5",
"mypy[reports]>=0.99",
@@ -67,9 +70,26 @@ include-package-data = true
where = ["src"]
[tool.setuptools.package-data]
"chacha_cicd_helper.data" = ["*.*"]
"chacha_cicd_helper" = ["py.typed"]
[[tool.mypy.overrides]]
module = "tomli"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "tomllib"
ignore_missing_imports = true
[tool.coverage.run]
cover_pylib = false
branch = true
data_file="helpers-results/cl_unit_test_raw_coverage/.coverage"
# debug = ["config","multiproc","process"]
parallel = true
concurrency = [
'thread'
]
[project.urls]
Homepage = "https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper"
Documentation = "https://chacha.ddns.net/mkdocs-web/chacha/chacha_cicd_helper/master/latest/"
@@ -79,7 +99,7 @@ Tracker = "https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper/issue
test = ["junitparser>=2.8","junit2html>=30.1","xmlrunner>=1.7","mypy>=0.99" ]
coverage-check = ["coverage>=7.0"]
complexity-check = ["radon>=5.1"]
quality-check = ["pylint>=2.15","pylint-json2html>=0.4","pandas>=1.5"]
quality-check = ["pylint>=2.15,<3","pylint-json2html>=0.4","pandas>=1.5","types-PyYAML"]
type-check = ["mypy[reports]>=0.99" ]
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"]

View File

@@ -1,17 +1,16 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pyGameCFG(c) by chacha
# chacha_cicd_helper(c) by chacha
#
# pyGameCFG is licensed under a
# chacha_cicd_helper 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/>.
# pylint: disable=wrong-import-position
"""
Main module __init__ file.
"""
"""Main module __init__ file."""
from importlib.metadata import distribution, version, PackageNotFoundError
import warnings
@@ -37,4 +36,4 @@ except PackageNotFoundError: # pragma: no cover
warnings.warn('can not read dist.metadata["Name"], assuming local test context, setting it to <chacha_cicd_helper>')
__Name__ = "chacha_cicd_helper"
from .__main__ import fct_main
from .coverage_tools import CoverageProcess

View File

@@ -1,89 +1,128 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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/>.
"""Main module"""
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Union
from pathlib import Path
import tomli
import argparse
import os
import logging
import sys
from tap import Tap
b_use_tomli=False
try:
import tomli
b_use_tomli=True
except ImportError:
import tomllib
from .helper_base import cl_helper_base
from .types_check import cl_types_check
from .quality_check import cl_quality_check
from .unit_test import cl_unit_test
from .doc_gen import cl_doc_gen
from .complexity_check import cl_complexity_check
from .install_deps import cl_install_deps
from .types_check import types_check
from .quality_check import quality_check
from .unit_test import unit_test
from .doc_gen import doc_gen
from .complexity_check import complexity_check
from . import __Summuary__, __Name__
logging.getLogger().setLevel(logging.INFO)
def fct_main(i_args: list[str]) -> None:
class chacha_cicd_helper_args(Tap):
"""class that describe cmd arguments"""
parser = argparse.ArgumentParser(
prog="continuous-integration-helper", description="A tiny set of scripts to help continous integration on python"
)
projectpath: Union[str, None] = None
installdeps: bool = False
typecheck: bool = False
unittest: bool = False
coveragecheck: bool = False
qualitycheck: bool = False
docgen: bool = False
docgenpdf: bool = False
complexitycheck: bool = False
parser.add_argument("-pp", "--project-path", dest="projectpath", help="path of the python project to process", default=os.getcwd())
def configure(self) -> None:
"""specific arguments initializer"""
self.add_argument("-pp", "--projectpath", help="path of the python project to process", default=os.getcwd())
self.add_argument("-id", "--installdeps", action="store_true", help="install dependencies through pip")
parser.add_argument("-tc", "--type-check", dest="typecheck", action="store_true", help="enable static typing check")
self.add_argument("-tc", "--typecheck", action="store_true", help="enable static typing check")
parser.add_argument("-ut", "--unit-test", dest="unittest", action="store_true", help="enable unit-test")
parser.add_argument(
"-cc", "--coverage-check", dest="coveragecheck", action="store_true", help="enable unit-test coverage check (requires unit-test)"
)
self.add_argument("-ut", "--unittest", action="store_true", help="enable unit-test")
self.add_argument(
"-cc",
"--coveragecheck",
action="store_true",
help="enable unit-test coverage check (requires unit-test)",
)
parser.add_argument("-qc", "--quality-check", dest="qualitycheck", action="store_true", help="enable code quality check")
self.add_argument("-qc", "--qualitycheck", action="store_true", help="enable code quality check")
parser.add_argument("-dg", "--doc-gen", dest="docgen", action="store_true", help="enable documentation generation using MkDoc")
parser.add_argument(
"-pdf", "--doc-gen-pdf", dest="docgenpdf", action="store_true", help="enable pdf documentation export (requires doc-gen)"
)
self.add_argument("-dg", "--docgen", action="store_true", help="enable documentation generation using MkDoc")
self.add_argument("-pdf", "--docgenpdf", action="store_true", help="enable pdf documentation export (requires doc-gen)")
parser.add_argument("-cpc", "--complexity-check", dest="complexitycheck", action="store_true", help="enable complexity check")
self.add_argument("-cpc", "--complexitycheck", action="store_true", help="enable complexity check")
def fct_main(i_args: list[str]) -> None: # pylint: disable=too-complex
"""argument processing function"""
parser = chacha_cicd_helper_args(prog=__Name__, description=__Summuary__)
args = parser.parse_args(i_args)
helpers = []
if args.typecheck == True:
helpers.append(types_check)
helpers: list[type[cl_helper_base]] = []
if args.installdeps is True:
helpers.append(cl_install_deps)
else:
if args.typecheck is True:
helpers.append(cl_types_check)
if args.unittest is True:
helpers.append(cl_unit_test)
if args.coveragecheck is True:
if args.unittest is True:
cl_unit_test.enable_coverage_check = True
else:
raise RuntimeError("unit-test is required to enable coverage-check")
if args.qualitycheck is True:
helpers.append(cl_quality_check)
if args.docgen is True:
helpers.append(cl_doc_gen)
if args.docgenpdf is True:
if args.docgen is True:
cl_doc_gen.enable_gen_pdf = True
else:
raise RuntimeError("doc-gen is required to enable doc-gen-pdf")
if args.complexitycheck is True:
helpers.append(cl_complexity_check)
if args.unittest == True:
helpers.append(unit_test)
project_rootdir_path = Path(os.getcwd()) if args.projectpath is None else Path(args.projectpath)
if args.coveragecheck == True:
if args.unittest == True:
unit_test.enable_coverage_check = True
else:
raise RuntimeError("unit-test is required to enable coverage-check")
if args.qualitycheck == True:
helpers.append(quality_check)
if args.docgen == True:
helpers.append(doc_gen)
if args.docgenpdf == True:
if args.docgen == True:
doc_gen.enable_gen_pdf = True
else:
raise RuntimeError("doc-gen is required to enable doc-gen-pdf")
if args.complexitycheck == True:
helpers.append(complexity_check)
project_rootdir_path = Path(args.projectpath)
print(f"Working directory: {project_rootdir_path}")
with open(project_rootdir_path / "pyproject.toml", mode="rb") as fp:
pyproject = tomli.load(fp)
if b_use_tomli:
pyproject = tomli.load(fp)
else:
pyproject = tomllib.load(fp)
for helper in helpers:
helper.set_context(project_rootdir_path, pyproject)

View File

@@ -1,31 +1,34 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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
"""module that handle code complexity measurement"""
from __future__ import annotations
import statistics
import csv
from json import loads as JSON_LOADS
from radon.complexity import cc_rank, SCORE
from radon.cli import Config
from radon.cli.harvest import CCHarvester, HCHarvester, MIHarvester
from pprint import pprint
from radon.complexity import SCORE # type: ignore
from radon.cli import Config # type: ignore
from radon.cli.harvest import CCHarvester, HCHarvester, MIHarvester # type: ignore
from .helper_base import helper_withresults_base
from .helper_base import cl_helper_withresults_base
class complexity_check(helper_withresults_base):
class cl_complexity_check(cl_helper_withresults_base):
"""complexity check implementation class"""
@classmethod
def do_job(cls):
def do_job(cls) -> None:
"""helper job method implementation"""
config = Config(
exclude="__init__\.py",
exclude=r"__init__.py", ##!!!!! . => \. ???
ignore=None,
order=SCORE,
show_closures=False,
@@ -38,7 +41,7 @@ class complexity_check(helper_withresults_base):
h = MIHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
res = JSON_LOADS(h)
with open(cls.get_result_dir() / "MI.json", "w", newline="") as oFile:
with open(cls.get_result_dir() / "MI.json", "w", newline="", encoding="utf8") as oFile:
oFile.write(h)
mean = statistics.mean(_["mi"] for _ in res.values())
@@ -53,17 +56,17 @@ class complexity_check(helper_withresults_base):
rank = "C"
RES_MI = {"MeanMaintainability": mean, "MaintainabilityIndex": rank}
with open(cls.get_result_dir() / "MI.csv", "w", newline="") as oFile:
with open(cls.get_result_dir() / "MI.csv", "w", newline="", encoding="utf8") as oFile:
writer = csv.DictWriter(oFile, fieldnames=RES_MI.keys())
writer.writeheader()
writer.writerow(RES_MI)
config = Config(exclude=None, ignore=None, order=SCORE, show_closures=False, no_assert=True, min="A", max="F", multi=False)
h = CCHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
with open(cls.get_result_dir() / "CC.json", "w", newline="") as oFile:
with open(cls.get_result_dir() / "CC.json", "w", newline="", encoding="utf8") as oFile:
oFile.write(h)
config = Config(exclude=None, ignore=None, order=SCORE, show_closures=False, no_assert=True, min="A", max="F", by_function=None)
h = HCHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
with open(cls.get_result_dir() / "HC.json", "w", newline="") as oFile:
with open(cls.get_result_dir() / "HC.json", "w", newline="", encoding="utf8") as oFile:
oFile.write(h)

View File

@@ -0,0 +1,16 @@
from coverage import Coverage
from multiprocessing import Process
import os
class CoverageProcess(Process):
def run(self):
cov = Coverage(config_file=True, data_suffix=os.getpid(), auto_data=True)
cov._warn_no_data = False
cov.start()
try:
super().run()
finally:
cov.stop()
cov.save()

View File

@@ -1,13 +1,14 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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/>.
"""module that handle code documentation generation"""
from __future__ import annotations
from typing import TYPE_CHECKING
import shutil
import sys
@@ -16,19 +17,17 @@ from distutils.dir_util import copy_tree
import yaml
try:
from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
from yaml import Loader, Dumper
from .helper_base import helper_withresults_base
from .helper_base import cl_helper_withresults_base
class doc_gen(helper_withresults_base):
class cl_doc_gen(cl_helper_withresults_base):
"""documentation generation implementation class"""
enable_gen_pdf: bool = False
@classmethod
def do_job(cls):
def do_job(cls) -> None:
"""helper job method implementation"""
# create doc root dir
doc_path = cls.project_rootdir_path / "docs"
@@ -60,7 +59,7 @@ class doc_gen(helper_withresults_base):
continue
cls._create_dir(full_doc_path.parent.resolve())
with open(full_doc_path, "w+") as fd:
with open(full_doc_path, "w+", encoding="utf8") as fd:
identifier = ".".join(parts)
print("::: " + identifier, file=fd)
@@ -69,13 +68,13 @@ 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.
with open(cls.project_rootdir_path / "mkdocs.yml", "r") as mkdocsCfgFile:
with open(cls.project_rootdir_path / "mkdocs.yml", "r", encoding="utf8") as mkdocsCfgFile:
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:
if cls.enable_gen_pdf is True:
mkdocsCfg["plugins"].append(
{
"with-pdf": {
@@ -87,8 +86,8 @@ 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))
with open(cls.project_rootdir_path / "mkdocs.yml", "w", encoding="utf8") as mkdocsCfgFile:
mkdocsCfgFile.write(yaml.dump(mkdocsCfg, Dumper=yaml.Dumper, default_flow_style=False, sort_keys=False))
print(" !! start doc generation")
res = cls.run_cmd(cmdopts)

View File

@@ -1,82 +1,96 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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/>.
"""module that describe the base helpers class"""
from __future__ import annotations
from abc import ABC, abstractmethod
import os
import subprocess
from pathlib import Path
import shutil
from typing import TYPE_CHECKING
if TYPE_CHECKING: # Only imports the below statements during type checking
from typing import Union
from abc import ABC, abstractmethod
import os
import shutil
from pathlib import Path
import subprocess
class cl_helper_base(ABC):
"""helpers base class"""
class helper_base(ABC):
project_rootdir_path: Union[Path, None] = None
pyproject: Union[dict, None] = None
current_dir: Union[Path, None] = None
project_rootdir_path: Path = Path()
pyproject: dict = {}
@classmethod
def set_context(cls, project_rootdir_path: Path, pyproject: dict):
def set_context(cls, project_rootdir_path: Path, pyproject: dict) -> None:
"""method to set contextual fields"""
cls.project_rootdir_path = project_rootdir_path
cls.pyproject = pyproject
cls.current_dir = Path(__file__).parent.absolute()
@classmethod
def get_result_dir(cls):
def get_result_dir(cls) -> Union[None, Path]:
"""retrieve the result directory path"""
return None
@staticmethod
def _create_dir(dirpath: Path):
def _create_dir(dirpath: Path) -> None:
"""helper method to create a directory"""
dirpath = Path(dirpath)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
@staticmethod
def _reset_dir(dirpath: Path):
def _reset_dir(dirpath: Path) -> None:
"""helper method to reset a directory"""
dirpath = Path(dirpath)
if os.path.exists(dirpath):
shutil.rmtree(dirpath)
os.makedirs(dirpath)
@classmethod
def reset_result_dir(cls):
def reset_result_dir(cls) -> None:
"""helper method to reset the results directory"""
result_dir = cls.get_result_dir()
if result_dir != None:
if result_dir is not None:
cls._reset_dir(result_dir)
@classmethod
@abstractmethod
def do_job(cls):
def do_job(cls) -> None:
"""helper job virtual method"""
raise NotImplementedError()
@classmethod
def run_cmd_(cls, cmdarray):
def run_cmd_(cls, cmdarray: list[str]):
"""helper method to run a command (piped output)"""
process = subprocess.run(cmdarray, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, check=True)
return process.stdout
@classmethod
def run_cmd(cls, cmdarray, silent: bool = False):
p = subprocess.run(cmdarray, capture_output=True)
"""helper method to run a command"""
p = subprocess.run(cmdarray, capture_output=True, check=True)
if not silent:
print(p.stdout.decode())
print(p.stderr.decode())
return p.stdout
class helper_withresults_base(helper_base):
class cl_helper_withresults_base(cl_helper_base):
"""derived class to handle results"""
helper_results_dir: Union[Path, None] = None
@classmethod
def get_result_dir(cls):
if cls.helper_results_dir == None:
cls.helper_results_dir = cls.__name__
return Path(__file__).parent.parent.absolute() / "helpers-results" / cls.helper_results_dir
def get_result_dir(cls) -> Path:
"""retrieve the results directory"""
if cls.helper_results_dir is None:
cls.helper_results_dir = Path(cls.__name__)
return cls.project_rootdir_path / "helpers-results" / cls.helper_results_dir

View File

@@ -0,0 +1,39 @@
# chacha_cicd_helper (c) by chacha
#
# chacha_cicd_helper 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/>.
"""module that handle code documentation generation"""
from __future__ import annotations
import subprocess
import sys
from pprint import pprint
from .helper_base import cl_helper_base
class cl_install_deps(cl_helper_base):
"""dependencies installer implementation class"""
@classmethod
def do_job(cls) -> None:
"""helper job method implementation"""
deps=[]
opt_deps={}
if 'project' in cls.pyproject:
prj = cls.pyproject["project"]
if 'dependencies' in prj:
deps = prj['dependencies']
if 'optional-dependencies'in prj:
opt_deps = prj['optional-dependencies']
if len(deps)>0:
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade"] + deps)
for opt_key in opt_deps.keys():
if len(opt_deps[opt_key]) > 0:
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade"] + opt_deps[opt_key])

View File

@@ -1,41 +1,47 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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/>.
"""module that handle code quality measurement"""
from __future__ import annotations
from typing import TYPE_CHECKING
from contextlib import redirect_stdout
from contextlib import redirect_stdout, suppress
from io import StringIO
import re
import json
from enum import Enum
from contextlib import suppress
import sys
import pandas
import csv
import copy
from pylint.lint import Run as pylint_Run
import pylint_json2html
from pylint.lint import Run as pylint_Run # type: ignore
import pylint_json2html # type: ignore
import pandas # type: ignore
from .helper_base import helper_withresults_base
from .helper_base import cl_helper_withresults_base
if TYPE_CHECKING: # Only imports the below statements during type checking
from typing import Any
class PyLintMetricNotFound(Warning):
pass
"""module specific warning"""
class quality_check(helper_withresults_base):
PylintMessageList = dict()
class cl_quality_check(cl_helper_withresults_base):
"""quality check implementation class"""
PylintMessageList: dict[str, str] = {}
@classmethod
def GetPylintMessageList(cls):
Messagelist = dict()
def GetPylintMessageList(cls) -> None:
"""helper method to parse pylint messages"""
Messagelist: dict[str, str] = {}
regex = r"^:([a-zA-Z-]+) \(([^\)]+)\)"
for line in cls.run_cmd([sys.executable, "-m", "pylint", "--list-msgs"], True).splitlines():
if res := re.search(regex, line.decode()):
@@ -43,19 +49,22 @@ class quality_check(helper_withresults_base):
cls.PylintMessageList = Messagelist
@staticmethod
def TryExtractPYReportMetric(line: str, tag: str):
regex = f"^(?:\|{tag}\s*\|)(\d+)(?=\s*|)"
def TryExtractPYReportMetric(line: str, tag: str) -> float:
"""helper method to parse pylint metrics"""
regex = rf"^(?:\|{tag}\s*\|)(\d+)(?=\s*|)"
if res := re.search(regex, line):
return float(res.group(1))
raise PyLintMetricNotFound()
@classmethod
def do_job(cls):
def do_job(cls) -> None: # pylint: disable=too-complex,too-many-locals,too-many-branches,too-many-statements
"""helper job method implementation"""
print("checking code quality ...")
cls.GetPylintMessageList()
RES_all = dict()
RES_all: dict[str, Any] = {}
with StringIO() as StdOutput:
JsonContent = ""
with redirect_stdout(StdOutput):
@@ -76,6 +85,8 @@ class quality_check(helper_withresults_base):
with open(cls.get_result_dir() / "report.json", "w+", encoding="utf-8") as Outfile:
# hacky way of exctracting json + having overall score...
class TScanState(Enum):
"""Quality report parsing FSM states definition"""
TEXT_REPORT = 1
JSON_REPORT = 2
OTHER_REPORT_START = 3
@@ -86,12 +97,12 @@ class quality_check(helper_withresults_base):
OTHER_REPORT_MESSAGES = 8
OTHER_REPORT_END = 99
RES_all["Statistics"] = dict()
RES_all["RawMetrics"] = dict()
RES_all["RawMetricsPercent"] = dict()
RES_all["Duplication"] = dict()
RES_all["MessagesCat"] = dict()
RES_all["Messages"] = dict()
RES_all["Statistics"] = {}
RES_all["RawMetrics"] = {}
RES_all["RawMetricsPercent"] = {}
RES_all["Duplication"] = {}
RES_all["MessagesCat"] = {}
RES_all["Messages"] = {}
RES_all["GlobalScore"] = -999
RES_all["NbAnalysedStatments"] = -999
RES_all["NbAnalysedLines"] = -999
@@ -180,7 +191,7 @@ class quality_check(helper_withresults_base):
if line.startswith("--------"):
ScanState = TScanState.OTHER_REPORT_END
else:
for PylintMessage in cls.PylintMessageList.keys():
for PylintMessage in cls.PylintMessageList:
with suppress(PyLintMetricNotFound):
RES_all["Messages"][PylintMessage] = cls.TryExtractPYReportMetric(line, PylintMessage)
@@ -192,7 +203,7 @@ class quality_check(helper_withresults_base):
raise RuntimeError("Invalid ScanState")
Outfile.write(JsonContent)
with open(cls.get_result_dir() / "metrics.json", "w") as json_file:
with open(cls.get_result_dir() / "metrics.json", "w", encoding="utf8") as json_file:
json.dump(RES_all, json_file)
# exporting all Data in one csv, unused atm because jenkins seems not able to select columns from csv an keep displaying all...
@@ -201,14 +212,14 @@ class quality_check(helper_withresults_base):
del RES_all_trim["Messages"]
flat_RES_all = pandas.json_normalize(RES_all_trim, sep="_").to_dict(orient="records")[0]
with open(cls.get_result_dir() / "metrics.csv", "w", newline="") as csv_file:
with open(cls.get_result_dir() / "metrics.csv", "w", newline="", encoding="utf8") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=flat_RES_all.keys())
writer.writeheader()
writer.writerow(flat_RES_all)
# splited csv exports for jenkins plots: RawMetricsPercent
RES_all_percent = RES_all["RawMetricsPercent"]
with open(cls.get_result_dir() / "metrics_rawpercent.csv", "w", newline="") as csv_file:
with open(cls.get_result_dir() / "metrics_rawpercent.csv", "w", newline="", encoding="utf8") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=RES_all_percent.keys())
writer.writeheader()
writer.writerow(RES_all_percent)
@@ -219,21 +230,21 @@ class quality_check(helper_withresults_base):
RES_all_stats["PersentDuplicatedLines"] = RES_all["Duplication"]["PersentDuplicatedLines"]
RES_all_stats["NbAnalysedStatments"] = RES_all["NbAnalysedStatments"]
RES_all_stats["NbAnalysedLines"] = RES_all["NbAnalysedLines"]
with open(cls.get_result_dir() / "metrics_Statistics.csv", "w", newline="") as csv_file:
with open(cls.get_result_dir() / "metrics_Statistics.csv", "w", newline="", encoding="utf8") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=RES_all_stats.keys())
writer.writeheader()
writer.writerow(RES_all_stats)
# splited csv exports for jenkins plots: Statistics + Duplication
RES_all_MessagesCat = RES_all["MessagesCat"]
with open(cls.get_result_dir() / "metrics_MessagesCat.csv", "w", newline="") as csv_file:
with open(cls.get_result_dir() / "metrics_MessagesCat.csv", "w", newline="", encoding="utf8") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=RES_all_MessagesCat.keys())
writer.writeheader()
writer.writerow(RES_all_MessagesCat)
# splited csv exports for jenkins plots: GlobalScore
RES_GlobalScore = {"GlobalScore": RES_all["GlobalScore"]}
with open(cls.get_result_dir() / "metrics_GlobalScore.csv", "w", newline="") as csv_file:
with open(cls.get_result_dir() / "metrics_GlobalScore.csv", "w", newline="", encoding="utf8") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=RES_GlobalScore.keys())
writer.writeheader()
writer.writerow(RES_GlobalScore)

View File

@@ -1,26 +1,29 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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
"""module that handle code type checking"""
from pathlib import Path
from __future__ import annotations
from mypy import api
from .helper_base import helper_withresults_base
from .helper_base import cl_helper_withresults_base
class types_check(helper_withresults_base):
class cl_types_check(cl_helper_withresults_base):
"""type check implementation class"""
JUnitReportName = "junit.xml"
@classmethod
def do_job(cls):
def do_job(cls) -> None:
"""helper job method implementation"""
print("checking code typing ...")
result = api.run(
[ # project path
@@ -31,6 +34,7 @@ class types_check(helper_withresults_base):
"--explicit-package-bases",
# "--strict-equality",
# "--check-untyped-defs",
"--enable-incomplete-feature=Unpack",
# reports generation
"--cobertura-xml-report",
str(cls.get_result_dir()),

View File

@@ -1,27 +1,30 @@
# pyChaChaDummyProject (c) by chacha
# chacha_cicd_helper (c) by chacha
#
# pyChaChaDummyProject is licensed under a
# chacha_cicd_helper 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/>.
"""module that handle code unit-test"""
from __future__ import annotations
from typing import TYPE_CHECKING
from pathlib import Path
import os
import datetime
import unittest
import xmlrunner
from junitparser import JUnitXml
from junit2htmlreport import parser as junit2html_parser
import xmlrunner # type: ignore
from junitparser import JUnitXml # type: ignore
from junit2htmlreport import parser as junit2html_parser # type: ignore
from .helper_base import helper_withresults_base
from .helper_base import cl_helper_withresults_base
class unit_test(helper_withresults_base):
class cl_unit_test(cl_helper_withresults_base):
"""unit test implementation class"""
enable_coverage_check: bool = False
enable_xml_export: bool = True
enable_full_xml_export: bool = True
@@ -29,18 +32,20 @@ class unit_test(helper_withresults_base):
CoverageReportName: str = "test_coverage"
@classmethod
def do_job(cls):
if cls.enable_coverage_check == True:
import coverage
def do_job(cls) -> None:
"""helper job method implementation"""
if cls.enable_coverage_check is True:
import coverage # type: ignore # pylint: disable=import-outside-toplevel
# preparing unittest framework
test_loader = unittest.TestLoader()
if cls.enable_coverage_check == True:
if cls.enable_coverage_check is True:
# we start coverage now because module files discovery is part of the coverage measurement
CoverageReportPath = Path(str(cls.get_result_dir()) + "_coverage")
cls._reset_dir(CoverageReportPath)
cov = coverage.Coverage(cover_pylib=False, branch=True, source_pkgs=["src." + cls.pyproject["project"]["name"]])
cov = coverage.Coverage(config_file=True, source_pkgs=["src." + cls.pyproject["project"]["name"]])
cov.start()
package_tests = test_loader.discover(
@@ -55,14 +60,15 @@ class unit_test(helper_withresults_base):
testRunner.run(package_tests)
print("Test Finished")
if cls.enable_coverage_check == True:
if cls.enable_coverage_check is True:
cov.stop()
cov.save()
cov.combine()
cov.html_report(directory=str(CoverageReportPath))
cov.xml_report(outfile=(CoverageReportPath / f"{cls.CoverageReportName}.xml"))
cov.xml_report(outfile=str(CoverageReportPath / f"{cls.CoverageReportName}.xml"))
# computing results (Only if xml available)
if cls.enable_full_xml_export == True:
if cls.enable_full_xml_export is True:
print("Full reports generation...")
FullReportPath = Path(str(cls.get_result_dir()) + "_full")
cls._reset_dir(FullReportPath)

View File

@@ -16,6 +16,7 @@ print(__name__)
print(__package__)
from src import chacha_cicd_helper
from src.chacha_cicd_helper.__main__ import fct_main
testdir_path = Path(__file__).parent.resolve()
@@ -29,12 +30,22 @@ class Test_main(unittest.TestCase):
self.assertNotEqual(chacha_cicd_helper.__version__, "?.?.?")
def test_help(self):
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
with self.assertRaises(SystemExit):
chacha_cicd_helper.fct_main(["-h", "-pp", str(testdir_path.parent.resolve())])
fct_main(["-h", "-pp", str(testdir_path.parent.resolve())])
self.assertIn(f"usage: {chacha_cicd_helper.__Name__}", capted_stdout.getvalue())
self.assertEqual(capted_stderr.getvalue(), "")
@unittest.skip
def test_help_print(self):
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
fct_main(["-h", "-pp", str(testdir_path.parent.resolve())])
print(capted_stdout.getvalue())
print(capted_stderr.getvalue())
self.assertIn("usage: continuous-integration-helper", capted_stdout.getvalue())
self.assertEqual(capted_stderr.getvalue(), "")
def test_install_deps(self):
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
fct_main(["--installdeps", "-pp", str(testdir_path.parent.resolve())])
print(capted_stdout.getvalue())
print(capted_stderr.getvalue())