UNPKG

7.6 kBJavaScriptView Raw
1(function(request, Joi, Promise, util, lodash, logger) {
2 'use strict';
3
4 var optionsValidation = Joi.object({
5 endpoint: Joi.string().min(1).optional().example('https://api.codacy.com/2.0/coverage/:commitId/:language')
6 });
7 var tokenValidation = Joi.string().required().min(1).example('1234567890');//TODO: Revisit this validation to see if we can better validate the values
8 var commitIdValidation = Joi.string().required().min(1).example('1234567890'); //TODO: Revisit this validation to see if we can better validate the values
9 var accountTokenValidation = Joi.string().required().min(1).example('1234567890');
10 var usernameValidation = Joi.string().required().min(1).example('1234567890');
11 var projectNameValidation = Joi.string().required().min(1).example('1234567890');
12 var coverageDataValidation = Joi.object({
13 total: Joi.number().integer().required().min(0).max(100),
14 fileReports: Joi.array().required().items(Joi.object({
15 filename: Joi.string().required().min(1),
16 total: Joi.number().integer().required().min(0).max(100),
17 coverage: Joi.object().pattern(/\d/, Joi.number().integer().min(0))
18 }).required())
19 }).example({total: 50, fileReports: [{filename: 'filename', total: 10, coverage: {1: 1, 2: 3}}]});
20
21 var languageMap = {
22 js: 'javascript',
23 jsx: 'javascript',
24 ts: 'typescript',
25 tsx: 'typescript',
26 coffee: 'coffeescript',
27 java: 'java'
28 };
29
30 function sendByLanguage(endpoint, commitId, token, data, accountToken, username, projectName) {
31 var reportsByLanguage = lodash.groupBy(data.fileReports, function(elem) {
32 return languageMap[lodash.head(lodash.takeRight(elem.filename.split('.'), 1))] || 'javascript';
33 });
34
35 var languageResponses = lodash.map(reportsByLanguage, function(fileReports, language) {
36
37 var weighedCoverage = lodash.reduce(fileReports, function(accom, elem) {
38 return accom + (elem.total * Object.keys(elem.coverage).length);
39 }, 0);
40
41 var coveredLines = lodash.reduce(fileReports, function(accom, elem) {
42 return accom + Object.keys(elem.coverage).length;
43 }, 0);
44
45 var finalCoverage = weighedCoverage / coveredLines;
46
47 var dataPerLanguage = lodash.clone(data);
48 dataPerLanguage.fileReports = fileReports;
49 dataPerLanguage.total = Math.floor(finalCoverage);
50
51 return sendLanguage(endpoint, commitId, language, token, dataPerLanguage, accountToken, username, projectName);
52 });
53
54 return Promise.all(languageResponses)
55 .then(function(errs) {
56 errs = lodash.filter(errs, function(e) {
57 return !lodash.isUndefined(e)
58 });
59
60 if (errs.length) {
61 return Promise.reject(errs[0]);
62 }
63
64 logger.trace('All languages sent successfully');
65 return Promise.resolve();
66 }, function(err) {
67 logger.trace('Failed to send some languages');
68 return Promise.reject(err);
69 });
70 }
71
72
73 function sendForLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName) {
74 return sendLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName)
75 .then(function(err) {
76 if (err) {
77 return Promise.reject(err);
78 }
79 return Promise.resolve();
80 }, function(err) {
81 return Promise.reject(err);
82 });
83 }
84
85 function sendLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName) {
86 var url = endpoint.replace(':commitId', commitId).replace(':language', language);
87 // jscs:disable
88 var headers = accountToken ? {api_token: accountToken} : {project_token: token};
89 // jscs:enable
90 if (accountToken) {
91 url = url.replace(':username', username).replace(':projectName', projectName);
92 }
93
94 logger.trace(util.format('Sending POST to %s', url));
95 return request({
96 url: url,
97 method: 'POST',
98 json: data,
99 headers: headers,
100 resolveWithFullResponse: true
101 }).then(function(res) {
102 if (res.statusCode !== 200) {
103 var err = new Error(util.format('Expected Status Code of 200, but got [%s]', res.statusCode));
104 logger.error(util.format('Status Code [%s] - Error [%j]', res.statusCode, res.error));
105 return Promise.reject(err);
106 }
107 logger.debug('Successfully sent coverage data');
108 return Promise.resolve();
109 }, function(res) {
110 var err = new Error(util.format('Expected Successful Status Code, but got [%s]', res.statusCode));
111 logger.error(util.format('Status Code [%s] - Error [%j]', res.statusCode, res.error));
112 return Promise.reject(err);
113 });
114 }
115
116 module.exports = function(options) {
117 logger.trace(util.format('Creating reporter for %j', options));
118 var optionsValid = Joi.validate(options, optionsValidation, {
119 stripUnknown: true
120 });
121
122 if (optionsValid.error) {
123 logger.error(optionsValid.error);
124 throw optionsValid.error;
125 }
126
127 var endpointPostfix = options.accountToken ? '/2.0/:username/:projectName/commit/:commitId/coverage/:language' : '/2.0/coverage/:commitId/:language';
128
129 var endpoint = (options.endpoint || 'https://api.codacy.com') + endpointPostfix;
130
131 logger.debug('Setting up reporter communicating to: ' + endpoint);
132
133 return {
134 sendCoverage: function sendCoverage(token, commitId, language, data, accountToken, username, projectName) {
135 logger.trace(util.format('Sending Coverage for token [%s] and commitId [%s]', token, commitId));
136 var tokenValid = Joi.validate(token, tokenValidation);
137 var commitIdValid = Joi.validate(commitId, commitIdValidation);
138 var dataValid = Joi.validate(data, coverageDataValidation, {
139 stripUnknown: true
140 });
141 var validationErr = commitIdValid.error || dataValid.error;
142
143 if (accountToken) {
144 var accountTokenValid = Joi.validate(accountToken, accountTokenValidation);
145 var usernameValid = Joi.validate(username, usernameValidation);
146 var projectNameValid = Joi.validate(projectName, projectNameValidation);
147
148 validationErr = validationErr || accountTokenValid.error || usernameValid.error || projectNameValid.error;
149 } else {
150 validationErr = validationErr || tokenValid.error;
151 }
152
153 if (validationErr) {
154 logger.error(validationErr);
155 return Promise.reject(validationErr);
156 }
157
158 if (language) {
159 return sendForLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName);
160 }
161
162 return sendByLanguage(endpoint, commitId, token, data, accountToken, username, projectName);
163 }
164 };
165 };
166}(require('request-promise'), require('joi'), require('bluebird'), require('util'), require('lodash'), require('./logger')()));