cicaddy-github 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 (43) hide show
  1. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/Dockerfile +1 -1
  2. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/PKG-INFO +1 -1
  3. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/pyproject.toml +1 -1
  4. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/github_integration/agents.py +22 -1
  5. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_agents.py +41 -2
  6. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.claude/skills/cicaddy-action/SKILL.md +0 -0
  7. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.github/dependabot.yml +0 -0
  8. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.github/workflows/changelog.yml +0 -0
  9. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.github/workflows/ci.yml +0 -0
  10. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.github/workflows/pr-review.yml +0 -0
  11. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.github/workflows/release.yml +0 -0
  12. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.gitignore +0 -0
  13. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/.pre-commit-config.yaml +0 -0
  14. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/CLAUDE.md +0 -0
  15. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/CODE_OF_CONDUCT.md +0 -0
  16. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/CONTRIBUTING.md +0 -0
  17. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/LICENSE +0 -0
  18. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/README.md +0 -0
  19. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/action.yml +0 -0
  20. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/entrypoint.sh +0 -0
  21. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/__init__.py +0 -0
  22. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/config/__init__.py +0 -0
  23. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/config/settings.py +0 -0
  24. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/github_integration/__init__.py +0 -0
  25. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/github_integration/analyzer.py +0 -0
  26. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/github_integration/detector.py +0 -0
  27. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/github_integration/tools.py +0 -0
  28. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/plugin.py +0 -0
  29. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/security/__init__.py +0 -0
  30. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/security/leak_detector.py +0 -0
  31. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/src/cicaddy_github/validation.py +0 -0
  32. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tasks/changelog_report.yml +0 -0
  33. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tasks/pr_review.yml +0 -0
  34. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/templates/report_template.html +0 -0
  35. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/__init__.py +0 -0
  36. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/conftest.py +0 -0
  37. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/__init__.py +0 -0
  38. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_analyzer.py +0 -0
  39. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_detector.py +0 -0
  40. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_leak_detector.py +0 -0
  41. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_plugin.py +0 -0
  42. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_settings.py +0 -0
  43. {cicaddy_github-0.2.0 → cicaddy_github-0.3.0}/tests/unit/test_tools.py +0 -0
@@ -1,4 +1,4 @@
1
- FROM python:3.12-slim
1
+ FROM python:3.14-slim
2
2
 
3
3
  WORKDIR /app
4
4
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cicaddy-github
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: GitHub Actions plugin for cicaddy AI agent framework
5
5
  Project-URL: Homepage, https://github.com/redhat-community-ai-tools/cicaddy-action
6
6
  Project-URL: Repository, https://github.com/redhat-community-ai-tools/cicaddy-action.git
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cicaddy-github"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "GitHub Actions plugin for cicaddy AI agent framework"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -43,6 +43,26 @@ def dedent_code_blocks(text: str) -> str:
43
43
  return _FENCED_CODE_BLOCK.sub(_dedent, text)
44
44
 
45
45
 
46
+ # Matches output wrapped in a single ```markdown ... ``` fence.
47
+ _MARKDOWN_WRAPPER = re.compile(
48
+ r"^\s*```(?:markdown|md)\s*\n(.*?)\n\s*```\s*$",
49
+ re.DOTALL | re.IGNORECASE,
50
+ )
51
+
52
+
53
+ def strip_markdown_wrapper(text: str) -> str:
54
+ """Strip a wrapping ```markdown fence from the entire AI output.
55
+
56
+ Some models interpret ``output_format: markdown`` as "wrap the response
57
+ in a markdown code fence", which causes GitHub to render the comment as
58
+ a literal code block instead of formatted markdown.
59
+ """
60
+ m = _MARKDOWN_WRAPPER.match(text.strip())
61
+ if m:
62
+ return m.group(1)
63
+ return text
64
+
65
+
46
66
  class GitHubTaskAgent(BaseAIAgent):
47
67
  """AI Agent for scheduled tasks and changelog generation."""
48
68
 
@@ -280,7 +300,8 @@ Please provide your comprehensive analysis in markdown format.
280
300
  comment = f"{BOT_COMMENT_MARKER_PR_REVIEW}\n"
281
301
 
282
302
  if "ai_analysis" in analysis_result:
283
- comment += dedent_code_blocks(analysis_result["ai_analysis"]) + "\n"
303
+ cleaned = strip_markdown_wrapper(analysis_result["ai_analysis"])
304
+ comment += dedent_code_blocks(cleaned) + "\n"
284
305
 
285
306
  comment += (
286
307
  "\n<!-- cicaddy-footer -->\n---\n"
@@ -1,6 +1,6 @@
1
- """Tests for dedent_code_blocks in agents module."""
1
+ """Tests for dedent_code_blocks and strip_markdown_wrapper in agents module."""
2
2
 
3
- from cicaddy_github.github_integration.agents import dedent_code_blocks
3
+ from cicaddy_github.github_integration.agents import dedent_code_blocks, strip_markdown_wrapper
4
4
 
5
5
 
6
6
  class TestDedentCodeBlocks:
@@ -72,3 +72,42 @@ class TestDedentCodeBlocks:
72
72
  assert result.startswith("* Item one\n")
73
73
  assert result.endswith("* Item two")
74
74
  assert "+added line" in result
75
+
76
+
77
+ class TestStripMarkdownWrapper:
78
+ """Test stripping wrapping ```markdown fences from AI output."""
79
+
80
+ def test_strips_markdown_wrapper(self):
81
+ """Output wrapped in ```markdown is unwrapped."""
82
+ text = "```markdown\n### Summary\nSome analysis.\n```"
83
+ result = strip_markdown_wrapper(text)
84
+ assert result == "### Summary\nSome analysis."
85
+
86
+ def test_strips_md_wrapper(self):
87
+ """Output wrapped in ```md is also unwrapped."""
88
+ text = "```md\n## Title\nContent.\n```"
89
+ result = strip_markdown_wrapper(text)
90
+ assert result == "## Title\nContent."
91
+
92
+ def test_strips_case_insensitive(self):
93
+ """Output wrapped in ```Markdown or ```MD is also unwrapped."""
94
+ for tag in ("Markdown", "MARKDOWN", "MD", "Md"):
95
+ text = f"```{tag}\nContent here.\n```"
96
+ result = strip_markdown_wrapper(text)
97
+ assert result == "Content here.", f"Failed for tag: {tag}"
98
+
99
+ def test_no_change_without_wrapper(self):
100
+ """Plain markdown without wrapper is unchanged."""
101
+ text = "### Summary\nSome analysis."
102
+ assert strip_markdown_wrapper(text) == text
103
+
104
+ def test_preserves_internal_code_blocks(self):
105
+ """Code blocks inside the markdown wrapper are preserved."""
106
+ text = "```markdown\n### Example\n```python\nprint('hi')\n```\n```"
107
+ result = strip_markdown_wrapper(text)
108
+ assert "```python\nprint('hi')\n```" in result
109
+
110
+ def test_no_change_for_non_markdown_fence(self):
111
+ """A ```python wrapper is NOT stripped."""
112
+ text = "```python\nprint('hi')\n```"
113
+ assert strip_markdown_wrapper(text) == text
File without changes
File without changes
File without changes