Skip to content

Instantly share code, notes, and snippets.

@gparlakov
Last active April 21, 2020 07:46
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 gparlakov/95e41ebee68c99baf36f36c12278deaf to your computer and use it in GitHub Desktop.
Save gparlakov/95e41ebee68c99baf36f36c12278deaf to your computer and use it in GitHub Desktop.
Read full text logs from Azure Dev Ops Build pipeline
/// <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