diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..70b693a --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,145 @@ +version: 2.1 + +jobs: + ai-insights-code-review: + docker: + - image: python:3.11-slim + steps: + - checkout + - run: + command: | + pip install virtualenv + virtualenv venv + source venv/bin/activate + cd outer-loop-cli/src + pip install -r requirements.txt + pip install --editable . + cd ../.. + devai echo + echo $(pwd) + + export PROJECT_ID=$(echo $PROJECT_ID) + export LOCATION=$(echo $LOCATION) + + export JIRA_USERNAME=$(echo $JIRA_USERNAME) + export JIRA_PROJECT_KEY=$(echo $JIRA_PROJECT_KEY) + export JIRA_INSTANCE_URL=$(echo $JIRA_INSTANCE_URL) + export JIRA_API_TOKEN=$(echo $JIRA_API_TOKEN) + + export GITLAB_URL=$(echo $GITLAB_URL) + export GITLAB_REPOSITORY=$(echo $GITLAB_REPOSITORY) + export GITLAB_PERSONAL_ACCESS_TOKEN=$(echo $GITLAB_PERSONAL_ACCESS_TOKEN) + export GITLAB_BRANCH=$(echo $GITLAB_BRANCH) + export GITLAB_BASE_BRANCH=$(echo $GITLAB_BASE_BRANCH) + + export LANGCHAIN_TRACING_V2=$(echo $LANGCHAIN_TRACING_V2) + export LANGCHAIN_ENDPOINT=$(echo $LANGCHAIN_ENDPOINT) + export LANGCHAIN_API_KEY=$(echo $LANGCHAIN_API_KEY) + + export GOOGLE_CLOUD_CREDENTIALS=$(echo $GOOGLE_CLOUD_CREDENTIALS) + echo $GOOGLE_CLOUD_CREDENTIALS > service-account-key.json + export GOOGLE_APPLICATION_CREDENTIALS="service-account-key.json" + echo "" + echo "=============================================================" + echo "Code Review" + devai review code -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + echo "" + echo "=============================================================" + + ai-insights-security-review: + docker: + - image: python:3.11-slim + steps: + - checkout + - run: + command: | + pip install virtualenv + virtualenv venv + source venv/bin/activate + cd outer-loop-cli/src + pip install -r requirements.txt + pip install --editable . + cd ../.. + devai echo + echo $(pwd) + + export PROJECT_ID=$(echo $PROJECT_ID) + export LOCATION=$(echo $LOCATION) + + export JIRA_USERNAME=$(echo $JIRA_USERNAME) + export JIRA_PROJECT_KEY=$(echo $JIRA_PROJECT_KEY) + export JIRA_INSTANCE_URL=$(echo $JIRA_INSTANCE_URL) + export JIRA_API_TOKEN=$(echo $JIRA_API_TOKEN) + + export GITLAB_URL=$(echo $GITLAB_URL) + export GITLAB_REPOSITORY=$(echo $GITLAB_REPOSITORY) + export GITLAB_PERSONAL_ACCESS_TOKEN=$(echo $GITLAB_PERSONAL_ACCESS_TOKEN) + export GITLAB_BRANCH=$(echo $GITLAB_BRANCH) + export GITLAB_BASE_BRANCH=$(echo $GITLAB_BASE_BRANCH) + + export LANGCHAIN_TRACING_V2=$(echo $LANGCHAIN_TRACING_V2) + export LANGCHAIN_ENDPOINT=$(echo $LANGCHAIN_ENDPOINT) + export LANGCHAIN_API_KEY=$(echo $LANGCHAIN_API_KEY) + + export GOOGLE_CLOUD_CREDENTIALS=$(echo $GOOGLE_CLOUD_CREDENTIALS) + echo $GOOGLE_CLOUD_CREDENTIALS > service-account-key.json + export GOOGLE_APPLICATION_CREDENTIALS="service-account-key.json" + echo "" + echo "=============================================================" + echo "Performance Review" + devai review performance -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + echo "" + echo "=============================================================" + + ai-insights-performance-review: + docker: + - image: python:3.11-slim + steps: + - checkout + - run: + command: | + pip install virtualenv + virtualenv venv + source venv/bin/activate + cd outer-loop-cli/src + pip install -r requirements.txt + pip install --editable . + cd ../.. + devai echo + echo $(pwd) + + export PROJECT_ID=$(echo $PROJECT_ID) + export LOCATION=$(echo $LOCATION) + + export JIRA_USERNAME=$(echo $JIRA_USERNAME) + export JIRA_PROJECT_KEY=$(echo $JIRA_PROJECT_KEY) + export JIRA_INSTANCE_URL=$(echo $JIRA_INSTANCE_URL) + export JIRA_API_TOKEN=$(echo $JIRA_API_TOKEN) + + export GITLAB_URL=$(echo $GITLAB_URL) + export GITLAB_REPOSITORY=$(echo $GITLAB_REPOSITORY) + export GITLAB_PERSONAL_ACCESS_TOKEN=$(echo $GITLAB_PERSONAL_ACCESS_TOKEN) + export GITLAB_BRANCH=$(echo $GITLAB_BRANCH) + export GITLAB_BASE_BRANCH=$(echo $GITLAB_BASE_BRANCH) + + export LANGCHAIN_TRACING_V2=$(echo $LANGCHAIN_TRACING_V2) + export LANGCHAIN_ENDPOINT=$(echo $LANGCHAIN_ENDPOINT) + export LANGCHAIN_API_KEY=$(echo $LANGCHAIN_API_KEY) + + export GOOGLE_CLOUD_CREDENTIALS=$(echo $GOOGLE_CLOUD_CREDENTIALS) + echo $GOOGLE_CLOUD_CREDENTIALS > service-account-key.json + export GOOGLE_APPLICATION_CREDENTIALS="service-account-key.json" + echo "" + echo "=============================================================" + echo "Security Review" + devai review security -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + echo "" + echo "=============================================================" + +workflows: + ai-insights-workflow: + jobs: + - ai-insights-code-review + - ai-insights-security-review + - ai-insights-performance-review + diff --git a/.github/workflows/devai-review.yml b/.github/workflows/devai-review.yml index 06d157c..bae708d 100644 --- a/.github/workflows/devai-review.yml +++ b/.github/workflows/devai-review.yml @@ -8,12 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: List files in the repository run: | ls ${{ github.workspace }} - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11.7' - run: pip install google-cloud-aiplatform @@ -37,7 +37,7 @@ jobs: shell: bash - name: Security Review - run: echo '## Performance Review Results 🚀' >> $GITHUB_STEP_SUMMARY + run: echo '## Security Review Results 🚀' >> $GITHUB_STEP_SUMMARY - run: echo "$(devai review security -c ${{ github.workspace }}/sample-app/src/main/java/anthos/samples/bankofanthos/balancereader)" >> $GITHUB_STEP_SUMMARY shell: bash diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2eb88cc..e149ab2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,7 @@ +# workflow: +# rules: +# - if: $CI_PIPELINE_SOURCE == "web" + image: python:3.11-slim variables: @@ -12,7 +16,7 @@ before_script: - pip install virtualenv - virtualenv venv - source venv/bin/activate - - cd cli-code-api/src + - cd outer-loop-cli/src - pip install -r requirements.txt - pip install --editable . - cd ../.. @@ -25,9 +29,28 @@ build-job: - echo "Hello, $GITLAB_USER_LOGIN!" - devai echo - echo $(pwd) + - export PROJECT_ID=$(echo $PROJECT_ID) + - export LOCATION=$(echo $LOCATION) + + - export LANGCHAIN_TRACING_V2=$(echo $LANGCHAIN_TRACING_V2) + - export LANGCHAIN_ENDPOINT=$(echo $LANGCHAIN_ENDPOINT) + - export LANGCHAIN_API_KEY=$(echo $LANGCHAIN_API_KEY) + + - export JIRA_API_TOKEN=$(echo $JIRA_API_TOKEN) + - export JIRA_USERNAME=$(echo $JIRA_USERNAME) + - export JIRA_INSTANCE_URL=$(echo $JIRA_INSTANCE_URL) + - export JIRA_PROJECT_KEY=$(echo $JIRA_PROJECT_KEY) + + - export GITLAB_PERSONAL_ACCESS_TOKEN=$(echo $GITLAB_PERSONAL_ACCESS_TOKEN) + - export GITLAB_URL=$(echo $GITLAB_URL) + - export GITLAB_REPOSITORY=$(echo $GITLAB_REPOSITORY) + - export GITLAB_BRANCH=$(echo $GITLAB_BRANCH) + - export GITLAB_BASE_BRANCH=$(echo $GITLAB_BASE_BRANCH) + - export GOOGLE_CLOUD_CREDENTIALS=$(echo $GOOGLE_CLOUD_CREDENTIALS) - - echo $GOOGLE_CLOUD_CREDENTIALS > service-account-key.json + - echo $GOOGLE_CLOUD_CREDENTIALS > service-account-key.json - export GOOGLE_APPLICATION_CREDENTIALS="service-account-key.json" - - devai review code -c ./cli-code-api/sample-app/src/main/java/anthos/samples/bankofanthos/balancereader - - devai review performance -c ./cli-code-api/sample-app/src/main/java/anthos/samples/bankofanthos/balancereader - - devai review security -c ./cli-code-api/sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + + - devai review code -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + - devai review performance -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + - devai review security -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader diff --git a/outer-loop-cli/README.md b/outer-loop-cli/README.md index 600b905..71f9bdf 100644 --- a/outer-loop-cli/README.md +++ b/outer-loop-cli/README.md @@ -1,4 +1,4 @@ -# GenAI CLI on Palm2 for Development +# GenAI CLI with Gemini Pro for Development This example demonstrates ways to integrate LLM models into a custom command line utility for use by developers both locally and in automation processes such as CICD pipelines. @@ -7,6 +7,13 @@ This directory contains a sample cli implementation called devai, as well as a t ## Install and use The cli is provided as a package on PyPi for demonstration purposes only. It is not intended for production use as is. To install the package for use locally or in CICD systems run the following command +Set environment variables in your local environment or in CICD pipeline environment variables. + +```sh +export PROJECT_ID=YOUR_GCP_PROJECT_ID +export LOCATION=us-central1 +``` + ```sh pip install -i https://test.pypi.org/simple/ devai ``` @@ -32,12 +39,58 @@ devai release notes_user_tag -t "v5.0.0" devai release notes_user -s "main" -e "feature-branch-name" ``` +## Enable APIs + +Enable Gemini chat and Vertex AI APIs. + +```sh +gcloud services enable \ + aiplatform.googleapis.com \ + cloudaicompanion.googleapis.com \ + cloudresourcemanager.googleapis.com +``` + +## Configure Service Account + +Run commands below to create service account and keys. + +```sh +PROJECT_ID=$(gcloud config get-value project) +SERVICE_ACCOUNT_NAME='vertex-client' +DISPLAY_NAME='Vertex Client' +KEY_FILE_NAME='vertex-client-key' + +gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME --display-name "$DISPLAY_NAME" + +gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com" --role="roles/aiplatform.admin" --condition None + +gcloud iam service-accounts keys create $KEY_FILE_NAME.json --iam-account=$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com +``` + +## Configure Environment Variables in CICD + +Add following environment variables/secrets to your CICD pipeline. + +If you have JIRA, GitLab and LangSmith integrations enabled, add additional env variables for respective systems, see details in sections below. + +- GOOGLE_CLOUD_CREDENTIALS +- PROJECT_ID +- LOCATION + +For GOOGLE_CLOUD_CREDENTIALS variable value, use service account key created in section above. + +```sh +cat $KEY_FILE_NAME.json +``` + ## Use in CICD This can be added in any build pipeline following the examples below: GitHub Actions (Full example at ${repoRoot/.github/workflows/devai-review.yml}) +[devai-review.yaml](../.github/workflows/devai-review.yml) + ```sh - name: Code Review run: echo '## Code Review Results 🚀' >> $GITHUB_STEP_SUMMARY @@ -45,6 +98,41 @@ GitHub Actions (Full example at ${repoRoot/.github/workflows/devai-review.yml}) shell: bash ``` +GitLab Pipeline example + +[.gitlab-ci.yml](../.gitlab-ci.yml) + +```sh +build-job: + stage: build + script: + . + . + - devai review code -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + - devai review performance -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader + - devai review security -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader +``` + +CircleCI Pipeline example + +[config.yml](../.circleci/config.yml) + +```sh +version: 2.1 + +jobs: + ai-insights-code-review: + docker: + - image: python:3.11-slim + steps: + - checkout + - run: + command: | + . + . + devai review code -c ./sample-app/src/main/java/anthos/samples/bankofanthos/balancereader +``` + ## Developers Guide ### Getting started @@ -164,3 +252,96 @@ python3 -m twine upload --repository testpypi src/dist/* --verbose pip install -i https://test.pypi.org/simple/ devai==0.1.4.2 devai ``` + +### LangSmith LLM tracing configuration +Create an account and generate API key. + +https://docs.smith.langchain.com/setup + +Set environment variables required for LangSmith integration. + +```sh +export LANGCHAIN_TRACING_V2=true +export LANGCHAIN_ENDPOINT="https://api.smith.langchain.com" + +read -s LANGCHAIN_API_KEY +export LANGCHAIN_API_KEY + +``` + +### JIRA command configuration + +Create JIRA API token for your project. + +https://id.atlassian.com/manage-profile/security/api-tokens + +Set environment variables required for JIRA integration. + +```sh +read -s JIRA_API_TOKEN +export JIRA_API_TOKEN + +export JIRA_USERNAME = "email that you used to register with JIRA" +export JIRA_INSTANCE_URL = "https://YOUR-PROJECT.atlassian.net" +export JIRA_PROJECT_KEY = "JIRA project key" +``` +Un-comment imports and function calls to use JIRA commands +- cli.py +- review.py + +Commands to test JIRA integration + +```sh +# Will return list of JIRA issues in specified JIRA project +devai jira list -c YOUR_JIRA_PROJECT_KEY + +# Will create a new JIRA issue with provided details as is +devai jira create -c "New Feature request to implement Login Page.\nExample code block:\n {code}print(\"devai cli\"){code}" + +# Will generate implementation and create a new JIRA issue with details +devai jira fix -c "write ring buffer implementation in Rust" +``` + +### GitLab command configuration + +Create Project Access Token with following details: + +- role: Maintainer +- selected scopes: api + +https://gitlab.com/YOUR-USERID/YOUR-PROJECT/-/settings/access_tokens + +Set environment variables required for GitLab integration. + +```sh +read -s GITLAB_PERSONAL_ACCESS_TOKEN +export GITLAB_PERSONAL_ACCESS_TOKEN + +export GITLAB_URL="https://gitlab.com" +export GITLAB_REPOSITORY="USERID/REPOSITORY" +export GITLAB_BRANCH="devai" +export GITLAB_BASE_BRANCH="main" +``` + +Un-comment imports and function calls to use GitLab commands +- cli.py +- review.py + +Commands to test GitLab integration + +```sh +# Will create a new merge request with provided details +# Requires a branch to be created off main - manual step at this point +# export GITLAB_BRANCH="fix-branch" +devai gitlab create-pr -c "Details with file changes, docs, etc" + +# Will create a new GitLab issue with provided details as is +devai gitlab fix-issue -c 4 + +# Will add a comment to GitLab issue +# issue name defaults to 'CICD AI Insights' for demonstration +devai gitlab create-comment -c "new comment content goes here" + +# Will add a comment to GitLab issue with name 'CICD AI Insights' +devai gitlab create-comment -i "CICD AI Insights" -c "new comment content goes here" +``` \ No newline at end of file diff --git a/outer-loop-cli/src/devai/cli.py b/outer-loop-cli/src/devai/cli.py index ec59b85..dfe0063 100644 --- a/outer-loop-cli/src/devai/cli.py +++ b/outer-loop-cli/src/devai/cli.py @@ -16,6 +16,10 @@ from devai.commands import cmd, prompt, review, release +# Uncomment after configuring JIRA and GitLab env variables - see README.md for details +# from devai.commands import jira +# from devai.commands import gitlab + @click.group() def devai(): @@ -35,6 +39,9 @@ def echo(): devai.add_command(review.review) devai.add_command(release.release) +# devai.add_command(jira.jira) +# devai.add_command(gitlab.gitlab) + if __name__ == '__main__': devai() diff --git a/outer-loop-cli/src/devai/commands/gitlab.py b/outer-loop-cli/src/devai/commands/gitlab.py new file mode 100644 index 0000000..86ca439 --- /dev/null +++ b/outer-loop-cli/src/devai/commands/gitlab.py @@ -0,0 +1,84 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click +import os, json +from langchain.agents import AgentType, initialize_agent +from langchain_google_vertexai import ChatVertexAI +from langchain_community.agent_toolkits.gitlab.toolkit import GitLabToolkit +from langchain_community.utilities.gitlab import GitLabAPIWrapper + +llm = ChatVertexAI(model_name="gemini-pro", + convert_system_message_to_human=True, + project=os.environ["PROJECT_ID"], + location=os.environ["LOCATION"]) + +gitlab = GitLabAPIWrapper() +toolkit = GitLabToolkit.from_gitlab_api_wrapper(gitlab) +agent = initialize_agent( + toolkit.get_tools(), + llm, + agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + verbose=True, + handle_parsing_errors=True, + max_iterations=5, + return_intermediate_steps=True, + early_stopping_method="generate", +) + +def create_pull_request(context): + return agent.invoke("""Create GitLab merge request, use provided details below: + {}""".format(context)) + + +def create_gitlab_issue_comment(context, issue_name='CICD AI Insights'): + + prompt = """Get GitLab issue with name '{}' and add a comment: + + + {}""".format(issue_name, json.dumps(context)) + + return agent.invoke(prompt) + +def fix_gitlab_issue_comment(context): + prompt = """You have the software engineering capabilities of a Google Principle engineer. + You are tasked with completing issues on a gitlab repository. + Please look at the open issue #{} and complete it by creating pull request that solves the issue." + """.format(context) + + return agent.invoke(prompt) + +@click.command() +@click.option('-c', '--context', required=False, type=str, default="") +def create_pr(context): + return create_pull_request(context) + +@click.command() +@click.option('-c', '--context', required=False, type=str, default="") +@click.option('-i', '--issue', required=False, type=str, default="") +def create_comment(issue, context): + return create_gitlab_issue_comment(issue, context) + +@click.command() +@click.option('-c', '--context', required=False, type=str, default="") +def fix_issue(context): + return fix_gitlab_issue_comment(context) + +@click.group() +def gitlab(): + pass + +gitlab.add_command(create_pr) +gitlab.add_command(create_comment) +gitlab.add_command(fix_issue) diff --git a/outer-loop-cli/src/devai/commands/jira.py b/outer-loop-cli/src/devai/commands/jira.py new file mode 100644 index 0000000..0c1b8d2 --- /dev/null +++ b/outer-loop-cli/src/devai/commands/jira.py @@ -0,0 +1,145 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import click +import datetime +import os, json +from langchain.tools import StructuredTool +from langchain.agents import AgentType, initialize_agent +from langchain_community.agent_toolkits.jira.toolkit import JiraToolkit +from langchain_community.utilities.jira import JiraAPIWrapper +from langchain_google_vertexai import ChatVertexAI +from jira import JIRA + + +llm = ChatVertexAI(model_name="gemini-pro", + convert_system_message_to_human=True, + project=os.environ["PROJECT_ID"], + location=os.environ["LOCATION"]) + +jira = JiraAPIWrapper() +toolkit = JiraToolkit.from_jira_api_wrapper(jira) +agent = initialize_agent( + toolkit.get_tools(), + llm, + agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, + verbose=True, + handle_parsing_errors=True, + max_iterations=5, + return_intermediate_steps=True, + early_stopping_method="generate", +) + + +def create_issue(description: str) -> str: + """Creates a Jira issue""" + JIRA_USERNAME = os.environ["JIRA_USERNAME"] + JIRA_API_TOKEN = os.environ["JIRA_API_TOKEN"] + JIRA_INSTANCE_URL = os.environ["JIRA_INSTANCE_URL"] + JIRA_PROJECT_KEY = os.environ["JIRA_PROJECT_KEY"] + + summary = "Issue {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + + issue_type = "Task" + project_key=JIRA_PROJECT_KEY + jira = JIRA(basic_auth=(JIRA_USERNAME, JIRA_API_TOKEN), server=JIRA_INSTANCE_URL) + + issue_dict = { + 'project': {'key': project_key}, + 'summary': summary, + 'description': description, + 'issuetype': {'name': issue_type}, + + } + new_issue = jira.create_issue(fields=issue_dict) + resp = f'New issue created with key: {new_issue.key}' + + print(resp) + return resp + +create_issue_tool = StructuredTool.from_function(create_issue, description="Create a new JIRA issue") + +create_agent = initialize_agent( + [create_issue_tool], + llm, + agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, + verbose=True, + handle_parsing_errors=True, + max_iterations=5, + return_intermediate_steps=True, + early_stopping_method="generate", +) + +@click.command() +@click.option('-c', '--context', required=False, type=str, default="") +def list(context): + agent(""" + INSTRUCTIONS: + Only read data - do not try to create/write/update any data. + + List JIRA tickets in the project {}. + Print/format output as a list with ticket number use template below, description and summary. + Example: + Issue-1: Issue Description # 1 + Issue-2: Issue Description # 2 + """.format(context)) + + +def create_jira_issue(summary, context): + """Creates a Jira issue""" + return create_agent("""Create a new JIRA issue with following description. + DESCRIPTION: + {}""".format(context)) + + +@click.command() +@click.option('-c', '--context', required=False, type=str, default="") +def create(context): + return create_jira_issue("Jira Issue Summary", context) + + +@click.command() +@click.option('-c', '--context', required=False, type=str, default="") +def fix(context): + + prompt = """ + INSTRUCTIONS: + You are principal software engineer and given requirements to implement. + Please provide implementation details and documentation. + + CONTEXT: + {} + """.format(context) + + fix = llm.invoke( + prompt + ) + + create_prompt = """Create a new JIRA issue with description below: + CONTENT: + {}""".format(json.dumps(fix.content)) + + cleaned_prompt = create_prompt.strip() + cleaned_prompt = cleaned_prompt.replace("```", "{code}") + + create_agent(cleaned_prompt) + +@click.group() +def jira(): + pass + +jira.add_command(list) +jira.add_command(fix) +jira.add_command(create) diff --git a/outer-loop-cli/src/devai/commands/review.py b/outer-loop-cli/src/devai/commands/review.py index 2ae4a22..6e3142e 100644 --- a/outer-loop-cli/src/devai/commands/review.py +++ b/outer-loop-cli/src/devai/commands/review.py @@ -1,4 +1,4 @@ -# Copyright 2023 Google LLC +# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,9 +15,12 @@ import click from devai.util.file_processor import format_files_as_string -from vertexai.language_models import CodeChatModel, ChatModel -from vertexai.preview.language_models import CodeGenerationModel +from vertexai.generative_models import GenerativeModel, ChatSession +# Uncomment after configuring JIRA and GitLab env variables - see README.md for details + +# from devai.commands.jira import create_jira_issue +# from devai.commands.gitlab import create_gitlab_issue_comment parameters = { "max_output_tokens": 2048, @@ -36,24 +39,42 @@ def code(context): ''' qry=''' INSTRUCTIONS: -You are a staff level programmer and a software architect doing a code review. -Find inefficiencies and poor coding practices in the code. -For each issue provide detailed explanation. -Output the findings with class and method names followed by the found issues. -Pose the output as suggestions or questions -If no significant issues are found output "No Issues" +You are an experienced software architect renowned for your ability to identify code quality issues, optimization opportunities, and adherence to best practices. Conduct a thorough code review of the provided codebase with the following focus: + +Key Areas + +Efficiency: Identify performance bottlenecks, redundant operations, or areas where algorithms and data structures could be improved for enhanced speed and resource usage. +Maintainability: Assess code readability, modularity, and the ease of future changes. Look for overly complex logic, tight coupling, or lack of proper code organization. +Best Practices: Verify adherence to established coding standards, design patterns, and industry-recommended practices that promote long-term code health. +Security: Scrutinize the code for potential vulnerabilities like improper input validation, susceptibility to injection attacks, or weaknesses in data handling. +Output Guidance + +Structure: Organize your findings by class and method names. This provides clear context for the issues and aids in refactoring. + +Tone: Frame your findings as constructive suggestions or open-ended questions. This encourages collaboration and avoids a purely critical tone. Examples: + +"Could we explore an alternative algorithm here to potentially improve performance?" +"Would refactoring this logic into smaller functions enhance readability and maintainability?" +Specificity: Provide detailed explanations for each issue. This helps the original developer understand the reasoning and implement effective solutions. + +Prioritization: If possible, indicate the severity or potential impact of each issue (e.g., critical, high, medium, low). This helps prioritize fixes. + +No Issues: If your review uncovers no significant areas for improvement, state "No major issues found. The code appears well-structured and adheres to good practices." ''' # Load files as text into source variable source=source.format(format_files_as_string(context)) - code_chat_model = CodeChatModel.from_pretrained("codechat-bison") - - chat = code_chat_model.start_chat(context=source, **parameters) - response = chat.send_message(qry) + code_chat_model = GenerativeModel("gemini-1.0-pro") + code_chat = code_chat_model.start_chat() + code_chat.send_message(qry) + response = code_chat.send_message(source) click.echo(f"Response from Model: {response.text}") + #create_jira_issue("Code Review Results", response.text) + # create_gitlab_issue_comment(response.text) + @click.command() @click.option('-c', '--context', required=False, type=str, default="") @@ -67,21 +88,47 @@ def performance(context): ''' qry=''' INSTRUCTIONS: -You are an experienced staff level programmer and an application performance tuning expert doing a code review. -Find language specific performance issues in the code, such string concatenation, as memory leaks, race conditions, and deadlocks. -For each issue provide detailed explanation. -Output the findings with class and method names followed by the found issues. +You are a seasoned application performance tuning expert with deep knowledge of Java's nuances. Conduct a meticulous code review focused on identifying performance pitfalls and optimization opportunities within the codebase. Pay close attention to: + +Performance Bottlenecks: + +Inefficient Operations: Pinpoint constructs known to be slow in the language, such as excessive string concatenation, unnecessary object creation, or suboptimal loop structures. +I/O-bound Operations: Examine file access, database queries, and network communication calls that could introduce latency. +Algorithmic Complexity: Analyze algorithms used for time and space complexity. Look for potential improvements using more efficient data structures or algorithms. +Memory Management: + +Memory Leaks: Identify objects that are no longer referenced but not garbage collected, leading to gradual memory consumption. +Memory Bloat: Look for unnecessary object allocations, the use of overly large data structures, or the retention of data beyond its useful life. +Concurrency: + +Race Conditions: Hunt for scenarios where multiple threads access shared data without proper synchronization, leading to unpredictable results. +Deadlocks: Detect situations where threads hold locks on resources while waiting for each other, causing the application to hang. +Output Guidance: +Structure: Organize your findings by class and method names. This provides clear context for the issues and aids in refactoring. + +Tone: Frame your findings as constructive suggestions or open-ended questions. This encourages collaboration and avoids a purely critical tone. Examples: + +"Could we explore an alternative algorithm here to potentially improve performance?" +"Would refactoring this logic into smaller functions enhance readability and maintainability?" +Specificity: Provide detailed explanations for each issue. This helps the original developer understand the reasoning and implement effective solutions. + +Prioritization: If possible, indicate the severity or potential impact of each issue (e.g., critical, high, medium, low). This helps prioritize fixes. + +No Issues: If your review uncovers no significant areas for improvement, state "No major issues found. The code appears well-structured and adheres to good practices." ''' # Load files as text into source variable source=source.format(format_files_as_string(context)) - code_chat_model = CodeChatModel.from_pretrained("codechat-bison") - chat = code_chat_model.start_chat(context=source, **parameters) - response = chat.send_message(qry) + code_chat_model = GenerativeModel("gemini-1.0-pro") + code_chat = code_chat_model.start_chat() + code_chat.send_message(qry) + response = code_chat.send_message(source) click.echo(f"Response from Model: {response.text}") + # create_jira_issue("Performance Review Results", response.text) + # create_gitlab_issue_comment(response.text) @click.command() @click.option('-c', '--context', required=False, type=str, default="") @@ -94,29 +141,40 @@ def security(context): ''' qry=''' INSTRUCTIONS: -You are an experienced security programmer doing a code review. Looking for security violations in the code. -Examine the attached code for potential security issues. Issues to look for, look for instances of insecure cookies, insecure session management, any instances of SQL injection, cross-site scripting (XSS), -or other vulnerabilities that could compromise user data or allow unauthorized access to the application. -Provide a comprehensive report of any identified vulnerabilities and recommend appropriate remediation measures. -Output the findings with class and method names followed by the found issues. - -Example of the output format to use: -Class name.Method name: -Issue: -Recommendation: - -If no issues are found, output "No issues found". +You are a seasoned security expert with a keen eye for identifying vulnerabilities in web applications. Conduct a thorough security review of the attached codebase, focusing on the following critical areas: + +Vulnerability Identification + +Insecure Cookies: Check for cookies lacking proper security flags (HttpOnly, Secure), sensitive data in cookies, or inadequate expiration settings. +Insecure Session Management: Examine session generation, storage, transmission, timeout mechanisms, and potential for session hijacking or fixation. +SQL Injection: Scrutinize all database interactions for lack of input sanitization or parameterized queries that could allow malicious SQL code execution. +Cross-Site Scripting (XSS): Inspect input handling, output encoding, and content filtering to prevent the injection of malicious scripts into user-facing pages. +Other Common Vulnerabilities: Keep an eye out for potential vulnerabilities listed in the OWASP Top 10 (https://owasp.org/Top10/), such as improper access control, misconfigurations, and sensitive data exposure. +Report Guidance + +Structure: Organize your findings by class and method names. This provides clear context for the issues and aids in refactoring. +Tone: Frame your findings as constructive suggestions or open-ended questions. This encourages collaboration and avoids a purely critical tone. Examples: + +"Could we explore an alternative algorithm here to potentially improve performance?" +"Would refactoring this logic into smaller functions enhance readability and maintainability?" +Specificity: Provide detailed explanations for each issue. This helps the original developer understand the reasoning and implement effective solutions. + +Prioritization: If possible, indicate the severity or potential impact of each issue (e.g., critical, high, medium, low). This helps prioritize fixes. + +No Issues: If your review uncovers no significant areas for improvement, state "No major issues found. The code appears well-structured and adheres to good practices." ''' # Load files as text into source variable source=source.format(format_files_as_string(context)) - - code_chat_model = CodeChatModel.from_pretrained("codechat-bison") - chat = code_chat_model.start_chat(context=source, **parameters) - response = chat.send_message(qry) + + code_chat_model = GenerativeModel("gemini-1.0-pro") + code_chat = code_chat_model.start_chat() + code_chat.send_message(qry) + response = code_chat.send_message(source) click.echo(f"Response from Model: {response.text}") - + # create_jira_issue("Security Review Results", response.text) + # create_gitlab_issue_comment(response.text) @click.group() diff --git a/outer-loop-cli/src/devai/util/file_processor.py b/outer-loop-cli/src/devai/util/file_processor.py index 1c6c03a..670ff7e 100644 --- a/outer-loop-cli/src/devai/util/file_processor.py +++ b/outer-loop-cli/src/devai/util/file_processor.py @@ -37,7 +37,7 @@ def get_text_files_contents(path, ignore=None): :return: Dictionary with file paths as keys and file contents as values """ if ignore is None: - ignore = [] + ignore = set(['venv', '__pycache__', '.gitignore']) result = {} for dirpath, dirnames, filenames in os.walk(path): @@ -56,8 +56,8 @@ def get_text_files_contents(path, ignore=None): def format_files_as_string(input): def process_file(file_path): if not is_ascii_text(file_path): - # return f"file: {file_path}\nsource: [Binary File - Not ASCII Text]\n" - pass + return f"file: {file_path}\nsource: [Binary File - Not ASCII Text]\n" + # pass with open(file_path, 'r') as file: content = file.read() @@ -65,10 +65,15 @@ def process_file(file_path): # return f"{content}\n\n" formatted_string = "" - + + exclude_directories = set(['venv', '__pycache__', '.gitignore']) + if isinstance(input, str): if os.path.isdir(input): + for root, dirs, files in os.walk(input): + dirs[:] = [d for d in dirs if d not in exclude_directories] + files[:] = [f for f in files if f not in exclude_directories] for file in files: file_path = os.path.join(root, file) if os.path.exists(file_path): diff --git a/outer-loop-cli/src/requirements.txt b/outer-loop-cli/src/requirements.txt index 02f2e26..595a180 100644 --- a/outer-loop-cli/src/requirements.txt +++ b/outer-loop-cli/src/requirements.txt @@ -1,2 +1,7 @@ click==8.1.7 -google-cloud-aiplatform==1.35.0 +google-cloud-aiplatform==1.42.1 +jira==3.6.0 +python-gitlab==4.4.0 +langchain==0.1.8 +langchain_google_vertexai==0.0.5 +atlassian-python-api==3.41.10 \ No newline at end of file