feat: rename hostRules.platform to hostRules.hostType (#3768)

Refactors hostRules to use field “hostType” instead of “platform”. hostType can include datasources like npm, maven, pypi, etc.
This commit is contained in:
Rhys Arkins 2019-05-21 13:20:09 +02:00 committed by GitHub
parent 69a766b85e
commit c02abf0976
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 162 additions and 133 deletions

View file

@ -23,6 +23,7 @@ function getConfig(input) {
.replace('--expose-env=true', '--trust-level=high') .replace('--expose-env=true', '--trust-level=high')
.replace('--expose-env', '--trust-level=high') .replace('--expose-env', '--trust-level=high')
.replace('--renovate-fork', '--include-forks') .replace('--renovate-fork', '--include-forks')
.replace('"platform":"', '"hostType":"')
); );
const options = configDefinitions.getOptions(); const options = configDefinitions.getOptions();

View file

@ -1687,6 +1687,16 @@ const options = [
cli: true, cli: true,
mergeable: true, mergeable: true,
}, },
{
name: 'hostType',
description:
'hostType for a package rule. Can be a platform name or a datasource name',
type: 'string',
stage: 'repository',
parent: 'hostRules',
cli: false,
env: false,
},
{ {
name: 'prBodyDefinitions', name: 'prBodyDefinitions',
description: 'Table column definitions for use in PR tables', description: 'Table column definitions for use in PR tables',

View file

@ -42,14 +42,14 @@ function getConfig(env) {
if (env.GITHUB_COM_TOKEN) { if (env.GITHUB_COM_TOKEN) {
config.hostRules.push({ config.hostRules.push({
endpoint: 'https://api.github.com/', endpoint: 'https://api.github.com/',
platform: 'github', hostType: 'github',
token: env.GITHUB_COM_TOKEN, token: env.GITHUB_COM_TOKEN,
}); });
} }
if (env.DOCKER_USERNAME && env.DOCKER_PASSWORD) { if (env.DOCKER_USERNAME && env.DOCKER_PASSWORD) {
config.hostRules.push({ config.hostRules.push({
platform: 'docker', hostType: 'docker',
username: env.DOCKER_USERNAME, username: env.DOCKER_USERNAME,
password: env.DOCKER_PASSWORD, password: env.DOCKER_PASSWORD,
}); });

View file

@ -25,7 +25,7 @@ const removedOptions = [
]; ];
// Returns a migrated config // Returns a migrated config
function migrateConfig(config) { function migrateConfig(config, parentKey) {
try { try {
if (!optionTypes) { if (!optionTypes) {
optionTypes = {}; optionTypes = {};
@ -50,7 +50,7 @@ function migrateConfig(config) {
if (is.array(val)) { if (is.array(val)) {
migratedConfig.packageRules = migratedConfig.packageRules || []; migratedConfig.packageRules = migratedConfig.packageRules || [];
const migratedPathRules = migratedConfig.pathRules.map( const migratedPathRules = migratedConfig.pathRules.map(
p => migrateConfig(p).migratedConfig p => migrateConfig(p, key).migratedConfig
); );
migratedConfig.packageRules = migratedPathRules.concat( migratedConfig.packageRules = migratedPathRules.concat(
migratedConfig.packageRules migratedConfig.packageRules
@ -74,6 +74,10 @@ function migrateConfig(config) {
isMigrated = true; isMigrated = true;
migratedConfig.gitFs = 'https'; migratedConfig.gitFs = 'https';
} }
} else if (parentKey === 'hostRules' && key === 'platform') {
isMigrated = true;
migratedConfig.hostType = val;
delete migratedConfig.platform;
} else if (key === 'packageFiles' && is.array(val)) { } else if (key === 'packageFiles' && is.array(val)) {
isMigrated = true; isMigrated = true;
const fileList = []; const fileList = [];
@ -82,7 +86,7 @@ function migrateConfig(config) {
fileList.push(packageFile.packageFile); fileList.push(packageFile.packageFile);
if (Object.keys(packageFile).length > 1) { if (Object.keys(packageFile).length > 1) {
migratedConfig.packageRules = migratedConfig.packageRules || []; migratedConfig.packageRules = migratedConfig.packageRules || [];
const payload = migrateConfig(packageFile).migratedConfig; const payload = migrateConfig(packageFile, key).migratedConfig;
for (const subrule of payload.packageRules || []) { for (const subrule of payload.packageRules || []) {
subrule.paths = [packageFile.packageFile]; subrule.paths = [packageFile.packageFile];
migratedConfig.packageRules.push(subrule); migratedConfig.packageRules.push(subrule);
@ -105,7 +109,7 @@ function migrateConfig(config) {
} else if (depTypes.includes(key)) { } else if (depTypes.includes(key)) {
isMigrated = true; isMigrated = true;
migratedConfig.packageRules = migratedConfig.packageRules || []; migratedConfig.packageRules = migratedConfig.packageRules || [];
const depTypePackageRule = migrateConfig(val).migratedConfig; const depTypePackageRule = migrateConfig(val, key).migratedConfig;
depTypePackageRule.depTypeList = [key]; depTypePackageRule.depTypeList = [key];
delete depTypePackageRule.packageRules; delete depTypePackageRule.packageRules;
migratedConfig.packageRules.push(depTypePackageRule); migratedConfig.packageRules.push(depTypePackageRule);
@ -229,7 +233,7 @@ function migrateConfig(config) {
isMigrated = true; isMigrated = true;
migratedConfig.packageRules = migratedConfig.packageRules || []; migratedConfig.packageRules = migratedConfig.packageRules || [];
migratedConfig.packageRules = migratedConfig.packageRules.concat( migratedConfig.packageRules = migratedConfig.packageRules.concat(
migratedConfig.packages.map(p => migrateConfig(p).migratedConfig) migratedConfig.packages.map(p => migrateConfig(p, key).migratedConfig)
); );
delete migratedConfig.packages; delete migratedConfig.packages;
} else if (key === 'excludedPackageNames') { } else if (key === 'excludedPackageNames') {
@ -340,7 +344,7 @@ function migrateConfig(config) {
const depTypeName = depType.depType; const depTypeName = depType.depType;
if (depTypeName) { if (depTypeName) {
migratedConfig.packageRules = migratedConfig.packageRules || []; migratedConfig.packageRules = migratedConfig.packageRules || [];
const newPackageRule = migrateConfig(depType).migratedConfig; const newPackageRule = migrateConfig(depType, key).migratedConfig;
delete newPackageRule.depType; delete newPackageRule.depType;
newPackageRule.depTypeList = [depTypeName]; newPackageRule.depTypeList = [depTypeName];
migratedConfig.packageRules.push(newPackageRule); migratedConfig.packageRules.push(newPackageRule);
@ -372,14 +376,14 @@ function migrateConfig(config) {
if (!Object.keys(migratedConfig.node).length) { if (!Object.keys(migratedConfig.node).length) {
delete migratedConfig.node; delete migratedConfig.node;
} else { } else {
const subMigrate = migrateConfig(migratedConfig.node); const subMigrate = migrateConfig(migratedConfig.node, key);
migratedConfig.node = subMigrate.migratedConfig; migratedConfig.node = subMigrate.migratedConfig;
} }
} else if (is.array(val)) { } else if (is.array(val)) {
const newArray = []; const newArray = [];
for (const item of migratedConfig[key]) { for (const item of migratedConfig[key]) {
if (is.object(item) && !is.array(item)) { if (is.object(item) && !is.array(item)) {
const arrMigrate = migrateConfig(item); const arrMigrate = migrateConfig(item, key);
newArray.push(arrMigrate.migratedConfig); newArray.push(arrMigrate.migratedConfig);
if (arrMigrate.isMigrated) { if (arrMigrate.isMigrated) {
isMigrated = true; isMigrated = true;
@ -390,7 +394,7 @@ function migrateConfig(config) {
} }
migratedConfig[key] = newArray; migratedConfig[key] = newArray;
} else if (is.object(val)) { } else if (is.object(val)) {
const subMigrate = migrateConfig(migratedConfig[key]); const subMigrate = migrateConfig(migratedConfig[key], key);
if (subMigrate.isMigrated) { if (subMigrate.isMigrated) {
isMigrated = true; isMigrated = true;
migratedConfig[key] = subMigrate.migratedConfig; migratedConfig[key] = subMigrate.migratedConfig;

View file

@ -36,7 +36,7 @@ async function getPkgReleases({ lookupName }) {
const crateUrl = baseUrl + path; const crateUrl = baseUrl + path;
try { try {
let res = await got(crateUrl, { let res = await got(crateUrl, {
platform: 'cargo', hostType: 'cargo',
}); });
if (!res || !res.body) { if (!res || !res.body) {
logger.warn( logger.warn(

View file

@ -51,7 +51,7 @@ async function getAuthHeaders(registry, repository) {
); );
const { host } = URL.parse(registry); const { host } = URL.parse(registry);
const opts = hostRules.find({ platform: 'docker', host }, { json: true }); const opts = hostRules.find({ hostType: 'docker', host }, { json: true });
if (opts.username && opts.password) { if (opts.username && opts.password) {
const auth = Buffer.from(`${opts.username}:${opts.password}`).toString( const auth = Buffer.from(`${opts.username}:${opts.password}`).toString(
'base64' 'base64'

View file

@ -16,7 +16,7 @@ async function fetchJSONFile(repo, fileName) {
: 'application/vnd.github.v3+json', : 'application/vnd.github.v3+json',
}, },
json: true, json: true,
platform: 'github', hostType: 'github',
}; };
let res; let res;
try { try {

View file

@ -25,7 +25,7 @@ async function getDatasource(name) {
const pkgUrl = `https://${name}?go-get=1`; const pkgUrl = `https://${name}?go-get=1`;
try { try {
const res = (await got(pkgUrl, { const res = (await got(pkgUrl, {
platform: 'go', hostType: 'go',
})).body; })).body;
const sourceMatch = res.match( const sourceMatch = res.match(
new RegExp(`<meta name="go-source" content="${name}\\s+([^\\s]+)`) new RegExp(`<meta name="go-source" content="${name}\\s+([^\\s]+)`)

View file

@ -7,7 +7,7 @@ module.exports = {
function getHostOpts() { function getHostOpts() {
return { return {
json: true, json: true,
platform: 'hex', hostType: 'hex',
}; };
} }

View file

@ -136,7 +136,7 @@ async function downloadFileProtocol(pkgUrl) {
async function downloadHttpProtocol(pkgUrl) { async function downloadHttpProtocol(pkgUrl) {
let raw; let raw;
try { try {
raw = await got(pkgUrl, { platform: 'maven' }); raw = await got(pkgUrl, { hostType: 'maven' });
} catch (err) { } catch (err) {
if (isNotFoundError(err)) { if (isNotFoundError(err)) {
logger.debug(`Url not found ${pkgUrl}`); logger.debug(`Url not found ${pkgUrl}`);

View file

@ -132,7 +132,7 @@ async function getDependency(name) {
if (res.repository && res.repository.url) { if (res.repository && res.repository.url) {
const extraBaseUrls = []; const extraBaseUrls = [];
// istanbul ignore next // istanbul ignore next
hostRules.hosts({ platform: 'github' }).forEach(host => { hostRules.hosts({ hostType: 'github' }).forEach(host => {
extraBaseUrls.push(host, `gist.${host}`); extraBaseUrls.push(host, `gist.${host}`);
}); });
// Massage www out of github URL // Massage www out of github URL

View file

@ -15,7 +15,7 @@ async function getPkgReleases(feedUrl, pkgName) {
let pkgUrlList = `${feedUrl}/FindPackagesById()?id=%27${pkgName}%27&$select=Version,IsLatestVersion,ProjectUrl`; let pkgUrlList = `${feedUrl}/FindPackagesById()?id=%27${pkgName}%27&$select=Version,IsLatestVersion,ProjectUrl`;
do { do {
const pkgVersionsListRaw = await got(pkgUrlList, { platform: 'nuget' }); const pkgVersionsListRaw = await got(pkgUrlList, { hostType: 'nuget' });
if (pkgVersionsListRaw.statusCode !== 200) { if (pkgVersionsListRaw.statusCode !== 200) {
logger.debug( logger.debug(
{ dependency: pkgName, pkgVersionsListRaw }, { dependency: pkgName, pkgVersionsListRaw },

View file

@ -29,7 +29,7 @@ async function getQueryUrl(url) {
} }
try { try {
const servicesIndexRaw = await got(url, { json: true, platform: 'nuget' }); const servicesIndexRaw = await got(url, { json: true, hostType: 'nuget' });
if (servicesIndexRaw.statusCode !== 200) { if (servicesIndexRaw.statusCode !== 200) {
logger.debug( logger.debug(
{ dependency: url, servicesIndexRaw }, { dependency: url, servicesIndexRaw },
@ -72,7 +72,7 @@ async function getPkgReleases(registryUrl, feedUrl, pkgName) {
try { try {
const pkgUrlListRaw = await got(queryUrl, { const pkgUrlListRaw = await got(queryUrl, {
json: true, json: true,
platform: 'nuget', hostType: 'nuget',
}); });
if (pkgUrlListRaw.statusCode !== 200) { if (pkgUrlListRaw.statusCode !== 200) {
logger.debug( logger.debug(
@ -112,7 +112,7 @@ async function getPkgReleases(registryUrl, feedUrl, pkgName) {
const nugetOrgApi = `https://api.nuget.org/v3-flatcontainer/${pkgName.toLowerCase()}/${lastVersion}/${pkgName.toLowerCase()}.nuspec`; const nugetOrgApi = `https://api.nuget.org/v3-flatcontainer/${pkgName.toLowerCase()}/${lastVersion}/${pkgName.toLowerCase()}.nuspec`;
let metaresult; let metaresult;
try { try {
metaresult = await got(nugetOrgApi, { platform: 'nuget' }); metaresult = await got(nugetOrgApi, { hostType: 'nuget' });
} catch (err) /* istanbul ignore next */ { } catch (err) /* istanbul ignore next */ {
logger.debug( logger.debug(
`Cannot fetch metadata for ${pkgName} using popped version ${lastVersion}` `Cannot fetch metadata for ${pkgName} using popped version ${lastVersion}`

View file

@ -13,7 +13,7 @@ module.exports = {
function getHostOpts(url) { function getHostOpts(url) {
const { host } = URL.parse(url); const { host } = URL.parse(url);
const opts = hostRules.find({ platform: 'packagist', host }, { json: true }); const opts = hostRules.find({ hostType: 'packagist', host }, { json: true });
if (opts && opts.username && opts.password) { if (opts && opts.username && opts.password) {
const auth = Buffer.from(`${opts.username}:${opts.password}`).toString( const auth = Buffer.from(`${opts.username}:${opts.password}`).toString(
'base64' 'base64'

View file

@ -56,7 +56,7 @@ async function getDependency(depName, hostUrl, compatibility) {
const dependency = {}; const dependency = {};
const rep = await got(url.parse(lookupUrl), { const rep = await got(url.parse(lookupUrl), {
json: true, json: true,
platform: 'pypi', hostType: 'pypi',
}); });
const dep = rep && rep.body; const dep = rep && rep.body;
if (!dep) { if (!dep) {
@ -105,7 +105,7 @@ async function getSimpleDependency(depName, hostUrl) {
const dependency = {}; const dependency = {};
const response = await got(url.parse(lookupUrl), { const response = await got(url.parse(lookupUrl), {
json: false, json: false,
platform: 'pypi', hostType: 'pypi',
}); });
const dep = response && response.body; const dep = response && response.body;
if (!dep) { if (!dep) {

View file

@ -31,7 +31,7 @@ const processError = ({ err, ...rest }) => {
}; };
const getHeaders = () => { const getHeaders = () => {
return { platform: 'rubygems' }; return { hostType: 'rubygems' };
}; };
const fetch = async ({ dependency, registry, path }) => { const fetch = async ({ dependency, registry, path }) => {

View file

@ -52,7 +52,7 @@ async function getPkgReleases({ lookupName, registryUrls }) {
try { try {
const res = (await got(pkgUrl, { const res = (await got(pkgUrl, {
json: true, json: true,
platform: 'terraform', hostType: 'terraform',
})).body; })).body;
const returnedName = res.namespace + '/' + res.name + '/' + res.provider; const returnedName = res.namespace + '/' + res.name + '/' + res.provider;
if (returnedName !== repository) { if (returnedName !== repository) {

View file

@ -40,7 +40,7 @@ async function getArtifacts(
} }
let authJson = {}; let authJson = {};
let credentials = hostRules.find({ let credentials = hostRules.find({
platform: 'github', hostType: 'github',
host: 'api.github.com', host: 'api.github.com',
}); });
// istanbul ignore if // istanbul ignore if
@ -50,7 +50,7 @@ async function getArtifacts(
}; };
} }
credentials = hostRules.find({ credentials = hostRules.find({
platform: 'gitlab', hostType: 'gitlab',
host: 'gitlab.com', host: 'gitlab.com',
}); });
// istanbul ignore if // istanbul ignore if
@ -66,7 +66,7 @@ async function getArtifacts(
if (regUrl.url) { if (regUrl.url) {
const { host } = URL.parse(regUrl.url); const { host } = URL.parse(regUrl.url);
const hostRule = hostRules.find({ const hostRule = hostRules.find({
platform: 'packagist', hostType: 'packagist',
host, host,
}); });
// istanbul ignore else // istanbul ignore else

View file

@ -62,7 +62,7 @@ async function getArtifacts(
cmd += `-w ${cwd} `; cmd += `-w ${cwd} `;
cmd += `renovate/go `; cmd += `renovate/go `;
const credentials = hostRules.find({ const credentials = hostRules.find({
platform: 'github', hostType: 'github',
host: 'api.github.com', host: 'api.github.com',
}); });
if (credentials && credentials.token) { if (credentials && credentials.token) {

View file

@ -304,7 +304,7 @@ async function writeUpdatedPackageFiles(config) {
delete massagedFile.engines; delete massagedFile.engines;
delete massagedFile.scripts; delete massagedFile.scripts;
try { try {
const { token } = hostRules.find({ platform: config.platform }); const { token } = hostRules.find({ hostType: config.platform });
for (const upgrade of config.upgrades) { for (const upgrade of config.upgrades) {
if (upgrade.gitRef && upgrade.packageFile === packageFile.name) { if (upgrade.gitRef && upgrade.packageFile === packageFile.name) {
massagedFile[upgrade.depType][upgrade.depName] = massagedFile[ massagedFile[upgrade.depType][upgrade.depName] = massagedFile[
@ -377,7 +377,7 @@ async function getAdditionalFiles(config, packageFiles) {
let token = ''; let token = '';
try { try {
({ token } = hostRules.find({ platform: config.platform })); ({ token } = hostRules.find({ hostType: config.platform }));
token += '@'; token += '@';
} catch (err) { } catch (err) {
logger.warn({ err }, 'Error getting token for packageFile'); logger.warn({ err }, 'Error getting token for packageFile');

View file

@ -1,7 +1,7 @@
const azure = require('azure-devops-node-api'); const azure = require('azure-devops-node-api');
const hostRules = require('../../util/host-rules'); const hostRules = require('../../util/host-rules');
const platform = 'azure'; const hostType = 'azure';
let endpoint; let endpoint;
module.exports = { module.exports = {
@ -12,7 +12,7 @@ module.exports = {
}; };
function azureObj() { function azureObj() {
const config = hostRules.find({ platform, endpoint }); const config = hostRules.find({ hostType, endpoint });
if (!(config && config.token)) { if (!(config && config.token)) {
throw new Error(`No token found for azure`); throw new Error(`No token found for azure`);
} }

View file

@ -8,7 +8,7 @@ const GitStorage = require('../git/storage');
let config = {}; let config = {};
const defaults = { const defaults = {
platform: 'azure', hostType: 'azure',
}; };
module.exports = { module.exports = {

View file

@ -5,7 +5,7 @@ import { IGotApiOptions, IGotApi } from '../common';
let cache: Renovate.IDict<got.Response<any>> = {}; let cache: Renovate.IDict<got.Response<any>> = {};
const platform = 'bitbucket-server'; const hostType = 'bitbucket-server';
let endpoint: string; let endpoint: string;
async function get(path: string, options: IGotApiOptions & got.GotJSONOptions) { async function get(path: string, options: IGotApiOptions & got.GotJSONOptions) {
@ -17,7 +17,7 @@ async function get(path: string, options: IGotApiOptions & got.GotJSONOptions) {
timeout: 60 * 1000, timeout: 60 * 1000,
json: true, json: true,
basic: false, basic: false,
...hostRules.find({ platform, host }), ...hostRules.find({ hostType, host }),
...options, ...options,
}; };
const url = URL.resolve(endpoint, path); const url = URL.resolve(endpoint, path);

View file

@ -6,8 +6,6 @@ import * as utils from './utils';
import * as hostRules from '../../util/host-rules'; import * as hostRules from '../../util/host-rules';
import GitStorage from '../git/storage'; import GitStorage from '../git/storage';
const platform = 'bitbucket-server';
interface BbsConfig { interface BbsConfig {
baseBranch: string; baseBranch: string;
bbUseDefaultReviewers: boolean; bbUseDefaultReviewers: boolean;
@ -25,7 +23,7 @@ interface BbsConfig {
let config: BbsConfig = {} as any; let config: BbsConfig = {} as any;
const defaults: any = { const defaults: any = {
platform: 'bitbucket-server', hostType: 'bitbucket-server',
}; };
export function initPlatform({ export function initPlatform({
@ -105,7 +103,7 @@ export async function initRepo({
2 2
)}")` )}")`
); );
const opts = hostRules.find({ platform }, { endpoint }); const opts = hostRules.find({ hostType: defaults.hostType, endpoint });
api.reset(); api.reset();
const [projectKey, repositorySlug] = repository.split('/'); const [projectKey, repositorySlug] = repository.split('/');

View file

@ -16,7 +16,7 @@ async function get(path: string, options: IGotApiOptions & got.GotJSONOptions) {
timeout: 60 * 1000, timeout: 60 * 1000,
json: true, json: true,
basic: false, basic: false,
...hostRules.find({ platform: 'bitbucket', host }), ...hostRules.find({ hostType: 'bitbucket', host }),
...options, ...options,
}; };
const url = URL.resolve(endpoint, path); const url = URL.resolve(endpoint, path);

View file

@ -70,7 +70,7 @@ export async function initRepo({
localDir: string; localDir: string;
}) { }) {
logger.debug(`initRepo("${repository}")`); logger.debug(`initRepo("${repository}")`);
const opts = hostRules.find({ platform: 'bitbucket' }); const opts = hostRules.find({ hostType: 'bitbucket' });
api.reset(); api.reset();
config = {} as any; config = {} as any;
// TODO: get in touch with @rarkins about lifting up the caching into the app layer // TODO: get in touch with @rarkins about lifting up the caching into the app layer

View file

@ -17,7 +17,7 @@ async function get(path, options, retries = 5) {
const opts = { const opts = {
// TODO: Move to configurable host rules, or use utils/got // TODO: Move to configurable host rules, or use utils/got
timeout: 60 * 1000, timeout: 60 * 1000,
...hostRules.find({ platform: 'github', host }), ...hostRules.find({ hostType: 'github', host }),
...options, ...options,
}; };
delete opts.endpoint; delete opts.endpoint;

View file

@ -19,7 +19,7 @@ const defaultConfigFile = configFileNames[0];
let config = {}; let config = {};
const defaults = { const defaults = {
platform: 'github', hostType: 'github',
endpoint: 'https://api.github.com/', endpoint: 'https://api.github.com/',
}; };
@ -138,13 +138,12 @@ async function initRepo({
// config is used by the platform api itself, not necessary for the app layer to know // config is used by the platform api itself, not necessary for the app layer to know
cleanRepo(); cleanRepo();
const opts = hostRules.find({ const opts = hostRules.find({
platform: 'github', hostType: 'github',
}); });
config.isGhe = config.isGhe =
opts.endpoint && !opts.endpoint.startsWith('https://api.github.com'); opts.endpoint && !opts.endpoint.startsWith('https://api.github.com');
config.renovateUsername = renovateUsername; config.renovateUsername = renovateUsername;
config.localDir = localDir; config.localDir = localDir;
config.platform = 'github';
config.repository = repository; config.repository = repository;
[config.repositoryOwner, config.repositoryName] = repository.split('/'); [config.repositoryOwner, config.repositoryName] = repository.split('/');
config.gitPrivateKey = gitPrivateKey; config.gitPrivateKey = gitPrivateKey;

View file

@ -13,7 +13,7 @@ async function get(path, options, retries = 5) {
const opts = { const opts = {
// TODO: Move to configurable host rules, or use utils/got // TODO: Move to configurable host rules, or use utils/got
timeout: 60 * 1000, timeout: 60 * 1000,
...hostRules.find({ platform: 'gitlab', host }), ...hostRules.find({ hostType: 'gitlab', host }),
...options, ...options,
}; };
const url = URL.resolve(endpoint, path); const url = URL.resolve(endpoint, path);

View file

@ -7,7 +7,7 @@ const GitStorage = require('../git/storage');
let config = {}; let config = {};
const defaults = { const defaults = {
platform: 'gitlab', hostType: 'gitlab',
endpoint: 'https://gitlab.com/api/v4/', endpoint: 'https://gitlab.com/api/v4/',
}; };
@ -72,8 +72,8 @@ function initPlatform({ endpoint, token }) {
get.setEndpoint(res.endpoint); get.setEndpoint(res.endpoint);
defaults.endpoint = res.endpoint; defaults.endpoint = res.endpoint;
} else { } else {
logger.info('Using default GitLab endpoint: ' + res.endpoint);
res.endpoint = defaults.endpoint; res.endpoint = defaults.endpoint;
logger.info('Using default GitLab endpoint: ' + res.endpoint);
} }
// TODO: Add a connection check that endpoint/token combination are valid // TODO: Add a connection check that endpoint/token combination are valid
return res; return res;
@ -139,7 +139,7 @@ async function initRepo({ repository, gitFs, localDir }) {
logger.debug('Enabling Git FS'); logger.debug('Enabling Git FS');
const { host, protocol } = URL.parse(defaults.endpoint); const { host, protocol } = URL.parse(defaults.endpoint);
const opts = hostRules.find({ const opts = hostRules.find({
platform: 'gitlab', hostType: 'gitlab',
host, host,
}); });
const url = GitStorage.getUrl({ const url = GitStorage.getUrl({

View file

@ -37,7 +37,7 @@ async function initPlatform(config) {
token = base64(`${config.username}:${config.password}`); token = base64(`${config.username}:${config.password}`);
} }
const platformRule = { const platformRule = {
platform: returnConfig.platform, hostType: returnConfig.platform,
endpoint: returnConfig.endpoint, endpoint: returnConfig.endpoint,
token, token,
username: returnConfig.username, username: returnConfig.username,

View file

@ -10,13 +10,13 @@ module.exports = got.create({
timeout: 60 * 1000, timeout: 60 * 1000,
}, },
handler: (options, next) => { handler: (options, next) => {
const { platform, ...opts } = options; const { hostType, ...opts } = options;
if (!options.hostname) { if (!options.hostname) {
return next(opts); return next(opts);
} }
const hostRule = hostRules.find({ const hostRule = hostRules.find({
host: options.hostname, host: options.hostname,
platform, hostType,
}); });
if (!hostRule) { if (!hostRule) {
return next(opts); return next(opts);

View file

@ -1,13 +1,5 @@
import URL from 'url'; import URL from 'url';
export const defaults: IDict<IPlatformConfig> = {
bitbucket: { name: 'Bitbucket', endpoint: 'https://api.bitbucket.org/' },
'bitbucket-server': { name: 'Bitbucket Server' },
github: { name: 'GitHub', endpoint: 'https://api.github.com/' },
gitlab: { name: 'GitLab', endpoint: 'https://gitlab.com/api/v4/' },
azure: { name: 'Azure DevOps' },
};
// TODO: add known properties // TODO: add known properties
export interface IPlatformConfig { export interface IPlatformConfig {
[prop: string]: any; [prop: string]: any;
@ -19,31 +11,31 @@ export interface IPlatformConfig {
interface IDict<T> { interface IDict<T> {
[key: string]: T; [key: string]: T;
} }
const platforms: IDict<IPlatformConfig> = {}; const hostTypes: IDict<IPlatformConfig> = {};
const hostsOnly: IDict<IPlatformConfig> = {}; const hostsOnly: IDict<IPlatformConfig> = {};
export function update(params: IPlatformConfig) { export function update(params: IPlatformConfig) {
const { platform } = params; const { hostType } = params;
if (!platform) { if (!hostType) {
if (params.endpoint) { if (params.endpoint) {
const { host } = URL.parse(params.endpoint); const { host } = URL.parse(params.endpoint);
hostsOnly[host!] = params; hostsOnly[host!] = params;
return true; return true;
} }
throw new Error( throw new Error(
'Failed to set configuration: no platform or endpoint specified' 'Failed to set configuration: no hostType or endpoint specified'
); );
} }
const config = { ...params }; const config = { ...params };
const { endpoint } = config; const { endpoint } = config;
if (!endpoint) { if (!endpoint) {
// istanbul ignore if // istanbul ignore if
if (platform === 'docker') { if (hostType === 'docker') {
platforms.docker = params; hostTypes.docker = params;
return true; return true;
} }
throw new Error( throw new Error(
`Failed to configure platform '${platform}': no endpoint defined` `Failed to configure hostType '${hostType}': no endpoint defined`
); );
} }
config.endpoint = endpoint.replace(/[^/]$/, '$&/'); config.endpoint = endpoint.replace(/[^/]$/, '$&/');
@ -54,42 +46,42 @@ export function update(params: IPlatformConfig) {
host = host || (endpoint && URL.parse('http://' + endpoint).host); host = host || (endpoint && URL.parse('http://' + endpoint).host);
if (!host) { if (!host) {
throw new Error( throw new Error(
`Failed to configure platform '${platform}': no host for endpoint '${endpoint}'` `Failed to configure hostType '${hostType}': no host for endpoint '${endpoint}'`
); );
} }
platforms[platform] = { ...platforms[platform] }; hostTypes[hostType] = { ...hostTypes[hostType] };
logger.debug({ config }, 'Setting hostRule'); logger.debug({ config }, 'Setting hostRule');
platforms[platform][host] = { ...platforms[platform][host], ...config }; hostTypes[hostType][host] = { ...hostTypes[hostType][host], ...config };
return true; return true;
} }
export function find( export function find(
{ {
platform, hostType,
host, host,
endpoint, endpoint,
}: { platform: string; host?: string; endpoint?: string }, }: { hostType: string; host?: string; endpoint?: string },
overrides?: IPlatformConfig overrides?: IPlatformConfig
) { ) {
const massagedHost = const massagedHost =
host || (endpoint ? URL.parse(endpoint).host : undefined); host || (endpoint ? URL.parse(endpoint).host : undefined);
if (!platforms[platform]) { if (!hostTypes[hostType]) {
if (massagedHost && hostsOnly[massagedHost]) { if (massagedHost && hostsOnly[massagedHost]) {
return merge(hostsOnly[massagedHost], overrides); return merge(hostsOnly[massagedHost], overrides);
} }
return merge(null, overrides); return merge(null, overrides);
} }
// istanbul ignore if // istanbul ignore if
if (platform === 'docker') { if (hostType === 'docker') {
if (platforms.docker.platform === 'docker') { if (hostTypes.docker.hostType === 'docker') {
return merge(platforms.docker, overrides); return merge(hostTypes.docker, overrides);
} }
return merge(platforms.docker[massagedHost!], overrides); return merge(hostTypes.docker[massagedHost!], overrides);
} }
if (massagedHost) { if (massagedHost) {
return merge(platforms[platform][massagedHost], overrides); return merge(hostTypes[hostType][massagedHost], overrides);
} }
const configs = Object.values(platforms[platform]); const configs = Object.values(hostTypes[hostType]);
let config; let config;
if (configs.length === 1) { if (configs.length === 1) {
[config] = configs; [config] = configs;
@ -97,8 +89,8 @@ export function find(
return merge(config, overrides); return merge(config, overrides);
} }
export function hosts({ platform }: { platform: string }) { export function hosts({ hostType }: { hostType: string }) {
return Object.keys({ ...platforms[platform] }); return Object.keys({ ...hostTypes[hostType] });
} }
function merge(config: IPlatformConfig | null, overrides?: IPlatformConfig) { function merge(config: IPlatformConfig | null, overrides?: IPlatformConfig) {
@ -115,5 +107,5 @@ function merge(config: IPlatformConfig | null, overrides?: IPlatformConfig) {
} }
export function clear() { export function clear() {
Object.keys(platforms).forEach(key => delete platforms[key]); Object.keys(hostTypes).forEach(key => delete hostTypes[key]);
} }

View file

@ -56,7 +56,7 @@ async function getChangeLogJSON({
const { protocol, host, pathname } = URL.parse(sourceUrl); const { protocol, host, pathname } = URL.parse(sourceUrl);
const githubBaseURL = `${protocol}//${host}/`; const githubBaseURL = `${protocol}//${host}/`;
const config = hostRules.find({ const config = hostRules.find({
platform: 'github', hostType: 'github',
host: host === 'github.com' ? 'api.github.com' : host, host: host === 'github.com' ? 'api.github.com' : host,
}); });
if (!config) { if (!config) {

View file

@ -1159,7 +1159,20 @@
}, },
"hostRules": { "hostRules": {
"description": "Host rules/configuration including credentials", "description": "Host rules/configuration including credentials",
"type": "array" "type": "array",
"items": {
"allOf": [
{
"type": "object",
"properties": {
"hostType": {
"description": "hostType for a package rule. Can be a platform name or a datasource name",
"type": "string"
}
}
}
]
}
}, },
"prBodyDefinitions": { "prBodyDefinitions": {
"description": "Table column definitions for use in PR tables", "description": "Table column definitions for use in PR tables",

View file

@ -42,7 +42,7 @@ Object {
"hostRules": Array [ "hostRules": Array [
Object { Object {
"endpoint": "https://api.github.com/", "endpoint": "https://api.github.com/",
"platform": "github", "hostType": "github",
"token": "a github.com token", "token": "a github.com token",
}, },
], ],
@ -78,8 +78,8 @@ exports[`config/env .getConfig(env) supports docker username/password 1`] = `
Object { Object {
"hostRules": Array [ "hostRules": Array [
Object { Object {
"hostType": "docker",
"password": "some-password", "password": "some-password",
"platform": "docker",
"username": "some-username", "username": "some-username",
}, },
], ],

View file

@ -121,6 +121,7 @@ Object {
"patch": Object { "patch": Object {
"automerge": true, "automerge": true,
}, },
"platform": "github",
"postUpdateOptions": Array [ "postUpdateOptions": Array [
"gomodTidy", "gomodTidy",
], ],

View file

@ -76,13 +76,13 @@ describe('config/cli', () => {
}); });
it('parses json lists correctly', () => { it('parses json lists correctly', () => {
argv.push( argv.push(
`--host-rules=[{"host":"docker.io","platform":"docker","username":"user","password":"password"}]` `--host-rules=[{"host":"docker.io","hostType":"docker","username":"user","password":"password"}]`
); );
cli.getConfig(argv).should.deep.equal({ cli.getConfig(argv).should.deep.equal({
hostRules: [ hostRules: [
{ {
host: 'docker.io', host: 'docker.io',
platform: 'docker', hostType: 'docker',
username: 'user', username: 'user',
password: 'password', password: 'password',
}, },

View file

@ -7,6 +7,14 @@ describe('config/migration', () => {
const config = { const config = {
endpoints: [{}], endpoints: [{}],
enabled: true, enabled: true,
platform: 'github',
hostRules: [
{
platform: 'docker',
username: 'some-username',
password: 'some-password',
},
],
extends: [':js-app', 'config:library'], extends: [':js-app', 'config:library'],
maintainYarnLock: true, maintainYarnLock: true,
onboarding: 'false', onboarding: 'false',
@ -99,6 +107,7 @@ describe('config/migration', () => {
expect(migratedConfig.depTypes).not.toBeDefined(); expect(migratedConfig.depTypes).not.toBeDefined();
expect(migratedConfig.automerge).toEqual(false); expect(migratedConfig.automerge).toEqual(false);
expect(migratedConfig.packageRules).toHaveLength(7); expect(migratedConfig.packageRules).toHaveLength(7);
expect(migratedConfig.hostRules).toHaveLength(1);
}); });
it('migrates before and after schedules', () => { it('migrates before and after schedules', () => {
const config = { const config = {

View file

@ -180,8 +180,8 @@ Array [
"slashes": true, "slashes": true,
}, },
Object { Object {
"hostType": "pypi",
"json": true, "json": true,
"platform": "pypi",
}, },
], ],
] ]
@ -205,8 +205,8 @@ Array [
"slashes": true, "slashes": true,
}, },
Object { Object {
"hostType": "pypi",
"json": true, "json": true,
"platform": "pypi",
}, },
], ],
] ]
@ -230,8 +230,8 @@ Array [
"slashes": true, "slashes": true,
}, },
Object { Object {
"hostType": "pypi",
"json": true, "json": true,
"platform": "pypi",
}, },
], ],
Array [ Array [
@ -250,8 +250,8 @@ Array [
"slashes": true, "slashes": true,
}, },
Object { Object {
"hostType": "pypi",
"json": true, "json": true,
"platform": "pypi",
}, },
], ],
] ]

View file

@ -141,8 +141,8 @@ Object {
"hostRules": Array [ "hostRules": Array [
Object { Object {
"endpoint": "https://api.bitbucket.org/", "endpoint": "https://api.bitbucket.org/",
"hostType": "bitbucket",
"password": "123", "password": "123",
"platform": "bitbucket",
"token": "YWJjOjEyMw==", "token": "YWJjOjEyMw==",
"username": "abc", "username": "abc",
}, },

View file

@ -15,7 +15,7 @@ describe('platform/azure/azure-got-wrapper', () => {
}); });
it('should set token and endpoint', async () => { it('should set token and endpoint', async () => {
hostRules.update({ hostRules.update({
platform: 'azure', hostType: 'azure',
token: 'token', token: 'token',
endpoint: 'https://dev.azure.com/renovate12345', endpoint: 'https://dev.azure.com/renovate12345',
}); });

View file

@ -66,7 +66,7 @@ describe('platform/bitbucket-server', () => {
? 'https://stash.renovatebot.com/vcs/' ? 'https://stash.renovatebot.com/vcs/'
: 'https://stash.renovatebot.com'; : 'https://stash.renovatebot.com';
hostRules.find.mockReturnValue({ hostRules.find.mockReturnValue({
platform: 'bitbucket-server', hostType: 'bitbucket-server',
endpoint, endpoint,
username: 'abc', username: 'abc',
password: '123', password: '123',

View file

@ -15,7 +15,7 @@ describe('platform/gl-got-wrapper', () => {
// clean up hostRules // clean up hostRules
hostRules.clear(); hostRules.clear();
hostRules.update({ hostRules.update({
platform: 'bitbucket', hostType: 'bitbucket',
endpoint: 'https://api.bitbucket.org', endpoint: 'https://api.bitbucket.org',
token: 'token', token: 'token',
}); });

View file

@ -40,7 +40,7 @@ describe('platform/bitbucket', () => {
// clean up hostRules // clean up hostRules
hostRules.clear(); hostRules.clear();
hostRules.find.mockReturnValue({ hostRules.find.mockReturnValue({
platform: 'bitbucket', hostType: 'bitbucket',
endpoint: 'https://bitbucket.org', endpoint: 'https://bitbucket.org',
username: 'abc', username: 'abc',
password: '123', password: '123',

View file

@ -15,7 +15,7 @@ describe('platform/github', () => {
hostRules = require('../../../lib/util/host-rules'); hostRules = require('../../../lib/util/host-rules');
delete global.gitAuthor; delete global.gitAuthor;
hostRules.find.mockReturnValue({ hostRules.find.mockReturnValue({
platform: 'github', hostType: 'github',
endpoint: 'https://api.github.com', endpoint: 'https://api.github.com',
token: 'abc123', token: 'abc123',
}); });
@ -1673,7 +1673,7 @@ describe('platform/github', () => {
}); });
it('returns not-updated pr body for GHE', async () => { it('returns not-updated pr body for GHE', async () => {
hostRules.find.mockReturnValue({ hostRules.find.mockReturnValue({
platform: 'github', hostType: 'github',
endpoint: 'https://github.company.com', endpoint: 'https://github.company.com',
token: 'abc123', token: 'abc123',
}); });

View file

@ -3,8 +3,8 @@
exports[`util/host-rules find() allows overrides 1`] = ` exports[`util/host-rules find() allows overrides 1`] = `
Object { Object {
"endpoint": "endpoint/", "endpoint": "endpoint/",
"hostType": "github",
"other": "data", "other": "data",
"platform": "github",
"token": "secret", "token": "secret",
} }
`; `;
@ -24,7 +24,7 @@ Object {
exports[`util/host-rules find() matches on endpoint 1`] = ` exports[`util/host-rules find() matches on endpoint 1`] = `
Object { Object {
"endpoint": "https://nuget.local/api/", "endpoint": "https://nuget.local/api/",
"platform": "nuget", "hostType": "nuget",
"token": "abc", "token": "abc",
} }
`; `;
@ -32,7 +32,7 @@ Object {
exports[`util/host-rules find() matches on endpoint subresource 1`] = ` exports[`util/host-rules find() matches on endpoint subresource 1`] = `
Object { Object {
"endpoint": "https://nuget.local/api/", "endpoint": "https://nuget.local/api/",
"platform": "nuget", "hostType": "nuget",
"token": "abc", "token": "abc",
} }
`; `;
@ -41,8 +41,8 @@ exports[`util/host-rules find() needs exact host matches 1`] = `
Object { Object {
"endpoint": "endpoint/", "endpoint": "endpoint/",
"host": "nuget.org", "host": "nuget.org",
"hostType": "nuget",
"password": "p4$$w0rd", "password": "p4$$w0rd",
"platform": "nuget",
"username": "root", "username": "root",
} }
`; `;

View file

@ -5,22 +5,22 @@ describe('util/host-rules', () => {
clear(); clear();
}); });
describe('update()', () => { describe('update()', () => {
it('throws if no platform ', () => { it('throws if no hostType ', () => {
expect(() => update({})).toThrow( expect(() => update({})).toThrow(
'Failed to set configuration: no platform or endpoint specified' 'Failed to set configuration: no hostType or endpoint specified'
); );
}); });
it('throws if no endpoint ', () => { it('throws if no endpoint ', () => {
expect(() => update({ platform: 'azure' })).toThrow( expect(() => update({ hostType: 'azure' })).toThrow(
`Failed to configure platform 'azure': no endpoint defined` `Failed to configure hostType 'azure': no endpoint defined`
); );
}); });
it('throws if invalid endpoint ', () => { it('throws if invalid endpoint ', () => {
expect(() => expect(() =>
update({ platform: 'azure', endpoint: '/some/path' }) update({ hostType: 'azure', endpoint: '/some/path' })
).toThrow( ).toThrow(
`Failed to configure platform 'azure': no host for endpoint '/some/path'` `Failed to configure hostType 'azure': no host for endpoint '/some/path'`
); );
}); });
it('supports endpoint-only', () => { it('supports endpoint-only', () => {
@ -35,7 +35,7 @@ describe('util/host-rules', () => {
describe('find()', () => { describe('find()', () => {
it('allows overrides', () => { it('allows overrides', () => {
update({ update({
platform: 'github', hostType: 'github',
endpoint: 'endpoint', endpoint: 'endpoint',
token: 'token', token: 'token',
other: 'data', other: 'data',
@ -45,49 +45,49 @@ describe('util/host-rules', () => {
other: null, other: null,
foo: undefined, foo: undefined,
}; };
expect(find({ platform: 'github' }, overrides)).toMatchSnapshot(); expect(find({ hostType: 'github' }, overrides)).toMatchSnapshot();
expect( expect(
find({ platform: 'github', host: 'api.github.com' }, overrides) find({ hostType: 'github', host: 'api.github.com' }, overrides)
).toMatchSnapshot(); ).toMatchSnapshot();
expect( expect(
find({ platform: 'github', host: 'example.com' }, overrides) find({ hostType: 'github', host: 'example.com' }, overrides)
).toMatchSnapshot(); ).toMatchSnapshot();
}); });
it('needs exact host matches', () => { it('needs exact host matches', () => {
update({ update({
platform: 'nuget', hostType: 'nuget',
endpoint: 'endpoint', endpoint: 'endpoint',
host: 'nuget.org', host: 'nuget.org',
username: 'root', username: 'root',
password: 'p4$$w0rd', password: 'p4$$w0rd',
}); });
expect(find({ platform: 'nuget', host: 'nuget.org' })).toMatchSnapshot(); expect(find({ hostType: 'nuget', host: 'nuget.org' })).toMatchSnapshot();
expect( expect(
find({ platform: 'nuget', host: 'not.nuget.org' }) find({ hostType: 'nuget', host: 'not.nuget.org' })
).toMatchSnapshot(); ).toMatchSnapshot();
expect( expect(
find({ platform: 'nuget', host: 'not-nuget.org' }) find({ hostType: 'nuget', host: 'not-nuget.org' })
).toMatchSnapshot(); ).toMatchSnapshot();
}); });
it('matches on endpoint', () => { it('matches on endpoint', () => {
update({ update({
platform: 'nuget', hostType: 'nuget',
endpoint: 'https://nuget.local/api', endpoint: 'https://nuget.local/api',
token: 'abc', token: 'abc',
}); });
expect( expect(
find({ platform: 'nuget', endpoint: 'https://nuget.local/api' }) find({ hostType: 'nuget', endpoint: 'https://nuget.local/api' })
).toMatchSnapshot(); ).toMatchSnapshot();
}); });
it('matches on endpoint subresource', () => { it('matches on endpoint subresource', () => {
update({ update({
platform: 'nuget', hostType: 'nuget',
endpoint: 'https://nuget.local/api', endpoint: 'https://nuget.local/api',
token: 'abc', token: 'abc',
}); });
expect( expect(
find({ find({
platform: 'nuget', hostType: 'nuget',
endpoint: 'https://nuget.local/api/sub-resource', endpoint: 'https://nuget.local/api/sub-resource',
}) })
).toMatchSnapshot(); ).toMatchSnapshot();

View file

@ -36,7 +36,7 @@ describe('lib/workers/global', () => {
repositories: ['a', 'b'], repositories: ['a', 'b'],
hostRules: [ hostRules: [
{ {
platform: 'docker', hostType: 'docker',
host: 'docker.io', host: 'docker.io',
username: 'some-user', username: 'some-user',
password: 'some-password', password: 'some-password',

View file

@ -36,7 +36,7 @@ describe('workers/pr/changelog', () => {
ghGot.mockClear(); ghGot.mockClear();
hostRules.clear(); hostRules.clear();
hostRules.update({ hostRules.update({
platform: 'github', hostType: 'github',
endpoint: 'https://api.github.com/', endpoint: 'https://api.github.com/',
}); });
await global.renovateCache.rmAll(); await global.renovateCache.rmAll();
@ -156,7 +156,7 @@ describe('workers/pr/changelog', () => {
}); });
it('supports github enterprise and github.com changelog', async () => { it('supports github enterprise and github.com changelog', async () => {
hostRules.update({ hostRules.update({
platform: 'github', hostType: 'github',
token: 'super_secret', token: 'super_secret',
endpoint: 'https://github-enterprise.example.com/', endpoint: 'https://github-enterprise.example.com/',
}); });
@ -168,7 +168,7 @@ describe('workers/pr/changelog', () => {
}); });
it('supports github enterprise and github enterprise changelog', async () => { it('supports github enterprise and github enterprise changelog', async () => {
hostRules.update({ hostRules.update({
platform: 'github', hostType: 'github',
endpoint: 'https://github-enterprise.example.com/', endpoint: 'https://github-enterprise.example.com/',
}); });
process.env.GITHUB_ENDPOINT = ''; process.env.GITHUB_ENDPOINT = '';

View file

@ -325,7 +325,7 @@ Example for configuring `docker` auth:
{ {
"hostRules": [ "hostRules": [
{ {
"platform": "docker", "hostType": "docker",
"username": "<some-username>", "username": "<some-username>",
"password": "<some-password>" "password": "<some-password>"
} }
@ -333,6 +333,8 @@ Example for configuring `docker` auth:
} }
``` ```
### hostType
## ignoreDeprecated ## ignoreDeprecated
By default, Renovate won't update any packages to deprecated versions unless the package version was _already_ deprecated. The goal of this is to make sure you don't upgrade from a non-deprecated version to a deprecated one just because it's higher than the current version. If for some reason you wish to _force_ deprecated updates on Renovate, you can set `ignoreDeprecated` to `false`, but this is not recommended for most situations. By default, Renovate won't update any packages to deprecated versions unless the package version was _already_ deprecated. The goal of this is to make sure you don't upgrade from a non-deprecated version to a deprecated one just because it's higher than the current version. If for some reason you wish to _force_ deprecated updates on Renovate, you can set `ignoreDeprecated` to `false`, but this is not recommended for most situations.

View file

@ -99,7 +99,7 @@ If you are running your own Renovate bot, add this to your `config.js`:
module.exports = { module.exports = {
hostRules: [ hostRules: [
{ {
platform: 'docker', hostType: 'docker',
username: '<your-username>', username: '<your-username>',
password: '<your-password>', password: '<your-password>',
}, },

View file

@ -44,12 +44,12 @@ Here is an example configuration to work with custom Artifactory servers using a
"enabled": true "enabled": true
}, },
"hostRules": [{ "hostRules": [{
"platform": "maven", "hostType": "maven",
"endpoint": "https://artifactoryurl1/", "endpoint": "https://artifactoryurl1/",
"username": "artifactoryusername", "username": "artifactoryusername",
"password": "artifactorypassword" "password": "artifactorypassword"
}, { }, {
"platform": "maven", "hostType": "maven",
"endpoint": "https://artifactoryurl2/", "endpoint": "https://artifactoryurl2/",
"username": "artifactoryusername", "username": "artifactoryusername",
"password": "artifactorypassword" "password": "artifactorypassword"

View file

@ -47,7 +47,7 @@ Credentials for authenticated/private feeds can be provided via host rules in th
```json ```json
"hostRules": [ "hostRules": [
{ {
"platform": "nuget", "hostType": "nuget",
"endpoint": "http://example1.com/nuget", "endpoint": "http://example1.com/nuget",
"username": "root", "username": "root",
"password": "p4$$w0rd" "password": "p4$$w0rd"