Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting up a new Github Action Application for AI Support #3

Merged
merged 96 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 93 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
5e39d6a
chore(application): fixed
DarrellRichards May 31, 2024
ea756f4
chore(action): updated node v
DarrellRichards May 31, 2024
d1b19df
chore(action): node latest
DarrellRichards May 31, 2024
359de21
chore(node): updated node
DarrellRichards May 31, 2024
38d26f0
chore(updated): moved libs to services
DarrellRichards May 31, 2024
1fcadcd
chore(action): fixed issue with var
DarrellRichards May 31, 2024
44903e2
chore(action): fixed issue with var
DarrellRichards May 31, 2024
d040757
chore(action): fixed issue with var
DarrellRichards May 31, 2024
19ece9f
chore(action): fixed issue with var
DarrellRichards May 31, 2024
00fbc88
chore(action): fixed issue with var
DarrellRichards May 31, 2024
cd1f545
chore(action): fixed issue with var
DarrellRichards May 31, 2024
cd7612e
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
2eea851
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
d1548d2
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
c255374
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
2670f16
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
3ba739b
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
9e7b01e
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
ad28ce7
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
90edab3
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
9779458
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
3392d42
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
c44418b
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
f9d9fb8
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
9532026
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
13af433
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
5a1f0b1
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
9235dd5
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
84608b5
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
926f206
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
08084a8
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
a17cbdf
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
1d3de99
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
f31493d
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
27ffb14
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
328e9f7
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
9c15f54
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
c892320
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
6867bab
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
288b79a
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
3d3f2da
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
443ee90
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
f699e0f
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
ecfa3df
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
eda91ff
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
93b24a1
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
716ada6
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
7e0ebe9
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
c244bfc
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
e91ae52
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
6691a7c
chore(action): fixed issue with var
DarrellRichards Jun 1, 2024
72eb518
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
3f4b20e
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
2f08e55
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
434df9b
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
76d58df
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
8bf7caf
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
df108ec
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
42b7769
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
78060e8
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
e1f0363
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
7fe820f
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
6660840
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
312f03f
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
61746e2
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
a52477e
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
764c820
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
6e79ab1
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
f54bd21
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
b73aea8
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
4795359
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
89d1351
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
1c77949
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
1eb203c
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
a4d7d5b
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
d051108
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
34a9de8
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
56a1938
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
042c527
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
dd04a67
chore(action): fixed issue with var
DarrellRichards Jun 2, 2024
99a9db5
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
0e6e6b7
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
4c62433
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
f1b4568
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
f1cb5f0
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
982a3b6
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
b25ee58
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
0a8671d
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
9219d7c
chore(action): fixed issue with var
DarrellRichards Jun 3, 2024
3b00d80
updated index.ts
DarrellRichards Jun 3, 2024
ed7639e
Merge branch 'main' of github.com:softrams/github-pr-magic into testing
DarrellRichards Jun 3, 2024
ddd2990
chore(project): updating project to support a new readme
DarrellRichards Jun 4, 2024
f73b3d7
chore(action): fixed issue with var
DarrellRichards Jun 4, 2024
7bf63f1
chore(actions): fixed typo
DarrellRichards Jun 4, 2024
58e54ff
chore(actions): fixed typo
DarrellRichards Jun 5, 2024
ab9f568
chore(issue): added a issue manager
DarrellRichards Jun 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Install dependencies
run: npm install
- name: Build Code
run: npm run build
- name: Run Custom Action
uses: ./
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.number }}
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
openai_model: 'gpt-4'
github_token: ${{ secrets.GITHUB_TOKEN }}
openai_api_key: ${{ secrets.OPEN_AI_KEY }}
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
openai_model: "gpt-4o"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DarrellRichards make this configurable but defaulted to this model

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already completed (:

review_code: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appears to be a typo here. The input key should be excluded_files instead of expluded_files.

expluded_files: "node_modules, package.json, package-lock.json"
17 changes: 13 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ name: 'Github PR Magic'
description: 'Automatically reviewing and approving PRs'
author: 'Darrell Richards'
inputs:
github-token:
github_token:
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
description: 'Github token'
required: true
pr-number:
description: 'PR number'
required: true
excluded_files:
description: 'Files to exclude from review'
required: false
default: "node_modules, package-lock.json, yarn.lock"
openai_api_key:
description: 'OpenAI API key'
required: true
Expand All @@ -19,6 +20,14 @@ inputs:
description: 'Review code'
required: false
default: true
generate_summary:
description: 'Generates Pull Request summary based on git diff and code changes'
required: false
default: false
overall_code_review:
description: 'Overall code review as a comment'
required: false
default: false
runs:
using: 'node20'
main: 'lib/index.js'
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
"dependencies": {
"@actions/core": "^1.10.1",
"@octokit/rest": "^20.1.1",
"@tandil/diffparse": "^0.2.0",
"@octokit/types": "^13.5.0",
"minimatch": "^9.0.4",
"openai": "^4.47.3"
"openai": "^4.47.3",
"parse-diff": "^0.11.1"
}
}
206 changes: 188 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,210 @@
const parser = require('@tandil/diffparse');
import { readFileSync } from "fs"
import OpenAI from "openai"
import core from "@actions/core";
import { PRDetails } from "./lib/github";
import parseDiff, { File } from "parse-diff"
import * as core from "@actions/core"

import { commentOnPullRequest, compareCommits, createReviewComment, getPullRequestDiff, PRDetails, updateBody } from "./services/github";
import { minimatch } from "minimatch";
import { obtainFeedback, prSummaryCreation, summaryAllMessages, summaryOfAllFeedback, validateCodeViaAI } from "./services/ai";


const excludedFiles = core.getInput("excluded_files").split(",").map((s: string) => s.trim());
const createPullRequestSummary = core.getInput("generate_summary");
const reviewCode = core.getInput("review_code")
const overallReview = core.getInput("overall_code_review");


export interface Details {
title: string;
description: string;
}

async function validatePullRequest(diff: File[], details: Details) {
const foundSummary = [];
for (const file of diff) {
for (const chunk of file.chunks) {
const message = await prSummaryCreation(file, chunk, details);
if (message) {
const mappedResults = message.flatMap((result: any) => {
if (!result.changes) {
return [];
}

if (!result.typeChanges) {
return [];
}

if (!result.checklist) {
return [];
}


return {
changes: result.changes,
typeChanges: result.typeChanges,
checklist: result.checklist,
};
});

foundSummary.push(...mappedResults);
}
}
}


if (foundSummary && foundSummary.length > 0) {
const compiledSummary = await summaryAllMessages(foundSummary);
return compiledSummary;
}

return '';
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
}

async function validateCode(diff: File[], details: Details) {
const neededComments = [];
for (const file of diff) {
for (const chunk of file.chunks) {
const results = await validateCodeViaAI(file, chunk, details);

if (results) {
const mappedResults = results.flatMap((result: any) => {
if (!file.to) {
return [];
}

if (!result.lineNumber) {
return [];
}

if (!result.review) {
return [];
}

return {
body: result.review,
path: file.to,
line: parseInt(result.lineNumber, 10)
};
});
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved

DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
if (mappedResults) {
neededComments.push(...mappedResults);
}
}
}
}

return neededComments;
}
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved

async function validateOverallCodeReview(diff: File[], details: Details) {
const detailedFeedback = [];
for (const file of diff) {
for (const chunk of file.chunks) {
const results = await obtainFeedback(file, chunk, details);
if (results) {
const mappedResults = results.flatMap((result: any) => {
if (!file.to) {
return [];
}

return {
changesOverview: result.changesOverview,
feedback: result.feedback,
improvements: result.improvements,
conclusion: result.conclusion,
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
};
});

if (mappedResults) {
detailedFeedback.push(...mappedResults);
}
}
}
}

return detailedFeedback;
}

const openai = new OpenAI()
const excludedFiles = core.getInput("exclude").split(",").map((s: string) => s.trim());

async function main() {
let dif: string | null = null;
const { action, repository, number } = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH || "", "utf-8"))
const { action, repository, number, before, after } = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH || "", "utf-8"))
const { title, description } = await PRDetails(repository, number);

if (action === "opened") {
// Generate a summary of the PR since it's a new PR

if (action === "opened" || action === "reopened") {
const data = await getPullRequestDiff(repository.owner.login, repository.name, number);
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
dif = data as unknown as string;
} else if (action === "synchronize") {
const newBaseSha = before;
const newHeadSha = after;

const data = await compareCommits({
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
owner: repository.owner.login,
repo: repository.name,
before: newBaseSha,
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
after: newHeadSha,
number
})

dif = String(data);
} else {
console.log('Unknown action', process.env.GITHUB_EVENT_NAME);
return;
}

if (!dif) {
// Well shit.
console.log('No diff found, exiting')
return;
}

const diff = parser.parseDiffString(dif);
const filteredDiff = diff.filter((file: { to: any; }) => {
const diff = parseDiff(dif);
const filteredDiff = diff.filter((file) => {
return !excludedFiles.some((pattern) =>
minimatch(file.to ?? "", pattern)
);
});

console.log(filteredDiff);
if (action === "opened") {
if (createPullRequestSummary) {
console.log('Generating summary for new PR');
const summary = await validatePullRequest(diff, {
title,
description
});

if (summary) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation for this line should be adjusted to match the surrounding code style. It seems to have an extra space.

await updateBody(repository.owner.login, repository.name, number, summary);
}
}

// Validate Some Code Yo!
if (overallReview) {
const detailedFeedback = await validateOverallCodeReview(filteredDiff, {
title,
description
});

if (detailedFeedback && detailedFeedback.length > 0) {
const resultsFullFeedback = await summaryOfAllFeedback(detailedFeedback);
if (resultsFullFeedback) {
await commentOnPullRequest({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if (resultsFullFeedback) check introduced here is a good safeguard. Ensure that the summaryOfAllFeedback function indeed returns null, undefined, or an equivalent falsy value in cases where no feedback is generated. This will prevent potential silent failures.

owner: repository.owner.login,
repo: repository.name,
number
}, resultsFullFeedback);
}
}
}
}

// Post some comments
if (reviewCode) {
const neededComments = await validateCode(filteredDiff, {
title,
description
});

if (neededComments) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since neededComments is an array, the previous check for neededComments && neededComments.length > 0 ensures that comments are only created when there are actual elements in the array. The new condition if (neededComments) is less restrictive as it will be true even if neededComments is an empty array, potentially leading to unnecessary API calls. Consider reverting to the original condition to avoid such scenarios.

await createReviewComment(repository.owner.login, repository.name, number, neededComments);
}
}
DarrellRichards marked this conversation as resolved.
Show resolved Hide resolved
}

main();
main();
Loading
Loading