From f25b1524b2b13fe1d1275abf3b0f16dc51afe5f1 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Sun, 21 Jan 2024 14:48:37 +0100 Subject: [PATCH] Fix copilot env --- .github/workflows/copilot.yml | 7 ++- etc/tool/copilot.py | 86 ++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/.github/workflows/copilot.yml b/.github/workflows/copilot.yml index 1de81cb6394..1781ca2fedc 100644 --- a/.github/workflows/copilot.yml +++ b/.github/workflows/copilot.yml @@ -6,6 +6,11 @@ on: - opened - synchronize +env: + COPILOT_REPOSITORY: ${{ github.repository }} + COPILOT_PR: ${{ github.ref_name }} + COPILOT_TOKEN: ${{ secrets.COPILOT_TOKEN }} + jobs: review: runs-on: ubuntu-latest @@ -25,5 +30,5 @@ jobs: run: pip install PyGithub - name: AI Code Review env: - GITHUB_TOKEN: ${{ secrets.COPILOT_TOKEN }} + COPILOT_TOKEN: ${{ secrets.COPILOT_TOKEN }} run: python -m etc.tool.copilot diff --git a/etc/tool/copilot.py b/etc/tool/copilot.py index 9be1291cd46..6ab84957fb1 100644 --- a/etc/tool/copilot.py +++ b/etc/tool/copilot.py @@ -15,40 +15,49 @@ g4f.debug.logging = True g4f.debug.version_check = False -GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') -G4F_PROVIDER = os.getenv('G4F_PROVIDER') -G4F_MODEL = os.getenv('G4F_MODEL') or g4f.models.gpt_4 +GITHUB_TOKEN = os.getenv('COPILOT_TOKEN') +G4F_PROVIDER = os.getenv('COPILOT_PROVIDER') +G4F_MODEL = os.getenv('COPILOT_MODEL') or g4f.models.gpt_4 def get_pr_details(github: Github) -> PullRequest: """ - Rteurns the details of the pull request from GitHub. + Retrieves the details of the pull request from GitHub. + + Args: + github (Github): The Github object to interact with the GitHub API. Returns: - PullRequest: A PullRequest instance. + PullRequest: An object representing the pull request. """ - with open(os.getenv('GITHUB_EVENT_PATH', ''), 'r') as file: - data = json.load(file) - - repo = github.get_repo(f"{data['repository']['owner']['login']}/{data['repository']['name']}") - pull = repo.get_pull(data['number']) + repo = github.get_repo(os.getenv('COPILOT_REPOSITORY')) + pull = repo.get_pull(os.getenv('COPILOT_PR')) return pull def get_diff(diff_url: str) -> str: """ - Fetches the diff of the pull request. + Fetches the diff of the pull request from a given URL. Args: - pull (PullRequest): Pull request. + diff_url (str): URL to the pull request diff. Returns: - str or None: The diff of the pull request or None if not available. + str: The diff of the pull request. """ response = requests.get(diff_url) response.raise_for_status() return response.text def read_json(text: str) -> dict: + """ + Parses JSON code block from a string. + + Args: + text (str): A string containing a JSON code block. + + Returns: + dict: A dictionary parsed from the JSON code block. + """ match = re.search(r"```(json|)\n(?P[\S\s]+?)\n```", text) if match: text = match.group("code") @@ -56,23 +65,33 @@ def read_json(text: str) -> dict: return json.loads(text.strip()) except json.JSONDecodeError: print("No valid json:", text) - return {} + return {} -def read_text(text: str) -> dict: +def read_text(text: str) -> str: + """ + Extracts text from a markdown code block. + + Args: + text (str): A string containing a markdown code block. + + Returns: + str: The extracted text. + """ match = re.search(r"```(markdown|)\n(?P[\S\s]+?)\n```", text) if match: return match.group("text") return text -def get_ai_response(prompt, as_json: bool = True) -> Union[dict, str]: +def get_ai_response(prompt: str, as_json: bool = True) -> Union[dict, str]: """ Gets a response from g4f API based on the prompt. Args: prompt (str): The prompt to send to g4f. + as_json (bool): Whether to parse the response as JSON. Returns: - dict: The parsed response from g4f. + Union[dict, str]: The parsed response from g4f, either as a dictionary or a string. """ response = g4f.ChatCompletion.create( G4F_MODEL, @@ -80,20 +99,18 @@ def get_ai_response(prompt, as_json: bool = True) -> Union[dict, str]: G4F_PROVIDER, ignore_stream_and_auth=True ) - if as_json: - return read_json(response) - return read_text(response) + return read_json(response) if as_json else read_text(response) -def analyze_code(pull: PullRequest, diff: str)-> list: +def analyze_code(pull: PullRequest, diff: str)-> list[dict]: """ Analyzes the code changes in the pull request. Args: + pull (PullRequest): The pull request object. diff (str): The diff of the pull request. - pr_details (dict): Details of the pull request. Returns: - list: List of comments generated by the analysis. + list[dict]: A list of comments generated by the analysis. """ comments = [] changed_lines = [] @@ -122,13 +139,14 @@ def analyze_code(pull: PullRequest, diff: str)-> list: return comments -def create_prompt(changed_lines: list, pull: PullRequest, file_path: str): +def create_prompt(changed_lines: list[str], pull: PullRequest, file_path: str): """ Creates a prompt for the g4f model. Args: - diff (str): The line of code to analyze. - pr_details (dict): Details of the pull request. + changed_lines (list[str]): The lines of code that have changed. + pull (PullRequest): The pull request object. + file_path (str): The path to the file being reviewed. Returns: str: The generated prompt. @@ -159,16 +177,17 @@ def create_prompt(changed_lines: list, pull: PullRequest, file_path: str): def create_review_prompt(pull: PullRequest, diff: str): """ - Creates a prompt to create a review. + Creates a prompt to create a review comment. Args: - diff (str): The line of code to analyze. + pull (PullRequest): The pull request object. + diff (str): The diff of the pull request. Returns: - str: The generated prompt. + str: The generated prompt for review. """ return f"""Your task is to review a pull request. Instructions: -- Your name / you are copilot. +- Write in name of you "g4f-copilot". - Write the review in GitHub Markdown format. - Thank the author for contributing to the project. - Point out that you might leave a few comments on the files. @@ -192,7 +211,7 @@ def main(): pull = get_pr_details(github) diff = get_diff(pull.diff_url) except Exception as e: - print(f"Error get details: {e}") + print(f"Error get details: {e.__class__.__name__}: {e}") exit(1) try: review = get_ai_response(create_review_prompt(pull, diff), False) @@ -206,7 +225,10 @@ def main(): exit(1) print("Comments:", comments) try: - pull.create_review(body=review, comments=comments) + if not comments: + pull.create_review(body=review, comments=comments) + else: + pull.create_comment(body=review) except Exception as e: print(f"Error posting review: {e}") exit(1)