Skip to content

Commit

Permalink
Disable routing/triaging for external collaborators (#546)
Browse files Browse the repository at this point in the history
* disable routing/triaging for external collaborators
  • Loading branch information
hubertdeng123 authored Jul 27, 2023
1 parent 1dc70ea commit bd3931c
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/brain/issueLabelHandler/followups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function isWaitingForSupport(payload) {
);
}

function isContractor(payload) {
function isCommentFromCollaborator(payload) {
// Contractors are outside collaborators on GitHub
return payload.comment.author_association === 'COLLABORATOR';
}
Expand All @@ -57,8 +57,8 @@ export async function updateCommunityFollowups({
const reasonsToDoNothing = [
isNotInARepoWeCareAboutForFollowups,
isNotFromAnExternalOrGTMUser,
isCommentFromCollaborator,
isWaitingForSupport,
isContractor,
isPullRequest,
isFromABot,
];
Expand Down
62 changes: 50 additions & 12 deletions src/brain/issueLabelHandler/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,7 @@ describe('issueLabelHandler', function () {
});
}

function makePayload(
repo?: string,
label?: string,
sender?: string,
state?: string
) {
function makePayload({ repo, label, sender, state, author_association }) {
repo = repo || 'test-ttt-simple';
state = state || 'open';

Expand All @@ -116,7 +111,7 @@ describe('issueLabelHandler', function () {
name: repo,
owner: { login: GETSENTRY_ORG.slug },
},
issue: { state, labels }, // mix in labels stored in mock
issue: { state, labels, author_association }, // mix in labels stored in mock
};

if (label) {
Expand All @@ -125,27 +120,49 @@ describe('issueLabelHandler', function () {
return payload;
}

async function createIssue(repo?: string, username?: string) {
async function createIssue(
repo?: string,
username?: string,
author_association?: string
) {
await createGitHubEvent(
fastify,
'issues.opened',
makePayload(repo, undefined, username)
makePayload({
repo,
label: undefined,
sender: username,
state: undefined,
author_association,
})
);
}

async function createPR(repo?: string, username?: string) {
await createGitHubEvent(
fastify,
'pull_request.opened',
makePayload(repo, undefined, username)
makePayload({
repo,
label: undefined,
sender: username,
state: undefined,
author_association: undefined,
})
);
}

async function addLabel(label: string, repo?: string, state?: string) {
await createGitHubEvent(
fastify,
'issues.labeled',
makePayload(repo, label, undefined, state)
makePayload({
repo,
label,
sender: undefined,
state,
author_association: undefined,
})
);
org.api.issues.addLabels({ labels: [label] });
}
Expand All @@ -162,7 +179,13 @@ describe('issueLabelHandler', function () {
throw `Unknown user: '${username}'`;
}
const payload = {
...makePayload(repo, undefined, username),
...makePayload({
repo,
label: undefined,
sender: username,
state: undefined,
author_association: undefined,
}),
comment: { author_association: membership },
};
if (isPR) {
Expand Down Expand Up @@ -249,6 +272,13 @@ describe('issueLabelHandler', function () {
expect(addIssueToGlobalIssuesProjectSpy).toHaveBeenCalled();
});

it('skips adding `Waiting for: Product Owner` for external collaborators', async function () {
await createIssue(undefined, 'External User', 'COLLABORATOR');
expectNotWaitingforProductOwner();
expectNoAdding();
expect(addIssueToGlobalIssuesProjectSpy).not.toHaveBeenCalled();
});

it('skips adding `Waiting for: Product Owner` in untracked repos', async function () {
await createIssue('other-repo');
expectNotWaitingforProductOwner();
Expand Down Expand Up @@ -372,6 +402,14 @@ describe('issueLabelHandler', function () {
expect(addIssueToGlobalIssuesProjectSpy).not.toHaveBeenCalled();
});

it('skips adding `Waiting for: Support` for external collaborators', async function () {
await createIssue('sentry-docs', 'External User', 'COLLABORATOR');
expectNotWaitingForSupport();
expect(org.api.issues._labels).not.toContain(WAITING_FOR_SUPPORT_LABEL);
expect(org.api.issues._comments).toEqual([]);
expect(addIssueToGlobalIssuesProjectSpy).not.toHaveBeenCalled();
});

it('skips adding `Waiting for: Support` in untracked repos', async function () {
await createIssue('Pizza Sandwich');
expectNotWaitingForSupport();
Expand Down
2 changes: 2 additions & 0 deletions src/brain/issueLabelHandler/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
WAITING_FOR_PRODUCT_OWNER_LABEL,
WAITING_FOR_SUPPORT_LABEL,
} from '@/config';
import { isFromOutsideCollaborator } from '@/utils/isFromOutsideCollaborator';
import { isNotFromAnExternalOrGTMUser } from '@utils/isNotFromAnExternalOrGTMUser';
import { shouldSkip } from '@utils/shouldSkip';
import { slugizeProductArea } from '@utils/slugizeProductArea';
Expand Down Expand Up @@ -61,6 +62,7 @@ export async function markWaitingForSupport({
isNotInARepoWeCareAboutForRouting,
isAlreadyWaitingForSupport,
isNotFromAnExternalOrGTMUser,
isFromOutsideCollaborator,
];
if (await shouldSkip(payload, org, reasonsToSkip)) {
return;
Expand Down
7 changes: 6 additions & 1 deletion src/brain/issueLabelHandler/triage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { EmitterWebhookEvent } from '@octokit/webhooks';
import * as Sentry from '@sentry/node';

import { GH_ORGS, WAITING_FOR_PRODUCT_OWNER_LABEL } from '@/config';
import {
GH_ORGS,
WAITING_FOR_PRODUCT_OWNER_LABEL,
} from '@/config';
import { isFromOutsideCollaborator } from '@/utils/isFromOutsideCollaborator';
import { isFromABot } from '@utils/isFromABot';
import { isNotFromAnExternalOrGTMUser } from '@utils/isNotFromAnExternalOrGTMUser';
import { shouldSkip } from '@utils/shouldSkip';
Expand Down Expand Up @@ -42,6 +46,7 @@ export async function markWaitingForProductOwner({
isNotInARepoWeCareAboutForTriage,
isAlreadyUntriaged,
isNotFromAnExternalOrGTMUser,
isFromOutsideCollaborator,
];
if (await shouldSkip(payload, org, reasonsToSkipTriage)) {
return;
Expand Down
9 changes: 9 additions & 0 deletions src/utils/isFromOutsideCollaborator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getOssUserType } from '@utils/getOssUserType';

export async function isFromOutsideCollaborator(payload) {
const type = await getOssUserType(payload);
// Need to check user type to make sure issues created by GTM are routed/triaged
return (
type === 'external' && payload.issue.author_association === 'COLLABORATOR'
);
}

0 comments on commit bd3931c

Please sign in to comment.