2019-04-05 16:12:38 +00:00
|
|
|
/* eslint no-plusplus: 0 default-case: 0 */
|
2018-06-01 13:38:20 +00:00
|
|
|
const parse = require('github-url-from-git');
|
2018-10-29 16:18:07 +00:00
|
|
|
const URL = require('url');
|
2019-07-15 09:04:05 +00:00
|
|
|
const { logger } = require('../../logger');
|
2018-06-01 13:38:20 +00:00
|
|
|
|
2017-12-07 08:22:10 +00:00
|
|
|
module.exports = {
|
2018-11-04 17:51:23 +00:00
|
|
|
extractPackageFile,
|
2017-12-07 08:22:10 +00:00
|
|
|
};
|
|
|
|
|
2018-10-29 16:18:07 +00:00
|
|
|
function parseUrl(urlString) {
|
|
|
|
// istanbul ignore if
|
|
|
|
if (!urlString) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const url = URL.parse(urlString);
|
|
|
|
if (url.host !== 'github.com') {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const path = url.path.split('/').slice(1);
|
|
|
|
const repo = path[0] + '/' + path[1];
|
|
|
|
let currentValue = null;
|
|
|
|
if (path[2] === 'releases' && path[3] === 'download') {
|
|
|
|
currentValue = path[4];
|
|
|
|
}
|
|
|
|
if (path[2] === 'archive') {
|
|
|
|
currentValue = path[3].replace(/\.tar\.gz$/, '');
|
|
|
|
}
|
|
|
|
if (currentValue) {
|
|
|
|
return { repo, currentValue };
|
|
|
|
}
|
|
|
|
// istanbul ignore next
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-04-05 16:12:38 +00:00
|
|
|
function findBalancedParenIndex(longString) {
|
|
|
|
/**
|
|
|
|
* Minimalistic string parser with single task -> find last char in def.
|
|
|
|
* It treats [)] as the last char.
|
|
|
|
* To find needed closing parenthesis we need to increment
|
|
|
|
* nesting depth when parser feeds opening parenthesis
|
|
|
|
* if one opening parenthesis -> 1
|
|
|
|
* if two opening parenthesis -> 2
|
|
|
|
* if two opening and one closing parenthesis -> 1
|
|
|
|
* if ["""] finded then ignore all [)] until closing ["""] parsed.
|
|
|
|
* https://github.com/renovatebot/renovate/pull/3459#issuecomment-478249702
|
|
|
|
*/
|
|
|
|
let intShouldNotBeOdd = 0; // openClosePythonMultiLineComment
|
|
|
|
let parenNestingDepth = 1;
|
|
|
|
return [...longString].findIndex((char, i, arr) => {
|
|
|
|
switch (char) {
|
|
|
|
case '(':
|
|
|
|
parenNestingDepth++;
|
|
|
|
break;
|
|
|
|
case ')':
|
|
|
|
parenNestingDepth--;
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
if (i > 1 && arr.slice(i - 2, i).every(prev => char === prev))
|
|
|
|
intShouldNotBeOdd++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !parenNestingDepth && !(intShouldNotBeOdd % 2) && char === ')';
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseContent(content) {
|
2019-04-12 11:27:49 +00:00
|
|
|
return [
|
|
|
|
'container_pull',
|
|
|
|
'http_archive',
|
|
|
|
'go_repository',
|
|
|
|
'git_repository',
|
|
|
|
].reduce(
|
2019-04-05 16:12:38 +00:00
|
|
|
(acc, prefix) => [
|
|
|
|
...acc,
|
|
|
|
...content
|
|
|
|
.split(new RegExp(prefix + '\\s*\\(', 'g'))
|
|
|
|
.slice(1)
|
|
|
|
.map(base => {
|
|
|
|
const ind = findBalancedParenIndex(base);
|
|
|
|
|
|
|
|
return ind >= 0 && `${prefix}(${base.slice(0, ind)})`;
|
|
|
|
})
|
|
|
|
.filter(Boolean),
|
|
|
|
],
|
|
|
|
[]
|
2017-12-14 19:05:45 +00:00
|
|
|
);
|
2019-04-05 16:12:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function extractPackageFile(content) {
|
|
|
|
const definitions = parseContent(content);
|
|
|
|
if (!definitions.length) {
|
2017-12-14 19:05:45 +00:00
|
|
|
logger.debug('No matching WORKSPACE definitions found');
|
2018-05-03 16:09:18 +00:00
|
|
|
return null;
|
2017-12-07 08:22:10 +00:00
|
|
|
}
|
2017-12-14 19:05:45 +00:00
|
|
|
logger.debug({ definitions }, `Found ${definitions.length} definitions`);
|
|
|
|
const deps = [];
|
|
|
|
definitions.forEach(def => {
|
|
|
|
logger.debug({ def }, 'Checking bazel definition');
|
2018-11-10 20:50:17 +00:00
|
|
|
const [depType] = def.split('(', 1);
|
2019-07-24 05:19:34 +00:00
|
|
|
const dep = { depType, managerData: { def } };
|
2017-12-14 19:05:45 +00:00
|
|
|
let depName;
|
2018-11-10 20:50:17 +00:00
|
|
|
let importpath;
|
2017-12-14 19:05:45 +00:00
|
|
|
let remote;
|
2018-06-04 03:48:20 +00:00
|
|
|
let currentValue;
|
2018-11-14 12:11:35 +00:00
|
|
|
let commit;
|
2017-12-14 19:05:45 +00:00
|
|
|
let url;
|
|
|
|
let sha256;
|
2019-04-12 11:27:49 +00:00
|
|
|
let digest;
|
|
|
|
let repository;
|
|
|
|
let registry;
|
2019-03-04 05:05:10 +00:00
|
|
|
let match = def.match(/name\s*=\s*"([^"]+)"/);
|
2017-12-14 19:05:45 +00:00
|
|
|
if (match) {
|
|
|
|
[, depName] = match;
|
|
|
|
}
|
2019-04-12 11:27:49 +00:00
|
|
|
match = def.match(/digest\s*=\s*"([^"]+)"/);
|
|
|
|
if (match) {
|
|
|
|
[, digest] = match;
|
|
|
|
}
|
|
|
|
match = def.match(/registry\s*=\s*"([^"]+)"/);
|
|
|
|
if (match) {
|
|
|
|
[, registry] = match;
|
|
|
|
}
|
|
|
|
match = def.match(/repository\s*=\s*"([^"]+)"/);
|
|
|
|
if (match) {
|
|
|
|
[, repository] = match;
|
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/remote\s*=\s*"([^"]+)"/);
|
2017-12-14 19:05:45 +00:00
|
|
|
if (match) {
|
|
|
|
[, remote] = match;
|
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/tag\s*=\s*"([^"]+)"/);
|
2017-12-14 19:05:45 +00:00
|
|
|
if (match) {
|
2018-06-04 03:48:20 +00:00
|
|
|
[, currentValue] = match;
|
2017-12-14 19:05:45 +00:00
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/url\s*=\s*"([^"]+)"/);
|
2017-12-14 19:05:45 +00:00
|
|
|
if (match) {
|
|
|
|
[, url] = match;
|
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/urls\s*=\s*\[\s*"([^\]]+)",?\s*\]/);
|
2018-10-29 16:18:07 +00:00
|
|
|
if (match) {
|
|
|
|
const urls = match[1].replace(/\s/g, '').split('","');
|
|
|
|
url = urls.find(parseUrl);
|
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/commit\s*=\s*"([^"]+)"/);
|
2018-11-14 12:11:35 +00:00
|
|
|
if (match) {
|
|
|
|
[, commit] = match;
|
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/sha256\s*=\s*"([^"]+)"/);
|
2017-12-14 19:05:45 +00:00
|
|
|
if (match) {
|
|
|
|
[, sha256] = match;
|
|
|
|
}
|
2019-03-04 05:05:10 +00:00
|
|
|
match = def.match(/importpath\s*=\s*"([^"]+)"/);
|
2018-11-10 20:50:17 +00:00
|
|
|
if (match) {
|
|
|
|
[, importpath] = match;
|
|
|
|
}
|
2018-09-20 10:13:18 +00:00
|
|
|
logger.debug({ dependency: depName, remote, currentValue });
|
2019-02-25 21:35:25 +00:00
|
|
|
if (
|
|
|
|
depType === 'git_repository' &&
|
|
|
|
depName &&
|
|
|
|
remote &&
|
|
|
|
(currentValue || commit)
|
|
|
|
) {
|
2017-12-14 19:05:45 +00:00
|
|
|
dep.depName = depName;
|
2019-02-25 21:35:25 +00:00
|
|
|
if (currentValue) {
|
|
|
|
dep.currentValue = currentValue;
|
|
|
|
}
|
|
|
|
if (commit) {
|
|
|
|
dep.currentDigest = commit;
|
|
|
|
}
|
2018-06-01 13:38:20 +00:00
|
|
|
const repo = parse(remote).substring('https://github.com/'.length);
|
2019-02-04 08:41:22 +00:00
|
|
|
dep.datasource = 'github';
|
|
|
|
dep.lookupName = repo;
|
2017-12-14 19:05:45 +00:00
|
|
|
deps.push(dep);
|
|
|
|
} else if (
|
2018-11-10 20:50:17 +00:00
|
|
|
depType === 'go_repository' &&
|
|
|
|
depName &&
|
|
|
|
importpath &&
|
2018-11-14 12:11:35 +00:00
|
|
|
(currentValue || commit)
|
2018-11-10 20:50:17 +00:00
|
|
|
) {
|
|
|
|
dep.depName = depName;
|
2018-11-14 12:11:35 +00:00
|
|
|
dep.currentValue = currentValue || commit.substr(0, 7);
|
2019-02-04 08:41:22 +00:00
|
|
|
dep.datasource = 'go';
|
|
|
|
dep.lookupName = importpath;
|
2018-11-29 07:39:45 +00:00
|
|
|
if (remote) {
|
|
|
|
const remoteMatch = remote.match(
|
|
|
|
/https:\/\/github\.com(?:.*\/)(([a-zA-Z]+)([-])?([a-zA-Z]+))/
|
|
|
|
);
|
|
|
|
if (remoteMatch && remoteMatch[0].length === remote.length) {
|
2019-02-04 08:41:22 +00:00
|
|
|
dep.lookupName = remote.replace('https://', '');
|
2018-11-29 07:39:45 +00:00
|
|
|
} else {
|
|
|
|
dep.skipReason = 'unsupported-remote';
|
|
|
|
}
|
|
|
|
}
|
2018-11-14 12:11:35 +00:00
|
|
|
if (commit) {
|
2018-11-18 21:27:20 +00:00
|
|
|
dep.currentValue = 'v0.0.0';
|
2018-11-14 12:11:35 +00:00
|
|
|
dep.currentDigest = commit;
|
2018-11-19 06:18:13 +00:00
|
|
|
dep.currentDigestShort = commit.substr(0, 7);
|
2018-11-14 12:11:35 +00:00
|
|
|
dep.digestOneAndOnly = true;
|
|
|
|
}
|
2018-11-10 20:50:17 +00:00
|
|
|
deps.push(dep);
|
|
|
|
} else if (
|
|
|
|
depType === 'http_archive' &&
|
2017-12-14 19:05:45 +00:00
|
|
|
depName &&
|
2018-10-29 16:18:07 +00:00
|
|
|
parseUrl(url) &&
|
|
|
|
sha256
|
2017-12-14 19:05:45 +00:00
|
|
|
) {
|
2018-10-29 16:18:07 +00:00
|
|
|
const parsedUrl = parseUrl(url);
|
2017-12-14 19:05:45 +00:00
|
|
|
dep.depName = depName;
|
2018-10-29 16:18:07 +00:00
|
|
|
dep.repo = parsedUrl.repo;
|
2019-03-04 06:48:58 +00:00
|
|
|
if (parsedUrl.currentValue.match(/^[a-f0-9]{40}$/i)) {
|
|
|
|
dep.currentDigest = parsedUrl.currentValue;
|
|
|
|
} else {
|
|
|
|
dep.currentValue = parsedUrl.currentValue;
|
|
|
|
}
|
2019-02-04 08:41:22 +00:00
|
|
|
dep.datasource = 'github';
|
|
|
|
dep.lookupName = dep.repo;
|
|
|
|
dep.lookupType = 'releases';
|
2017-12-14 19:05:45 +00:00
|
|
|
deps.push(dep);
|
2019-04-12 11:27:49 +00:00
|
|
|
} else if (
|
|
|
|
depType === 'container_pull' &&
|
|
|
|
currentValue &&
|
|
|
|
digest &&
|
|
|
|
repository &&
|
|
|
|
registry
|
|
|
|
) {
|
|
|
|
dep.currentDigest = digest;
|
|
|
|
dep.currentValue = currentValue;
|
|
|
|
dep.depName = depName;
|
|
|
|
dep.datasource = 'docker';
|
2019-06-24 16:49:23 +00:00
|
|
|
dep.versionScheme = 'docker';
|
2019-04-12 11:27:49 +00:00
|
|
|
dep.lookupName = repository;
|
|
|
|
deps.push(dep);
|
2017-12-14 19:05:45 +00:00
|
|
|
} else {
|
|
|
|
logger.info(
|
|
|
|
{ def },
|
|
|
|
'Failed to find dependency in bazel WORKSPACE definition'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2018-05-03 16:09:18 +00:00
|
|
|
if (!deps.length) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return { deps };
|
2017-12-07 08:22:10 +00:00
|
|
|
}
|