diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..20e58945 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,21 @@ +name: Build +on: + push: + branches: + - develop + pull_request: + types: [opened, synchronize, reopened] + workflow_dispatch: +jobs: + sonarcloud: + name: SonarCloud + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/metrics.yml b/.github/workflows/metrics.yml index e970b4a8..5107a671 100644 --- a/.github/workflows/metrics.yml +++ b/.github/workflows/metrics.yml @@ -5,6 +5,7 @@ on: branches: [main, develop] tags: - "v*" + workflow_dispatch: jobs: release: @@ -24,7 +25,7 @@ jobs: run: | git config --global user.email "${{secrets.USER_EMAIL}}" git config --global user.name "${{secrets.USER_NAME}}" - git clone --single-branch --branch main "https://x-access-token:${{secrets.API_TOKEN_DOC}}@github.com/fga-eps-mds/2023-1-MeasureSoftGram-Doc" doc + git clone --single-branch --branch main "https://x-access-token:${{secrets.API_TOKEN_DOC}}@github.com/fga-eps-mds/2023.2-MeasureSoftGram-DOC" doc mkdir -p doc/analytics-raw-data cp -R analytics-raw-data/*.json doc/analytics-raw-data cd doc/ diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 45f5e270..7feede77 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -5,6 +5,7 @@ on: branches: [ develop ] tags: - "v*" + workflow_dispatch: jobs: deploy: @@ -32,5 +33,5 @@ jobs: run: python -m twine upload -u __token__ -p ${{ secrets.TEST_PYPI_API_TOKEN }} --repository testpypi dist/* - name: Publish package on pypi - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + #if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') run: python -m twine upload -u __token__ -p ${{ secrets.PYPI_API_TOKEN }} dist/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d74f0fff..cd48269f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,5 +45,5 @@ jobs: fail_ci_if_error: true files: ./coverage.xml flags: unittests - name: 2023-1-MeasureSoftGram-CLI - verbose: true \ No newline at end of file + name: 2023-2-MeasureSoftGram-CLI + verbose: true diff --git a/README.md b/README.md index 51e38ecb..f128d3ff 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 2023-1-MeasureSoftGram-CLI +# 2023-2 MeasureSoftGram-CLI ## Badges diff --git a/outhelp.txt b/outhelp.txt new file mode 100644 index 00000000..2d8f7f1a --- /dev/null +++ b/outhelp.txt @@ -0,0 +1,32 @@ +──────────────────────────────────────────────────── Listing Configuration Parameters: ──────────────────────────────────────────────────── + + +Característica: +reliability +Peso: 50% +Subcaracteristica(s): + +Característica: +| testing_status +| Peso: 100% +| Medida(s): +| | passed_tests +| | Peso: 33% +| | Métrica(s): +| | | Valores de referência: Min: 0 e Max: 1 +| | Fim-Metrica(s) +| Fim-Medida(s) +| | test_builds +| | Peso: 33% +| | Métrica(s): +| | | Valores de referência: Min: 0 e Max: 300000 +| | Fim-Metrica(s) +| Fim-Medida(s) +| | test_coverage +| | Peso: 34% +| | Métrica(s): +| | | Valores de referência: Min: 60 e Max: 100 +| | Fim-Metrica(s) +| Fim-Medida(s) +Fim-SubCaracterística +Fim-Característica diff --git a/pyproject.toml b/pyproject.toml index 5511dd62..5925a41e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "msgram" -version = "3.0.0" +version = "3.0.3" description = "The msgram CLI is a command-line interface to use MeasureSoftGram software" readme = "README.md" authors = [ diff --git a/sonar-project.properties b/sonar-project.properties index f8a012c0..f313c8cf 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,4 +1,4 @@ -sonar.projectKey=fga-eps-mds_2023-1-MeasureSoftGram-CLI +sonar.projectKey=fga-eps-mds_2023-2-MeasureSoftGram-CLI sonar.organization=fga-eps-mds-1 sonar.python.version=3 @@ -9,6 +9,7 @@ sonar.sources.exclusions= \ **/parsers.py \ **/cli.py sonar.tests=./tests +sonar.test.inclusions=**/tests/ sonar.dynamicAnalysis=reuseReports sonar.core.codeCoveragePlugin=cobertura diff --git a/src/cli/commands/cmd_print_config.py b/src/cli/commands/cmd_print_config.py new file mode 100644 index 00000000..94a2c6c3 --- /dev/null +++ b/src/cli/commands/cmd_print_config.py @@ -0,0 +1,101 @@ +from rich.console import Console +from src.cli.utils import print_info, print_rule, print_error + +from src.config.settings import FILE_CONFIG, DEFAULT_CONFIG_PATH, DEFAULT_CONFIG_FILE_PATH + +from pathlib import Path + +import json +import os + +def print_json_tree(data): + result = [] + stack = [(data, "")] + is_top = True + + measure_to_metric = {} + measure_to_metric["passed_tests"] = ['test_success_density'] + measure_to_metric["test_builds"] = ['tests', 'tests_execution_time'] + measure_to_metric["test_coverage"] = ['coverage'] + measure_to_metric["non_complex_file_density"] = ['complexity_functions', 'total_number_of_files'] + measure_to_metric["commented_file_density"] = ['commented_lines_density'] + measure_to_metric["duplication_absense"] = ['duplication_lines_density'] + + while stack: + data, indent = stack.pop() + key = data.get("key") + + if is_top: + result.append(f"[#FFFFFF]\nCaracterística:") + is_top = False + result.append(f"[#FFFFFF]{indent}[#00FF00]{key}") + + weight = data.get("weight", 0) + result.append(f"[#FFFFFF]{indent}Peso: [#00FF00]{weight}%") + + if "subcharacteristics" in data: + for subchar in data["subcharacteristics"]: + result.append(f"[#FFFFFF]{indent}Sub-característica(s):") + stack.append((subchar, f"{indent}│ ")) # Use the ASCII character │ (code 179) + + if "measures" in data: + for measure in data["measures"]: + result.append(f"[#FFFFFF]{indent}│ Medida(s):") + measure_key = measure.get("key") + result.append(f"[#FFFFFF]{indent}{indent}│ [#00FF00]{measure_key}") # Use the ASCII character │ (code 179) + result.append(f"[#FFFFFF]{indent}{indent}│ Peso: [#00FF00]{measure['weight']}%") + if "min_threshold" in measure and "max_threshold" in measure: + min_threshold = measure.get("min_threshold") + max_threshold = measure.get("max_threshold") + result.append(f"[#FFFFFF]{indent}{indent}│ Métrica(s):") # Use the ASCII character │ (code 179) + metrics = measure_to_metric.get(measure_key, []) # Get associated metrics + for metric in metrics: + result.append(f"[#FFFFFF]{indent}{indent}│ └─[#00FF00]{metric}") # Print metrics in green color + result.append(f"[#FFFFFF]{indent}{indent}│ │ Valores de referência: Min = [#00FF00]{min_threshold} [#FFFFFF]e Max = [#00FF00]{max_threshold}") + result.append(f"[#FFFFFF]{indent}{indent}│ Fim-Métrica(s)") + result.append(f"[#FFFFFF]{indent}│ Fim-Medida(s)") + result.append("[#FFFFFF]Fim-SubCaracterística") + result.append("[#FFFFFF]Fim-Característica") + + return '\n'.join(result) + +def command_list_config(args): + console = Console() + console.clear() + + file_path = DEFAULT_CONFIG_FILE_PATH + try: + config_path: Path = args["config_path"] + + if config_path != DEFAULT_CONFIG_PATH: + print_info(f"[#A9A9A9] Será usado arquivo informado pelo usuário: ") + file_path = str(config_path) + "/msgram.json" + else: + print_info(f"[#A9A9A9] Não foi informado caminho do arquivo de configuração, será usado caminho padrão.") + + + except Exception as e: + print_error(f"KeyError: args[{e}] - non-existent parameters") + exit(1) + + + print_rule("[#FFFFFF] Listing Configuration Parameters") + + if not (os.path.exists(file_path)): + print_info(f"[#A9A9A9] O arquivo de configuração não foi encontrado. \n Execute o comando msgram init no projeto desejado para criá-lo.") + exit() + + print_info(f"MSGram config file [bold red]'{FILE_CONFIG}'[/] exists already!") + + #get data + f = open(file_path) + + data = json.load(f) + + for characteristic in data.get("characteristics", []): + output_string = print_json_tree(characteristic) + print_info(output_string) + + print_info( + "\n[#A9A9A9]Para editar o arquivo de configuração utilize em seu terminal o seguinte comando: vim <.msgram/msgram.json>" + ) diff --git a/src/cli/parsers.py b/src/cli/parsers.py index 987b1671..8d20733b 100644 --- a/src/cli/parsers.py +++ b/src/cli/parsers.py @@ -2,7 +2,11 @@ from pathlib import Path -from src.cli.commands import command_init, command_extract, command_calculate +from src.cli.commands.cmd_init import command_init +from src.cli.commands.cmd_extract import command_extract +from src.cli.commands.cmd_calculate import command_calculate +from src.cli.commands.cmd_print_config import command_list_config + from src.config.settings import ( AVAILABLE_IMPORTS, SUPPORTED_FORMATS, @@ -39,6 +43,31 @@ def create_parser(): ) parser_init.set_defaults(func=command_init) # function command init + # =====================================< COMMAND list_config >===================================== + parser_list_config = subparsers.add_parser( + "list", + help="Listing configurations parameters.", + ) + + parser_list_config.add_argument( + "-cp", + "--config_path", + type=lambda p: Path(p).absolute(), + default=DEFAULT_CONFIG_PATH, + help="Path to default config directory.", + ) + + parser_list_config.add_argument( + "all", + #type=str, + nargs="?", + help="Show configuration file.", + ) + + parser_list_config.set_defaults(func=command_list_config) # function command list config + + + # =====================================< COMMAND extract >===================================== parser_extract = subparsers.add_parser("extract", help="Extract supported metrics") diff --git a/src/cli/utils.py b/src/cli/utils.py index 44053418..4bde5f45 100644 --- a/src/cli/utils.py +++ b/src/cli/utils.py @@ -93,3 +93,5 @@ def print_panel(menssage: str, title: str = "Next steps"): width=140, ), ) + +# testegit \ No newline at end of file diff --git a/tests/unit/data/expected_list.txt b/tests/unit/data/expected_list.txt new file mode 100644 index 00000000..51acc197 --- /dev/null +++ b/tests/unit/data/expected_list.txt @@ -0,0 +1,33 @@ +Característica: +reliability +Peso: 50% +Sub-característica(s): +│ testing_status +│ Peso: 100% +│ │ Medida(s): +│ │ │ passed_tests +│ │ │ Peso: 33% +│ │ │ Métrica(s): +│ │ │ └─test_success_density +│ │ │ │ Valores de referência: Min = 0 e Max = 1 +│ │ │ Fim-Métrica(s) +│ │ Fim-Medida(s) +│ │ Medida(s): +│ │ │ test_builds +│ │ │ Peso: 33% +│ │ │ Métrica(s): +│ │ │ └─tests +│ │ │ └─tests_execution_time +│ │ │ │ Valores de referência: Min = 0 e Max = 300000 +│ │ │ Fim-Métrica(s) +│ │ Fim-Medida(s) +│ │ Medida(s): +│ │ │ test_coverage +│ │ │ Peso: 34% +│ │ │ Métrica(s): +│ │ │ └─coverage +│ │ │ │ Valores de referência: Min = 60 e Max = 100 +│ │ │ Fim-Métrica(s) +│ │ Fim-Medida(s) +Fim-SubCaracterística +Fim-Característica \ No newline at end of file diff --git a/tests/unit/data/newmsgram.json b/tests/unit/data/newmsgram.json new file mode 100644 index 00000000..4ded7c63 --- /dev/null +++ b/tests/unit/data/newmsgram.json @@ -0,0 +1,64 @@ +{ + "characteristics": [ + { + "key": "reliability", + "weight": 50, + "subcharacteristics": [ + { + "key": "testing_status", + "weight": 100, + "measures": [ + { + "key": "passed_tests", + "weight": 33, + "min_threshold": 0, + "max_threshold": 1 + }, + { + "key": "test_builds", + "weight": 33, + "min_threshold": 0, + "max_threshold": 300000 + }, + { + "key": "test_coverage", + "weight": 34, + "min_threshold": 60, + "max_threshold": 100 + } + ] + } + ] + }, + { + "key": "maintainability", + "weight": 50, + "subcharacteristics": [ + { + "key": "modifiability", + "weight": 100, + "measures": [ + { + "key": "non_complex_file_density", + "weight": 33, + "min_threshold": 0, + "max_threshold": 10 + }, + { + "key": "commented_file_density", + "weight": 33, + "min_threshold": 10, + "max_threshold": 30 + }, + { + "key": "duplication_absense", + "weight": 34, + "min_threshold": 0, + "max_threshold": 5 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/unit/test_print_config.py b/tests/unit/test_print_config.py new file mode 100644 index 00000000..3417d294 --- /dev/null +++ b/tests/unit/test_print_config.py @@ -0,0 +1,36 @@ +import unittest +from unittest.mock import patch +from io import StringIO +import sys +import json + +from src.cli.commands.cmd_print_config import print_json_tree +from src.cli.utils import print_info, print_rule + +import re + +def test_print_json_tree(): + + file = open("tests/unit/data/newmsgram.json") + data = json.load(file) + + captured_output = StringIO() + sys.stdout = captured_output + + characteristics = data.get("characteristics", []) + + result = print_json_tree(characteristics[0]) + + fileExpected = open("tests/unit/data/expected_list.txt") + + compare = fileExpected.read() + + # O padrão de regex para cores no formato [#FFFFFF] e [#458B00] + color_pattern = r'\[#\w+\]' + + # Substituir todas as ocorrências do padrão pelo texto vazio + result = re.sub(color_pattern, '', result) + result = re.sub('\n', '', result) + compare = re.sub('\n', '', compare) + + assert result == compare \ No newline at end of file