renovate/lib/util/host-rules.ts

158 lines
4 KiB
TypeScript
Raw Normal View History

import URL from 'url';
import merge from 'deepmerge';
import { logger } from '../logger';
2018-07-06 05:26:36 +00:00
export interface HostRule {
hostType?: string;
domainName?: string;
hostName?: string;
2019-07-17 08:14:56 +00:00
json?: true;
baseUrl?: string;
token?: string;
username?: string;
password?: string;
2019-07-17 08:14:56 +00:00
timeout?: number;
}
let hostRules: HostRule[] = [];
export function add(params: HostRule) {
if (params.domainName && params.hostName) {
throw new Error('hostRules cannot contain both a domainName and hostName');
2018-07-06 05:26:36 +00:00
}
if (params.domainName && params.baseUrl) {
throw new Error('hostRules cannot contain both a domainName and baseUrl');
2018-07-06 05:26:36 +00:00
}
if (params.hostName && params.baseUrl) {
throw new Error('hostRules cannot contain both a hostName and baseUrl');
2018-07-06 05:26:36 +00:00
}
hostRules.push(params);
}
export interface HostRuleSearch {
hostType?: string;
2019-07-17 08:14:56 +00:00
url?: string;
}
function isEmptyRule(rule: HostRule) {
return !rule.hostType && !rule.domainName && !rule.hostName && !rule.baseUrl;
}
function isHostTypeRule(rule: HostRule) {
return rule.hostType && !rule.domainName && !rule.hostName && !rule.baseUrl;
}
function isDomainNameRule(rule: HostRule) {
return !rule.hostType && rule.domainName;
}
function isHostNameRule(rule: HostRule) {
return !rule.hostType && rule.hostName;
}
function isBaseUrlRule(rule: HostRule) {
return !rule.hostType && rule.baseUrl;
}
function isMultiRule(rule: HostRule) {
return rule.hostType && (rule.domainName || rule.hostName || rule.baseUrl);
}
function matchesHostType(rule: HostRule, search: HostRuleSearch) {
return rule.hostType === search.hostType;
}
function matchesDomainName(rule: HostRule, search: HostRuleSearch) {
const hostname = search.url && URL.parse(search.url).hostname;
return (
search.url &&
rule.domainName &&
hostname &&
hostname.endsWith(rule.domainName)
);
}
function matchesHostName(rule: HostRule, search: HostRuleSearch) {
return (
search.url &&
rule.hostName &&
URL.parse(search.url).hostname === rule.hostName
);
}
function matchesBaseUrl(rule: HostRule, search: HostRuleSearch) {
return search.url && rule.baseUrl && search.url.startsWith(rule.baseUrl);
}
export function find(search: HostRuleSearch) {
if (!(search.hostType || search.url)) {
logger.warn({ search }, 'Invalid hostRules search');
return {};
2018-09-13 04:48:08 +00:00
}
let res = ({} as any) as HostRule;
// First, apply empty rule matches
hostRules
.filter(rule => isEmptyRule(rule))
.forEach(rule => {
res = merge(res, rule);
});
// Next, find hostType-only matches
hostRules
.filter(rule => isHostTypeRule(rule) && matchesHostType(rule, search))
.forEach(rule => {
res = merge(res, rule);
});
// Next, find domainName-only matches
hostRules
.filter(rule => isDomainNameRule(rule) && matchesDomainName(rule, search))
.forEach(rule => {
res = merge(res, rule);
});
// Next, find hostName-only matches
hostRules
.filter(rule => isHostNameRule(rule) && matchesHostName(rule, search))
.forEach(rule => {
res = merge(res, rule);
});
// Next, find baseUrl-only matches
hostRules
.filter(rule => isBaseUrlRule(rule) && matchesBaseUrl(rule, search))
.forEach(rule => {
res = merge(res, rule);
});
// Finally, find combination matches
hostRules
.filter(
rule =>
isMultiRule(rule) &&
matchesHostType(rule, search) &&
(matchesDomainName(rule, search) ||
matchesHostName(rule, search) ||
matchesBaseUrl(rule, search))
)
.forEach(rule => {
res = merge(res, rule);
});
delete res.hostType;
delete res.domainName;
delete res.hostName;
delete res.baseUrl;
return res;
2018-07-06 05:26:36 +00:00
}
export function hosts({ hostType }: { hostType: string }) {
return hostRules
.filter(rule => rule.hostType === hostType)
.map(rule => {
if (rule.hostName) return rule.hostName;
if (rule.baseUrl) return URL.parse(rule.baseUrl).hostname;
return null;
})
.filter(Boolean);
2018-07-06 05:26:36 +00:00
}
export function clear() {
hostRules = [];
2018-07-06 05:26:36 +00:00
}