const bbUrlPrefix = 'https://git.add123.com/rest/api/latest' let updateEmptySection const pullRequestHasErrored = async pr => { const latestCommitId = pr?.fromRef?.latestCommit if (!latestCommitId) { return false } const buildStats = await fetch(`https://git.add123.com/rest/build-status/latest/commits/stats/${latestCommitId}`).then(resp => resp.json()) return buildStats.failed !== 0 } 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 } const getErroredPrs = async () => { const allPullRequests = (await getAllRepos() .then(async allRepos => { 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) }).catch(console.error)).filter(Boolean) const erroredPullRequests = [] const dismissedCommitIds = getLocalStorage().dismissedCommitIds ?? [] for (const pullRequest of allPullRequests) { if (!dismissedCommitIds.includes(pullRequest?.fromRef?.latestCommit) && await pullRequestHasErrored(pullRequest)) { erroredPullRequests.push(pullRequest) } } return erroredPullRequests } const getElementAfterErrorList = mainPanel => { for (const child of mainPanel.children) { if (child.innerHTML.includes('Recently closed pull requests')) { return child } } return mainPanel.children[1] } 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 = `

${message}

${loading ? '' : '

Pray it stays that way.

'}
` 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) => { const row = document.createElement('tr') row.className = 'pull-request-row' const avatar = document.createElement('td') avatar.className = 'avatar-column' avatar.innerHTML = `
` 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 = ` ${pr.author.user.displayName} - #${pr.id} ${pr.toRef.repository.project.name} / ${pr.toRef.repository.name} ${pr.toRef.displayId} ` const placeholderColumn = document.createElement('td') 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) }) row.appendChild(placeholderColumn) const buildColumn = document.createElement('td') buildColumn.className = 'build-column' buildColumn.innerHTML = ' ' row.appendChild(buildColumn) return row } const showErroredPrs = async () => { if (getCurrentUser() !== 'sagevaillancourt') { return } const mainPanel = document.getElementsByClassName('main-panel')[0] let prErrorSection = document.getElementById('bb-addon-pr-error-section') const emptySection = document.getElementById(prEmptySectionId) ?? document.createElement('div') emptySection.id = prEmptySectionId let errorList = document.getElementById('bb-addon-pr-error-list') const table = document.getElementById(prErrorTableId) ?? buildErrorListTable() if (!prErrorSection) { prErrorSection = mainPanel.getElementsByClassName('closed-pull-requests')[0].cloneNode() prErrorSection.id = 'bb-addon-pr-error-section' const header = document.createElement('h3') header.innerText = 'Pull requests with errors' prErrorSection.appendChild(header) prErrorSection.appendChild(emptySection) configureEmptySection(true, emptySection) errorList = document.createElement('tbody') errorList.id = 'bb-addon-pr-error-list' mainPanel.insertBefore(prErrorSection, getElementAfterErrorList(mainPanel)) table.style.visibility = 'collapse' table.appendChild(errorList) prErrorSection.appendChild(table) } const erroredPrs = await getErroredPrs() Array.from(errorList.children).forEach(child => errorList.removeChild(child)) 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) } if (location.toString().includes('/dashboard')) { addFix(() => showErroredPrs().catch(console.error)) setInterval(() => showErroredPrs().catch(console.error), 1000 * 60 * 2) }