From e3846a480e9de360733132aef4fc5a949c388169 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 09:21:31 +0300 Subject: [PATCH 01/16] s --- CHANGELOG.md | 8 ++ pr_agent/cli.py | 12 ++- pr_agent/config_loader.py | 1 + pr_agent/settings/configuration.toml | 9 +- pr_agent/settings/pr_update_changelog.toml | 30 ++++++ pr_agent/tools/pr_update_changelog.py | 103 +++++++++++++++++++++ 6 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 pr_agent/settings/pr_update_changelog.toml create mode 100644 pr_agent/tools/pr_update_changelog.py diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..12dfefea --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +## [Unreleased] - 2023-07-23 + +### Added +- '/describe' operation now updates also the label of the PR + +### Changed + +### Fixed \ No newline at end of file diff --git a/pr_agent/cli.py b/pr_agent/cli.py index 4477016c..2bae6bd4 100644 --- a/pr_agent/cli.py +++ b/pr_agent/cli.py @@ -8,6 +8,7 @@ from pr_agent.tools.pr_description import PRDescription from pr_agent.tools.pr_information_from_user import PRInformationFromUser from pr_agent.tools.pr_questions import PRQuestions from pr_agent.tools.pr_reviewer import PRReviewer +from pr_agent.tools.pr_update_changelog import PRUpdateChangelog def run(args=None): @@ -27,13 +28,15 @@ ask / ask_question [question] - Ask a question about the PR. describe / describe_pr - Modify the PR title and description based on the PR's contents. improve / improve_code - Suggest improvements to the code in the PR as pull request comments ready to commit. reflect - Ask the PR author questions about the PR. +update_changelog - Update the changelog based on the PR's contents. """) parser.add_argument('--pr_url', type=str, help='The URL of the PR to review', required=True) parser.add_argument('command', type=str, help='The', choices=['review', 'review_pr', 'ask', 'ask_question', 'describe', 'describe_pr', 'improve', 'improve_code', - 'reflect', 'review_after_reflect'], + 'reflect', 'review_after_reflect', + 'update_changelog'], default='review') parser.add_argument('rest', nargs=argparse.REMAINDER, default=[]) args = parser.parse_args(args) @@ -49,7 +52,8 @@ reflect - Ask the PR author questions about the PR. 'review': _handle_review_command, 'review_pr': _handle_review_command, 'reflect': _handle_reflect_command, - 'review_after_reflect': _handle_review_after_reflect_command + 'review_after_reflect': _handle_review_after_reflect_command, + 'update_changelog': _handle_update_changelog, } if command in commands: commands[command](args.pr_url, args.rest) @@ -96,6 +100,10 @@ def _handle_review_after_reflect_command(pr_url: str, rest: list): reviewer = PRReviewer(pr_url, cli_mode=True, is_answer=True) asyncio.run(reviewer.review()) +def _handle_update_changelog(pr_url: str, rest: list): + print(f"Updating changlog for: {pr_url}") + reviewer = PRUpdateChangelog(pr_url, cli_mode=True) + asyncio.run(reviewer.update_changelog()) if __name__ == '__main__': run() diff --git a/pr_agent/config_loader.py b/pr_agent/config_loader.py index 7841f0b7..69d20d88 100644 --- a/pr_agent/config_loader.py +++ b/pr_agent/config_loader.py @@ -19,6 +19,7 @@ settings = Dynaconf( "settings/pr_description_prompts.toml", "settings/pr_code_suggestions_prompts.toml", "settings/pr_information_from_user_prompts.toml", + "settings/pr_update_changelog.toml", "settings_prod/.secrets.toml" ]] ) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index fbf8ffec..33b84f79 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -1,10 +1,10 @@ [config] model="gpt-4" -fallback-models=["gpt-3.5-turbo-16k", "gpt-3.5-turbo"] +fallback-models=["gpt-3.5-turbo-16k"] git_provider="github" -publish_output=true +publish_output=false publish_output_progress=true -verbosity_level=0 # 0,1,2 +verbosity_level=2 # 0,1,2 use_extra_bad_extensions=false [pr_reviewer] @@ -24,6 +24,9 @@ publish_description_as_comment=false [pr_code_suggestions] num_code_suggestions=4 +[pr_update_changelog] +push_changelog_changes=false + [github] # The type of deployment to create. Valid values are 'app' or 'user'. deployment_type = "user" diff --git a/pr_agent/settings/pr_update_changelog.toml b/pr_agent/settings/pr_update_changelog.toml new file mode 100644 index 00000000..9fb386ea --- /dev/null +++ b/pr_agent/settings/pr_update_changelog.toml @@ -0,0 +1,30 @@ +[pr_update_changelog_prompt] +system="""You are a language model called CodiumAI-PR-Code-Reviewer. +Your task is to update the CHANGELOG.md file of the project, based on the PR diff. +The update should be short and concise. It should match the existing CHANGELOG.md format. + +Note that the output should be only the added lines to the CHANGELOG.md file, and nothing else. + +""" + +user="""PR Info: +Title: '{{title}}' +Branch: '{{branch}}' +Description: '{{description}}' +{%- if language %} +Main language: {{language}} +{%- endif %} + + +The PR Diff: +``` +{{diff}} +``` + +The current CHANGELOG.md: +``` +{{changelog_file}} +``` + +Response: +""" diff --git a/pr_agent/tools/pr_update_changelog.py b/pr_agent/tools/pr_update_changelog.py new file mode 100644 index 00000000..71e5e6e7 --- /dev/null +++ b/pr_agent/tools/pr_update_changelog.py @@ -0,0 +1,103 @@ +import copy +import json +import logging +import textwrap +from typing import Tuple + +from jinja2 import Environment, StrictUndefined + +from pr_agent.algo.ai_handler import AiHandler +from pr_agent.algo.pr_processing import get_pr_diff, retry_with_fallback_models +from pr_agent.algo.token_handler import TokenHandler +from pr_agent.config_loader import settings +from pr_agent.git_providers import get_git_provider, GithubProvider +from pr_agent.git_providers.git_provider import get_main_pr_language + + +class PRUpdateChangelog: + def __init__(self, pr_url: str, cli_mode=False): + + self.git_provider = get_git_provider()(pr_url) + self.main_language = get_main_pr_language( + self.git_provider.get_languages(), self.git_provider.get_files() + ) + max_lines=50 + try: + self.changelog_file = self.git_provider.repo_obj.get_contents("CHANGELOG.md", ref=self.git_provider.get_pr_branch()) + changelog_file_lines = self.changelog_file.decoded_content.decode().splitlines() + changelog_file_lines = changelog_file_lines[:max_lines] + self.changelog_file_str = "\n".join(changelog_file_lines) + except: + raise Exception("No CHANGELOG.md file found in the repository") + + self.ai_handler = AiHandler() + self.patches_diff = None + self.prediction = None + self.cli_mode = cli_mode + self.vars = { + "title": self.git_provider.pr.title, + "branch": self.git_provider.get_pr_branch(), + "description": self.git_provider.get_pr_description(), + "language": self.main_language, + "diff": "", # empty diff for initial calculation + "changelog_file": self.changelog_file_str, + } + self.token_handler = TokenHandler(self.git_provider.pr, + self.vars, + settings.pr_update_changelog_prompt.system, + settings.pr_update_changelog_prompt.user) + + async def update_changelog(self): + assert type(self.git_provider) == GithubProvider, "Currently only Github is supported" + + logging.info('Updating the changelog...') + if settings.config.publish_output: + self.git_provider.publish_comment("Preparing changelog updates...", is_temporary=True) + await retry_with_fallback_models(self._prepare_prediction) + logging.info('Preparing PR changelog updates...') + new_file_content, answer = self._prepare_changelog_update() + if settings.config.publish_output or True: + self.git_provider.remove_initial_comment() + logging.info('publishing changelog updates...') + self.git_provider.publish_comment(f"**Changelog updates:**\n\n{answer}") + if settings.pr_update_changelog_prompt.push_changelog_changes: + logging.info('Pushing PR changelog updates...') + self.push_changelog_update(new_file_content) + + async def _prepare_prediction(self, model: str): + logging.info('Getting PR diff...') + # we are using extended hunk with line numbers for code suggestions + self.patches_diff = get_pr_diff(self.git_provider, + self.token_handler, + model, + add_line_numbers_to_hunks=True, + disable_extra_lines=True) + logging.info('Getting AI prediction...') + self.prediction = await self._get_prediction(model) + + async def _get_prediction(self, model: str): + variables = copy.deepcopy(self.vars) + variables["diff"] = self.patches_diff # update diff + environment = Environment(undefined=StrictUndefined) + system_prompt = environment.from_string(settings.pr_update_changelog_prompt.system).render(variables) + user_prompt = environment.from_string(settings.pr_update_changelog_prompt.user).render(variables) + if settings.config.verbosity_level >= 2: + logging.info(f"\nSystem prompt:\n{system_prompt}") + logging.info(f"\nUser prompt:\n{user_prompt}") + response, finish_reason = await self.ai_handler.chat_completion(model=model, temperature=0.2, + system=system_prompt, user=user_prompt) + + return response + + def _prepare_changelog_update(self) -> Tuple[str,str]: + answer = self.prediction.strip().strip("```").strip() + new_file_content = answer.strip().strip("```").strip() + "\n\n" + self.changelog_file.decoded_content.decode() + + return new_file_content, answer + + def push_changelog_update(self, new_file_content): + self.git_provider.repo_obj.update_file(path=self.changelog_file.path, + message="Update CHANGELOG.md", + content=new_file_content, + sha=self.changelog_file.sha, + branch=self.git_provider.get_pr_branch()) \ No newline at end of file From 99d53af28d70344c1967b72ac6e3874d4b4bf90b Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 09:50:21 +0300 Subject: [PATCH 02/16] Update CHANGELOG.md --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12dfefea..09d1463d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [Unreleased] - 2023-07-26 + +### Added +- New feature to update the changelog based on the contents of a pull request for the Github provider. +- Added 'update_changelog' command to the list of supported commands in the CLI. +- New configuration settings and prompts for the changelog update feature. +- New class `PRUpdateChangelog` in `pr_update_changelog.py` for handling changelog updates. + +### Changed +- Updated configuration settings in `configuration.toml` to include settings for the new feature. + ## [Unreleased] - 2023-07-23 ### Added From ccde68293f2a98a86058bfcbc161745d66506692 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 10:09:01 +0300 Subject: [PATCH 03/16] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 173b7844..6985d50d 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ CodiumAI `PR-Agent` is an open-source tool aiming to help developers review pull | | Auto-Description | :white_check_mark: | :white_check_mark: | | | | Improve Code | :white_check_mark: | :white_check_mark: | | | | Reflect and Review | :white_check_mark: | | | +| | Update CHANGELOG.md | :white_check_mark: | | | | | | | | | | USAGE | CLI | :white_check_mark: | :white_check_mark: | :white_check_mark: | | | App / webhook | :white_check_mark: | :white_check_mark: | | @@ -98,6 +99,7 @@ Examples for invoking the different tools via the CLI: - **Improve**: python cli.py --pr-url= improve - **Ask**: python cli.py --pr-url= ask "Write me a poem about this PR" - **Reflect**: python cli.py --pr-url= reflect +- **Update changelog**: python cli.py --pr-url= update_changelog "" is the url of the relevant PR (for example: https://github.com/Codium-ai/pr-agent/pull/50). From 7531ccd31fb66daeee369f5aa4ac37ec0b400357 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 16:29:42 +0300 Subject: [PATCH 04/16] stable --- pr_agent/settings/configuration.toml | 4 ++-- pr_agent/settings/pr_update_changelog.toml | 13 ++++++++--- pr_agent/tools/pr_update_changelog.py | 26 ++++++++++++++-------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 33b84f79..637d7394 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -2,7 +2,7 @@ model="gpt-4" fallback-models=["gpt-3.5-turbo-16k"] git_provider="github" -publish_output=false +publish_output=true publish_output_progress=true verbosity_level=2 # 0,1,2 use_extra_bad_extensions=false @@ -25,7 +25,7 @@ publish_description_as_comment=false num_code_suggestions=4 [pr_update_changelog] -push_changelog_changes=false +push_changelog_changes=true [github] # The type of deployment to create. Valid values are 'app' or 'user'. diff --git a/pr_agent/settings/pr_update_changelog.toml b/pr_agent/settings/pr_update_changelog.toml index 9fb386ea..802543a8 100644 --- a/pr_agent/settings/pr_update_changelog.toml +++ b/pr_agent/settings/pr_update_changelog.toml @@ -1,9 +1,11 @@ [pr_update_changelog_prompt] system="""You are a language model called CodiumAI-PR-Code-Reviewer. -Your task is to update the CHANGELOG.md file of the project, based on the PR diff. -The update should be short and concise. It should match the existing CHANGELOG.md format. +Your task is to update the CHANGELOG.md file of the project, to reflect the changes in this PR. +The updated content should be short and concise as possible. +It should match the existing CHANGELOG.md format, style and conventions, so it will look like a natural part of the file. +For example, if previous changes were summarized in a single line, you should do the same. -Note that the output should be only the added lines to the CHANGELOG.md file, and nothing else. +Don't repeat previous changes. Generate content that is not already in the CHANGELOG.md file. """ @@ -21,6 +23,11 @@ The PR Diff: {{diff}} ``` +Current date: +``` +{{today}} +``` + The current CHANGELOG.md: ``` {{changelog_file}} diff --git a/pr_agent/tools/pr_update_changelog.py b/pr_agent/tools/pr_update_changelog.py index 71e5e6e7..72234b3f 100644 --- a/pr_agent/tools/pr_update_changelog.py +++ b/pr_agent/tools/pr_update_changelog.py @@ -2,6 +2,7 @@ import copy import json import logging import textwrap +from datetime import date from typing import Tuple from jinja2 import Environment, StrictUndefined @@ -13,6 +14,8 @@ from pr_agent.config_loader import settings from pr_agent.git_providers import get_git_provider, GithubProvider from pr_agent.git_providers.git_provider import get_main_pr_language +CHANGELOG_LINES = 50 + class PRUpdateChangelog: def __init__(self, pr_url: str, cli_mode=False): @@ -21,15 +24,18 @@ class PRUpdateChangelog: self.main_language = get_main_pr_language( self.git_provider.get_languages(), self.git_provider.get_files() ) - max_lines=50 try: - self.changelog_file = self.git_provider.repo_obj.get_contents("CHANGELOG.md", ref=self.git_provider.get_pr_branch()) + self.changelog_file = self.git_provider.repo_obj.get_contents("CHANGELOG.md", + ref=self.git_provider.get_pr_branch()) changelog_file_lines = self.changelog_file.decoded_content.decode().splitlines() - changelog_file_lines = changelog_file_lines[:max_lines] + changelog_file_lines = changelog_file_lines[:CHANGELOG_LINES] self.changelog_file_str = "\n".join(changelog_file_lines) except: raise Exception("No CHANGELOG.md file found in the repository") + today = date.today() + print("Today's date:", today) + self.ai_handler = AiHandler() self.patches_diff = None self.prediction = None @@ -41,6 +47,7 @@ class PRUpdateChangelog: "language": self.main_language, "diff": "", # empty diff for initial calculation "changelog_file": self.changelog_file_str, + "today": today, } self.token_handler = TokenHandler(self.git_provider.pr, self.vars, @@ -56,11 +63,11 @@ class PRUpdateChangelog: await retry_with_fallback_models(self._prepare_prediction) logging.info('Preparing PR changelog updates...') new_file_content, answer = self._prepare_changelog_update() - if settings.config.publish_output or True: + if settings.config.publish_output: self.git_provider.remove_initial_comment() logging.info('publishing changelog updates...') self.git_provider.publish_comment(f"**Changelog updates:**\n\n{answer}") - if settings.pr_update_changelog_prompt.push_changelog_changes: + if settings.pr_update_changelog.push_changelog_changes: logging.info('Pushing PR changelog updates...') self.push_changelog_update(new_file_content) @@ -89,10 +96,11 @@ class PRUpdateChangelog: return response - def _prepare_changelog_update(self) -> Tuple[str,str]: + def _prepare_changelog_update(self) -> Tuple[str, str]: answer = self.prediction.strip().strip("```").strip() - new_file_content = answer.strip().strip("```").strip() + "\n\n" + self.changelog_file.decoded_content.decode() - + new_file_content = answer + "\n\n" + self.changelog_file.decoded_content.decode() + if settings.config.verbosity_level >= 2: + logging.info(f"answer:\n{answer}") return new_file_content, answer def push_changelog_update(self, new_file_content): @@ -100,4 +108,4 @@ class PRUpdateChangelog: message="Update CHANGELOG.md", content=new_file_content, sha=self.changelog_file.sha, - branch=self.git_provider.get_pr_branch()) \ No newline at end of file + branch=self.git_provider.get_pr_branch()) From 884317c4f7013471052ab79c131f2430cd72fef2 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:03:22 +0300 Subject: [PATCH 05/16] stable --- pr_agent/settings/configuration.toml | 4 +- pr_agent/settings/pr_update_changelog.toml | 2 +- pr_agent/tools/pr_update_changelog.py | 63 ++++++++++++++++++---- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 637d7394..4a71c04c 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -4,7 +4,7 @@ fallback-models=["gpt-3.5-turbo-16k"] git_provider="github" publish_output=true publish_output_progress=true -verbosity_level=2 # 0,1,2 +verbosity_level=0 # 0,1,2 use_extra_bad_extensions=false [pr_reviewer] @@ -25,7 +25,7 @@ publish_description_as_comment=false num_code_suggestions=4 [pr_update_changelog] -push_changelog_changes=true +push_changelog_changes=false [github] # The type of deployment to create. Valid values are 'app' or 'user'. diff --git a/pr_agent/settings/pr_update_changelog.toml b/pr_agent/settings/pr_update_changelog.toml index 802543a8..053d14c5 100644 --- a/pr_agent/settings/pr_update_changelog.toml +++ b/pr_agent/settings/pr_update_changelog.toml @@ -30,7 +30,7 @@ Current date: The current CHANGELOG.md: ``` -{{changelog_file}} +{{changelog_file_str}} ``` Response: diff --git a/pr_agent/tools/pr_update_changelog.py b/pr_agent/tools/pr_update_changelog.py index 72234b3f..2f9ee526 100644 --- a/pr_agent/tools/pr_update_changelog.py +++ b/pr_agent/tools/pr_update_changelog.py @@ -1,8 +1,7 @@ import copy -import json import logging -import textwrap from datetime import date +from time import sleep from typing import Tuple from jinja2 import Environment, StrictUndefined @@ -31,7 +30,17 @@ class PRUpdateChangelog: changelog_file_lines = changelog_file_lines[:CHANGELOG_LINES] self.changelog_file_str = "\n".join(changelog_file_lines) except: - raise Exception("No CHANGELOG.md file found in the repository") + if settings.pr_update_changelog.push_changelog_changes: + logging.info("No CHANGELOG.md file found in the repository. Creating one...") + changelog_file = self.git_provider.repo_obj.create_file(path="CHANGELOG.md", + message='add CHANGELOG.md', + content="", + branch=self.git_provider.get_pr_branch()) + self.changelog_file = changelog_file['content'] + self.changelog_file_str = "" + if not self.changelog_file_str: + self.changelog_file_str = self._get_default_changelog() + today = date.today() print("Today's date:", today) @@ -46,7 +55,7 @@ class PRUpdateChangelog: "description": self.git_provider.get_pr_description(), "language": self.main_language, "diff": "", # empty diff for initial calculation - "changelog_file": self.changelog_file_str, + "changelog_file_str": self.changelog_file_str, "today": today, } self.token_handler = TokenHandler(self.git_provider.pr, @@ -65,11 +74,13 @@ class PRUpdateChangelog: new_file_content, answer = self._prepare_changelog_update() if settings.config.publish_output: self.git_provider.remove_initial_comment() - logging.info('publishing changelog updates...') - self.git_provider.publish_comment(f"**Changelog updates:**\n\n{answer}") + logging.info('Publishing changelog updates...') if settings.pr_update_changelog.push_changelog_changes: - logging.info('Pushing PR changelog updates...') - self.push_changelog_update(new_file_content) + logging.info('Pushing PR changelog updates to repo...') + self._push_changelog_update(new_file_content, answer) + else: + logging.info('Publishing PR changelog as comment...') + self.git_provider.publish_comment(f"**Changelog updates:**\n\n{answer}") async def _prepare_prediction(self, model: str): logging.info('Getting PR diff...') @@ -98,14 +109,46 @@ class PRUpdateChangelog: def _prepare_changelog_update(self) -> Tuple[str, str]: answer = self.prediction.strip().strip("```").strip() - new_file_content = answer + "\n\n" + self.changelog_file.decoded_content.decode() + existing_content = self.changelog_file.decoded_content.decode() + if existing_content: + new_file_content = answer + "\n\n" + self.changelog_file.decoded_content.decode() + else: + new_file_content = answer if settings.config.verbosity_level >= 2: logging.info(f"answer:\n{answer}") return new_file_content, answer - def push_changelog_update(self, new_file_content): + def _push_changelog_update(self, new_file_content, answer): self.git_provider.repo_obj.update_file(path=self.changelog_file.path, message="Update CHANGELOG.md", content=new_file_content, sha=self.changelog_file.sha, branch=self.git_provider.get_pr_branch()) + d = dict(body="CHANGELOG.md update", + path=self.changelog_file.path, + line=max(2, len(answer.splitlines())), + start_line=1) + + sleep(5) # wait for the file to be updated + last_commit_id = list(self.git_provider.pr.get_commits())[-1] + try: + self.git_provider.pr.create_review(commit=last_commit_id, comments=[d]) + except: + # we can't create a review for some reason, let's just publish a comment + self.git_provider.publish_comment(f"**Changelog updates:**\n\n{answer}") + + + def _get_default_changelog(self): + example_changelog = \ +""" +Example: +## + +### Added +... +### Changed +... +### Fixed +... +""" + return example_changelog From 14eceb6e612977beec24d46b0219e873bec5aaef Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:05:18 +0300 Subject: [PATCH 06/16] PRUpdateChangelog --- pr_agent/agent/pr_agent.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pr_agent/agent/pr_agent.py b/pr_agent/agent/pr_agent.py index 7aa61c03..825338e6 100644 --- a/pr_agent/agent/pr_agent.py +++ b/pr_agent/agent/pr_agent.py @@ -6,6 +6,7 @@ from pr_agent.tools.pr_description import PRDescription from pr_agent.tools.pr_information_from_user import PRInformationFromUser from pr_agent.tools.pr_questions import PRQuestions from pr_agent.tools.pr_reviewer import PRReviewer +from pr_agent.tools.pr_update_changelog import PRUpdateChangelog class PRAgent: @@ -27,6 +28,8 @@ class PRAgent: await PRCodeSuggestions(pr_url).suggest() elif any(cmd == action for cmd in ["/ask", "/ask_question"]): await PRQuestions(pr_url, args).answer() + elif any(cmd == action for cmd in ["/update_changelog"]): + await PRUpdateChangelog(pr_url, args).update_changelog() else: return False From d8eae7faab6f6898bb5e70e70f4ba7c9f14309bd Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:06:23 +0300 Subject: [PATCH 07/16] Delete CHANGELOG.md --- CHANGELOG.md | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 09d1463d..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -## [Unreleased] - 2023-07-26 - -### Added -- New feature to update the changelog based on the contents of a pull request for the Github provider. -- Added 'update_changelog' command to the list of supported commands in the CLI. -- New configuration settings and prompts for the changelog update feature. -- New class `PRUpdateChangelog` in `pr_update_changelog.py` for handling changelog updates. - -### Changed -- Updated configuration settings in `configuration.toml` to include settings for the new feature. - -## [Unreleased] - 2023-07-23 - -### Added -- '/describe' operation now updates also the label of the PR - -### Changed - -### Fixed \ No newline at end of file From 1dbbafc30a5e324ae072e21412fbcbae51b055aa Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:08:06 +0300 Subject: [PATCH 08/16] add CHANGELOG.md --- CHANGELOG.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..e69de29b From 2e7a0a88faabf46347d44046e296f1be9fe2e568 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:08:29 +0300 Subject: [PATCH 09/16] Update CHANGELOG.md --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29b..fcb9c154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +## [Unreleased] + +### Added +- New feature to the PR Agent that allows it to update the changelog based on the contents of a pull request. This feature is currently implemented for the Github provider only. +- New command 'update_changelog' added to the list of supported commands in `pr_agent/cli.py`. +- New configuration file 'pr_update_changelog.toml' added to the list of settings files in `pr_agent/config_loader.py`. +- New class `PRUpdateChangelog` in `pr_agent/tools/pr_update_changelog.py` responsible for updating the changelog based on the PR's contents. +- New prompts for the changelog update feature in `pr_agent/settings/pr_update_changelog.toml`. + +### Changed +- Updated `pr_agent/agent/pr_agent.py` to handle the 'update_changelog' command. +- Updated `pr_agent/cli.py` to handle the 'update_changelog' command and reflect it in the help message. +- Updated `README.md` to include the 'update_changelog' command in the usage section and feature list. +- Updated `pr_agent/settings/configuration.toml` to include settings for the new feature. + +### Fixed +- No bug fixes in this PR. \ No newline at end of file From cfb696dfd5224588a8d0b330eb32e5099a38c963 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:09:18 +0300 Subject: [PATCH 10/16] Delete CHANGELOG.md --- CHANGELOG.md | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index fcb9c154..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,17 +0,0 @@ -## [Unreleased] - -### Added -- New feature to the PR Agent that allows it to update the changelog based on the contents of a pull request. This feature is currently implemented for the Github provider only. -- New command 'update_changelog' added to the list of supported commands in `pr_agent/cli.py`. -- New configuration file 'pr_update_changelog.toml' added to the list of settings files in `pr_agent/config_loader.py`. -- New class `PRUpdateChangelog` in `pr_agent/tools/pr_update_changelog.py` responsible for updating the changelog based on the PR's contents. -- New prompts for the changelog update feature in `pr_agent/settings/pr_update_changelog.toml`. - -### Changed -- Updated `pr_agent/agent/pr_agent.py` to handle the 'update_changelog' command. -- Updated `pr_agent/cli.py` to handle the 'update_changelog' command and reflect it in the help message. -- Updated `README.md` to include the 'update_changelog' command in the usage section and feature list. -- Updated `pr_agent/settings/configuration.toml` to include settings for the new feature. - -### Fixed -- No bug fixes in this PR. \ No newline at end of file From 801923789b5654d81e5ae094df8ccdf8943da92b Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:33:21 +0300 Subject: [PATCH 11/16] final --- pr_agent/settings/pr_update_changelog.toml | 15 ++++++--------- pr_agent/tools/pr_update_changelog.py | 17 ++++++++--------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/pr_agent/settings/pr_update_changelog.toml b/pr_agent/settings/pr_update_changelog.toml index 053d14c5..85867ec2 100644 --- a/pr_agent/settings/pr_update_changelog.toml +++ b/pr_agent/settings/pr_update_changelog.toml @@ -1,12 +1,9 @@ [pr_update_changelog_prompt] -system="""You are a language model called CodiumAI-PR-Code-Reviewer. -Your task is to update the CHANGELOG.md file of the project, to reflect the changes in this PR. -The updated content should be short and concise as possible. -It should match the existing CHANGELOG.md format, style and conventions, so it will look like a natural part of the file. -For example, if previous changes were summarized in a single line, you should do the same. - -Don't repeat previous changes. Generate content that is not already in the CHANGELOG.md file. - +system="""You are a language model called CodiumAI-PR-Changlog-summarizer. +Your task is to update the CHANGELOG.md file of the project, to shortly summarize important changes introduced in this PR (the '+' lines). +- The output should match the existing CHANGELOG.md format, style and conventions, so it will look like a natural part of the file. For example, if previous changes were summarized in a single line, you should do the same. +- Don't repeat previous changes. Generate only new content, that is not already in the CHANGELOG.md file. +- Be generic and avoid specific details. The output should be minimal, no more than 3-4 short lines. Ignore non-relevant subsections. """ user="""PR Info: @@ -30,7 +27,7 @@ Current date: The current CHANGELOG.md: ``` -{{changelog_file_str}} +{{ changelog_file_str }} ``` Response: diff --git a/pr_agent/tools/pr_update_changelog.py b/pr_agent/tools/pr_update_changelog.py index 2f9ee526..aa24afb6 100644 --- a/pr_agent/tools/pr_update_changelog.py +++ b/pr_agent/tools/pr_update_changelog.py @@ -30,14 +30,15 @@ class PRUpdateChangelog: changelog_file_lines = changelog_file_lines[:CHANGELOG_LINES] self.changelog_file_str = "\n".join(changelog_file_lines) except: - if settings.pr_update_changelog.push_changelog_changes: + self.changelog_file_str = "" + if settings.config.publish_output and settings.pr_update_changelog.push_changelog_changes: logging.info("No CHANGELOG.md file found in the repository. Creating one...") changelog_file = self.git_provider.repo_obj.create_file(path="CHANGELOG.md", message='add CHANGELOG.md', content="", branch=self.git_provider.get_pr_branch()) self.changelog_file = changelog_file['content'] - self.changelog_file_str = "" + if not self.changelog_file_str: self.changelog_file_str = self._get_default_changelog() @@ -84,12 +85,7 @@ class PRUpdateChangelog: async def _prepare_prediction(self, model: str): logging.info('Getting PR diff...') - # we are using extended hunk with line numbers for code suggestions - self.patches_diff = get_pr_diff(self.git_provider, - self.token_handler, - model, - add_line_numbers_to_hunks=True, - disable_extra_lines=True) + self.patches_diff = get_pr_diff(self.git_provider, self.token_handler, model) logging.info('Getting AI prediction...') self.prediction = await self._get_prediction(model) @@ -109,7 +105,10 @@ class PRUpdateChangelog: def _prepare_changelog_update(self) -> Tuple[str, str]: answer = self.prediction.strip().strip("```").strip() - existing_content = self.changelog_file.decoded_content.decode() + if hasattr(self, "changelog_file"): + existing_content = self.changelog_file.decoded_content.decode() + else: + existing_content = "" if existing_content: new_file_content = answer + "\n\n" + self.changelog_file.decoded_content.decode() else: From 413e5f6d771f3c27e388e7887e9ca09ca3965f18 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:36:05 +0300 Subject: [PATCH 12/16] general --- pr_agent/settings/configuration.toml | 2 +- pr_agent/settings/pr_update_changelog.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 4a71c04c..f951c648 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -1,6 +1,6 @@ [config] model="gpt-4" -fallback-models=["gpt-3.5-turbo-16k"] +fallback_models=["gpt-3.5-turbo-16k"] git_provider="github" publish_output=true publish_output_progress=true diff --git a/pr_agent/settings/pr_update_changelog.toml b/pr_agent/settings/pr_update_changelog.toml index 85867ec2..91413010 100644 --- a/pr_agent/settings/pr_update_changelog.toml +++ b/pr_agent/settings/pr_update_changelog.toml @@ -3,7 +3,7 @@ system="""You are a language model called CodiumAI-PR-Changlog-summarizer. Your task is to update the CHANGELOG.md file of the project, to shortly summarize important changes introduced in this PR (the '+' lines). - The output should match the existing CHANGELOG.md format, style and conventions, so it will look like a natural part of the file. For example, if previous changes were summarized in a single line, you should do the same. - Don't repeat previous changes. Generate only new content, that is not already in the CHANGELOG.md file. -- Be generic and avoid specific details. The output should be minimal, no more than 3-4 short lines. Ignore non-relevant subsections. +- Be general, and avoid specific details, files, etc. The output should be minimal, no more than 3-4 short lines. Ignore non-relevant subsections. """ user="""PR Info: From cce2a79a1fdd512a313dc518d9ec4be813138010 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:40:15 +0300 Subject: [PATCH 13/16] add CHANGELOG.md --- CHANGELOG.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..e69de29b From 52576c79b375bbcc58b296e15846f0a9d20cfe9b Mon Sep 17 00:00:00 2001 From: mrT23 Date: Wed, 26 Jul 2023 20:40:28 +0300 Subject: [PATCH 14/16] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29b..0a905f38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +## 2023-07-26 + +### Added +- New feature for updating the CHANGELOG.md based on the contents of a PR. +- Added support for this feature for the Github provider. +- New configuration settings and prompts for the changelog update feature. \ No newline at end of file From c827cbc0ae6f1e1abcb8ba9f64fb1ad897e01128 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 27 Jul 2023 08:47:26 +0300 Subject: [PATCH 15/16] final touches --- pr_agent/agent/pr_agent.py | 4 +- pr_agent/cli.py | 2 +- pr_agent/tools/pr_update_changelog.py | 70 +++++++++++++++++---------- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/pr_agent/agent/pr_agent.py b/pr_agent/agent/pr_agent.py index 825338e6..a30c411b 100644 --- a/pr_agent/agent/pr_agent.py +++ b/pr_agent/agent/pr_agent.py @@ -27,9 +27,9 @@ class PRAgent: elif any(cmd == action for cmd in ["/improve", "/improve_code"]): await PRCodeSuggestions(pr_url).suggest() elif any(cmd == action for cmd in ["/ask", "/ask_question"]): - await PRQuestions(pr_url, args).answer() + await PRQuestions(pr_url, args=args).answer() elif any(cmd == action for cmd in ["/update_changelog"]): - await PRUpdateChangelog(pr_url, args).update_changelog() + await PRUpdateChangelog(pr_url, args=args).update_changelog() else: return False diff --git a/pr_agent/cli.py b/pr_agent/cli.py index 2bae6bd4..f04e51d7 100644 --- a/pr_agent/cli.py +++ b/pr_agent/cli.py @@ -102,7 +102,7 @@ def _handle_review_after_reflect_command(pr_url: str, rest: list): def _handle_update_changelog(pr_url: str, rest: list): print(f"Updating changlog for: {pr_url}") - reviewer = PRUpdateChangelog(pr_url, cli_mode=True) + reviewer = PRUpdateChangelog(pr_url, cli_mode=True, args=rest) asyncio.run(reviewer.update_changelog()) if __name__ == '__main__': diff --git a/pr_agent/tools/pr_update_changelog.py b/pr_agent/tools/pr_update_changelog.py index aa24afb6..901c5b45 100644 --- a/pr_agent/tools/pr_update_changelog.py +++ b/pr_agent/tools/pr_update_changelog.py @@ -17,35 +17,14 @@ CHANGELOG_LINES = 50 class PRUpdateChangelog: - def __init__(self, pr_url: str, cli_mode=False): + def __init__(self, pr_url: str, cli_mode=False, args=None): self.git_provider = get_git_provider()(pr_url) self.main_language = get_main_pr_language( self.git_provider.get_languages(), self.git_provider.get_files() ) - try: - self.changelog_file = self.git_provider.repo_obj.get_contents("CHANGELOG.md", - ref=self.git_provider.get_pr_branch()) - changelog_file_lines = self.changelog_file.decoded_content.decode().splitlines() - changelog_file_lines = changelog_file_lines[:CHANGELOG_LINES] - self.changelog_file_str = "\n".join(changelog_file_lines) - except: - self.changelog_file_str = "" - if settings.config.publish_output and settings.pr_update_changelog.push_changelog_changes: - logging.info("No CHANGELOG.md file found in the repository. Creating one...") - changelog_file = self.git_provider.repo_obj.create_file(path="CHANGELOG.md", - message='add CHANGELOG.md', - content="", - branch=self.git_provider.get_pr_branch()) - self.changelog_file = changelog_file['content'] - - if not self.changelog_file_str: - self.changelog_file_str = self._get_default_changelog() - - - today = date.today() - print("Today's date:", today) - + self.commit_changelog = self._parse_args(args, settings) + self._get_changlog_file() # self.changelog_file_str self.ai_handler = AiHandler() self.patches_diff = None self.prediction = None @@ -57,7 +36,7 @@ class PRUpdateChangelog: "language": self.main_language, "diff": "", # empty diff for initial calculation "changelog_file_str": self.changelog_file_str, - "today": today, + "today": date.today(), } self.token_handler = TokenHandler(self.git_provider.pr, self.vars, @@ -76,7 +55,7 @@ class PRUpdateChangelog: if settings.config.publish_output: self.git_provider.remove_initial_comment() logging.info('Publishing changelog updates...') - if settings.pr_update_changelog.push_changelog_changes: + if self.commit_changelog: logging.info('Pushing PR changelog updates to repo...') self._push_changelog_update(new_file_content, answer) else: @@ -113,8 +92,14 @@ class PRUpdateChangelog: new_file_content = answer + "\n\n" + self.changelog_file.decoded_content.decode() else: new_file_content = answer + + if not self.cli_mode and self.commit_changelog: + answer += "\n\n\n>to commit the new contnet to the CHANGELOG.md file, please type:" \ + "\n>'/update_changelog -commit'\n" + if settings.config.verbosity_level >= 2: logging.info(f"answer:\n{answer}") + return new_file_content, answer def _push_changelog_update(self, new_file_content, answer): @@ -151,3 +136,36 @@ Example: ... """ return example_changelog + + def _parse_args(self, args, setting): + commit_changelog = False + if args and len(args) >= 1: + try: + if args[0] == "-commit": + commit_changelog = True + except: + pass + else: + commit_changelog = setting.pr_update_changelog.push_changelog_changes + + return commit_changelog + + def _get_changlog_file(self): + try: + self.changelog_file = self.git_provider.repo_obj.get_contents("CHANGELOG.md", + ref=self.git_provider.get_pr_branch()) + changelog_file_lines = self.changelog_file.decoded_content.decode().splitlines() + changelog_file_lines = changelog_file_lines[:CHANGELOG_LINES] + self.changelog_file_str = "\n".join(changelog_file_lines) + except: + self.changelog_file_str = "" + if self.commit_changelog: + logging.info("No CHANGELOG.md file found in the repository. Creating one...") + changelog_file = self.git_provider.repo_obj.create_file(path="CHANGELOG.md", + message='add CHANGELOG.md', + content="", + branch=self.git_provider.get_pr_branch()) + self.changelog_file = changelog_file['content'] + + if not self.changelog_file_str: + self.changelog_file_str = self._get_default_changelog() From 808ca48605956236b8766d6389c9bc47ea0d40fe Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 27 Jul 2023 08:48:39 +0300 Subject: [PATCH 16/16] if not self.commit_changelog: --- pr_agent/tools/pr_update_changelog.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pr_agent/tools/pr_update_changelog.py b/pr_agent/tools/pr_update_changelog.py index 901c5b45..1b06c381 100644 --- a/pr_agent/tools/pr_update_changelog.py +++ b/pr_agent/tools/pr_update_changelog.py @@ -93,8 +93,8 @@ class PRUpdateChangelog: else: new_file_content = answer - if not self.cli_mode and self.commit_changelog: - answer += "\n\n\n>to commit the new contnet to the CHANGELOG.md file, please type:" \ + if not self.commit_changelog: + answer += "\n\n\n>to commit the new content to the CHANGELOG.md file, please type:" \ "\n>'/update_changelog -commit'\n" if settings.config.verbosity_level >= 2: