Last active
April 21, 2020 07:46
-
-
Save gparlakov/95e41ebee68c99baf36f36c12278deaf to your computer and use it in GitHub Desktop.
Read full text logs from Azure Dev Ops Build pipeline
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference types="node" /> | |
import axios from 'axios'; | |
import * as yauzl from 'yauzl'; | |
const headers = { | |
Authorization: `Basic ${Buffer.from(`:${this.token}`).toString('base64')}`, | |
'X-TFS-FedAuthRedirect': 'Suppress', // we can't handle auth redirect so - suppress | |
}; | |
const accessToken = process.env.AZURE_ACCESS_TOKEN; | |
const project = undefined; // TODO Replace with your own | |
const organization = undefined; // TODO Replace with your own | |
if (accessToken == null || accessToken === '') { | |
throw new Error('Please provide an access token'); | |
} else { | |
console.log('token is present!'); | |
} | |
export const axiosInstance = axios.create({ | |
baseURL: `https://dev.azure.com/${organization}/${project}/_apis/`, | |
headers: headers, | |
}); | |
const buildId = undefined; // TODO Replace with your own | |
axiosInstance | |
.get(`build/builds/${buildId}/logs`, { | |
responseType: 'stream', | |
headers: { | |
accept: 'application/zip', | |
}, | |
}) | |
.then((logs) => { | |
if (logs.status != 200) { | |
throw new Error('logs missing'); | |
} | |
console.log(logs.data) | |
return readLogs(logs.data); | |
}) | |
.then(({logs}) => { | |
console.log(logs); | |
}); | |
function readLogs(zipBuffer: NodeJS.ReadableStream): Promise<{ logs: string; skippedFor: Error[] }> { | |
// we'll reject the promise when we can't read anything from the zip | |
// and resolve it when we could read (some) plus add the errors for the skipped parts | |
// in the end we'd like to say - yes the logs contain the Proof OR no the logs do not contain the proof but there were skipped parts | |
return new Promise((res, rej) => { | |
const es: Error[] = []; | |
const zipChunks: any[] = []; | |
zipBuffer.on('data', (d) => zipChunks.push(d)); | |
zipBuffer.on('end', () => { | |
yauzl.fromBuffer(Buffer.concat(zipChunks), { lazyEntries: true }, function (err, zipfile) { | |
// can not even open the archive just reject the promise | |
if (err) { | |
rej(err); | |
} | |
if (zipfile != null) { | |
const chunks: any[] = []; | |
zipfile.on('entry', function (entry) { | |
if (/\/$/.test(entry.fileName)) { | |
// Directory file names end with '/'. | |
// Note that entries for directories themselves are optional. | |
// An entry's fileName implicitly requires its parent directories to exist. | |
zipfile.readEntry(); | |
} else { | |
// file entry | |
zipfile.openReadStream(entry, function (err, readStream) { | |
if (err) { | |
es.push(err); | |
// skip this one - could not read it from zip | |
zipfile.readEntry(); | |
} | |
if (readStream == null) { | |
// just skip - could not get a read stream from it | |
es.push( | |
new Error( | |
'Could not create a readable stream for the log ' + (entry || {}).fileName || | |
'<missing file name>' | |
) | |
); | |
zipfile.readEntry(); | |
} else { | |
readStream.on('data', (c) => chunks.push(c)); | |
readStream.on('error', (e) => { | |
es.push(e); | |
// skip this one - could not read it from zip | |
zipfile.readEntry(); | |
}); | |
readStream.on('end', function () { | |
zipfile.readEntry(); | |
}); | |
} | |
}); | |
} | |
}); | |
zipfile.once('end', function () { | |
zipfile.close(); | |
res({ logs: Buffer.concat(chunks).toString('utf8'), skippedFor: es }); | |
}); | |
zipfile.readEntry(); | |
} else { | |
// can't read the archive - reject the promise | |
rej(new Error('Could not read the zipfile contents')); | |
} | |
}); | |
}); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment