From 83419710f93e6cb8e087ba40c5ab8e1c5cb64725 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:30:12 -0500 Subject: [PATCH 01/11] chore: refactor rigging pr decorator --- .github/scripts/rigging_pr_decorator.py | 201 ++++++++---------------- 1 file changed, 68 insertions(+), 133 deletions(-) diff --git a/.github/scripts/rigging_pr_decorator.py b/.github/scripts/rigging_pr_decorator.py index feb4bd6..11a7f85 100644 --- a/.github/scripts/rigging_pr_decorator.py +++ b/.github/scripts/rigging_pr_decorator.py @@ -1,142 +1,77 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "rigging", +# "typer", +# ] +# /// + import asyncio -import base64 -import os +import subprocess import typing as t -from pydantic import ConfigDict, StringConstraints +import typer import rigging as rg -from rigging import logger -from rigging.generator import GenerateParams, Generator, register_generator - -logger.enable("rigging") - -MAX_TOKENS = 8000 -TRUNCATION_WARNING = "\n\n**Note**: Due to the large size of this diff, some content has been truncated." -str_strip = t.Annotated[str, StringConstraints(strip_whitespace=True)] - - -class PRDiffData(rg.Model): - """XML model for PR diff data""" - - content: str_strip = rg.element() - - @classmethod - def xml_example(cls) -> str: - return """example diff content""" - - -class PRDecorator(Generator): - """Generator for creating PR descriptions""" - - model_config = ConfigDict(arbitrary_types_allowed=True, validate_assignment=True) - - api_key: str = "" - max_tokens: int = MAX_TOKENS - - def __init__(self, model: str, params: rg.GenerateParams) -> None: - api_key = params.extra.get("api_key") - if not api_key: - raise ValueError("api_key is required in params.extra") - - super().__init__(model=model, params=params, api_key=api_key) - self.api_key = api_key - self.max_tokens = params.max_tokens or MAX_TOKENS - - async def generate_messages( - self, - messages: t.Sequence[t.Sequence[rg.Message]], - params: t.Sequence[GenerateParams], - ) -> t.Sequence[rg.GeneratedMessage]: - responses = [] - for message_seq, p in zip(messages, params): - base_generator = rg.get_generator(self.model, params=p) - llm_response = await base_generator.generate_messages([message_seq], [p]) - responses.extend(llm_response) - return responses - - -register_generator("pr_decorator", PRDecorator) - - -async def generate_pr_description(diff_text: str) -> str: - """Generate a PR description from the diff text""" - diff_tokens = len(diff_text) // 4 - if diff_tokens >= MAX_TOKENS: - char_limit = (MAX_TOKENS * 4) - len(TRUNCATION_WARNING) - diff_text = diff_text[:char_limit] + TRUNCATION_WARNING - - diff_data = PRDiffData(content=diff_text) - params = rg.GenerateParams( - extra={ - "api_key": os.environ["OPENAI_API_KEY"], - "diff_text": diff_text, - }, - temperature=0.1, - max_tokens=500, - ) - - generator = rg.get_generator("pr_decorator!gpt-4-turbo-preview", params=params) - prompt = f"""You are a helpful AI that generates clear and concise PR descriptions with some pirate tongue. - Analyze the provided git diff and create a summary, specifically focusing on the elements of the code that - has changed, high severity functions etc using exactly this format: - - ### PR Summary - - #### Overview of Changes - - - #### Key Modifications - 1. ****: - (continue as needed) - - #### Potential Impact - - - (continue as needed) - - Here is the PR diff to analyze: - {diff_data.to_xml()}""" - - chat = await generator.chat(prompt).run() - return chat.last.content.strip() - - -async def main(): - """Main function for CI environment""" - if not os.environ.get("OPENAI_API_KEY"): - raise ValueError("OPENAI_API_KEY environment variable must be set") - - try: - diff_text = os.environ.get("GIT_DIFF", "") - if not diff_text: - raise ValueError("No diff found in GIT_DIFF environment variable") - - try: - diff_text = base64.b64decode(diff_text).decode("utf-8") - except Exception: - padding = 4 - (len(diff_text) % 4) - if padding != 4: - diff_text += "=" * padding - diff_text = base64.b64decode(diff_text).decode("utf-8") - logger.debug(f"Processing diff of length: {len(diff_text)}") - description = await generate_pr_description(diff_text) - - with open(os.environ["GITHUB_OUTPUT"], "a") as f: - f.write("content< t.Annotated[str, rg.Ctx("markdown")]: # type: ignore[empty-body] + """ + Analyze the provided git diff and create a PR description in markdown format. + + + - Keep the summary concise and informative. + - Use bullet points to structure important statements. + - Focus on key modifications and potential impact - if any. + - Do not add in general advice or best-practice information. + - Write like a developer who authored the changes. + - Prefer flat bullet lists over nested. + - Do not include any title structure. + + """ + + +def get_diff(target_ref: str, source_ref: str) -> str: + """ + Get the git diff between two branches. + """ + + merge_base = subprocess.run( + ["git", "merge-base", source_ref, target_ref], + capture_output=True, + text=True, + check=True, + ).stdout.strip() + diff_text = subprocess.run( + ["git", "diff", merge_base], + capture_output=True, + text=True, + check=True, + ).stdout + return diff_text + + +def main( + target_ref: str, + source_ref: str = "HEAD", + generator_id: str = "openai/gpt-4o-mini", + max_diff_lines: int = 1000, +) -> None: + """ + Use rigging to generate a PR description from a git diff. + """ + + diff = get_diff(target_ref, source_ref) + diff_lines = diff.split("\n") + if len(diff_lines) > max_diff_lines: + diff = "\n".join(diff_lines[:max_diff_lines]) + TRUNCATION_WARNING + + description = asyncio.run(generate_pr_description.bind(generator_id)(diff)) + print(description) if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file + typer.run(main) From f303cbfe1c0906630aa6f1ae49326e9fd1390ff7 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 20:08:03 -0500 Subject: [PATCH 02/11] fix: refactor workflow --- .github/workflows/rigging_pr_description.yml | 46 ++++++++------------ 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/.github/workflows/rigging_pr_description.yml b/.github/workflows/rigging_pr_description.yml index 5bb8b8f..1be4efa 100644 --- a/.github/workflows/rigging_pr_description.yml +++ b/.github/workflows/rigging_pr_description.yml @@ -2,7 +2,7 @@ name: Update PR Description with Rigging on: pull_request: - types: [opened] + types: [opened, synchronize] jobs: update-description: @@ -12,48 +12,40 @@ jobs: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - fetch-depth: 0 + fetch-depth: 0 # full history for proper diffing - # Get the diff first - - name: Get Diff - id: diff - # shellcheck disable=SC2102 - run: | - git fetch origin "${{ github.base_ref }}" - MERGE_BASE=$(git merge-base HEAD "origin/${{ github.base_ref }}") - # Use separate diff arguments instead of range notation - DIFF=$(git diff "$MERGE_BASE" HEAD | base64 --wrap=0) - echo "diff=${DIFF}" >> "$GITHUB_OUTPUT" - - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b #v5.0.3 + - name: Set up Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.0.3 with: - python-version: "3.11" + python-version: "3.10" - - name: Install dependencies + - name: Install uv run: | python -m pip install --upgrade pip - pip cache purge - pip install pydantic - pip install rigging[all] - # Generate the description using the diff + pip install uv + - name: Generate PR Description id: description env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - PR_NUMBER: ${{ github.event.pull_request.number }} - GIT_DIFF: ${{ steps.diff.outputs.diff }} run: | - python .github/scripts/rigging_pr_decorator.py - # Update the PR description + DESCRIPTION=$(uv run --no-project .github/scripts/rigging_pr_decorator.py origin/${{ github.base_ref }}) + echo "description<> $GITHUB_OUTPUT + echo "$DESCRIPTION" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + - name: Update PR Description - uses: nefrob/pr-description@4dcc9f3ad5ec06b2a197c5f8f93db5e69d2fdca7 #v1.2.0 + uses: nefrob/pr-description@4dcc9f3ad5ec06b2a197c5f8f93db5e69d2fdca7 # v1.2.0 with: content: | ## AI-Generated Summary - ${{ steps.description.outputs.content }} + + ${{ steps.description.outputs.description }} + --- + This summary was generated with ❤️ by [rigging](https://rigging.dreadnode.io/) regex: ".*" regexFlags: s From 9c908330e8e0d87476315773d0c15189ffe7a813 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 20:10:08 -0500 Subject: [PATCH 03/11] chore: tmp exclusion --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e2e0634..720dbe3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,3 +35,4 @@ repos: entry: python .scripts/check_pinned_hash_dependencies.py language: python files: \.github/.*\.yml$ + exclude: ^\.github/workflows/.*\.yml$ From 1862b9482d9ebd5ca8b2466f28ba1be9d7a1485d Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:27:14 -0500 Subject: [PATCH 04/11] fix: excludes in wrong block --- .pre-commit-config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 720dbe3..3304d43 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: - id: actionlint name: Check Github Actions args: ["--ignore", "SC2102"] + exclude: ^rigging_pr_decorator\.py$ # Python code security - repo: https://github.com/PyCQA/bandit @@ -26,6 +27,7 @@ repos: - id: bandit name: Code security checks args: ["-r", "--level", "2", "./"] + exclude: ^rigging_pr_decorator\.py$ - repo: local hooks: @@ -35,4 +37,3 @@ repos: entry: python .scripts/check_pinned_hash_dependencies.py language: python files: \.github/.*\.yml$ - exclude: ^\.github/workflows/.*\.yml$ From 0009344f576df196cd3f9e15856e53391c6cc376 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:30:42 -0500 Subject: [PATCH 05/11] chore: tmp remove bandit for now --- .pre-commit-config.yaml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3304d43..9a3c80f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,16 +18,7 @@ repos: - id: actionlint name: Check Github Actions args: ["--ignore", "SC2102"] - exclude: ^rigging_pr_decorator\.py$ - - # Python code security - - repo: https://github.com/PyCQA/bandit - rev: 8fd258abbac759d62863779f946d6a88e8eabb0f #1.8.0 - hooks: - - id: bandit - name: Code security checks - args: ["-r", "--level", "2", "./"] - exclude: ^rigging_pr_decorator\.py$ + exclude: ^rigging_pr_description\.yml$ - repo: local hooks: From 3241f94a1c221188adff77f5cbe26df953bf9dfe Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:31:53 -0500 Subject: [PATCH 06/11] chore: test with x flag --- .pre-commit-config.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9a3c80f..f7edfa9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,14 @@ repos: args: ["--ignore", "SC2102"] exclude: ^rigging_pr_description\.yml$ + # Python code security + - repo: https://github.com/PyCQA/bandit + rev: 8fd258abbac759d62863779f946d6a88e8eabb0f #1.8.0 + hooks: + - id: bandit + name: Code security checks + args: ["-r", "--level", "2", "./", --exclude, "rigging_pr_decorator.py"] + - repo: local hooks: # Ensure our GH actions are pinned to a specific hash From e1d9301e5fdc8e28d8f546f39300af4d33d38620 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:36:56 -0500 Subject: [PATCH 07/11] fix: missing dir --- .pre-commit-config.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f7edfa9..c92156b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,15 @@ repos: hooks: - id: bandit name: Code security checks - args: ["-r", "--level", "2", "./", --exclude, "rigging_pr_decorator.py"] + args: + [ + "-r", + "--level", + "2", + "./", + --exclude, + ".github/scripts/rigging_pr_decorator.py", + ] - repo: local hooks: From 23237f157e548814a3712fccb93ddade09bd66d2 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:39:37 -0500 Subject: [PATCH 08/11] fix: missing dir path --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c92156b..0b0fdc4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: hooks: - id: actionlint name: Check Github Actions - args: ["--ignore", "SC2102"] + args: ["--ignore", "SC2102", "SC2129", "SC2086"] exclude: ^rigging_pr_description\.yml$ # Python code security From cc2806bd77fcc8d8bc3459409c29665df73ee3af Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:43:05 -0500 Subject: [PATCH 09/11] fix: ignore regex --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0b0fdc4..f4f837e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: hooks: - id: actionlint name: Check Github Actions - args: ["--ignore", "SC2102", "SC2129", "SC2086"] + args: ["--ignore", "SC2102,SC2129,SC2086"] exclude: ^rigging_pr_description\.yml$ # Python code security From 43cb7f25510aa096669a55e42b7608c966ec1ac0 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:44:42 -0500 Subject: [PATCH 10/11] fix: parsing syntax --- .pre-commit-config.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f4f837e..85ba9e5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,15 +26,7 @@ repos: hooks: - id: bandit name: Code security checks - args: - [ - "-r", - "--level", - "2", - "./", - --exclude, - ".github/scripts/rigging_pr_decorator.py", - ] + args: ["-r", "./", --exclude, ".github/scripts/rigging_pr_decorator.py"] - repo: local hooks: From 2aa2d91bc8033235bb2ba7658c4201c2a734cb13 Mon Sep 17 00:00:00 2001 From: Ads Dawson <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:54:39 -0500 Subject: [PATCH 11/11] chore: args no quotes --- .pre-commit-config.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85ba9e5..0b362ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,15 @@ repos: hooks: - id: bandit name: Code security checks - args: ["-r", "./", --exclude, ".github/scripts/rigging_pr_decorator.py"] + args: + [ + -r, + ., + --severity-level, + high, + -x, + .github/scripts/rigging_pr_decorator.py, + ] - repo: local hooks: