diff --git a/services/codeclimate/codeclimate-analysis.service.js b/services/codeclimate/codeclimate-analysis.service.js index 811ceb6db1f97..e76351b6fd2e7 100644 --- a/services/codeclimate/codeclimate-analysis.service.js +++ b/services/codeclimate/codeclimate-analysis.service.js @@ -138,15 +138,19 @@ export default class CodeclimateAnalysis extends BaseJsonService { } async fetch({ user, repo }) { + const repoInfos = await fetchRepo(this, { user, repo }) + const repoInfosWithSnapshot = repoInfos.filter( + repoInfo => repoInfo.relationships.latest_default_branch_snapshot.data + ) + if (repoInfosWithSnapshot.length === 0) { + throw new NotFound({ prettyMessage: 'snapshot not found' }) + } const { id: repoId, relationships: { latest_default_branch_snapshot: { data: snapshotInfo }, }, - } = await fetchRepo(this, { user, repo }) - if (snapshotInfo === null) { - throw new NotFound({ prettyMessage: 'snapshot not found' }) - } + } = repoInfosWithSnapshot[0] const { data } = await this._requestJson({ schema, url: `https://api.codeclimate.com/v1/repos/${repoId}/snapshots/${snapshotInfo.id}`, diff --git a/services/codeclimate/codeclimate-analysis.tester.js b/services/codeclimate/codeclimate-analysis.tester.js index 9bab1043d1310..ea58bc765a835 100644 --- a/services/codeclimate/codeclimate-analysis.tester.js +++ b/services/codeclimate/codeclimate-analysis.tester.js @@ -32,6 +32,47 @@ t.create('maintainability letter') message: Joi.equal('A', 'B', 'C', 'D', 'E', 'F'), }) +t.create('issues when outer user repos query returns multiple items') + .get('/issues/angular/angular.json') + .intercept(nock => + nock('https://api.codeclimate.com', { allowUnmocked: true }) + .get('/v1/repos?github_slug=angular%2Fangular') + .reply(200, { + data: [ + { + id: '54fd4e6b6956804a10003df4', + relationships: { + latest_default_branch_snapshot: { + data: null, + }, + latest_default_branch_test_report: { + data: null, + }, + }, + }, + { + id: '54fd4e6b6956804a10003df3', + relationships: { + latest_default_branch_snapshot: { + data: { + id: '620e2b491b6a72000100ca1d', + type: 'snapshots', + }, + }, + latest_default_branch_test_report: { + data: null, + }, + }, + }, + ], + }) + ) + .networkOn() // Combined with allowUnmocked: true, this allows the inner snapshots query to go through. + .expectBadge({ + label: 'issues', + message: Joi.number().integer().positive(), + }) + t.create('maintainability letter for non-existent repo') .get('/maintainability/unknown/unknown.json') .expectBadge({ diff --git a/services/codeclimate/codeclimate-common.js b/services/codeclimate/codeclimate-common.js index 29a705aa76fff..0e919e6103d98 100644 --- a/services/codeclimate/codeclimate-common.js +++ b/services/codeclimate/codeclimate-common.js @@ -7,7 +7,6 @@ const isLetterGrade = Joi.equal('A', 'B', 'C', 'D', 'E', 'F').required() const repoSchema = Joi.object({ data: Joi.array() - .max(1) .items( Joi.object({ id: Joi.string().required(), @@ -29,17 +28,15 @@ const repoSchema = Joi.object({ }).required() async function fetchRepo(serviceInstance, { user, repo }) { - const { - data: [repoInfo], - } = await serviceInstance._requestJson({ + const { data: repoInfos } = await serviceInstance._requestJson({ schema: repoSchema, url: 'https://api.codeclimate.com/v1/repos', options: { searchParams: { github_slug: `${user}/${repo}` } }, }) - if (repoInfo === undefined) { + if (repoInfos.length === 0) { throw new NotFound({ prettyMessage: 'repo not found' }) } - return repoInfo + return repoInfos } export { keywords, isLetterGrade, fetchRepo } diff --git a/services/codeclimate/codeclimate-coverage.service.js b/services/codeclimate/codeclimate-coverage.service.js index 9b7f81eb8a416..7e764c6c5de94 100644 --- a/services/codeclimate/codeclimate-coverage.service.js +++ b/services/codeclimate/codeclimate-coverage.service.js @@ -53,15 +53,19 @@ export default class CodeclimateCoverage extends BaseJsonService { } async fetch({ user, repo }) { + const repoInfos = await fetchRepo(this, { user, repo }) + const repoInfosWithTestReport = repoInfos.filter( + repoInfo => repoInfo.relationships.latest_default_branch_test_report.data + ) + if (repoInfosWithTestReport.length === 0) { + throw new NotFound({ prettyMessage: 'test report not found' }) + } const { id: repoId, relationships: { latest_default_branch_test_report: { data: testReportInfo }, }, - } = await fetchRepo(this, { user, repo }) - if (testReportInfo === null) { - throw new NotFound({ prettyMessage: 'test report not found' }) - } + } = repoInfosWithTestReport[0] const { data } = await this._requestJson({ schema, url: `https://api.codeclimate.com/v1/repos/${repoId}/test_reports/${testReportInfo.id}`, diff --git a/services/codeclimate/codeclimate-coverage.tester.js b/services/codeclimate/codeclimate-coverage.tester.js index e8b806aa27dfc..4f5796613b051 100644 --- a/services/codeclimate/codeclimate-coverage.tester.js +++ b/services/codeclimate/codeclimate-coverage.tester.js @@ -20,6 +20,47 @@ t.create('test coverage letter') message: Joi.equal('A', 'B', 'C', 'D', 'E', 'F'), }) +t.create('test coverage when outer user repos query returns multiple items') + .get('/coverage/codeclimate/codeclimate.json') + .intercept(nock => + nock('https://api.codeclimate.com', { allowUnmocked: true }) + .get('/v1/repos?github_slug=codeclimate%2Fcodeclimate') + .reply(200, { + data: [ + { + id: '558479d6e30ba034120008a8', + relationships: { + latest_default_branch_snapshot: { + data: null, + }, + latest_default_branch_test_report: { + data: null, + }, + }, + }, + { + id: '558479d6e30ba034120008a9', + relationships: { + latest_default_branch_snapshot: { + data: null, + }, + latest_default_branch_test_report: { + data: { + id: '62110434a7160b00010b4b59', + type: 'test_reports', + }, + }, + }, + }, + ], + }) + ) + .networkOn() // Combined with allowUnmocked: true, this allows the inner test reports query to go through. + .expectBadge({ + label: 'coverage', + message: isIntegerPercentage, + }) + t.create('test coverage percentage for non-existent repo') .get('/coverage/unknown/unknown.json') .expectBadge({