gd-tools-cli 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/PKG-INFO +1 -1
  2. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/pyproject.toml +2 -2
  3. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/addons/gd-tools-coverage/pre_run_hook.gd +34 -3
  4. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/orchestrator.py +41 -23
  5. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/reporter.py +2 -1
  6. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/errors.py +34 -1
  7. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools_cli.egg-info/PKG-INFO +1 -1
  8. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/README.md +0 -0
  9. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/setup.cfg +0 -0
  10. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/__init__.py +0 -0
  11. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/__main__.py +0 -0
  12. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/addons/__init__.py +0 -0
  13. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/addons/gd-tools-coverage/coverage.gd +0 -0
  14. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/addons/gd-tools-coverage/post_run_hook.gd +0 -0
  15. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/cli.py +0 -0
  16. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/config.py +0 -0
  17. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/__init__.py +0 -0
  18. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/cobertura_reporter.py +0 -0
  19. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/html_reporter.py +0 -0
  20. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/lcov_reporter.py +0 -0
  21. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/plan_generator.py +0 -0
  22. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/templates/file.html +0 -0
  23. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/templates/index.html +0 -0
  24. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/coverage/terminal_reporter.py +0 -0
  25. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/doctor.py +0 -0
  26. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/file_discovery.py +0 -0
  27. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/format_runner.py +0 -0
  28. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/godot.py +0 -0
  29. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/init.py +0 -0
  30. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/lint_runner.py +0 -0
  31. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/test_runner.py +0 -0
  32. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools/update_check.py +0 -0
  33. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools_cli.egg-info/SOURCES.txt +0 -0
  34. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools_cli.egg-info/dependency_links.txt +0 -0
  35. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools_cli.egg-info/entry_points.txt +0 -0
  36. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools_cli.egg-info/requires.txt +0 -0
  37. {gd_tools_cli-0.2.0 → gd_tools_cli-0.3.0}/src/gd_tools_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gd-tools-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A modern development workflow CLI for GDScript projects in Godot 4.5+
5
5
  Author-email: mansyar <m.ansyarafi@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gd-tools-cli"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "A modern development workflow CLI for GDScript projects in Godot 4.5+"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -99,7 +99,7 @@ target-version = ["py310"]
99
99
 
100
100
  [tool.commitizen]
101
101
  name = "cz_conventional_commits"
102
- version = "0.2.0"
102
+ version = "0.3.0"
103
103
  version_files = ["pyproject.toml:version"]
104
104
  changelog_file = "CHANGELOG.md"
105
105
  tag_format = "v$version"
@@ -112,6 +112,19 @@ static func _extract_indent(line: String) -> String:
112
112
  return indent
113
113
 
114
114
 
115
+ static func _detect_body_indent(source_lines: PackedStringArray, pattern_index: int) -> String:
116
+ # Scan lines after the pattern line to find the next non-empty line
117
+ # and use its indentation as the body indent.
118
+ var i: int = pattern_index + 1
119
+ while i < source_lines.size():
120
+ var line: String = source_lines[i]
121
+ if not line.strip_edges().is_empty():
122
+ return _extract_indent(line)
123
+ i += 1
124
+ # Fallback: if no non-empty line found, use the pattern indent plus one tab.
125
+ return _extract_indent(source_lines[pattern_index]) + "\t"
126
+
127
+
115
128
  static func _inject_trackers(source: String, file_id: int, lines: Array) -> String:
116
129
  var source_lines: PackedStringArray = source.split("\n")
117
130
  var sorted_lines: Array = lines.duplicate(true)
@@ -123,9 +136,25 @@ static func _inject_trackers(source: String, file_id: int, lines: Array) -> Stri
123
136
  if target_index < 0 or target_index >= source_lines.size():
124
137
  continue
125
138
  var target_line: String = source_lines[target_index]
126
- var indent: String = _extract_indent(target_line)
139
+ var branch_type = entry.get("branch_type", "")
140
+ if branch_type == null:
141
+ branch_type = ""
142
+ var insert_index: int
143
+ var indent: String
144
+ if branch_type in ["match_case", "if_false", "elif_true"]:
145
+ # Inject AFTER the branch line (inside the body).
146
+ # match_case patterns, else: and elif: lines must have trackers
147
+ # placed inside their body — injecting before these lines would
148
+ # insert a statement between the if/elif/else keywords, breaking
149
+ # the GDScript block structure (orphaned else/elif = syntax error).
150
+ insert_index = target_index + 1
151
+ indent = _detect_body_indent(source_lines, target_index)
152
+ else:
153
+ # Inject BEFORE the tracked line (existing behavior)
154
+ insert_index = target_index
155
+ indent = _extract_indent(target_line)
127
156
  var tracker_call: String = "%s%s.hit(%d, %d)" % [indent, TRACKER_NAME, file_id, line_id]
128
- source_lines.insert(target_index, tracker_call)
157
+ source_lines.insert(insert_index, tracker_call)
129
158
  return "\n".join(source_lines)
130
159
 
131
160
 
@@ -232,4 +261,6 @@ func _validate_file_entry(file_entry: Variant) -> bool:
232
261
 
233
262
 
234
263
  func _log_error(what: String, cause: String, fix: String) -> void:
235
- push_error("[gd-tools] [Error] " + what + "\n\n" + " Cause: " + cause + "\n" + " Fix: " + fix)
264
+ push_error(
265
+ "[gd-tools] [Error] " + what + "\n\n" + " Cause: " + cause + "\n" + " Fix: " + fix
266
+ )
@@ -115,14 +115,16 @@ def run_coverage_test(
115
115
 
116
116
  min_threshold = min_percent / 100 if min_percent is not None else None
117
117
  try:
118
- reporter.generate_report(
118
+ report_result = reporter.generate_report(
119
119
  plan,
120
120
  data,
121
121
  output_dir,
122
122
  config.coverage.format,
123
123
  min_threshold=min_threshold,
124
124
  )
125
- except CoverageThresholdError:
125
+ except CoverageThresholdError as exc:
126
+ if exc.report_result is not None:
127
+ _print_coverage_table(exc.report_result.summary)
126
128
  if test_error is not None:
127
129
  raise test_error
128
130
  raise
@@ -130,6 +132,9 @@ def run_coverage_test(
130
132
  if test_error is not None:
131
133
  raise test_error
132
134
 
135
+ # Print coverage summary table on success.
136
+ _print_coverage_table(report_result.summary)
137
+
133
138
  if result is None:
134
139
  raise CoveragePlanError(
135
140
  "Coverage generation returned no result — "
@@ -229,6 +234,39 @@ def merge_coverage_files(
229
234
  return merged
230
235
 
231
236
 
237
+ def _print_coverage_table(summary: CoverageSummary) -> None:
238
+ """Print a Rich coverage summary table to stdout.
239
+
240
+ Renders a table with Lines and Branches rows, showing Found,
241
+ Hit, and Rate columns. Used by both :func:`show_coverage_summary`
242
+ and :func:`run_coverage_test` to ensure a consistent table format.
243
+
244
+ Args:
245
+ summary: The coverage summary to display.
246
+ """
247
+ console = Console()
248
+ table = Table(title="Coverage Summary")
249
+ table.add_column("Metric", style="cyan")
250
+ table.add_column("Found", justify="right")
251
+ table.add_column("Hit", justify="right")
252
+ table.add_column("Rate", justify="right", style="green")
253
+
254
+ table.add_row(
255
+ "Lines",
256
+ str(summary.total_lines),
257
+ str(summary.covered_lines),
258
+ f"{summary.line_rate * 100:.1f}%",
259
+ )
260
+ table.add_row(
261
+ "Branches",
262
+ str(summary.total_branches),
263
+ str(summary.covered_branches),
264
+ f"{summary.branch_rate * 100:.1f}%",
265
+ )
266
+
267
+ console.print(table)
268
+
269
+
232
270
  def show_coverage_summary(
233
271
  config: GdToolsConfig,
234
272
  min_percent: int | None = None,
@@ -265,27 +303,7 @@ def show_coverage_summary(
265
303
  summary = reporter.compute_summary(plan, data)
266
304
 
267
305
  # Print Rich terminal table.
268
- console = Console()
269
- table = Table(title="Coverage Summary")
270
- table.add_column("Metric", style="cyan")
271
- table.add_column("Found", justify="right")
272
- table.add_column("Hit", justify="right")
273
- table.add_column("Rate", justify="right", style="green")
274
-
275
- table.add_row(
276
- "Lines",
277
- str(summary.total_lines),
278
- str(summary.covered_lines),
279
- f"{summary.line_rate * 100:.1f}%",
280
- )
281
- table.add_row(
282
- "Branches",
283
- str(summary.total_branches),
284
- str(summary.covered_branches),
285
- f"{summary.branch_rate * 100:.1f}%",
286
- )
287
-
288
- console.print(table)
306
+ _print_coverage_table(summary)
289
307
 
290
308
  # Threshold check.
291
309
  if min_percent is not None and summary.line_rate * 100 < min_percent:
@@ -512,7 +512,8 @@ def generate_report(
512
512
  f" Cause: Line coverage {summary.line_rate:.2%} is "
513
513
  f"below minimum {min_threshold:.2%}.\n"
514
514
  f" Fix: Increase test coverage or lower the minimum "
515
- "threshold."
515
+ "threshold.",
516
+ report_result=result,
516
517
  )
517
518
 
518
519
  return result
@@ -12,6 +12,13 @@ Exit-code convention:
12
12
  threshold). These are "your code has a problem" errors.
13
13
  """
14
14
 
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING
18
+
19
+ if TYPE_CHECKING:
20
+ from gd_tools.coverage.reporter import ReportResult
21
+
15
22
 
16
23
  class GdToolsError(Exception):
17
24
  """Base exception for all gd-tools errors.
@@ -55,10 +62,36 @@ class CoveragePlanError(GdToolsError):
55
62
 
56
63
 
57
64
  class CoverageThresholdError(GdToolsError):
58
- """Raised when coverage falls below the required threshold."""
65
+ """Raised when coverage falls below the required threshold.
66
+
67
+ Attributes:
68
+ exit_code: Process exit code (1 for threshold failures).
69
+ report_result: The :class:`ReportResult` computed before the
70
+ threshold check failed, if available. Callers can use
71
+ this to display coverage information without recomputation.
72
+ """
59
73
 
60
74
  exit_code: int = 1
61
75
 
76
+ def __init__(
77
+ self,
78
+ message: str = "",
79
+ *,
80
+ exit_code: int | None = None,
81
+ report_result: ReportResult | None = None,
82
+ ) -> None:
83
+ """Initialize the error.
84
+
85
+ Args:
86
+ message: The error message.
87
+ exit_code: Override the class default exit code. If None,
88
+ the class-level ``exit_code`` is used.
89
+ report_result: The :class:`ReportResult` containing the
90
+ coverage summary computed before the threshold check.
91
+ """
92
+ super().__init__(message, exit_code=exit_code)
93
+ self.report_result = report_result
94
+
62
95
 
63
96
  class TestFailureError(GdToolsError):
64
97
  """Raised when tests fail."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gd-tools-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A modern development workflow CLI for GDScript projects in Godot 4.5+
5
5
  Author-email: mansyar <m.ansyarafi@gmail.com>
6
6
  License: MIT
File without changes
File without changes