Skip to content

Commit

Permalink
feat: [SETI-1289] skip jira check when associated with merged PR (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
therussiankid92 authored May 19, 2021
1 parent 805bdfb commit 0e57db6
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[allowlist]
files = ["README.md"]
regexes = ['''ullRequestsAssociatedWithCommit''']
32 changes: 26 additions & 6 deletions dist/index.js

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

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

73 changes: 53 additions & 20 deletions src/checks/jiraLinked.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { mocked } from 'ts-jest/utils'

import { github, PullsGetResponse } from '../infrastructure/github'
import {
github,
PullRequestsAssociatedWithCommitResponse,
PullsGetResponse,
} from '../infrastructure/github'
import { BOT_USERS } from '../triggeredByBot'

import jiraLinked, { hasJiraIssueKey } from './jiraLinked'
Expand All @@ -10,16 +14,14 @@ const mockGithub = mocked(github, true)
jest.mock('../infrastructure/github')

describe('Jira Linked check', () => {
describe('pul_request event', () => {
describe('pull_request event', () => {
const pullRequestResponse = {
data: {
title: '',
head: {
ref: '',
},
user: {
login: '',
},
title: '',
head: {
ref: '',
},
user: {
login: '',
},
}

Expand All @@ -35,39 +37,44 @@ describe('Jira Linked check', () => {
})

it('returns true for PR with Jira Issue key in title', async () => {
pullRequestResponse.data.title = 'JIRA-123: This title has a key'
pullRequestResponse.data.head.ref = 'no-issue-name-here'
pullRequestResponse.title = 'JIRA-123: This title has a key'
pullRequestResponse.head.ref = 'no-issue-name-here'

await expect(jiraLinked.run()).resolves.toBeTruthy()
})

it('returns true for PR with Jira Issue key in branch name', async () => {
pullRequestResponse.data.title = 'No Jira issue here'
pullRequestResponse.data.head.ref = 'JIRA-123-there-is-an-issue-here'
pullRequestResponse.title = 'No Jira issue here'
pullRequestResponse.head.ref = 'JIRA-123-there-is-an-issue-here'

await expect(jiraLinked.run()).resolves.toBeTruthy()
})

it.each(BOT_USERS)('returns true for bot users [%s]', async (botUser) => {
pullRequestResponse.data.title = 'No Jira isue here'
pullRequestResponse.data.head.ref = 'neither-here'
pullRequestResponse.data.user.login = botUser
pullRequestResponse.title = 'No Jira isue here'
pullRequestResponse.head.ref = 'neither-here'
pullRequestResponse.user.login = botUser

await expect(jiraLinked.run()).resolves.toBeTruthy()
})

it('throws error for PR without Jira Issue key and non bot user', async () => {
pullRequestResponse.data.title = 'No Jira isue here'
pullRequestResponse.data.head.ref = 'neither-here'
pullRequestResponse.data.user.login = 'regular-user'
pullRequestResponse.title = 'No Jira isue here'
pullRequestResponse.head.ref = 'neither-here'
pullRequestResponse.user.login = 'regular-user'

await expect(jiraLinked.run()).rejects.toThrow()
})
})

describe('push event', () => {
const noPullRequestsAssociatedWithCommitResponse = {}

beforeEach(() => {
mockGithub.context.eventName = 'push'
mockGithub.getPullRequestsAssociatedWithCommit.mockResolvedValue(
noPullRequestsAssociatedWithCommitResponse as PullRequestsAssociatedWithCommitResponse
)
})

it('returns true when all commits have Jira Issue keys', async () => {
Expand Down Expand Up @@ -119,6 +126,32 @@ describe('Jira Linked check', () => {
{ message: 'chore(JIRA-123): some chore commit' },
]

await expect(jiraLinked.run()).rejects.toThrow()
})
it('returns true if the commit is associated with a merged PR, but does not have Jira Issue keys', async () => {
mockGithub.context.payload.commits = [
{ message: 'fix(JIRA-123): some fix commit' },
{ message: 'feat(no-key): some feat commit' },
{ message: 'chore(JIRA-123): some chore commit' },
]
const pullRequestsAssociatedWithCommitResponse = [{ state: 'merged' }]
mockGithub.getPullRequestsAssociatedWithCommit.mockResolvedValueOnce(
pullRequestsAssociatedWithCommitResponse as PullRequestsAssociatedWithCommitResponse
)

await expect(jiraLinked.run()).resolves.toBeTruthy()
})
it('returns false if the commit is associated with a non-merged PR and does not have Jira Issue keys', async () => {
mockGithub.context.payload.commits = [
{ message: 'fix(JIRA-123): some fix commit' },
{ message: 'feat(no-key): some feat commit' },
{ message: 'chore(JIRA-123): some chore commit' },
]
const pullRequestsAssociatedWithCommitResponse = [{ state: 'open' }]
mockGithub.getPullRequestsAssociatedWithCommit.mockResolvedValueOnce(
pullRequestsAssociatedWithCommitResponse as PullRequestsAssociatedWithCommitResponse
)

await expect(jiraLinked.run()).rejects.toThrow()
})
})
Expand Down
16 changes: 11 additions & 5 deletions src/checks/jiraLinked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,18 @@ async function checkPullRequest(): Promise<boolean> {
const pullPayload = github.context.payload as WebhookEventMap['pull_request']
const pr = await github.getPullRequest(pullPayload.pull_request.number)

const prUser = pr.data.user?.login || ''
const prUser = pr.user?.login || ''

if (isBot(prUser)) {
core.info(`PR is from bot user ${prUser}. Skipping check`)
return true
}

core.info('Scanning PR Title and Branch Name for Jira Key Reference')
core.info(`Title: ${pr.data.title}`)
core.info(`Branch: ${pr.data.head.ref}`)
core.info(`Title: ${pr.title}`)
core.info(`Branch: ${pr.head.ref}`)

const isJiraLinked =
hasJiraIssueKey(pr.data.title) || hasJiraIssueKey(pr.data.head.ref)
const isJiraLinked = hasJiraIssueKey(pr.title) || hasJiraIssueKey(pr.head.ref)

if (!isJiraLinked)
throw new Error('Jira Issue key not present in PR title or branch name!')
Expand All @@ -49,6 +48,13 @@ async function checkPullRequest(): Promise<boolean> {

async function checkPush(): Promise<boolean> {
const pushPayload = github.context.payload as WebhookEventMap['push']
const prs = await github.getPullRequestsAssociatedWithCommit()
if (prs.length === 1 && prs[0]?.state === 'merged') {
core.info(
'A merged Pull Request associated with commit has been found. Skipping...'
)
return true
}
const errors = pushPayload.commits
.filter(
(c) =>
Expand Down
1 change: 1 addition & 0 deletions src/infrastructure/__mocks__/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export const github = {
},
},
getPullRequest: jest.fn(),
getPullRequestsAssociatedWithCommit: jest.fn(),
}
21 changes: 19 additions & 2 deletions src/infrastructure/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { Context } from '@actions/github/lib/context'
import { GitHub as ActionsGitHub } from '@actions/github/lib/utils'

export type Octokit = InstanceType<typeof ActionsGitHub>
export type PullsGetResponse = Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response']
export type PullsGetResponse =
Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response']['data']
export type PullRequestsAssociatedWithCommitResponse =
Endpoints['GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls']['response']['data']

export class GitHub {
context: Context
Expand All @@ -17,11 +20,25 @@ export class GitHub {
}

async getPullRequest(pull_number: number): Promise<PullsGetResponse> {
return this.octokit.pulls.get({
const response = await this.octokit.pulls.get({
owner: this.context.repo.owner,
repo: this.context.repo.repo,
pull_number,
})
return response.data
}

async getPullRequestsAssociatedWithCommit(): Promise<PullRequestsAssociatedWithCommitResponse> {
const response =
await this.octokit.repos.listPullRequestsAssociatedWithCommit({
owner: this.context.repo.owner,
repo: this.context.repo.repo,
commit_sha: this.context.sha,
mediaType: {
previews: ['groot'],
},
})
return response.data
}
}

Expand Down
16 changes: 7 additions & 9 deletions src/triggeredByBot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ jest.mock('./infrastructure/github')
describe('triggeredByBot', () => {
describe('pul_request event', () => {
const pullRequestResponse = {
data: {
title: '',
head: {
ref: '',
},
user: {
login: '',
},
title: '',
head: {
ref: '',
},
user: {
login: '',
},
}

Expand All @@ -32,7 +30,7 @@ describe('triggeredByBot', () => {
})

it.each(BOT_USERS)('returns true for bot users [%s]', async (botUser) => {
pullRequestResponse.data.user.login = botUser
pullRequestResponse.user.login = botUser

await expect(triggeredByBot()).resolves.toBeTruthy()
})
Expand Down
2 changes: 1 addition & 1 deletion src/triggeredByBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function checkPullRequest(): Promise<boolean> {
const pullPayload = github.context.payload as WebhookEventMap['pull_request']
const pr = await github.getPullRequest(pullPayload.pull_request.number)

const prUser = pr.data.user?.login || ''
const prUser = pr.user?.login || ''

return isBot(prUser)
}
Expand Down

0 comments on commit 0e57db6

Please sign in to comment.