-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Feat: Issue creation and sync comments with Github * Feat: show respective action icon when the resources are created * Fix: lint errors * Fix: github thread comment and activity * Fix: ignore comments from other integrations * Fix: slack is broken * Fix: slack and github integrations * Fix: lint errors --------- Co-authored-by: Harshith Mullapudi <[email protected]>
- Loading branch information
1 parent
7fb63ce
commit 6dbf42f
Showing
117 changed files
with
5,549 additions
and
442 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/** Copyright (c) 2024, Tegon, all rights reserved. **/ | ||
|
||
module.exports = { | ||
extends: [ | ||
'plugin:@typescript-eslint/recommended', | ||
'prettier', | ||
'plugin:prettier/recommended', | ||
], | ||
plugins: ['@typescript-eslint', 'prettier', 'unused-imports', 'import'], | ||
parserOptions: { | ||
ecmaVersion: 2020, | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
jsx: true, | ||
}, | ||
}, | ||
rules: { | ||
curly: 'warn', | ||
eqeqeq: 'error', | ||
'prettier/prettier': 'warn', | ||
'unused-imports/no-unused-imports': 'warn', | ||
'no-else-return': 'warn', | ||
'no-lonely-if': 'warn', | ||
'no-inner-declarations': 'off', | ||
'no-unused-vars': 'off', | ||
'no-useless-computed-key': 'warn', | ||
'no-useless-return': 'warn', | ||
'no-var': 'warn', | ||
'object-shorthand': ['warn', 'always'], | ||
'prefer-arrow-callback': 'warn', | ||
'prefer-const': 'warn', | ||
'prefer-destructuring': ['warn', { AssignmentExpression: { array: true } }], | ||
'prefer-object-spread': 'warn', | ||
'prefer-template': 'warn', | ||
'spaced-comment': ['warn', 'always', { markers: ['/'] }], | ||
yoda: 'warn', | ||
'@typescript-eslint/array-type': ['warn', { default: 'array-simple' }], | ||
'@typescript-eslint/ban-ts-comment': [ | ||
'warn', | ||
{ | ||
'ts-expect-error': 'allow-with-description', | ||
}, | ||
], | ||
'@typescript-eslint/ban-types': 'warn', | ||
'@typescript-eslint/consistent-indexed-object-style': ['warn', 'record'], | ||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'], | ||
'@typescript-eslint/no-unused-vars': 'warn', | ||
}, | ||
parser: '@typescript-eslint/parser', | ||
ignorePatterns: ['src/@@generated/**/*.tsx', 'src/@@generated/**/*.ts'], | ||
overrides: [ | ||
{ | ||
files: ['scripts/**/*'], | ||
rules: { | ||
'@typescript-eslint/no-var-requires': 'off', | ||
}, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
.trigger | ||
trigger | ||
trigger.config.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"singleQuote": true, | ||
"trailingComma": "all" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
## Overview | ||
|
||
Effortlessly integrate Tegon with Slack to transform your project communication and management: | ||
|
||
1. Create Issues from Slack Messages: | ||
|
||
- Use the "..." menu on any Slack message to effortlessly create a Tegon issue. | ||
|
||
2. Automate Issue Creation with Emoji 👀: | ||
|
||
- Assign 👀 emoji to a Slack thread to automatically trigger Tegon AI to create a triage issue. | ||
- This feature empowers even non-Tegon users to easily report issues. | ||
|
||
3. Synchronized Conversation Threads: | ||
- When issues are reported in Slack, a synced comment thread is automatically created within the corresponding Tegon issue. | ||
- Tegon comments are automatically reflected in the Slack thread, keeping everyone in the loop and vice versa. | ||
- Both the Slack thread and the Tegon comments update in real-time, ensuring everyone stays on the same page regardless of their chosen platform. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"slug": "github", | ||
"name": "Github", | ||
"icon": "github", | ||
"description": "Create issues from Github messages, sync Issues and Comments", | ||
"triggers": [ | ||
{ | ||
"type": "on_create", | ||
"entities": [ "Issue", "IssueComment", "LinkedIssue" ] | ||
}, | ||
{ | ||
"type": "on_update", | ||
"entities": [ "Issue", "IssueComment" ] | ||
}, | ||
{ | ||
"type": "source_webhook", | ||
"entities": [ "github" ] | ||
} | ||
], | ||
"integrations": [ "github" ] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { | ||
ActionEventPayload, | ||
getLabels, | ||
getTeams, | ||
Label, | ||
Team, | ||
} from '@tegonhq/sdk'; | ||
import axios from 'axios'; | ||
import { getGithubHeaders } from 'utils'; | ||
|
||
export const getInputs = async (payload: ActionEventPayload) => { | ||
const { workspaceId, integrationAccounts } = payload; | ||
|
||
const integrationAccount = integrationAccounts.github; | ||
const integrationConfig = | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
integrationAccount.integrationConfiguration as Record<string, any>; | ||
// Fetch teams from the API | ||
const teams = await getTeams({ workspaceId }); | ||
|
||
// Create a map of teams with label and value properties | ||
const teamOptions = teams.map((team: Team) => ({ | ||
label: team.name, | ||
value: team.id, | ||
})); | ||
|
||
const labels = await getLabels({ workspaceId, teamId: null }); | ||
// Create a map of label with label and value properties | ||
const labelOptions = labels.map((label: Label) => ({ | ||
label: label.name, | ||
value: label.id, | ||
})); | ||
|
||
const response = ( | ||
await axios.get( | ||
`https://api.github.com/user/installations/${integrationAccount.accountId}/repositories`, | ||
getGithubHeaders(integrationConfig.token), | ||
) | ||
).data; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
let repo: any = { | ||
type: 'text', | ||
title: 'Repository Id', | ||
validation: { | ||
required: true, | ||
}, | ||
}; | ||
if (response) { | ||
const repositoryOptions = response.repositories.map( | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(repo: any) => ({ | ||
label: repo.full_name, | ||
value: repo.id, | ||
}), | ||
); | ||
repo = { | ||
type: 'select', | ||
title: 'Repositories', | ||
validation: { | ||
required: true, | ||
}, | ||
options: repositoryOptions, | ||
}; | ||
} | ||
|
||
return { | ||
type: 'object', | ||
properties: { | ||
repoTeamMappings: { | ||
type: 'array', | ||
title: 'Repo to Team Mappings', | ||
description: 'Map each repo to a team', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
repo, | ||
teamId: { | ||
type: 'select', | ||
title: 'Teams', | ||
validation: { | ||
required: true, | ||
}, | ||
options: teamOptions, | ||
}, | ||
}, | ||
}, | ||
}, | ||
githubLabel: { | ||
type: 'select', | ||
title: 'Select a label to sync with Github', | ||
validate: { required: true }, | ||
options: labelOptions, | ||
}, | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { ActionEventPayload, ModelNameEnum, logger } from '@tegonhq/sdk'; | ||
import { onLabelHandler } from './on-label-handler'; | ||
import { commentSync } from 'triggers/comment-sync'; | ||
|
||
export const onCreateHandler = async (actionPayload: ActionEventPayload) => { | ||
// Handle different event types | ||
switch (actionPayload.type) { | ||
case ModelNameEnum.Issue: | ||
return await onLabelHandler(actionPayload); | ||
|
||
case ModelNameEnum.IssueComment: | ||
return await commentSync(actionPayload); | ||
|
||
case ModelNameEnum.LinkedIssue: | ||
return undefined; | ||
|
||
default: | ||
logger.debug('Unhandled Github event type:', actionPayload.type); | ||
} | ||
|
||
return { status: 200 }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ActionEventPayload, getIssueById, logger } from '@tegonhq/sdk'; | ||
import { issueSync } from 'triggers/issue-sync'; | ||
|
||
export const onLabelHandler = async (actionPayload: ActionEventPayload) => { | ||
const { modelId: issueId, action } = actionPayload; | ||
const issue = await getIssueById({ issueId }); | ||
|
||
const githubLabel = action.data.inputs.githubLabel; | ||
|
||
if (githubLabel && issue.labelIds.includes(githubLabel)) { | ||
logger.log(`Github mapped label present in the issue`); | ||
return await issueSync(actionPayload); | ||
} | ||
|
||
logger.log(`Github mapped label is not present in the issue`); | ||
return { message: 'Github mapped label is not present in the issue' }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { | ||
ActionEventPayload, | ||
LinkedIssue, | ||
ModelNameEnum, | ||
logger, | ||
} from '@tegonhq/sdk'; | ||
import { onLabelHandler } from './on-label-handler'; | ||
import axios from 'axios'; | ||
import { issueSync } from 'triggers/issue-sync'; | ||
|
||
export const onUpdateHandler = async (actionPayload: ActionEventPayload) => { | ||
// Handle different event types | ||
switch (actionPayload.type) { | ||
case ModelNameEnum.Issue: | ||
// TODO(new): Modify this to service | ||
// const linkedIssue = await getLinkedIssuesByIssueId({issueId: actionPayload.modelId}) | ||
const linkedIssues = ( | ||
await axios.get( | ||
`/api/v1/linked_issues/issue?issueId=${actionPayload.modelId}`, | ||
) | ||
).data; | ||
if (linkedIssues.length > 0) { | ||
const githubLinkedIssues = linkedIssues.filter( | ||
(linkedIssue: LinkedIssue) => { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const sourceData = linkedIssue.sourceData as Record<string, any>; | ||
return sourceData.type === 'github'; | ||
}, | ||
); | ||
|
||
if (githubLinkedIssues.length > 0) { | ||
return await Promise.all( | ||
githubLinkedIssues.map(async (linkedIssue: LinkedIssue) => { | ||
actionPayload.linkedIssue = linkedIssue; | ||
return await issueSync(actionPayload); | ||
}), | ||
); | ||
} | ||
} | ||
return await onLabelHandler(actionPayload); | ||
|
||
case ModelNameEnum.IssueComment: | ||
return undefined; | ||
|
||
case ModelNameEnum.LinkedIssue: | ||
return undefined; | ||
|
||
default: | ||
logger.debug('Unhandled Github event type:', actionPayload.type); | ||
} | ||
|
||
return { status: 200 }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { ActionEventPayload, logger } from '@tegonhq/sdk'; | ||
import { commentEvent } from 'triggers/comment-event'; | ||
|
||
export const webhookHandler = async ( | ||
payload: ActionEventPayload, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
): Promise<any> => { | ||
const { eventBody, eventHeaders } = payload; | ||
|
||
const eventType = eventHeaders['x-github-event']; | ||
if ( | ||
['tegon-bot[bot]', 'tegon-bot-dev[bot]'].includes(eventBody.sender.login) | ||
) { | ||
logger.log('Ignoring BOT message from Github'); | ||
return undefined; | ||
} | ||
|
||
switch (eventType) { | ||
case 'issues': | ||
return undefined; | ||
|
||
case 'issue_comment': | ||
return await commentEvent(payload); | ||
|
||
case 'pull_request': | ||
return undefined; | ||
|
||
case 'installation': | ||
return undefined; | ||
|
||
case 'installation_repositories': | ||
return undefined; | ||
|
||
default: | ||
logger.log(`couldn't find eventType ${eventType}`); | ||
} | ||
|
||
return undefined; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { ActionEventPayload, ActionTypesEnum } from '@tegonhq/sdk'; | ||
import { getInputs } from 'handlers/get-inputs'; | ||
import { onCreateHandler } from 'handlers/on-create-handler'; | ||
import { onUpdateHandler } from 'handlers/on-update-handler'; | ||
import { webhookHandler } from 'handlers/webhook-handler'; | ||
|
||
export async function run(eventPayload: ActionEventPayload) { | ||
switch (eventPayload.event) { | ||
case ActionTypesEnum.GET_INPUTS: | ||
return getInputs(eventPayload); | ||
|
||
case ActionTypesEnum.ON_CREATE: | ||
return await onCreateHandler(eventPayload); | ||
|
||
case ActionTypesEnum.ON_UPDATE: | ||
return await onUpdateHandler(eventPayload); | ||
|
||
case ActionTypesEnum.SOURCE_WEBHOOK: | ||
return webhookHandler(eventPayload); | ||
|
||
default: | ||
return { | ||
message: `The event payload type "${eventPayload.event}" is not recognized`, | ||
}; | ||
} | ||
} |
Oops, something went wrong.