create-adobug-azure-helper
Version:
A helper library for Azure DevOps automation functions (bug creation, test result update, step logging, etc.)
150 lines (147 loc) • 6.93 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateBugADOHelper = void 0;
const axios_retry_1 = __importDefault(require("axios-retry"));
const crypto_1 = __importDefault(require("crypto"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const axios_1 = __importDefault(require("axios"));
//import { extractReproSteps } from './BugUtilities/extractReproSteps';
//import { getMostRecentFile } from './BugUtilities/getMostRecentFile';
const moduleUserMapping_1 = require("./moduleUserMapping");
class CreateBugADOHelper {
//private httpsAgent: https.Agent;
constructor(azureUrl, adoProjectName, initialMapping = {}) {
this.azureUrl = azureUrl;
this.adoProjectName = adoProjectName;
this.moduleUserMapping = new moduleUserMapping_1.ModuleUserMapping(initialMapping);
//this.httpsAgent = new https.Agent({ keepAlive: true });
(0, axios_retry_1.default)(axios_1.default, { retries: 3 }); // Retry up to 3 times
}
decryptPAT(encryptedData, iv, key) {
const algorithm = 'aes-256-cbc';
const decipher = crypto_1.default.createDecipheriv(algorithm, Buffer.from(key, 'hex'), Buffer.from(iv, 'hex'));
let decrypted = decipher.update(Buffer.from(encryptedData, 'hex'));
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
async createBugInADO(moduleName, bugTitle, bugDescription, steps, failedStep, attachmentDirPath, userDetails) {
const decryptedPAT = this.decryptPAT(userDetails.encryptedData, userDetails.iv, userDetails.key);
const auth = Buffer.from(`:${decryptedPAT}`).toString('base64');
const assignedTo = this.moduleUserMapping.getUserForModule(moduleName);
if (!assignedTo) {
throw new Error(`No user found for module: ${moduleName}`);
}
let attachmentUrls = [];
if (attachmentDirPath) {
const resolvedDirPath = path_1.default.resolve(attachmentDirPath);
console.log(`Scanning directory for attachments: ${resolvedDirPath}`);
if (fs_1.default.existsSync(resolvedDirPath)) {
const files = fs_1.default.readdirSync(resolvedDirPath);
if (files.length > 0) {
for (const file of files) {
const filePath = path_1.default.join(resolvedDirPath, file);
try {
const attachmentUrl = await this.uploadAttachment(auth, filePath);
attachmentUrls.push(attachmentUrl);
}
catch (uploadError) {
console.error(`Failed to upload attachment ${file}:`, uploadError);
}
}
}
else {
console.log(`No files found in the directory: ${resolvedDirPath}`);
}
}
else {
console.error(`Directory not found: ${resolvedDirPath}`);
}
}
const formattedReproSteps = `
### Steps to Reproduce:
${steps
.map((step, index) => {
if (step.step === failedStep) {
return null; // Exclude the failed step from the "Passed" list
}
return `**Step ${index + 1}:** - ${step.status}`;
})
.filter(Boolean)
.join('\n')}
---
### Failed Step:
**Step ${steps.findIndex(step => step.step === failedStep) + 1}: ${failedStep}**
`;
const createBugUrl = `${this.azureUrl}/${this.adoProjectName}/_apis/wit/workitems/$Bug?api-version=6.0`;
const bugPayload = [
{ op: 'add', path: '/fields/System.Title', value: bugTitle },
{ op: 'add', path: '/fields/Microsoft.VSTS.TCM.ReproSteps', value: formattedReproSteps },
{ op: 'add', path: '/fields/System.Description', value: bugDescription },
{ op: 'add', path: '/fields/System.AssignedTo', value: assignedTo },
{ op: 'add', path: '/fields/System.Tags', value: 'Automation' }
];
for (const attachmentUrl of attachmentUrls) {
bugPayload.push({
op: 'add',
path: '/relations/-',
value: JSON.stringify({
rel: 'AttachedFile',
url: attachmentUrl,
attributes: { comment: 'Attached file for debugging' },
}),
});
}
try {
const createBugResponse = await axios_1.default.post(createBugUrl, bugPayload, {
headers: {
'Content-Type': 'application/json-patch+json',
Authorization: `Basic ${auth}`,
},
timeout: 60000,
});
if (!createBugResponse || !createBugResponse.data || typeof createBugResponse.data.id !== 'number') {
throw new Error('Bug creation response is invalid or missing required fields.');
}
const bugId = createBugResponse.data.id;
console.log(`Bug created successfully with ID: ${bugId}`);
}
catch (error) {
console.error('Error creating bug in Azure DevOps:', error);
throw new Error('Failed to create bug in Azure DevOps.');
}
}
async uploadAttachment(auth, filePath) {
const fileName = path_1.default.basename(filePath);
const fileContent = fs_1.default.readFileSync(filePath);
const uploadUrl = `${this.azureUrl}/${this.adoProjectName}/_apis/wit/attachments?fileName=${fileName}&api-version=6.0`;
try {
const response = await axios_1.default.post(uploadUrl, fileContent, {
headers: {
'Content-Type': 'application/octet-stream',
Authorization: `Basic ${auth}`,
},
//httpsAgent: this.httpsAgent,
});
if (response && response.data && typeof response.data === 'object' && 'url' in response.data) {
if (typeof response.data.url === 'string') {
return response.data.url;
}
else {
throw new Error('Attachment URL is not a string.');
}
}
else {
throw new Error('Unexpected response format.');
}
}
catch (error) {
console.error('Error uploading attachment:', error);
throw new Error('Failed to upload attachment.');
}
}
}
exports.CreateBugADOHelper = CreateBugADOHelper;