mirror of
https://github.com/feeddeck/feeddeck.git
synced 2026-05-04 10:08:20 -05:00
This commit updates all used Deno modules to their latest version. Since some of the used modules / functions were deprecated we had to adjust our encrypt / descrypt functions and the generation of the source and item ids, where we have to use a new md5 function.
805 lines
25 KiB
TypeScript
805 lines
25 KiB
TypeScript
import { SupabaseClient } from '@supabase/supabase-js';
|
|
import { Redis } from 'redis';
|
|
|
|
import { ISource } from '../models/source.ts';
|
|
import { IItem } from '../models/item.ts';
|
|
import { IProfile } from '../models/profile.ts';
|
|
import { utils } from '../utils/index.ts';
|
|
import { feedutils } from './utils/index.ts';
|
|
|
|
export const getGithubFeed = async (
|
|
supabaseClient: SupabaseClient,
|
|
_redisClient: Redis | undefined,
|
|
profile: IProfile,
|
|
source: ISource,
|
|
): Promise<{ source: ISource; items: IItem[] }> => {
|
|
if (!source.options?.github || !source.options?.github.type) {
|
|
throw new Error('Invalid source options');
|
|
}
|
|
|
|
if (!profile.accountGithub?.token) {
|
|
throw new Error('GitHub token is missing');
|
|
}
|
|
const token = await utils.decrypt(profile.accountGithub.token);
|
|
|
|
if (
|
|
source.options.github.type === 'notifications' ||
|
|
source.options.github.type === 'repositorynotifications'
|
|
) {
|
|
/**
|
|
* With `notifications` and `repositorynotifications` type users can add
|
|
* there GitHub notifications or repository notifications as source to
|
|
* FeedDeck. The notifications are retrieved from the GitHub API via the
|
|
* list notifications endpoint.
|
|
*
|
|
* - https://docs.github.com/en/rest/activity/notifications?apiVersion=2022-11-28#list-notifications-for-the-authenticated-user
|
|
* - https://docs.github.com/en/rest/activity/notifications?apiVersion=2022-11-28#list-repository-notifications-for-the-authenticated-user
|
|
* - https://docs.github.com/en/rest/activity/notifications?apiVersion=2022-11-28#about-notification-reasons
|
|
*/
|
|
const notifications = [];
|
|
|
|
if (source.options.github.type === 'notifications') {
|
|
const tmpNotifications = await request('/notifications', {
|
|
token: token,
|
|
params: {
|
|
all: 'true',
|
|
participating: source.options.github.participating ? 'true' : 'false',
|
|
page: '1',
|
|
per_page: '50',
|
|
},
|
|
});
|
|
|
|
const user = await request('/user', {
|
|
token: token,
|
|
});
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}-${source.options.github.participating}`;
|
|
source.title = user.login;
|
|
source.icon = user.avatar_url;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
notifications.push(...tmpNotifications);
|
|
} else if (
|
|
source.options.github.type === 'repositorynotifications' &&
|
|
source.options.github.repository
|
|
) {
|
|
const [owner, repo] = source.options.github.repository.split('/');
|
|
const tmpNotifications = await request(
|
|
`/repos/${owner}/${repo}/notifications`,
|
|
{
|
|
token: token,
|
|
params: {
|
|
all: 'true',
|
|
participating: source.options.github.participating
|
|
? 'true'
|
|
: 'false',
|
|
page: '1',
|
|
per_page: '50',
|
|
},
|
|
},
|
|
);
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}--${source.options.github.participating}-${source.options.github.repository}`;
|
|
source.title = `${owner}/${repo}`;
|
|
if (
|
|
tmpNotifications.length > 0 &&
|
|
tmpNotifications[0].repository?.owner?.avatar_url
|
|
) {
|
|
source.icon = tmpNotifications[0].repository.owner.avatar_url;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
} else {
|
|
source.icon = `https://github.com/${owner}.png`;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
}
|
|
notifications.push(...tmpNotifications);
|
|
} else {
|
|
throw new Error('Invalid source options');
|
|
}
|
|
|
|
source.type = 'github';
|
|
source.link = 'https://github.com/notifications';
|
|
|
|
const items: IItem[] = [];
|
|
|
|
for (const [_, notification] of notifications.entries()) {
|
|
items.push({
|
|
id: `${source.id}-${notification.id}`,
|
|
userId: source.userId,
|
|
columnId: source.columnId,
|
|
sourceId: source.id,
|
|
title: notification.subject?.title ?? 'Notification',
|
|
link: getLinkFromApiUrl(notification.subject?.url),
|
|
media: notification.repository.owner.avatar_url,
|
|
description: formatDescription(notification),
|
|
author: notification.repository?.full_name,
|
|
publishedAt: Math.floor(
|
|
new Date(notification.updated_at).getTime() / 1000,
|
|
),
|
|
});
|
|
}
|
|
|
|
return { source, items };
|
|
} else if (
|
|
source.options.github.type === 'useractivities' ||
|
|
source.options.github.type === 'repositoryactivities' ||
|
|
source.options.github.type === 'organizationactivitiespublic' ||
|
|
source.options.github.type === 'organizationactivitiesprivate'
|
|
) {
|
|
/**
|
|
* `useractivities`, `repositoryactivities`, `organizationactivitiespublic`
|
|
* and `organizationactivitiesprivate` lets a user add the user, repository
|
|
* or organization notifications as source. We are using the corresponding
|
|
* events endpoint to get the notifications and add the id, title, icon and
|
|
* link to the source. Then we are going though all the events and adding
|
|
* the actor of an event as author. The title, description and link is
|
|
* different for each notification type and generated via the `formatEvent`
|
|
* function.
|
|
*
|
|
* - https://docs.github.com/en/developers/webhooks-and-events/events/github-event-types
|
|
* - GitHubTypeUserActivities: https://docs.github.com/en/rest/activity/events?apiVersion=2022-11-28#list-events-received-by-the-authenticated-user
|
|
* - GitHubTypeRepositoryActivities: https://docs.github.com/en/rest/activity/events?apiVersion=2022-11-28#list-organization-events-for-the-authenticated-user
|
|
* - GitHubTypeOrganizationActivitiesPublic: https://docs.github.com/en/rest/activity/events?apiVersion=2022-11-28#list-public-organization-events
|
|
* - GitHubTypeOrganizationActivitiesPrivate: https://docs.github.com/en/rest/activity/events?apiVersion=2022-11-28#list-organization-events-for-the-authenticated-user
|
|
*/
|
|
const events = [];
|
|
|
|
if (
|
|
source.options.github.type === 'useractivities' &&
|
|
source.options.github.user
|
|
) {
|
|
const tmpEvents = await request(
|
|
`/users/${source.options.github.user}/received_events/public`,
|
|
{
|
|
token: token,
|
|
params: {
|
|
page: '1',
|
|
per_page: '100',
|
|
},
|
|
},
|
|
);
|
|
|
|
const user = await request(`/users/${source.options.github.user}`, {
|
|
token: token,
|
|
});
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}-${source.options.github.user}`;
|
|
source.title = source.options.github.user;
|
|
source.icon = user.avatar_url;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
source.link = `https://github.com/${source.options.github.user}`;
|
|
|
|
events.push(...tmpEvents);
|
|
} else if (
|
|
source.options.github.type === 'repositoryactivities' &&
|
|
source.options.github.repository
|
|
) {
|
|
const [owner, repo] = source.options.github.repository.split('/');
|
|
const tmpEvents = await request(
|
|
`/repos/${owner}/${repo}/events`,
|
|
{
|
|
token: token,
|
|
params: {
|
|
page: '1',
|
|
per_page: '100',
|
|
},
|
|
},
|
|
);
|
|
|
|
const user = await request(`/users/${owner}`, {
|
|
token: token,
|
|
});
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}-${owner}-${repo}`;
|
|
source.title = `${owner}/${repo}`;
|
|
source.icon = user.avatar_url;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
source.link = `https://github.com/${owner}/${repo}`;
|
|
|
|
events.push(...tmpEvents);
|
|
} else if (
|
|
source.options.github.type === 'organizationactivitiespublic' &&
|
|
source.options.github.organization
|
|
) {
|
|
const tmpEvents = await request(
|
|
`/orgs/${source.options.github.organization}/events`,
|
|
{
|
|
token: token,
|
|
params: {
|
|
page: '1',
|
|
per_page: '100',
|
|
},
|
|
},
|
|
);
|
|
|
|
const user = await request(
|
|
`/users/${source.options.github.organization}`,
|
|
{
|
|
token: token,
|
|
},
|
|
);
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}-${source.options.github.organization}`;
|
|
source.title = source.options.github.organization;
|
|
source.icon = user.avatar_url;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
source.link = `https://github.com/${source.options.github.organization}`;
|
|
|
|
events.push(...tmpEvents);
|
|
} else if (
|
|
source.options.github.type === 'organizationactivitiesprivate' &&
|
|
source.options.github.organization
|
|
) {
|
|
const user = await request('/user', {
|
|
token: token,
|
|
});
|
|
|
|
const tmpEvents = await request(
|
|
`/users/${user.login}/events/orgs/${source.options.github.organization}`,
|
|
{
|
|
token: token,
|
|
params: {
|
|
page: '1',
|
|
per_page: '100',
|
|
},
|
|
},
|
|
);
|
|
|
|
const org = await request(
|
|
`/users/${source.options.github.organization}`,
|
|
{
|
|
token: token,
|
|
},
|
|
);
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}-${source.options.github.organization}`;
|
|
source.title = source.options.github.organization;
|
|
source.icon = org.avatar_url;
|
|
source.icon = await feedutils.uploadSourceIcon(supabaseClient, source);
|
|
source.link = `https://github.com/${source.options.github.organization}`;
|
|
|
|
events.push(...tmpEvents);
|
|
} else {
|
|
throw new Error('Invalid source options');
|
|
}
|
|
|
|
source.type = 'github';
|
|
|
|
const items: IItem[] = [];
|
|
|
|
for (const [_, event] of events.entries()) {
|
|
const eventDetails = formatEvent(event);
|
|
if (eventDetails) {
|
|
items.push({
|
|
id: `${source.id}-${event.id}`,
|
|
userId: source.userId,
|
|
columnId: source.columnId,
|
|
sourceId: source.id,
|
|
title: eventDetails.title ?? '',
|
|
link: eventDetails.link ?? '',
|
|
media: event.actor?.avatar_url
|
|
? event.actor?.avatar_url
|
|
: event.actor?.login
|
|
? `https://github.com/${event.actor.login}.png`
|
|
: undefined,
|
|
description: eventDetails.description,
|
|
author: event.actor?.login ? event.actor.login : undefined,
|
|
publishedAt: Math.floor(
|
|
new Date(event.created_at).getTime() / 1000,
|
|
),
|
|
});
|
|
}
|
|
}
|
|
|
|
return { source, items };
|
|
} else if (
|
|
source.options.github.type === 'searchissuesandpullrequests' &&
|
|
source.options.github.query
|
|
) {
|
|
/**
|
|
* The `searchissuesandpullrequests` let a user add a seach query as source.
|
|
* With this type it is possible to follow all issues and pull requests of
|
|
* an user, repository or organization. Since we allow a custom query we do
|
|
* not add a icon and link to the source. The id of the source is generated
|
|
* based on a hash of the query. Then we are going through all the returned
|
|
* issues and generating an item for each issue, where we are using the user
|
|
* as author (we were also thinking about using the repository, but decided
|
|
* against it).
|
|
*
|
|
* - https://docs.github.com/en/rest/search?apiVersion=2022-11-28#search-issues-and-pull-requests
|
|
*/
|
|
const issues = await request(
|
|
`/search/issues`,
|
|
{
|
|
token: token,
|
|
params: {
|
|
q: source.options.github.query,
|
|
sort: 'created',
|
|
direction: 'desc',
|
|
page: '1',
|
|
per_page: '100',
|
|
},
|
|
},
|
|
);
|
|
|
|
source.id =
|
|
`github-${source.userId}-${source.columnId}-${source.options.github.type}-${await utils
|
|
.md5(source.options.github.query)}`;
|
|
source.type = 'github';
|
|
source.title = source.options.github.queryName || 'Search';
|
|
source.icon = undefined;
|
|
source.link = undefined;
|
|
|
|
const items: IItem[] = [];
|
|
|
|
for (const [_, issue] of issues.items.entries()) {
|
|
items.push({
|
|
id: `${source.id}-${issue.node_id}`,
|
|
userId: source.userId,
|
|
columnId: source.columnId,
|
|
sourceId: source.id,
|
|
title: issue.title,
|
|
link: issue.html_url,
|
|
media: issue?.user?.avatar_url
|
|
? issue.user.avatar_url
|
|
: issue?.user?.login
|
|
? `https://github.com/${issue.user.login}.png`
|
|
: undefined,
|
|
description: `${
|
|
issue.repository_url.replace(
|
|
'https://api.github.com/repos/',
|
|
'',
|
|
)
|
|
} #${issue.number}`,
|
|
author: issue.user.login,
|
|
publishedAt: Math.floor(
|
|
new Date(issue.created_at).getTime() / 1000,
|
|
),
|
|
});
|
|
}
|
|
|
|
return { source, items };
|
|
}
|
|
|
|
throw new Error('Invalid source options');
|
|
};
|
|
|
|
/**
|
|
* `request` is a helper function to make a request to the GitHub API.
|
|
*/
|
|
const request = async (
|
|
url: string,
|
|
options: { token: string; params?: Record<string, string> },
|
|
) => {
|
|
const res = await utils.fetchWithTimeout(
|
|
`https://api.github.com${url}${
|
|
options.params ? `?${new URLSearchParams(options.params).toString()}` : ''
|
|
}`,
|
|
{
|
|
method: 'GET',
|
|
headers: {
|
|
Accept: 'application/vnd.github+json',
|
|
Authorization: `Bearer ${options.token}`,
|
|
'X-GitHub-Api-Version': '2022-11-28',
|
|
},
|
|
},
|
|
5000,
|
|
);
|
|
|
|
if (!res.ok) {
|
|
const error = await res.json();
|
|
throw new Error(error?.message ?? 'Unknown error');
|
|
}
|
|
|
|
return await res.json();
|
|
};
|
|
|
|
/**
|
|
* `getLinkFromApiUrl` returns a link which can be clicked by a user based on
|
|
* the given GitHub API url. If there is no url given we return the default
|
|
* GitHub notifications link.
|
|
*/
|
|
const getLinkFromApiUrl = (url?: string): string => {
|
|
if (!url) {
|
|
return 'https://github.com/notifications';
|
|
}
|
|
|
|
if (/^https:\/\/api.github.com\/repos\/.*\/.*\/pulls\/\d+$/.test(url)) {
|
|
const n = url.lastIndexOf('pulls');
|
|
url = url.slice(0, n) + url.slice(n).replace('pulls', 'pull');
|
|
}
|
|
|
|
return `https://github.com/${
|
|
url.replace('https://api.github.com/repos/', '')
|
|
}`;
|
|
};
|
|
|
|
/**
|
|
* `formatDescription` formats the description for a notification based on the
|
|
* notification reason.
|
|
* See: https://docs.github.com/en/rest/activity/notifications?apiVersion=2022-11-28#about-notification-reasons
|
|
*/
|
|
// deno-lint-ignore no-explicit-any
|
|
const formatDescription = (notification: any): string | undefined => {
|
|
switch (notification.reason) {
|
|
case 'assign':
|
|
return 'You were assigned to the issue.';
|
|
case 'author':
|
|
return 'You created the thread.';
|
|
case 'comment':
|
|
return 'You commented on the thread.';
|
|
case 'ci_activity':
|
|
return 'A GitHub Actions workflow run that you triggered was completed.';
|
|
case 'invitation':
|
|
return 'You accepted an invitation to contribute to the repository.';
|
|
case 'manual':
|
|
return 'You subscribed to the thread (via an issue or pull request).';
|
|
case 'mention':
|
|
return 'You were specifically @mentioned in the content.';
|
|
case 'review_requested':
|
|
return 'You, or a team you\'re a member of, were requested to review a pull request.';
|
|
case 'security_alert':
|
|
return 'GitHub discovered a security vulnerability in your repository.';
|
|
case 'state_change':
|
|
return 'You changed the thread state (for example, closing an issue or merging a pull request).';
|
|
case 'subscribed':
|
|
return 'You\'re watching the repository.';
|
|
case 'team_mention':
|
|
return 'You were on a team that was mentioned.';
|
|
default:
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* `formatEvent` formats the given event by returning a proper title, link and
|
|
* description for a item as we save it in our database. If the event type is
|
|
* not supported or a required field is missing we return an error.
|
|
*/
|
|
const formatEvent = (
|
|
// deno-lint-ignore no-explicit-any
|
|
event: any,
|
|
): {
|
|
title: string | undefined;
|
|
link: string | undefined;
|
|
description: string | undefined;
|
|
} | undefined => {
|
|
switch (event.type) {
|
|
case 'CommitCommentEvent':
|
|
if (event.payload?.comment?.html_url) {
|
|
return {
|
|
title: '',
|
|
link: event.payload.comment.html_url,
|
|
description: 'Added a comment to a commit',
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'CreateEvent':
|
|
if (event.payload?.ref_type) {
|
|
let description = '';
|
|
switch (event.payload?.ref_type) {
|
|
case 'repository':
|
|
description = 'Created a new repository';
|
|
break;
|
|
case 'branch':
|
|
description = 'Created a new branch';
|
|
break;
|
|
case 'tag':
|
|
description = 'Created a new tag';
|
|
break;
|
|
default:
|
|
description = 'Created something';
|
|
break;
|
|
}
|
|
return {
|
|
title: '',
|
|
link: event.repo.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'DeleteEvent':
|
|
if (event.payload?.ref_type) {
|
|
let description = '';
|
|
switch (event.payload?.ref_type) {
|
|
case 'repository':
|
|
description = 'Deleted a repository';
|
|
break;
|
|
case 'branch':
|
|
description = 'Deleted a branch';
|
|
break;
|
|
case 'tag':
|
|
description = 'Deleted a tag';
|
|
break;
|
|
default:
|
|
description = 'Deleted something';
|
|
break;
|
|
}
|
|
return {
|
|
title: '',
|
|
link: event.repo.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'ForkEvent':
|
|
if (event.payload?.forkee) {
|
|
return {
|
|
title: event.payload.forkee.name,
|
|
link: event.payload.forkee.html_url,
|
|
description: 'Forked a repository',
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'GollumEvent':
|
|
if (event.payload?.pages && event.payload?.pages.length > 0) {
|
|
let description = '';
|
|
switch (event.payload?.pages[0].action) {
|
|
case 'created':
|
|
description = 'Created a new wiki page';
|
|
break;
|
|
default:
|
|
description = 'Updated a wiki page';
|
|
break;
|
|
}
|
|
return {
|
|
title: event.payload.pages[0].title,
|
|
link: event.payload.pages[0].html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'IssueCommentEvent':
|
|
if (event.payload?.issue && event.payload?.comment) {
|
|
return {
|
|
title: event.payload.issue.title,
|
|
link: event.payload.comment.html_url,
|
|
description: 'Added a comment',
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'IssuesEvent':
|
|
if (event.payload?.action && event.payload?.issue) {
|
|
let description = '';
|
|
switch (event.payload?.action) {
|
|
case 'assigned':
|
|
description = 'Assigned';
|
|
break;
|
|
case 'unassigned':
|
|
description = 'Unassigned';
|
|
break;
|
|
case 'review_requested':
|
|
description = 'Requested a review';
|
|
break;
|
|
case 'review_request_removed':
|
|
description = 'Removed a requested review';
|
|
break;
|
|
case 'labeled':
|
|
description = 'Added a label';
|
|
break;
|
|
case 'unlabeled':
|
|
description = 'Removed a label';
|
|
break;
|
|
case 'opened':
|
|
description = 'Opened an issue';
|
|
if (event.payload.issue.pull_request) {
|
|
description = 'Opened a pull request';
|
|
}
|
|
break;
|
|
case 'closed':
|
|
description = 'Closed an issue';
|
|
if (event.payload.issue.pull_request) {
|
|
description = 'Closed a pull request';
|
|
}
|
|
break;
|
|
case 'reopened':
|
|
description = 'Reopened an issue';
|
|
if (event.payload.issue.pull_request) {
|
|
description = 'Reopened a pull request';
|
|
}
|
|
break;
|
|
case 'synchronize':
|
|
description = 'Synchronized an issue';
|
|
if (event.payload.issue.pull_request) {
|
|
description = 'Synchronized a pull request';
|
|
}
|
|
break;
|
|
case 'edited':
|
|
description = 'Edited an issue';
|
|
if (event.payload.issue.pull_request) {
|
|
description = 'Edited a pull request';
|
|
}
|
|
break;
|
|
}
|
|
return {
|
|
title: event.payload.issue.title,
|
|
link: event.payload.issue.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'MemberEvent':
|
|
if (event.payload?.action && event.payload?.member) {
|
|
let description = '';
|
|
switch (event.payload?.action) {
|
|
case 'added':
|
|
description = 'Was added as member';
|
|
break;
|
|
}
|
|
return {
|
|
title: event.payload.member.login,
|
|
link: event.payload.member.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'PullRequestEvent':
|
|
if (event.payload?.action && event.payload?.pull_request) {
|
|
let description = '';
|
|
switch (event.payload?.action) {
|
|
case 'assigned':
|
|
description = 'Assigned';
|
|
break;
|
|
case 'unassigned':
|
|
description = 'Unassigned';
|
|
break;
|
|
case 'review_requested':
|
|
description = 'Requested a review';
|
|
break;
|
|
case 'review_request_removed':
|
|
description = 'Removed a requested review';
|
|
break;
|
|
case 'labeled':
|
|
description = 'Added a label';
|
|
break;
|
|
case 'unlabeled':
|
|
description = 'Removed a label';
|
|
break;
|
|
case 'opened':
|
|
description = 'Opened';
|
|
break;
|
|
case 'closed':
|
|
if (
|
|
event.payload?.pull_request.merged &&
|
|
event.payload?.pull_request.merged == true
|
|
) {
|
|
description = 'Merged';
|
|
break;
|
|
} else {
|
|
description = 'Closed';
|
|
break;
|
|
}
|
|
case 'reopened':
|
|
description = 'Reopened';
|
|
break;
|
|
case 'synchronize':
|
|
description = 'Synchronized';
|
|
break;
|
|
case 'edited':
|
|
description = 'Edited';
|
|
break;
|
|
}
|
|
return {
|
|
title: event.payload.pull_request.title,
|
|
link: event.payload.pull_request.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'PullRequestReviewEvent':
|
|
if (
|
|
event.payload?.pull_request &&
|
|
event.payload?.review
|
|
) {
|
|
return {
|
|
title: event.payload.pull_request.title,
|
|
link: event.payload.review.html_url,
|
|
description: 'Added a review',
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'PullRequestReviewCommentEvent':
|
|
if (
|
|
event.payload?.action &&
|
|
event.payload?.pull_request &&
|
|
event.payload?.comment
|
|
) {
|
|
let description = '';
|
|
switch (event.payload?.action) {
|
|
case 'created':
|
|
description = 'Added a review comment';
|
|
break;
|
|
case 'edited':
|
|
description = 'Updated a review comment';
|
|
break;
|
|
case 'deleted':
|
|
description = 'Deleted a review comment';
|
|
break;
|
|
}
|
|
return {
|
|
title: event.payload.pull_request.title,
|
|
link: event.payload.comment.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'PushEvent':
|
|
if (event.payload?.repository) {
|
|
return {
|
|
title: '',
|
|
link: event.payload.repository.html_url,
|
|
description: event.payload.commits
|
|
? event.payload.commits.length === 1
|
|
? `Pushed ${event.payload.commits.length} commit`
|
|
: `Pushed ${event.payload.commits.length} commits`
|
|
: '',
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'ReleaseEvent':
|
|
if (event.payload?.action && event.payload?.release) {
|
|
let description = '';
|
|
switch (event.payload?.action) {
|
|
case 'created':
|
|
description = 'Release was created';
|
|
break;
|
|
case 'deleted':
|
|
description = 'Release was created';
|
|
break;
|
|
case 'edited':
|
|
description = 'Release was updated';
|
|
break;
|
|
case 'prereleased':
|
|
description = 'Prerelease was created';
|
|
break;
|
|
case 'published':
|
|
description = 'Release was published';
|
|
break;
|
|
case 'released':
|
|
description = 'Release was released';
|
|
break;
|
|
case 'unpublished':
|
|
description = 'Release was unpublished';
|
|
break;
|
|
}
|
|
return {
|
|
title: event.payload.release.name,
|
|
link: event.payload.release.html_url,
|
|
description: description,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
case 'WatchEvent':
|
|
if (event.actor) {
|
|
return {
|
|
title: '',
|
|
link: `https://github.com/${event.actor.login}`,
|
|
description: `${event.actor.login} starred ${
|
|
event.payload?.repository?.name || 'the repository'
|
|
}`,
|
|
};
|
|
}
|
|
return undefined;
|
|
|
|
default:
|
|
return undefined;
|
|
}
|
|
};
|