Skip to content

Commit

Permalink
feat: ✨ Link to functions
Browse files Browse the repository at this point in the history
  • Loading branch information
robvanderleek committed Dec 18, 2024
1 parent 788eb0a commit b4a9e0d
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 95 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@ jobs:
poetry run pyinstaller -n codelimit -F codelimit/__main__.py
./dist/codelimit scan .
- name: 'Run Code Limit action'
- name: 'Run CodeLimit action'
uses: getcodelimit/codelimit-action@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
upload: true

- name: 'Upload coverage reports to Codecov'
uses: codecov/codecov-action@v3
2 changes: 1 addition & 1 deletion codelimit/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typer.core import TyperGroup

from codelimit.commands.check import check_command
from codelimit.commands.report import report_command, ReportFormat
from codelimit.commands.report.report import ReportFormat, report_command
from codelimit.commands.scan import scan_command
from codelimit.common.Configuration import Configuration
from codelimit.common.utils import configure_github_repository
Expand Down
Empty file.
80 changes: 80 additions & 0 deletions codelimit/commands/report/format_markdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from pathlib import Path

from codelimit.common.GithubRepository import GithubRepository
from codelimit.common.ScanTotals import ScanTotals
from codelimit.common.report.ReportUnit import ReportUnit


def report_totals_markdown(st: ScanTotals) -> str:
result = ""
result += (
"| **Language** | **Files** | **Lines of Code** | **Functions** | \u26A0 | \u274C |\n"
)
result += "| --- | ---: | ---: | ---: | ---: | ---: |\n"
for lt in st.languages_totals():
result += (
f"| {lt.language} | "
f"{lt.files} | "
f"{lt.loc} | "
f"{lt.functions} | "
f"{lt.hard_to_maintain} | "
f"{lt.unmaintainable} |\n"
)
if len(st.languages_totals()) > 1:
result += (
f"| **Totals** | "
f"**{st.total_files()}** | "
f"**{st.total_loc()}** | "
f"**{st.total_functions()}** | "
f"**{st.total_hard_to_maintain()}** | "
f"**{st.total_unmaintainable()}** |"
)
result += "\n"
result += "Generated by [CodeLimit](https://getcodelimit.github.io)"
return result


def report_functions_markdown(root: Path | None, report_units: list[ReportUnit],
repository: GithubRepository | None = None) -> str:
result = ""
if repository:
result += report_functions_markdown_with_repository(root, report_units, repository)
else:
result += report_functions_markdown_without_repository(root, report_units)
result += "\n"
result += "Generated by [CodeLimit](https://getcodelimit.github.io)"
return result


def report_functions_markdown_without_repository(
root: Path | None, report_units: list[ReportUnit]
) -> str:
result = ""
result += "| **File** | **Line** | **Column** | **Length** | **Function** |\n"
result += "| --- | ---: | ---: | ---: | --- |\n"
for unit in report_units:
file_path = unit.file if root is None else root.joinpath(unit.file)
type = "\u274C" if unit.measurement.value > 60 else "\u26A0"
result += (
f"| {str(file_path)} | {unit.measurement.start.line} | {unit.measurement.start.column} | "
f"{unit.measurement.value} | {type} {unit.measurement.unit_name} |\n"
)
return result


def report_functions_markdown_with_repository(root: Path | None, report_units: list[ReportUnit],
repository: GithubRepository) -> str:
result = ""
result += "| **Function** | **Length** |\n"
result += "| --- | ---: |\n"
for unit in report_units:
violation_type = "\u274C" if unit.measurement.value > 60 else "\u26A0"
owner = repository.owner
name = repository.name
branch = repository.branch
link = (f'https://github.com/{owner}/{name}/blob/{branch}/{unit.file}#L{unit.measurement.start.line}-L'
f'{unit.measurement.end.line}')
result += (
f"| {violation_type} \[{unit.measurement.unit_name}]({link}) | {unit.measurement.value} |\n"
)
return result
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from rich.console import Console
from rich.text import Text

from codelimit.commands.report.format_markdown import report_functions_markdown, report_totals_markdown
from codelimit.common.ScanResultTable import ScanResultTable
from codelimit.common.ScanTotals import ScanTotals
from codelimit.common.report.Report import Report
from codelimit.common.report.ReportReader import ReportReader
from codelimit.common.report.ReportUnit import ReportUnit
from codelimit.common.utils import format_measurement
from codelimit.utils import make_report_path

Expand All @@ -28,40 +28,13 @@ def report_command(path: Path, full: bool, totals: bool, fmt: ReportFormat):
if totals:
scan_totals = ScanTotals(report.codebase.totals)
if fmt == ReportFormat.markdown:
stdout.print(_report_totals_markdown(scan_totals), soft_wrap=True)
stdout.print(report_totals_markdown(scan_totals), soft_wrap=True)
else:
stdout.print(ScanResultTable(scan_totals), soft_wrap=True)
else:
_report_functions(report, path, full, fmt, stdout)


def _report_totals_markdown(st: ScanTotals) -> str:
result = ""
result += (
"| **Language** | **Files** | **Lines of Code** | **Functions** | \u26A0 | \u274C |\n"
)
result += "| --- | ---: | ---: | ---: | ---: | ---: |\n"
for lt in st.languages_totals():
result += (
f"| {lt.language} | "
f"{lt.files} | "
f"{lt.loc} | "
f"{lt.functions} | "
f"{lt.hard_to_maintain} | "
f"{lt.unmaintainable} |\n"
)
if len(st.languages_totals()) > 1:
result += (
f"| **Totals** | "
f"**{st.total_files()}** | "
f"**{st.total_loc()}** | "
f"**{st.total_functions()}** | "
f"**{st.total_hard_to_maintain()}** | "
f"**{st.total_unmaintainable()}** |"
)
return result


def _report_functions(report: Report, path: Path, full: bool, fmt, console: Console):
units = report.all_report_units_sorted_by_length_asc(30)
if len(units) == 0:
Expand All @@ -75,7 +48,7 @@ def _report_functions(report: Report, path: Path, full: bool, fmt, console: Cons
report_units = units[0:REPORT_LENGTH]
root = get_root(path)
if fmt == ReportFormat.markdown:
console.print(_report_functions_markdown(root, report_units), soft_wrap=True)
console.print(report_functions_markdown(root, report_units, report.repository), soft_wrap=True)
else:
console.print(
_report_functions_text(root, units, report_units, full), soft_wrap=True
Expand Down Expand Up @@ -115,19 +88,3 @@ def _report_functions_text(root, units, report_units, full) -> Text:
f"{len(units) - REPORT_LENGTH} more rows, use --full option to get all rows\n", style="bold"
)
return result


def _report_functions_markdown(
root: Path | None, report_units: list[ReportUnit]
) -> str:
result = ""
result += "| **File** | **Line** | **Column** | **Length** | **Function** |\n"
result += "| --- | ---: | ---: | ---: | --- |\n"
for unit in report_units:
file_path = unit.file if root is None else root.joinpath(unit.file)
type = "\u274C" if unit.measurement.value > 60 else "\u26A0"
result += (
f"| {str(file_path)} | {unit.measurement.start.line} | {unit.measurement.start.column} | "
f"{unit.measurement.value} | {type} {unit.measurement.unit_name} |\n"
)
return result
3 changes: 2 additions & 1 deletion codelimit/commands/scan.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pathlib import Path
from typing import Optional

from codelimit.common.Configuration import Configuration
from codelimit.common.Scanner import scan_codebase
from codelimit.common.report.Report import Report
from codelimit.common.report.ReportReader import ReportReader
Expand All @@ -13,7 +14,7 @@ def scan_command(path: Path):
cached_report = _read_cached_report(report_path)
codebase = scan_codebase(path, cached_report)
codebase.aggregate()
report = Report(codebase)
report = Report(codebase, Configuration.repository)
if not cache_dir.exists():
cache_dir.mkdir()
cache_dir_tag = cache_dir.joinpath("CACHEDIR.TAG").resolve()
Expand Down
4 changes: 3 additions & 1 deletion codelimit/common/report/Report.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from uuid import uuid4

from codelimit.common.Codebase import Codebase
from codelimit.common.GithubRepository import GithubRepository
from codelimit.common.report.ReportUnit import ReportUnit
from codelimit.common.utils import make_profile
from codelimit.version import version
Expand All @@ -10,9 +11,10 @@
class Report:
VERSION = version

def __init__(self, codebase: Codebase):
def __init__(self, codebase: Codebase, repository: GithubRepository | None = None):
self.version: str | None = self.VERSION
self.uuid = str(uuid4())
self.repository = repository
self.codebase = codebase

def get_average(self):
Expand Down
7 changes: 6 additions & 1 deletion codelimit/common/report/ReportReader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import Optional

from codelimit.common.Codebase import Codebase
from codelimit.common.GithubRepository import GithubRepository
from codelimit.common.Location import Location
from codelimit.common.Measurement import Measurement
from codelimit.common.SourceFileEntry import SourceFileEntry
Expand All @@ -18,7 +19,11 @@ def get_report_version(json: str) -> Optional[str]:
def from_json(json: str) -> Report:
d = loads(json)
codebase = Codebase(d["root"])
report = Report(codebase)
if 'repository' in d:
repository = GithubRepository(**d["repository"])
report = Report(codebase, repository)
else:
report = Report(codebase)
report.uuid = d["uuid"]
for k, v in d["codebase"]["files"].items():
measurements: list[Measurement] = []
Expand Down
26 changes: 17 additions & 9 deletions codelimit/common/report/ReportWriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ def to_json(self) -> str:
self.level = 0
json = ""
json += self._open("{")
json += self._collection(
[
self._line(f'"version": "{self.report.version}"'),
self._line(f'"uuid": "{self.report.uuid}"'),
self._line(f'"root": "{self.report.codebase.root}"'),
self._codebase_to_json(),
]
)
content: [str] = [self._line(f'"version": "{self.report.version}"'),
self._line(f'"uuid": "{self.report.uuid}"'),
self._line(f'"root": "{self.report.codebase.root}"')]
if self.report.repository:
content.append(self._repository_to_json())
content.append(self._codebase_to_json())
json += self._collection(content)
json += self._close("}")
return json

Expand All @@ -50,7 +49,16 @@ def _collection(self, items: list):
json = separator.join([i.rstrip() for i in items])
return json + "\n" if self.pretty_print and len(items) > 0 else json

def _codebase_to_json(self):
def _repository_to_json(self):
json = ""
json += self._open('"repository": {')
json += self._collection([self._line(f'"owner": "{self.report.repository.owner}"'),
self._line(f'"name": "{self.report.repository.name}"'),
self._line(f'"branch": "{self.report.repository.branch}"')])
json += self._close("}")
return json

def _codebase_to_json(self) -> str:
json = ""
json += self._open('"codebase": {')
json += self._collection(
Expand Down
17 changes: 10 additions & 7 deletions tests/commands/test_report.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from codelimit.commands.report import (
_report_totals_markdown,
_report_functions_markdown,
)
from codelimit.commands.report.format_markdown import report_totals_markdown, report_functions_markdown
from codelimit.common.LanguageTotals import LanguageTotals
from codelimit.common.Location import Location
from codelimit.common.Measurement import Measurement
Expand All @@ -17,12 +14,14 @@ def test_report_totals_markdown_one_language():
python_totals.hard_to_maintain = 4
python_totals.unmaintainable = 5
st = ScanTotals({"Python": python_totals})
result = _report_totals_markdown(st)
result = report_totals_markdown(st)

assert result == (
"| **Language** | **Files** | **Lines of Code** | **Functions** | \u26A0 | \u274C |\n"
"| --- | ---: | ---: | ---: | ---: | ---: |\n"
"| Python | 1 | 2 | 3 | 4 | 5 |\n"
"\n"
"Generated by [CodeLimit](https://getcodelimit.github.io)"
)


Expand All @@ -40,19 +39,21 @@ def test_report_totals_markdown_two_languages():
ts_totals.hard_to_maintain = 4
ts_totals.unmaintainable = 5
st = ScanTotals({"Python": python_totals, "TypeScript": ts_totals})
result = _report_totals_markdown(st)
result = report_totals_markdown(st)

assert result == (
"| **Language** | **Files** | **Lines of Code** | **Functions** | \u26A0 | \u274C |\n"
"| --- | ---: | ---: | ---: | ---: | ---: |\n"
"| Python | 1 | 2 | 3 | 4 | 5 |\n"
"| TypeScript | 1 | 2 | 3 | 4 | 5 |\n"
"| **Totals** | **2** | **4** | **6** | **8** | **10** |"
"\n"
"Generated by [CodeLimit](https://getcodelimit.github.io)"
)


def test_print_functions_markdown():
result = _report_functions_markdown(
result = report_functions_markdown(
None,
[
ReportUnit(
Expand All @@ -65,4 +66,6 @@ def test_print_functions_markdown():
"| **File** | **Line** | **Column** | **Length** | **Function** |\n"
"| --- | ---: | ---: | ---: | --- |\n"
"| foo.py | 1 | 1 | 31 | ⚠ bar() |\n"
"\n"
"Generated by [CodeLimit](https://getcodelimit.github.io)"
)
Empty file added tests/common/report/__init__.py
Empty file.
25 changes: 0 additions & 25 deletions tests/common/test_Report.py → tests/common/report/test_Report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from codelimit.common.Measurement import Measurement
from codelimit.common.SourceFileEntry import SourceFileEntry
from codelimit.common.report.Report import Report
from codelimit.common.report.ReportWriter import ReportWriter


def test_empty_measurements_collection():
Expand All @@ -13,30 +12,6 @@ def test_empty_measurements_collection():
assert report.ninetieth_percentile() == 0
assert report.quality_profile() == [0, 0, 0, 0]

serializer = ReportWriter(report)

json = ""
json += "{\n"
json += f' "version": "{report.version}",\n'
json += f' "uuid": "{report.uuid}",\n'
json += ' "root": "/",\n'
json += ' "codebase": {\n'
json += ' "totals": {\n'
json += " },\n"
json += ' "tree": {\n'
json += ' "./": {\n'
json += ' "entries": [\n'
json += " ],\n"
json += ' "profile": [0, 0, 0, 0]\n'
json += " }\n"
json += " },\n"
json += ' "files": {\n'
json += " }\n"
json += " }\n"
json += "}\n"

assert serializer.to_json() == json


def test_all_units():
codebase = Codebase("/")
Expand Down
Loading

0 comments on commit b4a9e0d

Please sign in to comment.