github-haystack 2.0.0__tar.gz → 3.0.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.
- github_haystack-3.0.0/CHANGELOG.md +102 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/LICENSE.txt +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/PKG-INFO +5 -4
- github_haystack-3.0.0/pydoc/config_docusaurus.yml +18 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/pyproject.toml +19 -5
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/file_editor.py +2 -2
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/issue_commenter.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/issue_viewer.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/pr_creator.py +7 -2
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/repo_forker.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/repo_viewer.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/context_prompt.py +0 -5
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/file_editor_tool.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/issue_commenter_tool.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/issue_viewer_tool.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/pr_creator_tool.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/repo_forker_tool.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/repo_viewer_tool.py +1 -1
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/utils.py +2 -2
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_file_editor.py +91 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_file_editor_tool.py +18 -11
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_pr_creator.py +79 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_repo_forker.py +54 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_repo_viewer.py +49 -0
- github_haystack-3.0.0/tests/test_utils.py +63 -0
- github_haystack-2.0.0/CHANGELOG.md +0 -52
- github_haystack-2.0.0/pydoc/config_docusaurus.yml +0 -33
- {github_haystack-2.0.0 → github_haystack-3.0.0}/.gitignore +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/README.md +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/github/__init__.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/components/connectors/py.typed +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/__init__.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/file_editor_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/issue_commenter_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/issue_viewer_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/pr_creator_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/repo_forker_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/repo_viewer_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/system_prompt.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/py.typed +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/__init__.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/py.typed +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/__init__.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_issue_commenter.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_issue_commenter_tool.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_issue_viewer.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_issue_viewer_tool.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_pr_creator_tool.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_repo_forker_tool.py +0 -0
- {github_haystack-2.0.0 → github_haystack-3.0.0}/tests/test_repo_viewer_tool.py +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [integrations/github-v2.1.0] - 2026-05-13
|
|
4
|
+
|
|
5
|
+
### 📚 Documentation
|
|
6
|
+
|
|
7
|
+
- Simplify pydoc configs (#2855)
|
|
8
|
+
|
|
9
|
+
### 🧪 Testing
|
|
10
|
+
|
|
11
|
+
- GitHub - make tests compatible with new Agent parameters (#2865)
|
|
12
|
+
- Test compatible integrations with python 3.14; update pyproject (#3001)
|
|
13
|
+
- Track test coverage for all integrations (#3065)
|
|
14
|
+
- Add unit tests for github + fix small handler bug (#3280)
|
|
15
|
+
|
|
16
|
+
### 🧹 Chores
|
|
17
|
+
|
|
18
|
+
- Add ANN type annotations to faiss, fastembed, firecrawl, github, google_ai (#2988)
|
|
19
|
+
- Enforce ruff docstring rules (D102/D103/D205/D209/D213/D417/D419) in integrations 11-20 (#3009)
|
|
20
|
+
|
|
21
|
+
### 🌀 Miscellaneous
|
|
22
|
+
|
|
23
|
+
- Test: Fix github tests due to changes on Haystack main (#2778)
|
|
24
|
+
|
|
25
|
+
## [integrations/github-v2.0.0] - 2026-01-12
|
|
26
|
+
|
|
27
|
+
### 📚 Documentation
|
|
28
|
+
|
|
29
|
+
- Add pydoc configurations for Docusaurus (#2411)
|
|
30
|
+
|
|
31
|
+
### ⚙️ CI
|
|
32
|
+
|
|
33
|
+
- Change pytest command (#2475)
|
|
34
|
+
|
|
35
|
+
### 🧹 Chores
|
|
36
|
+
|
|
37
|
+
- Remove Readme API CI workflow and configs (#2573)
|
|
38
|
+
- Fix nightly test (#2580)
|
|
39
|
+
- Make fmt command more forgiving (#2671)
|
|
40
|
+
- [**breaking**] Github - drop Python 3.9 and use X|Y typing (#2705)
|
|
41
|
+
|
|
42
|
+
### 🌀 Miscellaneous
|
|
43
|
+
|
|
44
|
+
- Adopt PEP 585 type hinting (part 3) (#2510)
|
|
45
|
+
- Chore: Fix tool validation test failures in github integration (#2659)
|
|
46
|
+
- Fix: Fix github integration unit tests (#2703)
|
|
47
|
+
|
|
48
|
+
## [integrations/github-v1.2.1] - 2025-10-20
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### 🌀 Miscellaneous
|
|
52
|
+
|
|
53
|
+
- Fix: handle empty GitHub tokens in authentication headers (#2400)
|
|
54
|
+
|
|
55
|
+
## [integrations/github-v1.2.0] - 2025-10-10
|
|
56
|
+
|
|
57
|
+
### 🚀 Features
|
|
58
|
+
|
|
59
|
+
- Add support for GitHubRepoForkerTool (#1968)
|
|
60
|
+
|
|
61
|
+
### 🧪 Testing
|
|
62
|
+
|
|
63
|
+
- Fix GitHub test (#2119)
|
|
64
|
+
|
|
65
|
+
### 🧹 Chores
|
|
66
|
+
|
|
67
|
+
- Standardize readmes - part 2 (#2205)
|
|
68
|
+
|
|
69
|
+
### 🌀 Miscellaneous
|
|
70
|
+
|
|
71
|
+
- Chore: Fix linting github (#2255)
|
|
72
|
+
|
|
73
|
+
## [integrations/github-v1.1.0] - 2025-07-01
|
|
74
|
+
|
|
75
|
+
### 🐛 Bug Fixes
|
|
76
|
+
|
|
77
|
+
- Fix Github types + add py.typed (#2024)
|
|
78
|
+
|
|
79
|
+
### 🧹 Chores
|
|
80
|
+
|
|
81
|
+
- Fix linting for ruff 0.12.0 (#1969)
|
|
82
|
+
- Remove black (#1985)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## [integrations/github-v1.0.1] - 2025-06-12
|
|
86
|
+
|
|
87
|
+
### 🐛 Bug Fixes
|
|
88
|
+
|
|
89
|
+
- Prompts and schemas of GitHubIssueCommenterTool and GitHubIssueViewerTool now properly explain url parameter (#1929)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
### 🧹 Chores
|
|
93
|
+
|
|
94
|
+
- Align core-integrations Hatch scripts (#1898)
|
|
95
|
+
|
|
96
|
+
## [integrations/github-v1.0.0] - 2025-05-28
|
|
97
|
+
|
|
98
|
+
### 🚀 Features
|
|
99
|
+
|
|
100
|
+
- Add GitHub integration with components, tools, and prompts (#1637)
|
|
101
|
+
|
|
102
|
+
<!-- generated by git-cliff -->
|
|
@@ -58,7 +58,7 @@ APPENDIX: How to apply the Apache License to your work.
|
|
|
58
58
|
|
|
59
59
|
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
|
60
60
|
|
|
61
|
-
Copyright
|
|
61
|
+
Copyright 2023-present deepset GmbH
|
|
62
62
|
|
|
63
63
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
64
64
|
you may not use this file except in compliance with the License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: github-haystack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Haystack components for interacting with GitHub repositories
|
|
5
5
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations/github
|
|
6
6
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/github/README.md
|
|
@@ -11,13 +11,14 @@ License-File: LICENSE.txt
|
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
18
19
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
19
20
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
20
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.11
|
|
21
22
|
Requires-Dist: haystack-ai>=2.22.0
|
|
22
23
|
Description-Content-Type: text/markdown
|
|
23
24
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
loaders:
|
|
2
|
+
- modules:
|
|
3
|
+
- haystack_integrations.components.connectors.github.file_editor
|
|
4
|
+
- haystack_integrations.components.connectors.github.issue_commenter
|
|
5
|
+
- haystack_integrations.components.connectors.github.issue_viewer
|
|
6
|
+
- haystack_integrations.components.connectors.github.pr_creator
|
|
7
|
+
- haystack_integrations.components.connectors.github.repo_viewer
|
|
8
|
+
- haystack_integrations.components.connectors.github.repo_forker
|
|
9
|
+
search_path: [../src]
|
|
10
|
+
processors:
|
|
11
|
+
- type: filter
|
|
12
|
+
documented_only: true
|
|
13
|
+
skip_empty_modules: true
|
|
14
|
+
renderer:
|
|
15
|
+
description: GitHub integration for Haystack
|
|
16
|
+
id: integrations-github
|
|
17
|
+
filename: github.md
|
|
18
|
+
title: GitHub
|
|
@@ -7,7 +7,7 @@ name = "github-haystack"
|
|
|
7
7
|
dynamic = ["version"]
|
|
8
8
|
description = 'Haystack components for interacting with GitHub repositories'
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = []
|
|
13
13
|
authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
|
|
@@ -15,10 +15,11 @@ classifiers = [
|
|
|
15
15
|
"License :: OSI Approved :: Apache Software License",
|
|
16
16
|
"Development Status :: 4 - Beta",
|
|
17
17
|
"Programming Language :: Python",
|
|
18
|
-
"Programming Language :: Python :: 3.10",
|
|
19
18
|
"Programming Language :: Python :: 3.11",
|
|
20
19
|
"Programming Language :: Python :: 3.12",
|
|
21
20
|
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Programming Language :: Python :: 3.15",
|
|
22
23
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
23
24
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
24
25
|
]
|
|
@@ -45,7 +46,7 @@ installer = "uv"
|
|
|
45
46
|
dependencies = ["haystack-pydoc-tools", "ruff"]
|
|
46
47
|
|
|
47
48
|
[tool.hatch.envs.default.scripts]
|
|
48
|
-
docs = ["pydoc
|
|
49
|
+
docs = ["haystack-pydoc pydoc/config_docusaurus.yml"]
|
|
49
50
|
fmt = "ruff check --fix {args}; ruff format {args}"
|
|
50
51
|
fmt-check = "ruff check {args} && ruff format --check {args}"
|
|
51
52
|
|
|
@@ -63,7 +64,8 @@ dependencies = [
|
|
|
63
64
|
unit = 'pytest -m "not integration" {args:tests}'
|
|
64
65
|
integration = 'pytest -m "integration" {args:tests}'
|
|
65
66
|
all = 'pytest {args:tests}'
|
|
66
|
-
cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x {args:tests}'
|
|
67
|
+
unit-cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x -m "not integration" {args:tests}'
|
|
68
|
+
integration-cov-append-retry = 'pytest --cov=haystack_integrations --cov-append --reruns 3 --reruns-delay 30 -x -m "integration" {args:tests}'
|
|
67
69
|
|
|
68
70
|
types = """mypy -p haystack_integrations.components.connectors.github \
|
|
69
71
|
-p haystack_integrations.prompts.github \
|
|
@@ -81,9 +83,17 @@ line-length = 120
|
|
|
81
83
|
[tool.ruff.lint]
|
|
82
84
|
select = [
|
|
83
85
|
"A",
|
|
86
|
+
"ANN",
|
|
84
87
|
"ARG",
|
|
85
88
|
"B",
|
|
86
89
|
"C",
|
|
90
|
+
"D102", # Missing docstring in public method
|
|
91
|
+
"D103", # Missing docstring in public function
|
|
92
|
+
"D205", # 1 blank line required between summary line and description
|
|
93
|
+
"D209", # Closing triple quotes go to new line
|
|
94
|
+
"D213", # summary lines must be positioned on the second physical line of the docstring
|
|
95
|
+
"D417", # Missing argument descriptions in the docstring
|
|
96
|
+
"D419", # Docstring is empty
|
|
87
97
|
"DTZ",
|
|
88
98
|
"E",
|
|
89
99
|
"EM",
|
|
@@ -118,9 +128,12 @@ ignore = [
|
|
|
118
128
|
"PLR0912",
|
|
119
129
|
"PLR0913",
|
|
120
130
|
"PLR0915",
|
|
131
|
+
"PLR0917",
|
|
121
132
|
# Misc
|
|
122
133
|
"B008",
|
|
123
134
|
"S101",
|
|
135
|
+
# Allow `Any` - used legitimately for dynamic types and SDK boundaries
|
|
136
|
+
"ANN401",
|
|
124
137
|
]
|
|
125
138
|
|
|
126
139
|
[tool.ruff.lint.isort]
|
|
@@ -131,13 +144,14 @@ ban-relative-imports = "parents"
|
|
|
131
144
|
|
|
132
145
|
[tool.ruff.lint.per-file-ignores]
|
|
133
146
|
# Tests can use magic values, assertions, and relative imports
|
|
134
|
-
"tests/**/*" = ["PLR2004", "S101", "TID252"]
|
|
147
|
+
"tests/**/*" = ["D", "PLR2004", "S101", "TID252", "ANN"]
|
|
135
148
|
# Ignore RUF001 for all files in the prompts directory
|
|
136
149
|
"src/haystack_integrations/components/prompts/**/*" = ["RUF001"]
|
|
137
150
|
|
|
138
151
|
[tool.coverage.run]
|
|
139
152
|
source = ["haystack_integrations"]
|
|
140
153
|
branch = true
|
|
154
|
+
relative_files = true
|
|
141
155
|
parallel = false
|
|
142
156
|
|
|
143
157
|
|
|
@@ -12,7 +12,7 @@ from haystack.utils import Secret, deserialize_secrets_inplace
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
class Command(str, Enum):
|
|
15
|
+
class Command(str, Enum): # noqa: UP042 # StrEnum would change str() of this public enum
|
|
16
16
|
"""
|
|
17
17
|
Available commands for file operations in GitHub.
|
|
18
18
|
|
|
@@ -82,7 +82,7 @@ class GitHubFileEditor:
|
|
|
82
82
|
repo: str | None = None,
|
|
83
83
|
branch: str = "main",
|
|
84
84
|
raise_on_failure: bool = True,
|
|
85
|
-
):
|
|
85
|
+
) -> None:
|
|
86
86
|
"""
|
|
87
87
|
Initialize the component.
|
|
88
88
|
|
|
@@ -38,7 +38,12 @@ class GitHubPRCreator:
|
|
|
38
38
|
```
|
|
39
39
|
"""
|
|
40
40
|
|
|
41
|
-
def __init__(
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
github_token: Secret = Secret.from_env_var("GITHUB_TOKEN"),
|
|
45
|
+
raise_on_failure: bool = True,
|
|
46
|
+
) -> None:
|
|
42
47
|
"""
|
|
43
48
|
Initialize the component.
|
|
44
49
|
|
|
@@ -243,7 +248,7 @@ class GitHubPRCreator:
|
|
|
243
248
|
# For cross-repository PRs, head must be in the format username:branch
|
|
244
249
|
head = f"{fork_owner}:{branch}"
|
|
245
250
|
|
|
246
|
-
pr_data = {
|
|
251
|
+
pr_data: dict[str, Any] = {
|
|
247
252
|
"title": title,
|
|
248
253
|
"body": body,
|
|
249
254
|
"head": head,
|
|
@@ -168,9 +168,4 @@ This is a mono-repo maintained by the deepset-Team that contains integrations fo
|
|
|
168
168
|
Typically, an integration consists of one or more components. Some integrations only contain document stores.
|
|
169
169
|
Each integration is a standalone pypi-package but you can find all of them in the core integrations repo.
|
|
170
170
|
|
|
171
|
-
|
|
172
|
-
3. "deepset-ai/haystack-experimental"
|
|
173
|
-
|
|
174
|
-
Contains experimental features for the Haystack framework.
|
|
175
|
-
|
|
176
171
|
"""
|
|
@@ -31,7 +31,7 @@ class GitHubFileEditorTool(ComponentTool):
|
|
|
31
31
|
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
|
32
32
|
inputs_from_state: dict[str, str] | None = None,
|
|
33
33
|
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None,
|
|
34
|
-
):
|
|
34
|
+
) -> None:
|
|
35
35
|
"""
|
|
36
36
|
Initialize the GitHub file editor tool.
|
|
37
37
|
|
|
@@ -30,7 +30,7 @@ class GitHubIssueCommenterTool(ComponentTool):
|
|
|
30
30
|
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
|
31
31
|
inputs_from_state: dict[str, str] | None = None,
|
|
32
32
|
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None,
|
|
33
|
-
):
|
|
33
|
+
) -> None:
|
|
34
34
|
"""
|
|
35
35
|
Initialize the GitHub issue commenter tool.
|
|
36
36
|
|
|
@@ -30,7 +30,7 @@ class GitHubIssueViewerTool(ComponentTool):
|
|
|
30
30
|
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
|
31
31
|
inputs_from_state: dict[str, str] | None = None,
|
|
32
32
|
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None,
|
|
33
|
-
):
|
|
33
|
+
) -> None:
|
|
34
34
|
"""
|
|
35
35
|
Initialize the GitHub issue viewer tool.
|
|
36
36
|
|
|
@@ -29,7 +29,7 @@ class GitHubPRCreatorTool(ComponentTool):
|
|
|
29
29
|
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
|
30
30
|
inputs_from_state: dict[str, str] | None = None,
|
|
31
31
|
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None,
|
|
32
|
-
):
|
|
32
|
+
) -> None:
|
|
33
33
|
"""
|
|
34
34
|
Initialize the GitHub PR creator tool.
|
|
35
35
|
|
|
@@ -29,7 +29,7 @@ class GitHubRepoForkerTool(ComponentTool):
|
|
|
29
29
|
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
|
30
30
|
inputs_from_state: dict[str, str] | None = None,
|
|
31
31
|
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None,
|
|
32
|
-
):
|
|
32
|
+
) -> None:
|
|
33
33
|
"""
|
|
34
34
|
Initialize the GitHub Repo Forker tool.
|
|
35
35
|
|
|
@@ -32,7 +32,7 @@ class GitHubRepoViewerTool(ComponentTool):
|
|
|
32
32
|
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
|
33
33
|
inputs_from_state: dict[str, str] | None = None,
|
|
34
34
|
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None,
|
|
35
|
-
):
|
|
35
|
+
) -> None:
|
|
36
36
|
"""
|
|
37
37
|
Initialize the GitHub repository viewer tool.
|
|
38
38
|
|
{github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/utils.py
RENAMED
|
@@ -21,7 +21,7 @@ def message_handler(documents: list[Document], max_length: int = 150_000) -> str
|
|
|
21
21
|
result_str = ""
|
|
22
22
|
for document in documents:
|
|
23
23
|
if document.meta["type"] in ["file", "dir", "error"]:
|
|
24
|
-
result_str += document.content or "" + "\n"
|
|
24
|
+
result_str += (document.content or "") + "\n"
|
|
25
25
|
else:
|
|
26
26
|
result_str += f"File Content for {document.meta['path']}\n\n"
|
|
27
27
|
result_str += document.content or ""
|
|
@@ -29,7 +29,7 @@ def message_handler(documents: list[Document], max_length: int = 150_000) -> str
|
|
|
29
29
|
if len(result_str) > max_length:
|
|
30
30
|
result_str = result_str[:max_length] + "...(large file can't be fully displayed)"
|
|
31
31
|
|
|
32
|
-
return result_str
|
|
32
|
+
return result_str.strip()
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def serialize_handlers(
|
|
@@ -280,3 +280,94 @@ class TestGitHubFileEditor:
|
|
|
280
280
|
assert "Authorization" not in headers
|
|
281
281
|
assert headers["Accept"] == "application/vnd.github.v3+json"
|
|
282
282
|
assert headers["User-Agent"] == "Haystack/GitHubFileEditor"
|
|
283
|
+
|
|
284
|
+
@pytest.mark.parametrize(
|
|
285
|
+
"file_b64,original,expected",
|
|
286
|
+
[
|
|
287
|
+
("SGVsbG8gV29ybGQ=", "missing", "Error: Original string not found in file"),
|
|
288
|
+
("SGVsbG8gSGVsbG8=", "Hello", "Error: Original string appears multiple times. Please provide more context"),
|
|
289
|
+
],
|
|
290
|
+
)
|
|
291
|
+
@patch("requests.get")
|
|
292
|
+
def test_run_edit_string_edge_cases(self, mock_get, file_b64, original, expected, monkeypatch):
|
|
293
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
294
|
+
mock_get.return_value.json.return_value = {"content": file_b64, "sha": "abc123"}
|
|
295
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
296
|
+
|
|
297
|
+
editor = GitHubFileEditor()
|
|
298
|
+
result = editor.run(
|
|
299
|
+
command=Command.EDIT,
|
|
300
|
+
payload={"path": "f.txt", "original": original, "replacement": "X", "message": "m"},
|
|
301
|
+
repo="owner/repo",
|
|
302
|
+
branch="main",
|
|
303
|
+
)
|
|
304
|
+
assert result["result"] == expected
|
|
305
|
+
|
|
306
|
+
@patch("requests.get")
|
|
307
|
+
def test_run_undo_not_last_user(self, mock_get, monkeypatch):
|
|
308
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
309
|
+
|
|
310
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
311
|
+
mock_get.return_value.json.side_effect = [
|
|
312
|
+
[{"author": {"login": "different_user"}, "sha": "sha1"}],
|
|
313
|
+
{"login": "another_user"},
|
|
314
|
+
]
|
|
315
|
+
|
|
316
|
+
editor = GitHubFileEditor()
|
|
317
|
+
result = editor.run(command=Command.UNDO, payload={"message": "m"}, repo="owner/repo", branch="main")
|
|
318
|
+
assert result["result"] == "Error: Last commit was not made by the current user"
|
|
319
|
+
|
|
320
|
+
@pytest.mark.parametrize(
|
|
321
|
+
"kwargs,expected_substring",
|
|
322
|
+
[
|
|
323
|
+
({"command": Command.EDIT, "payload": {}}, "Error: No repository specified"),
|
|
324
|
+
(
|
|
325
|
+
{"command": "bogus", "payload": {}, "repo": "owner/repo"},
|
|
326
|
+
None,
|
|
327
|
+
),
|
|
328
|
+
],
|
|
329
|
+
)
|
|
330
|
+
def test_run_validation_errors(self, kwargs, expected_substring, monkeypatch):
|
|
331
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
332
|
+
editor = GitHubFileEditor()
|
|
333
|
+
if expected_substring is None:
|
|
334
|
+
with pytest.raises(ValueError):
|
|
335
|
+
editor.run(**kwargs)
|
|
336
|
+
else:
|
|
337
|
+
result = editor.run(**kwargs)
|
|
338
|
+
assert expected_substring in result["result"]
|
|
339
|
+
|
|
340
|
+
@patch("requests.get")
|
|
341
|
+
def test_run_command_as_string(self, mock_get, monkeypatch):
|
|
342
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
343
|
+
mock_get.return_value.json.return_value = {"content": "SGVsbG8=", "sha": "abc"}
|
|
344
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
345
|
+
|
|
346
|
+
editor = GitHubFileEditor(repo="owner/repo")
|
|
347
|
+
with patch.object(editor, "_update_file", return_value=True):
|
|
348
|
+
result = editor.run(
|
|
349
|
+
command="EDIT",
|
|
350
|
+
payload={"path": "f.txt", "original": "Hello", "replacement": "Hi", "message": "m"},
|
|
351
|
+
)
|
|
352
|
+
assert result["result"] == "Edit successful"
|
|
353
|
+
|
|
354
|
+
@pytest.mark.parametrize(
|
|
355
|
+
"command,payload",
|
|
356
|
+
[
|
|
357
|
+
(Command.UNDO, {"message": "m"}),
|
|
358
|
+
(Command.CREATE, {"path": "n.txt", "content": "x", "message": "m"}),
|
|
359
|
+
(Command.DELETE, {"path": "n.txt", "message": "m"}),
|
|
360
|
+
],
|
|
361
|
+
)
|
|
362
|
+
@patch("requests.get")
|
|
363
|
+
def test_run_command_error_handling_no_raise(self, mock_get, command, payload, monkeypatch):
|
|
364
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
365
|
+
mock_get.side_effect = requests.RequestException("API Error")
|
|
366
|
+
|
|
367
|
+
editor = GitHubFileEditor(raise_on_failure=False)
|
|
368
|
+
with (
|
|
369
|
+
patch("requests.put", side_effect=requests.RequestException("API Error")),
|
|
370
|
+
patch("requests.delete", side_effect=requests.RequestException("API Error")),
|
|
371
|
+
):
|
|
372
|
+
result = editor.run(command=command, payload=payload, repo="owner/repo", branch="main")
|
|
373
|
+
assert "Error: API Error" in result["result"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import unittest
|
|
4
|
+
import unittest.mock
|
|
5
5
|
|
|
6
6
|
from haystack import Pipeline
|
|
7
7
|
from haystack.components.agents import Agent
|
|
@@ -143,16 +143,6 @@ class TestGitHubFileEditorTool:
|
|
|
143
143
|
|
|
144
144
|
pipeline_dict = pipeline.to_dict()
|
|
145
145
|
|
|
146
|
-
# Remove parameters introduced after haystack-ai==2.12.0 (the minimum supported version)
|
|
147
|
-
# to maintain compatibility
|
|
148
|
-
try:
|
|
149
|
-
pipeline_dict["components"]["agent"]["init_parameters"]["chat_generator"]["init_parameters"].pop(
|
|
150
|
-
"http_client_kwargs", None
|
|
151
|
-
)
|
|
152
|
-
pipeline_dict["components"]["agent"]["init_parameters"].pop("tool_invoker_kwargs", None)
|
|
153
|
-
except KeyError:
|
|
154
|
-
pass
|
|
155
|
-
|
|
156
146
|
expected_dict = {
|
|
157
147
|
"metadata": {},
|
|
158
148
|
"max_runs_per_component": 100,
|
|
@@ -205,9 +195,26 @@ class TestGitHubFileEditorTool:
|
|
|
205
195
|
"connection_type_validation": True,
|
|
206
196
|
}
|
|
207
197
|
|
|
198
|
+
# The Agent and the OpenAIChatGenerator belong to haystack-ai, and their init parameters vary across the
|
|
199
|
+
# haystack-ai versions this integration supports. Accept whatever the installed version adds beyond the
|
|
200
|
+
# expected baseline: this test only pins the serialization of GitHubFileEditorTool.
|
|
201
|
+
actual_agent_params = pipeline_dict["components"]["agent"]["init_parameters"]
|
|
202
|
+
expected_agent_params = expected_dict["components"]["agent"]["init_parameters"]
|
|
203
|
+
for actual_params, expected_params in [
|
|
204
|
+
(actual_agent_params, expected_agent_params),
|
|
205
|
+
(
|
|
206
|
+
actual_agent_params["chat_generator"]["init_parameters"],
|
|
207
|
+
expected_agent_params["chat_generator"]["init_parameters"],
|
|
208
|
+
),
|
|
209
|
+
]:
|
|
210
|
+
for key in actual_params.keys() - expected_params.keys():
|
|
211
|
+
expected_params[key] = actual_params[key]
|
|
212
|
+
|
|
208
213
|
assert pipeline_dict == expected_dict
|
|
209
214
|
|
|
210
215
|
deserialized_pipeline = Pipeline.from_dict(pipeline_dict)
|
|
216
|
+
assert deserialized_pipeline == pipeline
|
|
217
|
+
|
|
211
218
|
deserialized_components = [instance for _, instance in deserialized_pipeline.graph.nodes(data="instance")]
|
|
212
219
|
deserialized_agent = deserialized_components[0]
|
|
213
220
|
assert isinstance(deserialized_agent, Agent)
|
|
@@ -143,3 +143,82 @@ class TestGitHubPRCreator:
|
|
|
143
143
|
assert "Authorization" not in headers
|
|
144
144
|
assert headers["Accept"] == "application/vnd.github.v3+json"
|
|
145
145
|
assert headers["User-Agent"] == "Haystack/GitHubPRCreator"
|
|
146
|
+
|
|
147
|
+
def test_parse_issue_url_invalid(self, monkeypatch):
|
|
148
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
149
|
+
pr_creator = GitHubPRCreator()
|
|
150
|
+
with pytest.raises(ValueError, match="Invalid GitHub issue URL format"):
|
|
151
|
+
pr_creator._parse_issue_url("https://github.com/owner/repo/pull/1")
|
|
152
|
+
|
|
153
|
+
@patch("requests.get")
|
|
154
|
+
def test_run_returns_error_when_fork_not_found(self, mock_get, monkeypatch):
|
|
155
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
156
|
+
mock_get.return_value.json.return_value = {"login": "test_user"}
|
|
157
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
158
|
+
|
|
159
|
+
pr_creator = GitHubPRCreator()
|
|
160
|
+
with patch.object(pr_creator, "_check_fork_exists", return_value=False):
|
|
161
|
+
result = pr_creator.run(
|
|
162
|
+
issue_url="https://github.com/owner/repo/issues/456",
|
|
163
|
+
title="Test PR",
|
|
164
|
+
branch="feature-branch",
|
|
165
|
+
base="main",
|
|
166
|
+
)
|
|
167
|
+
assert result == {"result": "Error: Fork not found at test_user/repo"}
|
|
168
|
+
|
|
169
|
+
@pytest.mark.parametrize(
|
|
170
|
+
"fork_payload,raises_request,expected",
|
|
171
|
+
[
|
|
172
|
+
({"fork": True}, False, True),
|
|
173
|
+
({"fork": False}, False, False),
|
|
174
|
+
({}, False, False),
|
|
175
|
+
(None, True, False),
|
|
176
|
+
],
|
|
177
|
+
)
|
|
178
|
+
@patch("requests.get")
|
|
179
|
+
def test_check_fork_exists(self, mock_get, fork_payload, raises_request, expected, monkeypatch):
|
|
180
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
181
|
+
if raises_request:
|
|
182
|
+
mock_get.side_effect = requests.RequestException("boom")
|
|
183
|
+
else:
|
|
184
|
+
mock_get.return_value.json.return_value = fork_payload
|
|
185
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
186
|
+
|
|
187
|
+
pr_creator = GitHubPRCreator()
|
|
188
|
+
assert pr_creator._check_fork_exists("repo", "test_user") is expected
|
|
189
|
+
|
|
190
|
+
@pytest.mark.parametrize("raise_on_failure", [True, False])
|
|
191
|
+
@patch("requests.post")
|
|
192
|
+
def test_create_fork(self, mock_post, raise_on_failure, monkeypatch):
|
|
193
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
194
|
+
mock_post.return_value.json.return_value = {"owner": {"login": "test_user"}}
|
|
195
|
+
mock_post.return_value.raise_for_status.return_value = None
|
|
196
|
+
|
|
197
|
+
pr_creator = GitHubPRCreator(raise_on_failure=raise_on_failure)
|
|
198
|
+
assert pr_creator._create_fork("owner", "repo") == "test_user"
|
|
199
|
+
|
|
200
|
+
mock_post.side_effect = requests.RequestException("boom")
|
|
201
|
+
if raise_on_failure:
|
|
202
|
+
with pytest.raises(RuntimeError, match="Failed to create fork"):
|
|
203
|
+
pr_creator._create_fork("owner", "repo")
|
|
204
|
+
else:
|
|
205
|
+
assert pr_creator._create_fork("owner", "repo") is None
|
|
206
|
+
|
|
207
|
+
@pytest.mark.parametrize("raise_on_failure", [True, False])
|
|
208
|
+
@patch("requests.post")
|
|
209
|
+
@patch("requests.get")
|
|
210
|
+
def test_create_branch(self, mock_get, mock_post, raise_on_failure, monkeypatch):
|
|
211
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
212
|
+
mock_get.return_value.json.return_value = {"object": {"sha": "abc123"}}
|
|
213
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
214
|
+
mock_post.return_value.raise_for_status.return_value = None
|
|
215
|
+
|
|
216
|
+
pr_creator = GitHubPRCreator(raise_on_failure=raise_on_failure)
|
|
217
|
+
assert pr_creator._create_branch("owner", "repo", "feature", "main") is True
|
|
218
|
+
|
|
219
|
+
mock_get.side_effect = requests.RequestException("boom")
|
|
220
|
+
if raise_on_failure:
|
|
221
|
+
with pytest.raises(RuntimeError, match="Failed to create branch"):
|
|
222
|
+
pr_creator._create_branch("owner", "repo", "feature", "main")
|
|
223
|
+
else:
|
|
224
|
+
assert pr_creator._create_branch("owner", "repo", "feature", "main") is False
|
|
@@ -272,3 +272,57 @@ class TestGitHubRepoForker:
|
|
|
272
272
|
assert "Authorization" not in headers
|
|
273
273
|
assert headers["Accept"] == "application/vnd.github.v3+json"
|
|
274
274
|
assert headers["User-Agent"] == "Haystack/GitHubRepoForker"
|
|
275
|
+
|
|
276
|
+
@pytest.mark.parametrize(
|
|
277
|
+
"status_code,raises,expected",
|
|
278
|
+
[
|
|
279
|
+
(200, False, True),
|
|
280
|
+
(404, False, False),
|
|
281
|
+
(None, True, False),
|
|
282
|
+
],
|
|
283
|
+
)
|
|
284
|
+
@patch("requests.get")
|
|
285
|
+
def test_check_fork_status(self, mock_get, status_code, raises, expected, monkeypatch):
|
|
286
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
287
|
+
if raises:
|
|
288
|
+
mock_get.side_effect = requests.RequestException("boom")
|
|
289
|
+
else:
|
|
290
|
+
mock_get.return_value.status_code = status_code
|
|
291
|
+
|
|
292
|
+
forker = GitHubRepoForker()
|
|
293
|
+
assert forker._check_fork_status("test_user/repo") is expected
|
|
294
|
+
|
|
295
|
+
def test_get_existing_repository_returns_none_on_exception(self, monkeypatch):
|
|
296
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
297
|
+
|
|
298
|
+
forker = GitHubRepoForker()
|
|
299
|
+
with (
|
|
300
|
+
patch.object(forker, "_get_authenticated_user", return_value="test_user"),
|
|
301
|
+
patch("requests.get", side_effect=requests.RequestException("boom")),
|
|
302
|
+
):
|
|
303
|
+
assert forker._get_existing_repository("repo") is None
|
|
304
|
+
|
|
305
|
+
@pytest.mark.parametrize("succeeds_within_timeout", [True, False])
|
|
306
|
+
def test_run_wait_for_completion(self, succeeds_within_timeout, monkeypatch):
|
|
307
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
308
|
+
|
|
309
|
+
forker = GitHubRepoForker(
|
|
310
|
+
wait_for_completion=True,
|
|
311
|
+
max_wait_seconds=5 if succeeds_within_timeout else 0,
|
|
312
|
+
poll_interval=0,
|
|
313
|
+
create_branch=False,
|
|
314
|
+
)
|
|
315
|
+
with (
|
|
316
|
+
patch.object(forker, "_parse_github_url", return_value=("owner", "repo", "123")),
|
|
317
|
+
patch.object(forker, "_get_authenticated_user", return_value="test_user"),
|
|
318
|
+
patch.object(forker, "_get_existing_repository", return_value=None),
|
|
319
|
+
patch.object(forker, "_create_fork", return_value="test_user/repo"),
|
|
320
|
+
patch.object(forker, "_check_fork_status", side_effect=[False, True]),
|
|
321
|
+
patch("time.sleep", lambda _: None),
|
|
322
|
+
):
|
|
323
|
+
if succeeds_within_timeout:
|
|
324
|
+
result = forker.run(url="https://github.com/owner/repo/issues/123")
|
|
325
|
+
assert result == {"repo": "test_user/repo", "issue_branch": None}
|
|
326
|
+
else:
|
|
327
|
+
with pytest.raises(TimeoutError):
|
|
328
|
+
forker.run(url="https://github.com/owner/repo/issues/123")
|
|
@@ -186,3 +186,52 @@ class TestGitHubRepoViewer:
|
|
|
186
186
|
assert "Authorization" not in headers
|
|
187
187
|
assert headers["Accept"] == "application/vnd.github.v3+json"
|
|
188
188
|
assert headers["User-Agent"] == "Haystack/GitHubRepoViewer"
|
|
189
|
+
|
|
190
|
+
def test_run_no_repo_raises(self, monkeypatch):
|
|
191
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
192
|
+
viewer = GitHubRepoViewer()
|
|
193
|
+
with pytest.raises(ValueError, match="Repository not provided"):
|
|
194
|
+
viewer.run(path="README.md")
|
|
195
|
+
|
|
196
|
+
@pytest.mark.parametrize(
|
|
197
|
+
"file_payload,error_substring",
|
|
198
|
+
[
|
|
199
|
+
(
|
|
200
|
+
{
|
|
201
|
+
"name": "big.bin",
|
|
202
|
+
"path": "big.bin",
|
|
203
|
+
"size": 2_000_000,
|
|
204
|
+
"html_url": "https://x",
|
|
205
|
+
"content": "",
|
|
206
|
+
"encoding": "base64",
|
|
207
|
+
},
|
|
208
|
+
"exceeds limit",
|
|
209
|
+
),
|
|
210
|
+
(
|
|
211
|
+
{
|
|
212
|
+
"name": "raw.txt",
|
|
213
|
+
"path": "raw.txt",
|
|
214
|
+
"size": 5,
|
|
215
|
+
"html_url": "https://x",
|
|
216
|
+
"content": "Hello",
|
|
217
|
+
"encoding": "utf-8",
|
|
218
|
+
},
|
|
219
|
+
None,
|
|
220
|
+
),
|
|
221
|
+
],
|
|
222
|
+
)
|
|
223
|
+
@patch("requests.get")
|
|
224
|
+
def test_run_file_size_and_encoding(self, mock_get, file_payload, error_substring, monkeypatch):
|
|
225
|
+
monkeypatch.setenv("GITHUB_TOKEN", "test-token")
|
|
226
|
+
mock_get.return_value.json.return_value = file_payload
|
|
227
|
+
mock_get.return_value.raise_for_status.return_value = None
|
|
228
|
+
|
|
229
|
+
viewer = GitHubRepoViewer(raise_on_failure=False)
|
|
230
|
+
result = viewer.run(repo="owner/repo", path=file_payload["path"])
|
|
231
|
+
doc = result["documents"][0]
|
|
232
|
+
if error_substring is None:
|
|
233
|
+
assert doc.content == "Hello"
|
|
234
|
+
assert doc.meta["type"] == "file_content"
|
|
235
|
+
else:
|
|
236
|
+
assert doc.meta["type"] == "error"
|
|
237
|
+
assert error_substring in doc.content
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import pytest
|
|
5
|
+
from haystack import Document
|
|
6
|
+
|
|
7
|
+
from haystack_integrations.tools.github.utils import message_handler, serialize_handlers
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestMessageHandler:
|
|
11
|
+
@pytest.mark.parametrize(
|
|
12
|
+
"documents,expected",
|
|
13
|
+
[
|
|
14
|
+
(
|
|
15
|
+
[Document(content="error message", meta={"type": "error"})],
|
|
16
|
+
"error message",
|
|
17
|
+
),
|
|
18
|
+
(
|
|
19
|
+
[
|
|
20
|
+
Document(content="docs", meta={"type": "dir"}),
|
|
21
|
+
Document(content="README.md", meta={"type": "file"}),
|
|
22
|
+
],
|
|
23
|
+
"docs\nREADME.md",
|
|
24
|
+
),
|
|
25
|
+
(
|
|
26
|
+
[Document(content="print('hi')", meta={"type": "file_content", "path": "main.py"})],
|
|
27
|
+
"File Content for main.py\n\nprint('hi')",
|
|
28
|
+
),
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
def test_message_handler_renders_documents(self, documents, expected):
|
|
32
|
+
assert message_handler(documents) == expected
|
|
33
|
+
|
|
34
|
+
def test_message_handler_truncates_to_max_length(self):
|
|
35
|
+
big_content = "x" * 200
|
|
36
|
+
doc = Document(content=big_content, meta={"type": "file_content", "path": "main.py"})
|
|
37
|
+
result = message_handler([doc], max_length=50)
|
|
38
|
+
assert result.endswith("...(large file can't be fully displayed)")
|
|
39
|
+
assert len(result) == 50 + len("...(large file can't be fully displayed)")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestSerializeHandlers:
|
|
43
|
+
@pytest.mark.parametrize(
|
|
44
|
+
"outputs_to_state,outputs_to_string,error_match",
|
|
45
|
+
[
|
|
46
|
+
(
|
|
47
|
+
{"documents": {"handler": "not_callable"}},
|
|
48
|
+
None,
|
|
49
|
+
"outputs_to_state\\[documents\\] is not a callable",
|
|
50
|
+
),
|
|
51
|
+
(
|
|
52
|
+
None,
|
|
53
|
+
{"handler": "not_callable"},
|
|
54
|
+
"outputs_to_string is not a callable",
|
|
55
|
+
),
|
|
56
|
+
],
|
|
57
|
+
)
|
|
58
|
+
def test_serialize_handlers_raises_when_handler_not_callable(
|
|
59
|
+
self, outputs_to_state, outputs_to_string, error_match
|
|
60
|
+
):
|
|
61
|
+
serialized: dict = {}
|
|
62
|
+
with pytest.raises(ValueError, match=error_match):
|
|
63
|
+
serialize_handlers(serialized, outputs_to_state, outputs_to_string)
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [integrations/github-v1.2.1] - 2025-10-20
|
|
4
|
-
|
|
5
|
-
### 🚀 Features
|
|
6
|
-
|
|
7
|
-
- Add support for GitHubRepoForkerTool (#1968)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
### 🧪 Testing
|
|
11
|
-
|
|
12
|
-
- Fix GitHub test (#2119)
|
|
13
|
-
|
|
14
|
-
### 🧹 Chores
|
|
15
|
-
|
|
16
|
-
- Standardize readmes - part 2 (#2205)
|
|
17
|
-
|
|
18
|
-
### 🌀 Miscellaneous
|
|
19
|
-
|
|
20
|
-
- Chore: Fix linting github (#2255)
|
|
21
|
-
- Fix: handle empty GitHub tokens in authentication headers (#2400)
|
|
22
|
-
|
|
23
|
-
## [integrations/github-v1.1.0] - 2025-07-01
|
|
24
|
-
|
|
25
|
-
### 🐛 Bug Fixes
|
|
26
|
-
|
|
27
|
-
- Fix Github types + add py.typed (#2024)
|
|
28
|
-
|
|
29
|
-
### 🧹 Chores
|
|
30
|
-
|
|
31
|
-
- Fix linting for ruff 0.12.0 (#1969)
|
|
32
|
-
- Remove black (#1985)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## [integrations/github-v1.0.1] - 2025-06-12
|
|
36
|
-
|
|
37
|
-
### 🐛 Bug Fixes
|
|
38
|
-
|
|
39
|
-
- Prompts and schemas of GitHubIssueCommenterTool and GitHubIssueViewerTool now properly explain url parameter (#1929)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
### 🧹 Chores
|
|
43
|
-
|
|
44
|
-
- Align core-integrations Hatch scripts (#1898)
|
|
45
|
-
|
|
46
|
-
## [integrations/github-v1.0.0] - 2025-05-28
|
|
47
|
-
|
|
48
|
-
### 🚀 Features
|
|
49
|
-
|
|
50
|
-
- Add GitHub integration with components, tools, and prompts (#1637)
|
|
51
|
-
|
|
52
|
-
<!-- generated by git-cliff -->
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
loaders:
|
|
2
|
-
- ignore_when_discovered:
|
|
3
|
-
- __init__
|
|
4
|
-
modules:
|
|
5
|
-
- haystack_integrations.components.connectors.github.file_editor
|
|
6
|
-
- haystack_integrations.components.connectors.github.issue_commenter
|
|
7
|
-
- haystack_integrations.components.connectors.github.issue_viewer
|
|
8
|
-
- haystack_integrations.components.connectors.github.pr_creator
|
|
9
|
-
- haystack_integrations.components.connectors.github.repo_viewer
|
|
10
|
-
- haystack_integrations.components.connectors.github.repo_forker
|
|
11
|
-
search_path:
|
|
12
|
-
- ../src
|
|
13
|
-
type: haystack_pydoc_tools.loaders.CustomPythonLoader
|
|
14
|
-
processors:
|
|
15
|
-
- do_not_filter_modules: false
|
|
16
|
-
documented_only: true
|
|
17
|
-
expression: null
|
|
18
|
-
skip_empty_modules: true
|
|
19
|
-
type: filter
|
|
20
|
-
- type: smart
|
|
21
|
-
- type: crossref
|
|
22
|
-
renderer:
|
|
23
|
-
description: GitHub integration for Haystack
|
|
24
|
-
id: integrations-github
|
|
25
|
-
markdown:
|
|
26
|
-
add_member_class_prefix: false
|
|
27
|
-
add_method_class_prefix: true
|
|
28
|
-
classdef_code_block: false
|
|
29
|
-
descriptive_class_title: false
|
|
30
|
-
descriptive_module_title: true
|
|
31
|
-
filename: github.md
|
|
32
|
-
title: GitHub
|
|
33
|
-
type: haystack_pydoc_tools.renderers.DocusaurusRenderer
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/prompts/github/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_haystack-2.0.0 → github_haystack-3.0.0}/src/haystack_integrations/tools/github/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|