Skip to content

Commit 981d5a9

Browse files
plon-Susk7patched.codes[bot]
andauthored
Created a new patchflow that can generate unit tests (#998)
* initial changes * Patched /home/priyash7/Desktop/open-source/patchwork/patchwork/patchflows/GenerateUnitTests/README.md * final changes * intermediate changes * made changes to modifyCode step * added README and fixed code * partition changes * added test to CI * added default extension to yaml --------- Co-authored-by: patched.codes[bot] <298395+patched.codes[bot]@users.noreply.github.com>
1 parent 42c3c42 commit 981d5a9

File tree

9 files changed

+127
-3
lines changed

9 files changed

+127
-3
lines changed

.github/workflows/test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
- dependencyupgrade-*
99
- generatereadme-*
1010
- generatedocstring-*
11+
- generateunittests-*
1112
- demo*
1213

1314
jobs:
@@ -201,6 +202,14 @@ jobs:
201202
--base_path=tests/cicd/generate_docstring \
202203
--disable_telemetry
203204
205+
- name: Generate UnitTests
206+
run: |
207+
poetry run patchwork GenerateUnitTests --log debug \
208+
--patched_api_key=${{ secrets.PATCHED_API_KEY }} \
209+
--github_api_key=${{ secrets.SCM_GITHUB_KEY }} \
210+
--folder_path=tests/cicd/generate_docstring \
211+
--disable_telemetry
212+
204213
- name: Generate README
205214
run: |
206215
# Specify the parent folder you want to check

patchwork/patchflows/GenerateREADME/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,4 @@ You can update the default [prompt template](./generate_readme_prompt.json). Not
9292
Here are some example PRs generated with the GenerateREADME patchflow:
9393

9494
- https://github.com/patched-codes/patchwork/pull/53
95-
- https://github.com/patched-codes/patchwork/pull/52
95+
- https://github.com/patched-codes/patchwork/pull/52
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import json
2+
from pathlib import Path
3+
import yaml
4+
5+
from patchwork.common.utils.step_typing import validate_steps_with_inputs
6+
from patchwork.step import Step
7+
from patchwork.steps import (
8+
LLM,
9+
CallCode2Prompt,
10+
ModifyCode,
11+
PR
12+
)
13+
14+
_DEFAULT_INPUT_FILE = Path(__file__).parent / "defaults.yml"
15+
_DEFAULT_PROMPT_JSON = Path(__file__).parent / "default_prompt.json"
16+
17+
class GenerateUnitTests(Step):
18+
def __init__(self, inputs):
19+
super().__init__(inputs)
20+
21+
final_inputs = yaml.safe_load(_DEFAULT_INPUT_FILE.read_text())
22+
if final_inputs is None:
23+
final_inputs = {}
24+
25+
final_inputs.update(inputs)
26+
27+
final_inputs["prompt_id"] = "GenerateUnitTests"
28+
if "folder_path" not in final_inputs.keys():
29+
final_inputs["folder_path"] = Path.cwd()
30+
else:
31+
final_inputs["folder_path"] = Path(final_inputs["folder_path"])
32+
33+
if "prompt_template_file" not in final_inputs:
34+
final_inputs["prompt_template_file"] = _DEFAULT_PROMPT_JSON
35+
36+
final_inputs["pr_title"] = f"PatchWork Unit Tests generated"
37+
final_inputs["branch_prefix"] = f"{self.__class__.__name__.lower()}-"
38+
39+
validate_steps_with_inputs(
40+
set(final_inputs.keys()).union({"prompt_values","files_to_patch"}), LLM, CallCode2Prompt,ModifyCode,PR
41+
)
42+
self.inputs = final_inputs
43+
44+
def run(self):
45+
outputs = CallCode2Prompt(self.inputs).run()
46+
new_file_name = f"test_file.{self.inputs['test_file_extension']}"
47+
new_file_path = Path(outputs['uri']).with_name(new_file_name)
48+
Path(outputs['uri']).rename(new_file_path)
49+
outputs['uri'] = str(new_file_path)
50+
self.inputs["response_partitions"] = {"patch": ["```", "\n", "```"]}
51+
self.inputs["files_to_patch"] = self.inputs["prompt_values"] = [outputs]
52+
outputs = LLM(self.inputs).run()
53+
self.inputs.update(outputs)
54+
outputs = ModifyCode(self.inputs).run()
55+
self.inputs.update(outputs)
56+
number = len(self.inputs["modified_code_files"])
57+
self.inputs["pr_header"] = f"This pull request from patchwork adds tests."
58+
outputs = PR(self.inputs).run()
59+
self.inputs.update(outputs)
60+
61+
return self.inputs
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## Code Documentation
2+
3+
### Inputs
4+
- The code reads default inputs from a YAML file (`defaults.yml`) and a JSON file (`default_prompt.json`).
5+
- The code takes user inputs and updates the default inputs accordingly.
6+
- The code expects inputs like `folder_path`, `prompt_template_file`, `test_file_extension`, etc.
7+
8+
### Outputs
9+
- The code generates unit tests based on the provided inputs.
10+
- It creates a new test file with the specified extension.
11+
- The code updates various parameters in the inputs dictionary during its execution.
12+
- The final output includes the modified inputs after running the unit test generation process.

patchwork/patchflows/GenerateUnitTests/__init__.py

Whitespace-only changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
{
3+
"id": "GenerateUnitTests",
4+
"prompts": [
5+
{
6+
"role": "system",
7+
"content": "You are a senior software tester who is highly skilled at writing unit tests across various programming languages. Users will specify classes or functions to test, and you will generate appropriate unit tests using the most relevant framework for the detected language. Output the code directly with no additional text, formatting, or triple quotes. The response should appear as if directly pasted into an editor."
8+
},
9+
{
10+
"role": "user",
11+
"content": "Code: {{fullContent}}"
12+
}
13+
]
14+
}
15+
]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# CallLLM Inputs
2+
# openai_api_key: required-for-chatgpt
3+
# google_api_key: required-for-gemini
4+
# model: gpt-4o
5+
# client_base_url: https://api.openai.com/v1
6+
# Example HF model
7+
# client_base_url: https://api-inference.huggingface.co/models/codellama/CodeLlama-70b-Instruct-hf/v1
8+
# model: codellama/CodeLlama-70b-Instruct-hf
9+
# model_temperature: 0.2
10+
# model_top_p: 0.95
11+
# model_max_tokens: 2000
12+
13+
# folder_path : path/to/folder/with/class
14+
15+
# Default value
16+
test_file_extension : py
17+
18+
# CommitChanges Inputs
19+
disable_branch: false
20+
21+
# CreatePR Inputs
22+
disable_pr: false
23+
force_pr_creation: true
24+
# github_api_key: required-for-github-scm
25+
# gitlab_api_key: required-for-gitlab-scm

patchwork/patchflows/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
from .GenerateREADME.GenerateREADME import GenerateREADME
55
from .PRReview.PRReview import PRReview
66
from .ResolveIssue.ResolveIssue import ResolveIssue
7+
from .GenerateUnitTests.GenerateUnitTests import GenerateUnitTests
78

8-
__all__ = ["AutoFix", "DependencyUpgrade", "GenerateREADME", "PRReview", "ResolveIssue", "GenerateDocstring"]
9+
__all__ = ["AutoFix", "DependencyUpgrade", "GenerateREADME", "PRReview", "ResolveIssue", "GenerateDocstring", "GenerateUnitTests"]

patchwork/steps/ModifyCode/ModifyCode.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ def run(self) -> dict:
8585
start_line = code_snippet.get("startLine")
8686
end_line = code_snippet.get("endLine")
8787
new_code = extracted_response.get("patch")
88+
8889
if new_code is None:
8990
continue
90-
91+
9192
replace_code_in_file(uri, start_line, end_line, new_code)
9293
modified_code_file = dict(path=uri, start_line=start_line, end_line=end_line, **extracted_response)
9394
modified_code_files.append(modified_code_file)

0 commit comments

Comments
 (0)