refactor: encapsulate hostRulesFromEnv (#12277)

This commit is contained in:
Florian Greinacher 2021-10-23 08:38:23 +02:00 committed by GitHub
parent a0b8b52a75
commit 42fd18d101
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 184 additions and 54 deletions

View file

@ -0,0 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`workers/global/config/parse/host-rules-from-env regression test for #10937 1`] = `
Array [
Object {
"hostType": "git-tags",
"matchHost": "gitlab.example-domain.net",
"password": "some-password",
"username": "some-user",
},
]
`;
exports[`workers/global/config/parse/host-rules-from-env supports datasource env token 1`] = `
Array [
Object {
"hostType": "pypi",
"token": "some-token",
},
]
`;
exports[`workers/global/config/parse/host-rules-from-env supports docker username/password 1`] = `
Array [
Object {
"hostType": "docker",
"password": "some-password",
"username": "some-username",
},
]
`;
exports[`workers/global/config/parse/host-rules-from-env supports domain and host names with case insensitivity 1`] = `
Array [
Object {
"hostType": "github-tags",
"matchHost": "github.com",
"token": "some-token",
},
Object {
"hostType": "pypi",
"matchHost": "my.custom.host",
"password": "some-password",
},
]
`;
exports[`workers/global/config/parse/host-rules-from-env supports password-only 1`] = `
Array [
Object {
"hostType": "npm",
"password": "some-password",
},
]
`;

View file

@ -3,9 +3,8 @@ import is from '@sindresorhus/is';
import { getOptions } from '../../../../config/options'; import { getOptions } from '../../../../config/options';
import type { AllConfig, RenovateOptions } from '../../../../config/types'; import type { AllConfig, RenovateOptions } from '../../../../config/types';
import { PlatformId } from '../../../../constants'; import { PlatformId } from '../../../../constants';
import { getDatasourceList } from '../../../../datasource';
import { logger } from '../../../../logger'; import { logger } from '../../../../logger';
import type { HostRule } from '../../../../types'; import { hostRulesFromEnv } from './host-rules-from-env';
function normalizePrefixes( function normalizePrefixes(
env: NodeJS.ProcessEnv, env: NodeJS.ProcessEnv,
@ -120,58 +119,7 @@ export function getConfig(inputEnv: NodeJS.ProcessEnv): AllConfig {
}); });
} }
const datasources = new Set(getDatasourceList()); config.hostRules = [...config.hostRules, ...hostRulesFromEnv(env)];
const fields = ['token', 'username', 'password'];
const hostRules: HostRule[] = [];
const npmEnvPrefixes = ['npm_config_', 'npm_lifecycle_', 'npm_package_'];
for (const envName of Object.keys(env).sort()) {
if (npmEnvPrefixes.some((prefix) => envName.startsWith(prefix))) {
logger.trace('Ignoring npm env: ' + envName);
continue; // eslint-disable-line no-continue
}
// Double underscore __ is used in place of hyphen -
const splitEnv = envName.toLowerCase().replace(/__/g, '-').split('_');
const hostType = splitEnv.shift();
if (datasources.has(hostType)) {
const suffix = splitEnv.pop();
if (fields.includes(suffix)) {
let matchHost: string;
const rule: HostRule = {};
rule[suffix] = env[envName];
if (splitEnv.length === 0) {
// host-less rule
} else if (splitEnv.length === 1) {
logger.warn(`Cannot parse ${envName} env`);
continue; // eslint-disable-line no-continue
} else {
matchHost = splitEnv.join('.');
}
const existingRule = hostRules.find(
(hr) => hr.hostType === hostType && hr.matchHost === matchHost
);
logger.debug(`Converting ${envName} into a global host rule`);
if (existingRule) {
// Add current field to existing rule
existingRule[suffix] = env[envName];
} else {
// Create a new rule
const newRule: HostRule = {
hostType,
};
if (matchHost) {
newRule.matchHost = matchHost;
}
newRule[suffix] = env[envName];
hostRules.push(newRule);
}
}
}
}
config.hostRules = [...config.hostRules, ...hostRules];
// These env vars are deprecated and deleted to make sure they're not used // These env vars are deprecated and deleted to make sure they're not used
const unsupportedEnv = [ const unsupportedEnv = [

View file

@ -0,0 +1,70 @@
import { hostRulesFromEnv } from './host-rules-from-env';
describe('workers/global/config/parse/host-rules-from-env', () => {
it('supports docker username/password', () => {
const envParam: NodeJS.ProcessEnv = {
DOCKER_USERNAME: 'some-username',
DOCKER_PASSWORD: 'some-password',
};
expect(hostRulesFromEnv(envParam)).toMatchSnapshot([
{
hostType: 'docker',
password: 'some-password',
username: 'some-username',
},
]);
});
it('supports password-only', () => {
const envParam: NodeJS.ProcessEnv = {
NPM_PASSWORD: 'some-password',
};
expect(hostRulesFromEnv(envParam)).toMatchSnapshot([
{ hostType: 'npm', password: 'some-password' },
]);
});
it('supports domain and host names with case insensitivity', () => {
const envParam: NodeJS.ProcessEnv = {
GITHUB__TAGS_GITHUB_COM_TOKEN: 'some-token',
pypi_my_CUSTOM_HOST_passWORD: 'some-password',
};
expect(hostRulesFromEnv(envParam)).toMatchSnapshot([
{ matchHost: 'github.com', token: 'some-token' },
{ matchHost: 'my.custom.host', password: 'some-password' },
]);
});
it('regression test for #10937', () => {
const envParam: NodeJS.ProcessEnv = {
GIT__TAGS_GITLAB_EXAMPLE__DOMAIN_NET_USERNAME: 'some-user',
GIT__TAGS_GITLAB_EXAMPLE__DOMAIN_NET_PASSWORD: 'some-password',
};
expect(hostRulesFromEnv(envParam)).toMatchSnapshot([
{
hostType: 'git-tags',
matchHost: 'gitlab.example-domain.net',
password: 'some-password',
username: 'some-user',
},
]);
});
it('supports datasource env token', () => {
const envParam: NodeJS.ProcessEnv = {
PYPI_TOKEN: 'some-token',
};
expect(hostRulesFromEnv(envParam)).toMatchSnapshot([
{ hostType: 'pypi', token: 'some-token' },
]);
});
it('rejects incomplete datasource env token', () => {
const envParam: NodeJS.ProcessEnv = {
PYPI_FOO_TOKEN: 'some-token',
};
expect(hostRulesFromEnv(envParam)).toHaveLength(0);
});
it('rejects npm env', () => {
const envParam: NodeJS.ProcessEnv = {
npm_package_devDependencies__types_registry_auth_token: '4.2.0',
};
expect(hostRulesFromEnv(envParam)).toHaveLength(0);
});
});

View file

@ -0,0 +1,57 @@
import { getDatasourceList } from '../../../../datasource';
import { logger } from '../../../../logger';
import type { HostRule } from '../../../../types';
export function hostRulesFromEnv(env: NodeJS.ProcessEnv): HostRule[] {
const datasources = new Set(getDatasourceList());
const fields = ['token', 'username', 'password'];
const hostRules: HostRule[] = [];
const npmEnvPrefixes = ['npm_config_', 'npm_lifecycle_', 'npm_package_'];
for (const envName of Object.keys(env).sort()) {
if (npmEnvPrefixes.some((prefix) => envName.startsWith(prefix))) {
logger.trace('Ignoring npm env: ' + envName);
continue; // eslint-disable-line no-continue
}
// Double underscore __ is used in place of hyphen -
const splitEnv = envName.toLowerCase().replace(/__/g, '-').split('_');
const hostType = splitEnv.shift();
if (datasources.has(hostType)) {
const suffix = splitEnv.pop();
if (fields.includes(suffix)) {
let matchHost: string;
const rule: HostRule = {};
rule[suffix] = env[envName];
if (splitEnv.length === 0) {
// host-less rule
} else if (splitEnv.length === 1) {
logger.warn(`Cannot parse ${envName} env`);
continue; // eslint-disable-line no-continue
} else {
matchHost = splitEnv.join('.');
}
const existingRule = hostRules.find(
(hr) => hr.hostType === hostType && hr.matchHost === matchHost
);
logger.debug(`Converting ${envName} into a global host rule`);
if (existingRule) {
// Add current field to existing rule
existingRule[suffix] = env[envName];
} else {
// Create a new rule
const newRule: HostRule = {
hostType,
};
if (matchHost) {
newRule.matchHost = matchHost;
}
newRule[suffix] = env[envName];
hostRules.push(newRule);
}
}
}
}
return hostRules;
}