Skip to content

Commit

Permalink
Feature trello-switch-members-in-review vol 2 (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
ukupat authored Jul 26, 2024
1 parent a7971b8 commit 1b00995
Show file tree
Hide file tree
Showing 14 changed files with 451 additions and 283 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ Default: `true`

#### 3. `trello-switch-members-in-review`

Replaces Trello card members with PR reviewers when PR is opened. It reassigns the PR author, contributors and assignees when the card is moved away from trello-list-id-pr-open.
Replaces Trello card members with PR reviewers when PR is opened. It reassigns the PR author, contributors and assignees when the card is moved away from `trello-list-id-pr-open`.

Default: `false`

Expand Down
319 changes: 196 additions & 123 deletions dist/index.js

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"collectCoverageFrom": [
"src/**",
"!src/index.ts",
"!src/actions/utils/logger.ts",
"!src/actions/api/**"
]
},
Expand All @@ -63,10 +64,7 @@
],
"ignorePatterns": [
"dist"
],
"rules": {
"no-console": 0
}
]
},
"packageManager": "yarn@4.1.0+sha512.5b7bc055cad63273dda27df1570a5d2eb4a9f03b35b394d3d55393c2a5560a17f5cef30944b11d6a48bcbcfc1c3a26d618aae77044774c529ba36cb771ad5b0f"
}
7 changes: 5 additions & 2 deletions src/actions/addCardLinksToPullRequest.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { Conf } from '../types'
import { createComment, getPullRequest, getPullRequestComments } from './api/github'
import { getCardInfo } from './api/trello'
import logger from './utils/logger'
import matchCardIds from './utils/matchCardIds'

export default async function addCardLinksToPullRequest(conf: Conf, cardIds: string[]) {
logger.log('--- ADD CARD LINKS TO PR ---')

const bodyCardIds = await getCardIdsFromBody(conf)
const commentsCardIds = await getCardIdsFromComments(conf)
const linkedCardIds = [...bodyCardIds, ...commentsCardIds]

const unlinkedCardIds = cardIds.filter((id) => !linkedCardIds.includes(id))

if (!unlinkedCardIds.length) {
console.log('Skipping card linking as all cards are already mentioned under the PR')
logger.log('Skipping card linking as all cards are already mentioned under the PR')

return
}
console.log('Commenting Trello card URLs to PR', unlinkedCardIds)
logger.log('Commenting Trello card URLs to PR', unlinkedCardIds)

const cards = await Promise.all(unlinkedCardIds.map((id) => getCardInfo(id)))
const urls = cards.map((card) => card.shortUrl)
Expand Down
17 changes: 9 additions & 8 deletions src/actions/addLabelToCards.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { BoardLabel, Conf, PRHead } from '../types'
import { getBranchName } from './api/github'
import { addLabelToCard, getBoardLabels, getCardInfo } from './api/trello'
import logger from './utils/logger'

export default async function addLabelToCards(conf: Conf, cardIds: string[], head?: PRHead) {
logger.log('--- ADD LABEL TO CARDS ---')

if (!conf.trelloAddLabelsToCards) {
console.log('Skipping label adding')
logger.log('Skipping label adding')

return
}
console.log('Starting to add labels to cards')

const branchLabel = await getBranchLabel(head)

if (!branchLabel) {
console.log('Could not find branch label')
logger.log('Could not find branch label')

return
}
Expand All @@ -26,7 +27,7 @@ export default async function addLabelToCards(conf: Conf, cardIds: string[], hea
)

if (hasConflictingLabel) {
console.log('Skipping label adding to a card because it has a conflicting label', cardInfo.labels)
logger.log('Skipping label adding to a card as it has a conflicting label', cardInfo.labels)

return
}
Expand All @@ -36,7 +37,7 @@ export default async function addLabelToCards(conf: Conf, cardIds: string[], hea
if (matchingLabel) {
await addLabelToCard(cardId, matchingLabel.id)
} else {
console.log('Could not find a matching label from the board', branchLabel, boardLabels)
logger.log('Could not find a matching label from the board', { branchLabel, boardLabels })
}
}),
)
Expand All @@ -49,7 +50,7 @@ async function getBranchLabel(prHead?: PRHead) {
if (matches) {
return matches[1]
} else {
console.log('Did not find branch label', branchName)
logger.log('Did not find branch label', branchName)
}
}

Expand All @@ -59,7 +60,7 @@ function findMatchingLabel(branchLabel: string, boardLabels: BoardLabel[]) {
if (match) {
return match
}
console.log('Could not match the exact label name, trying to find partially matching label')
logger.log('Could not match the exact label name, trying to find partially matching label')

return boardLabels.find((label) => branchLabel.startsWith(label.name))
}
5 changes: 4 additions & 1 deletion src/actions/addPullRequestLinkToCards.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { PR } from '../types'
import { addAttachmentToCard, getCardAttachments } from './api/trello'
import logger from './utils/logger'

export default async function addPullRequestLinkToCards(cardIds: string[], pr: PR) {
logger.log('--- ADD PR LINK TO CARDS ---')

const link = pr.html_url || pr.url

return Promise.all(
cardIds.map(async (cardId) => {
const existingAttachments = await getCardAttachments(cardId)

if (existingAttachments?.some((it) => it.url.includes(link))) {
console.log('Found existing attachment, skipping adding attachment', cardId, link)
logger.log('Found existing attachment, skipping adding attachment', { cardId, link })

return
}
Expand Down
5 changes: 3 additions & 2 deletions src/actions/api/github.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getInput } from '@actions/core'
import { getOctokit, context } from '@actions/github'
import logger from '../utils/logger'

const githubToken = getInput('github-token', { required: true })

Expand Down Expand Up @@ -84,7 +85,7 @@ export async function getPullRequestRequestedReviewers() {
}

export async function createComment(shortUrl: string) {
console.log('Creating PR comment', shortUrl)
logger.log('Creating PR comment', shortUrl)

await octokit.rest.issues.createComment({
owner,
Expand All @@ -95,7 +96,7 @@ export async function createComment(shortUrl: string) {
}

export async function updatePullRequestBody(newBody: string) {
console.log('Updating PR body', newBody)
logger.log('Updating PR body', newBody)

await octokit.rest.issues.update({
owner,
Expand Down
59 changes: 30 additions & 29 deletions src/actions/api/trello.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import axios from 'axios'
import * as core from '@actions/core'
import { BoardLabel } from '../../types'
import logger from '../utils/logger'

const trelloApiKey = core.getInput('trello-api-key', { required: true })
const trelloAuthToken = core.getInput('trello-auth-token', { required: true })
Expand All @@ -27,26 +28,26 @@ export async function getCardInfo(
return response?.data
}

export async function getMemberInfo(username?: string): Promise<{ id: string; organizations: { name: string }[] }> {
const response = await makeRequest('get', `https://api.trello.com/1/members/${username}`, {
organizations: 'all',
})

return response?.data
}

export async function getCardAttachments(cardId: string): Promise<{ url: string }[]> {
const response = await makeRequest('get', `https://api.trello.com/1/cards/${cardId}/attachments`)

return response?.data || null
}

export async function addAttachmentToCard(cardId: string, link: string) {
console.log('Adding attachment to the card', cardId, link)
logger.log('Adding attachment to the card', { cardId, link })

return makeRequest('post', `https://api.trello.com/1/cards/${cardId}/attachments`, { url: link })
}

export async function addMemberToCard(cardId: string, memberId: string) {
console.log('Adding member to a card', cardId, memberId)

return makeRequest('post', `https://api.trello.com/1/cards/${cardId}/idMembers`, {
value: memberId,
})
}

export async function getBoardLabels(boardId: string): Promise<BoardLabel[]> {
const response = await makeRequest('get', `https://api.trello.com/1/boards/${boardId}/labels`)

Expand All @@ -55,28 +56,36 @@ export async function getBoardLabels(boardId: string): Promise<BoardLabel[]> {
return response?.data?.filter((label: { name: string }) => label.name)
}

export async function getBoardLists(boardId: string): Promise<{ id: string }[]> {
const response = await makeRequest('get', `https://api.trello.com/1/boards/${boardId}/lists`)

return response?.data
}

export async function addLabelToCard(cardId: string, labelId: string) {
console.log('Adding label to a card', cardId, labelId)
logger.log('Adding label to a card', { cardId, labelId })

return makeRequest('post', `https://api.trello.com/1/cards/${cardId}/idLabels`, {
value: labelId,
})
}

export async function addMemberToCard(cardId: string, memberId: string) {
logger.log('Adding member to a card', { cardId, memberId })

return makeRequest('post', `https://api.trello.com/1/cards/${cardId}/idMembers`, {
value: memberId,
})
}

export async function removeMemberFromCard(cardId: string, memberId: string) {
console.log('Removing card member', cardId, memberId)
logger.log('Removing member from a card', { cardId, memberId })

return makeRequest('delete', `https://api.trello.com/1/cards/${cardId}/idMembers/${memberId}`)
}

export async function getBoardLists(boardId: string): Promise<{ id: string }[]> {
const response = await makeRequest('get', `https://api.trello.com/1/boards/${boardId}/lists`)

return response?.data
}

export async function moveCardToList(cardId: string, listId: string, boardId?: string) {
console.log('Moving card to list', cardId, listId)
logger.log('Moving card to list', { cardId, listId, boardId })

return makeRequest('put', `https://api.trello.com/1/cards/${cardId}`, {
pos: trelloCardPosition,
Expand All @@ -86,27 +95,19 @@ export async function moveCardToList(cardId: string, listId: string, boardId?: s
}

export async function archiveCard(cardId: string) {
console.log('Archiving card', cardId)
logger.log('ARCHIVE: Archiving card', { cardId })

return makeRequest('put', `https://api.trello.com/1/cards/${cardId}`, {
closed: true,
})
}

export async function getMemberInfo(username?: string): Promise<{ id: string; organizations: { name: string }[] }> {
const response = await makeRequest('get', `https://api.trello.com/1/members/${username}`, {
organizations: 'all',
})

return response?.data
}

export async function createCard(
listId: string,
title: string,
body?: string,
): Promise<{ id: string; url: string; shortLink: string }> {
console.log('Creating card based on PR info', title, body)
logger.log('Creating card based on PR info', { title, body })

const response = await makeRequest('post', `https://api.trello.com/1/cards`, {
idList: listId,
Expand Down Expand Up @@ -144,7 +145,7 @@ async function makeRequest(method: 'get' | 'put' | 'post' | 'delete', url: strin
message: error.message,
},
}
console.error(JSON.stringify(errorMessage, null, 2))
logger.error(JSON.stringify(errorMessage, null, 2))

throw error
}
Expand Down
15 changes: 8 additions & 7 deletions src/actions/getCardIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { getBranchName, getCommits, getPullRequest, getPullRequestComments, upda
import { createCard, searchTrelloCards } from './api/trello'
import matchCardIds from './utils/matchCardIds'
import isPullRequestInDraft from './utils/isPullRequestInDraft'
import logger from './utils/logger'

export default async function getCardIds(conf: Conf, pr: PR) {
console.log('Searching for card IDs')
logger.log('--- FIND CARDS ---')

const latestPRInfo = (await getPullRequest()) || pr
let cardIds = matchCardIds(conf, latestPRInfo.body || '')
Expand Down Expand Up @@ -42,11 +43,11 @@ export default async function getCardIds(conf: Conf, pr: PR) {
}

if (cardIds.length) {
console.log('Found card IDs', cardIds)
logger.log('Found card IDs', cardIds)

return [...new Set(cardIds)]
} else {
console.log('Could not find card IDs')
logger.log('Could not find card IDs')

if (conf.githubRequireTrelloCard) {
setFailed('The PR does not contain a link to a Trello card')
Expand All @@ -59,13 +60,13 @@ export default async function getCardIds(conf: Conf, pr: PR) {
async function getCardIdsFromBranchName(conf: Conf, prHead?: PRHead) {
const branchName = prHead?.ref || (await getBranchName())

console.log('Searching cards from branch name', branchName)
logger.log('Searching cards from branch name', branchName)

if (conf.githubAllowMultipleCardsInPrBranchName) {
const shortIdMatches = branchName.match(/(?<=^|\/)\d+(?:-\d+)+/gi)?.[0].split('-')

if (shortIdMatches && shortIdMatches.length > 1) {
console.log('Matched multiple potential Trello short IDs from branch name', shortIdMatches)
logger.log('Matched multiple potential Trello short IDs from branch name', shortIdMatches)

const potentialCardIds = await Promise.all(
shortIdMatches.map((shortId: string) => getTrelloCardByShortId(shortId, conf.trelloBoardId)),
Expand All @@ -80,15 +81,15 @@ async function getCardIdsFromBranchName(conf: Conf, prHead?: PRHead) {
const matches = branchName.match(/(?<=^|\/)(\d+)-\S+/i)

if (matches) {
console.log('Matched one potential card from branch name', matches)
logger.log('Matched one potential card from branch name', matches)

const cardsWithExactMatch = await searchTrelloCards(matches[0])

if (cardsWithExactMatch?.length) {
return [cardsWithExactMatch[0].shortLink]
}

console.log('Could not find Trello card with branch name, trying only with short ID', matches[1])
logger.log('Could not find Trello card with branch name, trying only with short ID', matches[1])

const cardId = await getTrelloCardByShortId(matches[1])

Expand Down
Loading

0 comments on commit 1b00995

Please sign in to comment.