Skip to content

Commit

Permalink
feat(Slack): link PR to messages (#158)
Browse files Browse the repository at this point in the history
* get conversation when generating summary

* fetch thread messages directly via url param

* send slack message per link

* Bot - Fix Formatting

* make slack link optional, and fix test

* uncomment test

* make all org slack access token optional

* fix get replied test

---------

Co-authored-by: homie bot <[email protected]>
  • Loading branch information
mikewuu and homieggbot authored Jul 28, 2024
1 parent 51f9d13 commit 2834019
Show file tree
Hide file tree
Showing 22 changed files with 391 additions and 130 deletions.
6 changes: 6 additions & 0 deletions src/app/api/gitlab/projects/[project_id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export const PATCH = createRoute(
'gitlab.app_user.organization_id',
'homie.organization.id',
)
.leftJoin(
'slack.workspace',
'slack.workspace.organization_id',
'homie.organization.id',
)
.leftJoin(
'trello.workspace',
'trello.workspace.organization_id',
Expand All @@ -54,6 +59,7 @@ export const PATCH = createRoute(
'trello.workspace.trello_access_token',
'asana_access_token',
'homie.organization.has_unlimited_usage',
'slack_access_token',
])
.executeTakeFirst()

Expand Down
12 changes: 11 additions & 1 deletion src/app/api/gitlab/webhook/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const POST = async (request: NextRequest) => {
'gitlab.app_user.organization_id',
'homie.organization.id',
)
.leftJoin(
'slack.workspace',
'slack.workspace.organization_id',
'homie.organization.id',
)
.leftJoin(
'homie.subscription',
'homie.subscription.organization_id',
Expand All @@ -38,6 +43,7 @@ export const POST = async (request: NextRequest) => {
'has_unlimited_usage',
'trello_access_token',
'asana_access_token',
'slack_access_token',
])
.executeTakeFirst()

Expand Down Expand Up @@ -82,7 +88,11 @@ export const POST = async (request: NextRequest) => {
})

await dispatch('close_linked_tasks', {
pullRequestBody: mergeRequest.description,
pull_request: {
body: mergeRequest.description,
title: mergeRequest.title,
html_url: mergeRequest.url,
},
organization,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ it('should ask to select repo', async () => {
messages: [
{
text: 'some slack message',
ts: '12345.6789',
},
{
text: 'some reply',
ts: '12345.6789',
},
],
})
Expand Down
128 changes: 18 additions & 110 deletions src/lib/ai/summarize-code-change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ interface SummarizeCodeChangeParams {
title: string
diff: string | null
issue: string | null
conversation: string | null
body: string | null
length: 'short' | 'long'
logData?: Record<string, any>
}

export async function summarizeCodeChange(params: SummarizeCodeChangeParams) {
const { body, issue, diff, title, length, logData } = params
const { body, issue, diff, title, length, logData, conversation } = params

logger.debug('Summarize Code Change - Start', {
...logData,
Expand All @@ -25,24 +26,18 @@ export async function summarizeCodeChange(params: SummarizeCodeChangeParams) {
diff,
title,
length,
conversation,
})

const diffSummary = diff ? await summarizeDiff({ diff, logData }) : null

const template = getTemplate({
title,
diffSummary,
issue,
body,
length,
})

const rules = getRules({
title,
diffSummary,
issue,
body,
length,
conversation,
})

const chatPrompt = ChatPromptTemplate.fromTemplate(template)
Expand All @@ -56,11 +51,12 @@ export async function summarizeCodeChange(params: SummarizeCodeChangeParams) {
const chain = RunnableSequence.from([chatPrompt, model, parser])

const result = await chain.invoke({
diff: diffSummary ?? '',
issue: issue ?? '',
diff: diffSummary ?? 'NONE',
issue: issue ?? 'NONE',
title,
body: body ?? '',
body: body ?? 'NONE',
rules,
conversation: conversation ?? 'NONE',
})

logger.debug('Summarize Code Change - Result', {
Expand All @@ -73,6 +69,7 @@ export async function summarizeCodeChange(params: SummarizeCodeChangeParams) {
title,
length,
result,
conversation,
})

return result
Expand All @@ -82,31 +79,11 @@ interface GetInputParams {
title: string
diffSummary: string | null
issue: string | null
conversation: string | null
body: string | null
length: 'short' | 'long'
}

function getTemplate(params: GetInputParams) {
const { diffSummary, issue, body } = params
if (diffSummary && issue && !body) {
return prompts.diffAndIssue
}

if (!diffSummary && issue && !body) {
return prompts.issueOnly
}

if (!diffSummary && issue && body) {
return prompts.issueAndBody
}

if (!diffSummary && !issue && body) {
return prompts.bodyOnly
}

return prompts.allVariables
}

/**
* Additional rules to append to the prompt
*/
Expand Down Expand Up @@ -136,85 +113,14 @@ function getRules(params: GetInputParams): string {
return ''
}

const prompts = {
diffAndIssue: `Write a Pull Request summary. You MUST follow the following rules when generating the summary:
- The TITLE is the pull request title.
- The CHANGES will be a summary of all the changes.
- The ISSUE will contain the description of the issue that this pull request aims to solve.
- The summary should only be based on the CHANGES, and ISSUE. Do not generate the summary without a clear reference to CHANGES, or ISSUE.
- Do not infer any initiatives, or features other than what has already been mentioned in the CHANGES, or ISSUE.
- Do not include a conclusion.
- Use bullet points to present the summary
- The summary should be a single list with no headings, or sub-lists
{rules}
TITLE:
{title}
CHANGES:
{diff}
ISSUE:
{issue}`,
issueOnly: `Create a Pull Request summary from the information below. You MUST follow the following rules when generating the summary:
- The TITLE is the pull request title.
- The ISSUE will contain the description of an issue that this pull request aims to solve.
- The summary should only be based on the ISSUE only. Do not generate the summary without a clear reference to the ISSUE.
- Do not infer any initiatives, or features other than what has already been mentioned in the ISSUE.
- Do not include a conclusion.
- Use bullet points to present the summary
- The summary should be a single list with no headings, or sub-lists
{rules}
TITLE:
{title}
ISSUE:
{issue}
`,
issueAndBody: `Create a Pull Request summary from the information below. You MUST follow the following rules when generating the summary:
- The TITLE is the pull request title.
- The ISSUE will contain the description of a issue that this pull request aims to solve.
- The BODY will contain a description of what this pull request attempts to achieve.
- The summary should only be based on the ISSUE, and BODY. Do not generate the summary without a clear reference to the ISSUE, OR BODY.
- Do not infer any initiatives, or features other than what has already been mentioned in the ISSUE, or BODY.
- Do not include a conclusion.
- Use bullet points to present the summary
- The summary should be a single list with no headings, or sub-lists
{rules}
TITLE:
{title}
ISSUE:
{issue}
BODY:
{body}
`,
bodyOnly: `Create a Pull Request summary from the information below. You MUST follow the following rules when generating the summary:
- The TITLE is the pull request title.
- The BODY will contain a description of what this pull request attempts to achieve.
- The summary should only be based on the BODY only. Do not generate the summary without a clear reference to the BODY.
- Do not infer any initiatives, or features other than what has already been mentioned in the ISSUE, or BODY.
- Do not include a conclusion.
- Use bullet points to present the summary
- The summary should be a single list with no headings, or sub-lists
{rules}
TITLE:
{title}
BODY:
{body}
`,
allVariables: `Create a Pull Request summary from the information below. You MUST follow the following rules when generating the summary:
const template = `Create a Pull Request summary from the information below. You MUST follow the following rules when generating the summary:
- The TITLE is the pull request title.
- The CHANGES will be a summary of all the changes.
- The ISSUE will contain the description of a issue that this pull request aims to solve.
- The BODY will contain a description of what this pull request attempts to achieve.
- The summary should only be based on the CHANGES, ISSUE, and BODY. Do not generate the summary without a clear reference to the CHANGES, ISSUE, OR BODY.
- Do not infer any initiatives, or features other than what has already been mentioned in the CHANGES, ISSUE, or BODY.
- The CONVERSATION will background information to why this Pull Request is required.
- The summary should only be based on the CHANGES, ISSUE, BODY, and CONVERSATION. Do not generate the summary without a clear reference to the CHANGES, ISSUE, BODY, or CONVERSATION.
- Do not infer any initiatives, or features other than what has already been mentioned in the CHANGES, ISSUE, BODY, or CONVERSATION.
- Use bullet points to present the summary
- The summary should be a single list with no headings, or sub-lists
{rules}
Expand All @@ -230,5 +136,7 @@ ISSUE:
BODY:
{body}
`,
}
CONVERSATION:
{conversation}
`
13 changes: 13 additions & 0 deletions src/lib/github/save-merged-pull-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { logger } from '@/lib/log/logger'
import { parseISO } from 'date-fns'
import { getLinkedIssuesAndTasksInPullRequest } from '@/lib/github/get-linked-issues-and-tasks-in-pull-request'
import { embedCodeChange } from '@/lib/ai/embed-code-change'
import { getReferencedSlackMessages } from '@/lib/slack/get-referenced-slack-messages'

interface SaveMergedPullRequestParams {
pullRequest: {
Expand Down Expand Up @@ -41,6 +42,7 @@ interface SaveMergedPullRequestParams {
ext_gh_install_id: number
trello_access_token: string | null
asana_access_token: string | null
slack_access_token: string | null
}
}

Expand Down Expand Up @@ -119,6 +121,16 @@ export async function saveMergedPullRequest(
organization,
})

const conversation = organization.slack_access_token
? await getReferencedSlackMessages({
pullRequestBody: pullRequest.body,
organization: {
id: organization.id,
slack_access_token: organization.slack_access_token,
},
})
: null

const { summary, diff } = await summarizeGithubPullRequest({
pullRequest: {
id: pullRequest.id,
Expand All @@ -136,6 +148,7 @@ export async function saveMergedPullRequest(
github,
issue,
length: 'long',
conversation,
})

const wasMergedToDefaultBranch =
Expand Down
9 changes: 7 additions & 2 deletions src/lib/github/summarize-github-pull-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@ interface SummarizeGithubPullRequestParams {
github: GithubClient
issue: string | null
length: 'short' | 'long'
conversation: string | null
}

export async function summarizeGithubPullRequest(
params: SummarizeGithubPullRequestParams,
) {
const { pullRequest, github, repo, owner, issue, length: type } = params
const { pullRequest, github, repo, owner, issue, length, conversation } =
params

logger.debug('Summarize PR - Start', {
event: 'summarize_pr:start',
pull_request: getPullRequestLogData(pullRequest),
issue,
conversation,
})

const diff = await github.rest.pulls
Expand Down Expand Up @@ -61,14 +64,16 @@ export async function summarizeGithubPullRequest(
pull_request: getPullRequestLogData(pullRequest),
issue,
diff,
conversation,
})

const summary = await summarizeCodeChange({
title: pullRequest.title,
diff,
issue,
body: pullRequest.body,
length: type,
conversation,
length,
logData: {
pull_request: getPullRequestLogData(pullRequest),
issue,
Expand Down
13 changes: 13 additions & 0 deletions src/lib/gitlab/save-merged-merge-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { summarizeGitlabMergeRequest } from '@/lib/gitlab/summarize-gitlab-merge
import { getOrganizationLogData } from '@/lib/organization/get-organization-log-data'
import { logger } from '@/lib/log/logger'
import { parseISO } from 'date-fns'
import { getReferencedSlackMessages } from '@/lib/slack/get-referenced-slack-messages'

interface SaveMergedMergeRequestParams {
mergeRequest: {
Expand Down Expand Up @@ -35,6 +36,7 @@ interface SaveMergedMergeRequestParams {
gitlab_access_token: string
trello_access_token: string | null
asana_access_token: string | null
slack_access_token: string | null
}
defaultBranch: string
}
Expand Down Expand Up @@ -76,12 +78,23 @@ export async function saveMergedMergeRequest(

const gitlab = createGitlabClient(organization.gitlab_access_token)

const conversation = organization.slack_access_token
? await getReferencedSlackMessages({
pullRequestBody: mergeRequest.description,
organization: {
id: organization.id,
slack_access_token: organization.slack_access_token,
},
})
: null

const { summary, diff } = await summarizeGitlabMergeRequest({
mergeRequest,
length: 'long',
issue,
gitlab,
project,
conversation,
})

const wasMergedToDefaultBranch = mergeRequest.target_branch === defaultBranch
Expand Down
Loading

0 comments on commit 2834019

Please sign in to comment.