Skip to content
This repository was archived by the owner on Feb 19, 2020. It is now read-only.

Commit 6b7e13c

Browse files
authored
Merge pull request #49 from autodesk-forks/add-account-api-token-support
Add account api token support
2 parents 3ae9c8d + 992bb79 commit 6b7e13c

File tree

6 files changed

+106
-24
lines changed

6 files changed

+106
-24
lines changed

bin/codacy-coverage.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
.usage('[options]')
2020
.option('-f, --format [value]', 'Coverage input format')
2121
.option('-t, --token [value]', 'Codacy Project API Token')
22+
.option('-a, --accountToken [value]', 'Codacy Account Token')
23+
.option('-u, --username [value]', 'Codacy Username/Organization')
24+
.option('-n, --projectName [value]', 'Codacy Project Name')
2225
.option('-c, --commit [value]', 'Commit SHA hash')
2326
.option('-l, --language [value', 'Project Language')
2427
.option('-e, --endpoint [value]', 'Codacy API Endpoint')
@@ -32,8 +35,8 @@
3235
debug: program.debug
3336
});
3437

35-
loggerImpl.info(util.format('Started with: token [%j], commitId [%j], language [%j], endpoint [%j], format [%j], path prefix [%j], verbose [%j], debug [%j]',
36-
program.token, program.commit, program.language, program.endpoint, program.format, program.prefix, program.verbose, program.debug));
38+
loggerImpl.info(util.format('Started with: token [%j], accountToken [%j], username [%j], projectName [%j], commitId [%j], language [%j], endpoint [%j], format [%j], path prefix [%j], verbose [%j], debug [%j]',
39+
program.token, program.accountToken, program.username, program.projectName, program.commit, program.language, program.endpoint, program.format, program.prefix, program.verbose, program.debug));
3740

3841
process.stdin.on('end', function () {
3942
loggerImpl.trace('Received file through stdin');

lib/handleInput.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
opts = opts || {};
55

66
var token = opts.token || process.env.CODACY_PROJECT_TOKEN || process.env.CODACY_REPO_TOKEN;
7+
var accountToken = opts.accountToken || process.env.CODACY_ACCOUNT_TOKEN;
8+
var username = opts.username;
9+
var projectName = opts.projectName;
710
var commit = opts.commit;
811
var format = opts.format || 'lcov';
912
var pathPrefix = opts.prefix || '';
@@ -15,21 +18,31 @@
1518
debug: opts.debug
1619
});
1720

18-
if (!token) {
21+
if (!token && !accountToken) {
1922
return Promise.reject(new Error('Token is required'));
2023
}
2124

22-
loggerImpl.info(util.format('Handling input for: token [%j], commitId [%j], language [%j], endpoint [%j], format [%j], path prefix [%j], verbose [%j], debug [%j]',
23-
token, commit, language, opts.endpoint, format, pathPrefix, opts.verbose, opts.debug));
25+
if (accountToken) {
26+
if (!username) {
27+
return Promise.reject(new Error('When using an account token, a username is required.'));
28+
}
29+
if (!projectName) {
30+
return Promise.reject(new Error('When using an account token, a project name is required.'));
31+
}
32+
}
33+
34+
loggerImpl.info(util.format('Handling input for: token [%j], accountToken [%j], username [%j], projectName [%j], commitId [%j], language [%j], endpoint [%j], format [%j], path prefix [%j], verbose [%j], debug [%j]',
35+
token, accountToken, username, projectName, commit, language, opts.endpoint, format, pathPrefix, opts.verbose, opts.debug));
2436

2537
// Parse the coverage data for the given format and retrieve the commit id if we don't have it.
2638
return Promise.all([parser.getParser(format).parse(pathPrefix, input), getGitData.getCommitId(commit)]).spread(function (parsedCoverage, commitId) {
2739
// Now that we've parse the coverage data to the correct format, send it to Codacy.
2840
loggerImpl.trace(parsedCoverage);
2941
loggerImpl.debug('Sending coverage');
3042
return reporter({
31-
endpoint: opts.endpoint
32-
}).sendCoverage(token, commitId, language, parsedCoverage);
43+
endpoint: opts.endpoint,
44+
accountToken: accountToken
45+
}).sendCoverage(token, commitId, language, parsedCoverage, accountToken, username, projectName);
3346
});
3447
};
3548
}(require('./coverageParser'), require('./reporter'), require('./getGitData'), require('./logger'), require('bluebird'), require('util')));

lib/reporter.js

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
});
77
var tokenValidation = Joi.string().required().min(1).example('1234567890');//TODO: Revisit this validation to see if we can better validate the values
88
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');
912
var coverageDataValidation = Joi.object({
1013
total: Joi.number().integer().required().min(0).max(100),
1114
fileReports: Joi.array().required().items(Joi.object({
@@ -23,7 +26,7 @@
2326
coffee: 'coffeescript'
2427
};
2528

26-
function sendByLanguage(endpoint, commitId, token, data) {
29+
function sendByLanguage(endpoint, commitId, token, data, accountToken, username, projectName) {
2730
var reportsByLanguage = lodash.groupBy(data.fileReports, function(elem) {
2831
return languageMap[lodash.head(lodash.takeRight(elem.filename.split('.'), 1))] || 'javascript';
2932
});
@@ -44,7 +47,7 @@
4447
dataPerLanguage.fileReports = fileReports;
4548
dataPerLanguage.total = Math.floor(finalCoverage);
4649

47-
return sendLanguage(endpoint, commitId, language, token, dataPerLanguage);
50+
return sendLanguage(endpoint, commitId, language, token, dataPerLanguage, accountToken, username, projectName);
4851
});
4952

5053
return Promise.all(languageResponses)
@@ -65,8 +68,9 @@
6568
});
6669
}
6770

68-
function sendForLanguage(endpoint, commitId, language, token, data) {
69-
return sendLanguage(endpoint, commitId, language, token, data)
71+
72+
function sendForLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName) {
73+
return sendLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName)
7074
.then(function(err) {
7175
if (err) {
7276
return Promise.reject(err);
@@ -77,18 +81,21 @@
7781
});
7882
}
7983

80-
function sendLanguage(endpoint, commitId, language, token, data) {
84+
function sendLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName) {
8185
var url = endpoint.replace(':commitId', commitId).replace(':language', language);
86+
// jscs:disable
87+
var headers = accountToken ? {api_token: accountToken} : {project_token: token};
88+
// jscs:enable
89+
if (accountToken) {
90+
url = url.replace(':username', username).replace(':projectName', projectName);
91+
}
92+
8293
logger.trace(util.format('Sending POST to %s', url));
8394
return request({
8495
url: url,
8596
method: 'POST',
8697
json: data,
87-
headers: {
88-
// jscs:disable
89-
project_token: token
90-
// jscs:enable
91-
},
98+
headers: headers,
9299
resolveWithFullResponse: true
93100
}).then(function(res) {
94101
if (res.statusCode !== 200) {
@@ -116,29 +123,42 @@
116123
throw optionsValid.error;
117124
}
118125

119-
var endpoint = (options.endpoint || 'https://api.codacy.com') + '/2.0/coverage/:commitId/:language';
126+
var endpointPostfix = options.accountToken ? '/2.0/:username/:projectName/commit/:commitId/coverage/:language' : '/2.0/coverage/:commitId/:language';
127+
128+
var endpoint = (options.endpoint || 'https://api.codacy.com') + endpointPostfix;
129+
120130
logger.debug('Setting up reporter communicating to: ' + endpoint);
121131

122132
return {
123-
sendCoverage: function sendCoverage(token, commitId, language, data) {
133+
sendCoverage: function sendCoverage(token, commitId, language, data, accountToken, username, projectName) {
124134
logger.trace(util.format('Sending Coverage for token [%s] and commitId [%s]', token, commitId));
125135
var tokenValid = Joi.validate(token, tokenValidation);
126136
var commitIdValid = Joi.validate(commitId, commitIdValidation);
127137
var dataValid = Joi.validate(data, coverageDataValidation, {
128138
stripUnknown: true
129139
});
130-
var validationErr = tokenValid.error || commitIdValid.error || dataValid.error;
140+
var validationErr = commitIdValid.error || dataValid.error;
141+
142+
if (accountToken) {
143+
var accountTokenValid = Joi.validate(accountToken, accountTokenValidation);
144+
var usernameValid = Joi.validate(username, usernameValidation);
145+
var projectNameValid = Joi.validate(projectName, projectNameValidation);
146+
147+
validationErr = validationErr || accountTokenValid.error || usernameValid.error || projectNameValid.error;
148+
} else {
149+
validationErr = validationErr || tokenValid.error;
150+
}
131151

132152
if (validationErr) {
133153
logger.error(validationErr);
134154
return Promise.reject(validationErr);
135155
}
136156

137157
if (language) {
138-
return sendForLanguage(endpoint, commitId, language, token, data);
158+
return sendForLanguage(endpoint, commitId, language, token, data, accountToken, username, projectName);
139159
}
140160

141-
return sendByLanguage(endpoint, commitId, token, data);
161+
return sendByLanguage(endpoint, commitId, token, data, accountToken, username, projectName);
142162
}
143163
};
144164
};

test/cli.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
return done(new Error('Should return with error'));
6363
}
6464

65-
expect(res).to.match(/Started with: token \["1234"], commitId \["4321"], language \[undefined], endpoint \["something"], format \["lcov"], path prefix \["asdf\/"], verbose \[true], debug \[true]/);
66-
expect(res).to.match(/Handling input for: token \["1234"], commitId \["4321"], language \[undefined], endpoint \["something"], format \["lcov"], path prefix \["asdf\/"], verbose \[true], debug \[true]/);
65+
expect(res).to.match(/Started with: token \["1234"], accountToken \[undefined], username \[undefined], projectName \[undefined], commitId \["4321"], language \[undefined], endpoint \["something"], format \["lcov"], path prefix \["asdf\/"], verbose \[true], debug \[true]/);
66+
expect(res).to.match(/Handling input for: token \["1234"], accountToken \[undefined], username \[undefined], projectName \[undefined], commitId \["4321"], language \[undefined], endpoint \["something"], format \["lcov"], path prefix \["asdf\/"], verbose \[true], debug \[true]/);
6767
expect(err.code).to.equal(1);
6868
done();
6969
});

test/helper.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,25 @@
4545
});
4646
}
4747

48+
function setupMockAccountApiEndpoint(apiToken, commitId, username, projectName, bodyValidator) {
49+
return new Promise(function (resolve) {
50+
expect(apiToken).to.be.ok();
51+
expect(commitId).to.be.ok();
52+
expect(username).to.be.ok();
53+
expect(projectName).to.be.ok();
54+
expect(bodyValidator).to.be.ok();
55+
return resolve(nock('https://api.codacy.com')
56+
.post('/2.0/' + username + '/' + projectName + '/commit/' + commitId + '/coverage' + '/javascript', function(body) {
57+
var result = bodyValidator.validate(body);
58+
return !result.error;
59+
}).reply(200));
60+
});
61+
}
62+
4863
module.exports = {
4964
setupMockEndpoint: setupMockEndpoint,
5065
setupLangMockEndpoint: setupLangMockEndpoint,
66+
setupMockAccountApiEndpoint: setupMockAccountApiEndpoint,
5167
chai: chai,
5268
clearEnvironmentVariables: function () {
5369
process.env.CODACY_GIT_COMMIT = '';

test/reporter.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@
4949
});
5050
});
5151
});
52+
it('should be able to use the account api mock end-point', function() {
53+
return helper.setupMockAccountApiEndpoint('1234', '4321', 'username', 'project-name', bodyValidator)
54+
.then(function() {
55+
return expect(request({
56+
url: 'https://api.codacy.com/2.0/username/project-name/commit/4321/coverage/javascript',
57+
method: 'POST',
58+
json: sampleCoverageData,
59+
resolveWithFullResponse: true
60+
}).promise()).to.eventually.satisfy(function (res) {
61+
expect(res.statusCode).to.equal(200);
62+
return true;
63+
});
64+
});
65+
});
5266
it('shouldn\'t be able to create a reporter with invalid options', function () {
5367
return expect(function () {
5468
reporter({endpoint: 1});
@@ -78,6 +92,22 @@
7892
.to.eventually.be.rejectedWith(Error, 'Expected Successful Status Code, but got [418]');
7993
});
8094
});
95+
it('should be able to report data with an api token', function() {
96+
return helper.setupMockAccountApiEndpoint('1234', '4321', 'username', 'project-name', bodyValidator)
97+
.then(function() {
98+
return expect(reporter({accountToken: '1234'})
99+
.sendCoverage(null, '4321', 'javascript', sampleCoverageData, '1234', 'username', 'project-name'))
100+
.to.eventually.be.fulfilled();
101+
});
102+
});
103+
it('should not report data without a project name', function() {
104+
return helper.setupMockAccountApiEndpoint('1234', '4321', 'username', 'project-name', bodyValidator)
105+
.then(function() {
106+
return expect(reporter({accountToken: '1234'})
107+
.sendCoverage(null, '4321', 'javascript', sampleCoverageData, '1234', null, 'project-name'))
108+
.to.eventually.be.rejected();
109+
});
110+
});
81111
});
82112

83113
}(require('joi'), require('request-promise'), require('../lib/reporter'), require('./helper')));

0 commit comments

Comments
 (0)