diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4d2ab6..8a2a083 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,9 +12,9 @@ jobs: fetch-depth: 0 - name: Run script - id: spelling uses: ./ with: + token: ${{ secrets.PAT }} files: | tests/file.txt tests/file.json diff --git a/README.md b/README.md index e69de29..ac362c9 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,16 @@ +# actions/check-typo + +This Github Action uses AI to find typos and grammatical errors in PR changes. + +## Usage +Refer [test.yml](./.github/workflows/test.yml) +```yaml + - name: Check typos in data files + uses: actions/check-diff-typo@v1 + with: + token: ${{ secrets.PAT }} + files: | + tests/file.txt + tests/file.json + GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }} +``` diff --git a/action.yml b/action.yml index 7fd5e1f..6fd5c6a 100644 --- a/action.yml +++ b/action.yml @@ -1,11 +1,15 @@ -name: 'Check-Diff-Typo' -description: 'Analyzes and comments on PR diff typos for specified files' +name: 'Check-Typo' +description: 'Checks diff of specified files for typos and suggests fixes on PR.' author: 'Rishabh B' branding: icon: 'git-pull-request' color: 'green' inputs: + token: + description: 'PAT with `pull_request:write` permission' + required: true + default: ${{ github.token }} files: description: 'Comma-separated list of files to analyze' required: true @@ -14,10 +18,6 @@ inputs: description: 'Groq API Key' required: true -outputs: - comment: - description: 'Generated comment markdown' - value: ${{ steps.spelling.outputs.comment }} runs: using: "composite" @@ -28,6 +28,8 @@ runs: cache: 'pip' - name: Setup python env run: | + python -m venv .venv + source .venv/bin/activate python -m pip install --upgrade pip pip install -r requirements.txt shell: bash @@ -40,13 +42,11 @@ runs: id: spelling shell: bash env: - PR_BASE: ${{ github.event.pull_request.base.ref }} + PR_BASE: ${{ github.base_ref }} INPUT_FILES: ${{ inputs.files }} GROQ_API_KEY: ${{ inputs.GROQ_API_KEY }} - run: python src/spell_check.py - - - name: Comment PR - uses: peter-evans/create-or-update-comment@v4 - with: - issue-number: ${{ github.event.pull_request.number }} - body: ${{ steps.spelling.outputs.comment }} + token: ${{ inputs.token }} + PR_NO: ${{ github.event.pull_request.number }} + run: | + source .venv/bin/activate + python main.py diff --git a/local_test.py b/local_test.py index b4b1d73..56bb2e9 100644 --- a/local_test.py +++ b/local_test.py @@ -1,18 +1,8 @@ -import os -import tempfile - -from src.spell_check import main - - -def run(): - if "GITHUB_OUTPUT" not in os.environ: - from dotenv import load_dotenv - - load_dotenv() - with tempfile.NamedTemporaryFile(mode="w+", delete_on_close=False) as f: - os.environ["GITHUB_OUTPUT"] = f.name - main() +from dotenv import load_dotenv +load_dotenv() if __name__ == "__main__": - run() + from src.spell_check import main + + main() diff --git a/main.py b/main.py new file mode 100644 index 0000000..fb8beb2 --- /dev/null +++ b/main.py @@ -0,0 +1,4 @@ +from src.spell_check import main + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index 277e504..728655f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ groq==0.13.0 +requests~=2.32.3 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..44b2b63 --- /dev/null +++ b/src/config.py @@ -0,0 +1,14 @@ +import os + + +def get_env(x): + return os.environ[x] + + +GROQ_API_KEY = get_env("GROQ_API_KEY") +PAT_TOKEN = get_env("token") + +REPO = get_env("GITHUB_REPOSITORY") +PR_BASE = get_env("PR_BASE") +PR_NO = get_env("PR_NO") +INPUT_FILES = [*map(str.strip, get_env("INPUT_FILES").splitlines())] diff --git a/src/groq_ai.py b/src/groq_ai.py index 3f70555..4348089 100644 --- a/src/groq_ai.py +++ b/src/groq_ai.py @@ -1,15 +1,16 @@ import json -import os from functools import cache from groq import NOT_GIVEN, BadRequestError, Groq +from src.config import GROQ_API_KEY + model = ["llama-3.1-8b-instant", "llama3-70b-8192"][1] @cache def get_groq_client(): - return Groq(api_key=os.environ.get("GROQ_API_KEY")) + return Groq(api_key=GROQ_API_KEY) def ask_groq(query_text: str, system_content: str, json_schema: dict = None) -> dict: @@ -25,16 +26,19 @@ def ask_groq(query_text: str, system_content: str, json_schema: dict = None) -> response_format=response_format, ) json_str = chat_completion.choices[0].message.content + json_str = json_str.strip() except BadRequestError as e: failed_json = e.body["error"]["failed_generation"] # noqa json_str = failed_json.replace('"""', '"').replace("\n", "\\n") if not json_schema: return json_str try: - return json.loads(json_str.replace("\n", "")) + # json_str = re.sub("\n +", "", json_str) + return json.loads(json_str) except json.JSONDecodeError as e: - print(e.doc, e.pos) - raise + print(e.doc.encode(), e.pos) + print(f"ERROR : {e.args}") + return {"suggestions": ["..."]} def find_typos(query_text): diff --git a/src/spell_check.py b/src/spell_check.py index 7725960..412c69c 100644 --- a/src/spell_check.py +++ b/src/spell_check.py @@ -1,35 +1,43 @@ -import json -import os import subprocess -from groq_ai import find_typos +import requests +from src.config import INPUT_FILES, PAT_TOKEN, PR_BASE, PR_NO, REPO +from src.groq_ai import find_typos -def process_diff(file_path, base_branch): + +def process_diff(file_path, base_branch=PR_BASE): try: # Get diff from PR diff_command = f"git diff -U0 origin/{base_branch}... -- {file_path}" diff_output = subprocess.check_output(diff_command.split()).decode("utf-8") except subprocess.CalledProcessError: print("Error in process diff") - return 0 + return -1 # only checks for typos in added text new_text = "".join(x for x in diff_output.splitlines(keepends=True) if x.startswith("+")) return find_typos(new_text) if new_text else -1 -def main(): - # Get required inputs - pr_base = os.environ["PR_BASE"] - files = [*map(str.strip, os.environ["INPUT_FILES"].splitlines())] - print(pr_base, *files, sep="\n") +def post_comment(comment): + url = f"https://api.github.com/repos/{REPO}/issues/{PR_NO}/comments" + headers = { + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {PAT_TOKEN}", + "X-GitHub-Api-Version": "2022-11-28", + } + resp = requests.post(url, headers=headers, json={"body": comment}) + resp.raise_for_status() - results = {file_path: process_diff(file_path, pr_base) for file_path in files if file_path} + +def main(): + # Process diff(s) for each file + results = {file_path: process_diff(file_path) for file_path in INPUT_FILES if file_path} # Create markdown comment for fixes flag = False - comment = "## Suggested Typo Fixes\n\n" + comment = "### Suggested Typo Fixes\n" for file_path, suggestion in results.items(): if suggestion == -1: continue @@ -41,10 +49,8 @@ def main(): else: comment = "### No typos found" - # Set output for GitHub Actions - with open(os.environ["GITHUB_OUTPUT"], "a") as f: - f.write(f"comment={json.dumps(comment)}\n") print(comment) + post_comment(comment) if __name__ == "__main__": diff --git a/tests/file.json b/tests/file.json index a67a9c7..237b021 100644 --- a/tests/file.json +++ b/tests/file.json @@ -1 +1 @@ -{"fruit1": "pineaple", "friut2": "gauva"} +{"fruit1": "pineaple", "friut2": "graep"}