Skip to content

Instantly share code, notes, and snippets.

@doug-numetric
Last active October 25, 2023 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doug-numetric/52e18d818dd46affce6070a063403a42 to your computer and use it in GitHub Desktop.
Save doug-numetric/52e18d818dd46affce6070a063403a42 to your computer and use it in GitHub Desktop.
bamboo download combined ci logs
// ==UserScript==
// @name Download all
// @namespace Violentmonkey Scripts
// @include https://bamboo.internal.numetric.com/*/ci_test_logs
// @grant none
// @version 1.0
// @author -
// @description 10/24/2023, 1:01:20 PM
// ==/UserScript==
async function main() {
const [parent, ...links] = [...document.querySelectorAll('table>tbody>tr>td>a')].map(({ href }) => href)
const job = parent.split('/')[5].toLowerCase()
const records = links.map((link) => {
const filename = link.split('/')[9];
const tag = `_${job}_`;
const tagIndex = filename.indexOf(tag);
if (filename.endsWith(`_${job}.log`)) {
let containerName = filename.split('_').slice(1, -1).join('_');
containerName = containerName.substring(0, containerName.length - 32);
return { link, containerName };
} else if(tagIndex !== -1) {
const containerName = filename.substring(tagIndex + tag.length, filename.length - '.log'.length);
return { link, containerName };
}
}).filter((obj) => !!obj);
let parts = [];
for (const { link, containerName } of records) {
const response = await fetch(link);
const text = await response.text();
const lines = text.split('\n');
const newlines = lines.map((line) => {
const [timestamp, ...rest] = line.split(' ');
return [timestamp, containerName, ...rest].join(' ');
});
parts.push(`${newlines.join('\n')}\n`);
}
parts = [parts.join('').split('\n').sort().join('\n')];
function downloadBlob(blob, filename) {
// Create an object URL for the blob object
const url = URL.createObjectURL(blob);
// Create a new anchor element
const a = document.createElement('a');
// Set the href and download attributes for the anchor element
// You can optionally set other attributes like `title`, etc
// Especially, if the anchor element will be attached to the DOM
a.href = url;
a.download = filename || 'download';
// Click handler that releases the object URL after the element has been clicked
// This is required for one-off downloads of the blob content
const clickHandler = () => {
setTimeout(() => {
URL.revokeObjectURL(url);
removeEventListener('click', clickHandler);
}, 150);
};
// Add the click event listener on the anchor element
// Comment out this line if you don't want a one-off download of the blob content
a.addEventListener('click', clickHandler, false);
// Programmatically trigger a click on the anchor element
// Useful if you want the download to happen automatically
// Without attaching the anchor element to the DOM
// Comment out this line if you don't want an automatic download of the blob content
//a.click();
// Return the anchor element
// Useful if you want a reference to the element
// in order to attach it to the DOM or use it in some other way
return a;
}
const element = downloadBlob(new Blob(parts), 'all-combined.log');
element.title = 'all-combined.log';
element.classList.add('btn-link', 'download-link');
element.textContent = 'all-combined.log';
document.body.appendChild(element);
}
main().catch(e => console.error(e));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment