2024-12-19 13:55:49 -05:00
|
|
|
const bbUrlPrefix = 'https://git.add123.com/rest/api/latest'
|
|
|
|
|
2024-12-20 15:45:49 -05:00
|
|
|
let updateEmptySection
|
|
|
|
|
2024-12-19 13:55:49 -05:00
|
|
|
const pullRequestHasErrored = async pr => {
|
2024-12-19 14:26:03 -05:00
|
|
|
const latestCommitId = pr?.fromRef?.latestCommit
|
|
|
|
if (!latestCommitId) {
|
|
|
|
return false
|
|
|
|
}
|
2024-12-19 13:55:49 -05:00
|
|
|
const buildStats = await fetch(`https://git.add123.com/rest/build-status/latest/commits/stats/${latestCommitId}`).then(resp => resp.json())
|
|
|
|
return buildStats.failed !== 0
|
|
|
|
}
|
|
|
|
|
2024-12-19 14:26:03 -05:00
|
|
|
const getAllRepos = async () => {
|
|
|
|
const allProjects = (await fetch(`${bbUrlPrefix}/projects`).then(resp => resp.json())).values
|
|
|
|
const allProjectKeys = allProjects.map(project => project.key)
|
|
|
|
let allRepos = await Promise.all(allProjectKeys.map(async key =>
|
|
|
|
await fetch(`${bbUrlPrefix}/projects/${key}/repos?limit=999`)
|
|
|
|
.then(resp => resp.json()).then(({ values }) => values)))
|
|
|
|
allRepos = allRepos.flatMap(a => a)
|
|
|
|
return allRepos
|
|
|
|
}
|
|
|
|
|
2024-12-19 14:45:58 -05:00
|
|
|
const getErroredPrs = async () => {
|
2024-12-19 14:26:03 -05:00
|
|
|
const allPullRequests = (await getAllRepos()
|
|
|
|
.then(async allRepos => {
|
2024-12-19 13:55:49 -05:00
|
|
|
const prListUrls = allRepos.map(repo => `${bbUrlPrefix}/projects/ADD/repos/${repo.slug}/pull-requests`)
|
|
|
|
return (await Promise.all(
|
|
|
|
prListUrls.map(async prListUrl => await fetch(prListUrl).then(resp => resp.json())))
|
|
|
|
).flatMap(({values}) => values)
|
2024-12-19 14:26:03 -05:00
|
|
|
}).catch(console.error)).filter(Boolean)
|
2024-12-19 13:55:49 -05:00
|
|
|
const erroredPullRequests = []
|
2024-12-20 15:45:49 -05:00
|
|
|
const dismissedCommitIds = getLocalStorage().dismissedCommitIds ?? []
|
2024-12-19 13:55:49 -05:00
|
|
|
for (const pullRequest of allPullRequests) {
|
2024-12-20 15:45:49 -05:00
|
|
|
if (!dismissedCommitIds.includes(pullRequest?.fromRef?.latestCommit) && await pullRequestHasErrored(pullRequest)) {
|
2024-12-19 14:45:58 -05:00
|
|
|
erroredPullRequests.push(pullRequest)
|
2024-12-19 13:55:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return erroredPullRequests
|
|
|
|
}
|
|
|
|
|
2024-12-19 14:26:03 -05:00
|
|
|
const getElementAfterErrorList = mainPanel => {
|
|
|
|
for (const child of mainPanel.children) {
|
|
|
|
if (child.innerHTML.includes('Recently closed pull requests')) {
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mainPanel.children[1]
|
|
|
|
}
|
|
|
|
|
2024-12-20 15:45:49 -05:00
|
|
|
const getLocalStorage = () => {
|
|
|
|
return JSON.parse(localStorage.getItem('bb-addon-data') ?? '{}')
|
|
|
|
}
|
|
|
|
|
|
|
|
const setLocalStorage = data => {
|
|
|
|
localStorage.setItem('bb-addon-data', JSON.stringify(data))
|
|
|
|
}
|
|
|
|
|
|
|
|
const addLocalStorage = data => {
|
|
|
|
localStorage.setItem('bb-addon-data', JSON.stringify({
|
|
|
|
...getLocalStorage(),
|
|
|
|
...data
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
const prErrorTableId = 'bb-addon-error-table'
|
|
|
|
const prEmptySectionId = 'bb-addon-empty-section'
|
|
|
|
|
|
|
|
const configureEmptySection = (loading, emptyState) => {
|
|
|
|
const message = loading ? 'Loading PRs with errors...' : 'No pull requests have errors!'
|
|
|
|
emptyState.id = prEmptySectionId
|
|
|
|
emptyState.className = 'empty-state'
|
|
|
|
emptyState.innerHTML = `
|
|
|
|
<div className="dashboard-empty-reviewing">
|
|
|
|
<p className="dashboard-empty-title" style="font-weight: 500">${message}</p>
|
|
|
|
${loading ? '' : '<p className="dashboard-empty-description"><em>Pray it stays that way.</em></p>'}
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
return emptyState
|
|
|
|
}
|
|
|
|
|
|
|
|
const buildErrorListTable = () => {
|
|
|
|
const table = document.createElement('table')
|
|
|
|
table.id = prErrorTableId
|
|
|
|
|
|
|
|
const thead = document.createElement('thead')
|
|
|
|
table.appendChild(thead)
|
|
|
|
|
|
|
|
const tr = document.createElement('tr')
|
|
|
|
thead.appendChild(tr)
|
|
|
|
|
|
|
|
const summaryColumn = document.createElement('th')
|
|
|
|
summaryColumn.className = 'summary-column'
|
|
|
|
summaryColumn.colSpan = 6
|
|
|
|
tr.appendChild(summaryColumn)
|
|
|
|
|
|
|
|
const reviewersColumn = document.createElement('th')
|
|
|
|
reviewersColumn.className = 'reviewers-column'
|
|
|
|
reviewersColumn.innerHTML = ' '
|
|
|
|
tr.appendChild(reviewersColumn)
|
|
|
|
|
|
|
|
const buildsColumn = document.createElement('th')
|
|
|
|
buildsColumn.className = 'builds-column'
|
|
|
|
buildsColumn.innerHTML = ' '
|
|
|
|
tr.appendChild(buildsColumn)
|
|
|
|
return table
|
|
|
|
}
|
|
|
|
|
|
|
|
const buildPrRow = (pr, parent) => {
|
2024-12-19 15:26:50 -05:00
|
|
|
const row = document.createElement('tr')
|
|
|
|
row.className = 'pull-request-row'
|
|
|
|
|
|
|
|
const avatar = document.createElement('td')
|
|
|
|
avatar.className = 'avatar-column'
|
|
|
|
avatar.innerHTML = `
|
|
|
|
<div class="user-avatar author-avatar">
|
|
|
|
<div style="display: inline-block; position: relative; outline: 0px;">
|
|
|
|
<span class="css-1dyoea">
|
|
|
|
<span style="background-image: url('/users/${pr.author.user.name}/avatar.png?s=64'); border-radius: 50%;"
|
2024-12-20 15:45:49 -05:00
|
|
|
role="img" aria-label="${pr.author.user.name}" class="css-ob4lje"></span>
|
2024-12-19 15:26:50 -05:00
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
row.appendChild(avatar)
|
|
|
|
|
|
|
|
const summaryColumn = document.createElement('td')
|
|
|
|
summaryColumn.className = 'summary-column'
|
|
|
|
row.appendChild(summaryColumn)
|
|
|
|
|
|
|
|
const prSummary = document.createElement('div')
|
|
|
|
prSummary.className = 'pr-summary'
|
|
|
|
summaryColumn.appendChild(prSummary)
|
|
|
|
|
|
|
|
const title = document.createElement('div')
|
|
|
|
title.className = 'title'
|
|
|
|
prSummary.appendChild(title)
|
|
|
|
|
|
|
|
const link = document.createElement('a')
|
|
|
|
link.href = pr.links.self[0].href
|
|
|
|
link.innerText = pr.title
|
|
|
|
title.appendChild(link)
|
|
|
|
|
|
|
|
const details = document.createElement('div')
|
|
|
|
details.className = 'details'
|
|
|
|
prSummary.appendChild(details)
|
|
|
|
details.innerHTML = `
|
|
|
|
<span class="user-name details-item">${pr.author.user.displayName}</span>
|
|
|
|
<span class="details-item">-</span>
|
|
|
|
<span class="details-item pr-id">#${pr.id}</span>
|
|
|
|
<span class="details-item pr-project-repo">${pr.toRef.repository.project.name} / ${pr.toRef.repository.name}</span>
|
|
|
|
<span class="ref-lozenge details-item" data-project-key="${pr.toRef.repository.project.key}" data-repo-slug="${pr.toRef.repository.name}">
|
|
|
|
<span role="presentation">
|
|
|
|
<span class="ref-lozenge-content" role="presentation">
|
|
|
|
<span>${pr.toRef.displayId}</span>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
`
|
|
|
|
|
|
|
|
const placeholderColumn = document.createElement('td')
|
2024-12-20 15:45:49 -05:00
|
|
|
placeholderColumn.className = 'reviewers-column'
|
|
|
|
placeholderColumn.innerHTML = 'Dismiss'
|
|
|
|
placeholderColumn.addEventListener('click', () => {
|
|
|
|
const localStorageData = getLocalStorage()
|
|
|
|
localStorageData.dismissedCommitIds ??= []
|
|
|
|
localStorageData.dismissedCommitIds.push(pr.fromRef.latestCommit)
|
|
|
|
setLocalStorage(localStorageData)
|
|
|
|
parent.removeChild(row)
|
|
|
|
updateEmptySection(parent.children.length)
|
|
|
|
})
|
2024-12-19 15:26:50 -05:00
|
|
|
row.appendChild(placeholderColumn)
|
|
|
|
|
|
|
|
const buildColumn = document.createElement('td')
|
|
|
|
buildColumn.className = 'build-column'
|
|
|
|
buildColumn.innerHTML = ' '
|
|
|
|
row.appendChild(buildColumn)
|
|
|
|
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
2024-12-19 13:55:49 -05:00
|
|
|
const showErroredPrs = async () => {
|
|
|
|
if (getCurrentUser() !== 'sagevaillancourt') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const mainPanel = document.getElementsByClassName('main-panel')[0]
|
2024-12-20 15:45:49 -05:00
|
|
|
let prErrorSection = document.getElementById('bb-addon-pr-error-section')
|
|
|
|
const emptySection = document.getElementById(prEmptySectionId) ?? document.createElement('div')
|
|
|
|
emptySection.id = prEmptySectionId
|
2024-12-19 13:55:49 -05:00
|
|
|
let errorList = document.getElementById('bb-addon-pr-error-list')
|
2024-12-20 15:45:49 -05:00
|
|
|
const table = document.getElementById(prErrorTableId) ?? buildErrorListTable()
|
|
|
|
|
|
|
|
if (!prErrorSection) {
|
|
|
|
prErrorSection = mainPanel.getElementsByClassName('closed-pull-requests')[0].cloneNode()
|
|
|
|
prErrorSection.id = 'bb-addon-pr-error-section'
|
2024-12-19 13:55:49 -05:00
|
|
|
|
|
|
|
const header = document.createElement('h3')
|
|
|
|
header.innerText = 'Pull requests with errors'
|
2024-12-20 15:45:49 -05:00
|
|
|
prErrorSection.appendChild(header)
|
2024-12-19 15:26:50 -05:00
|
|
|
|
2024-12-20 15:45:49 -05:00
|
|
|
prErrorSection.appendChild(emptySection)
|
|
|
|
configureEmptySection(true, emptySection)
|
2024-12-19 15:26:50 -05:00
|
|
|
|
|
|
|
errorList = document.createElement('tbody')
|
|
|
|
|
2024-12-19 13:55:49 -05:00
|
|
|
errorList.id = 'bb-addon-pr-error-list'
|
|
|
|
|
2024-12-20 15:45:49 -05:00
|
|
|
mainPanel.insertBefore(prErrorSection, getElementAfterErrorList(mainPanel))
|
|
|
|
|
|
|
|
table.style.visibility = 'collapse'
|
|
|
|
table.appendChild(errorList)
|
|
|
|
prErrorSection.appendChild(table)
|
2024-12-19 13:55:49 -05:00
|
|
|
}
|
|
|
|
|
2024-12-19 14:45:58 -05:00
|
|
|
const erroredPrs = await getErroredPrs()
|
|
|
|
Array.from(errorList.children).forEach(child => errorList.removeChild(child))
|
2024-12-20 15:45:49 -05:00
|
|
|
erroredPrs.map(pr => buildPrRow(pr, errorList)).forEach(row => errorList.appendChild(row))
|
|
|
|
updateEmptySection = length => {
|
|
|
|
if (length) {
|
|
|
|
table.style.visibility = 'visible'
|
|
|
|
emptySection.style.visibility = 'collapse'
|
|
|
|
} else {
|
|
|
|
configureEmptySection(false, emptySection)
|
|
|
|
table.style.visibility = 'collapse'
|
|
|
|
emptySection.style.visibility = 'visible'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateEmptySection(erroredPrs.length)
|
2024-12-19 13:55:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (location.toString().includes('/dashboard')) {
|
|
|
|
addFix(() => showErroredPrs().catch(console.error))
|
2024-12-19 14:45:58 -05:00
|
|
|
setInterval(() => showErroredPrs().catch(console.error), 1000 * 60 * 2)
|
2024-12-19 13:55:49 -05:00
|
|
|
}
|