diff --git a/lib/issues2eslint.js b/lib/issues2eslint.js index b86e6ab..751ed23 100644 --- a/lib/issues2eslint.js +++ b/lib/issues2eslint.js @@ -150,7 +150,7 @@ class MythXIssues { const sourceLocation = this.sourceMappingDecoder.atIndex(instNum, this.deployedSourceMap); assert(sourceLocation, 'sourceMappingDecoder.atIndex() should not return null'); const loc = this.sourceMappingDecoder - .convertOffsetToLineColumn(sourceLocation, lineBreakPositions); + .convertOffsetToLineColumn(sourceLocation, lineBreakPositions || []); if (loc.start) { loc.start.line++; @@ -172,7 +172,7 @@ class MythXIssues { start: parseInt(ary[0], 10), }; const loc = this.sourceMappingDecoder - .convertOffsetToLineColumn(sourceLocation, lineBreakPositions); + .convertOffsetToLineColumn(sourceLocation, lineBreakPositions || []); if (loc.start) { loc.start.line++; } @@ -271,6 +271,7 @@ function doReport(config, objects, errors, notAnalyzedContracts) { const eslintIssuesByBaseName = groupEslintIssuesByBasename(eslintIssues); const uniqueIssues = getUniqueIssues(eslintIssuesByBaseName); + printSummary(objects, uniqueIssues, config.logger); const formatter = getFormatter(config.style); const report = formatter(uniqueIssues); config.logger.info(report); @@ -317,6 +318,29 @@ function doReport(config, objects, errors, notAnalyzedContracts) { return ret; } +function printSummary(objects, uniqueIssues, logger) { + if (objects && objects.length) { + logger.info('\nMythX Report Summary'.underline.bold); + + const groupBy = 'groupId'; + const groups = objects.reduce((accum, curr) => { + const issue = uniqueIssues.find((issue) => issue.filePath === curr.buildObj.mainSource); + const issueCount = issue.errorCount + issue.warningCount; + const marking = issueCount > 0 ? '✖'.red : '✔︎'.green; + (accum[curr[groupBy]] = accum[curr[groupBy]] || []).push(` ${marking} ${issue.filePath.cyan}: ${issueCount} issues ${curr.uuid.dim.bold}`); + return accum; + }, {}); + + let count = 0; + Object.keys(groups).forEach((groupId) => { + logger.info(` ${++count}. Group ${groupId.bold.dim}:`); + Object.values(groups[groupId]).forEach((contract) => { + logger.info(contract); + }); + }); + } +} + function getFormatter(style) { const formatterName = style || 'stylish'; try { diff --git a/lib/mythXUtil.js b/lib/mythXUtil.js index bc16d4b..2e8d060 100644 --- a/lib/mythXUtil.js +++ b/lib/mythXUtil.js @@ -47,14 +47,20 @@ const buildRequestData = contractObjects => { const contractFile = contractObjects.contracts[fileKey]; Object.keys(contractFile).forEach(function(contractKey, index) { - const contractJSON = contractFile[contractKey] + const contractJSON = contractFile[contractKey]; + const sourcesToInclude = Object.keys(JSON.parse(contractJSON.metadata).sources); + const sourcesFiltered = Object.entries(allSources).filter(([filename, { ast }]) => sourcesToInclude.includes(ast.absolutePath)); + const sources = {}; + sourcesFiltered.forEach(([key, value]) => { + sources[key] = value; + }); const contract = { contractName: contractKey, bytecode: contractJSON.evm.bytecode.object, deployedBytecode: contractJSON.evm.deployedBytecode.object, sourceMap: contractJSON.evm.bytecode.sourceMap, deployedSourceMap: contractJSON.evm.deployedBytecode.sourceMap, - sources: allSources, + sources, sourcePath: fileKey }; diff --git a/mythx.js b/mythx.js index 44cdbba..1f7b2e9 100644 --- a/mythx.js +++ b/mythx.js @@ -96,9 +96,9 @@ async function getStatus(uuid, embark) { password: process.env.MYTHX_PASSWORD, ethAddress: process.env.MYTHX_USERNAME, }); - + await armletClient.login(); - + try { const results = await armletClient.getIssues(uuid.toLowerCase()); return ghettoReport(embark.logger, results); @@ -135,6 +135,7 @@ const doAnalysis = async (armletClient, config, contracts, contractNames = null, config.logger.info("Submitting '" + obj.contractName + "' for " + analyzeOpts.data.analysisMode + " analysis...") const { issues, status } = await armletClient.analyzeWithStatus(analyzeOpts); obj.uuid = status.uuid; + obj.groupId = status.groupId; if (status.status === 'Error') { return [status, null];