From c02abf0976f3e2a54ba0be785127870324856b06 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Tue, 21 May 2019 13:20:09 +0200 Subject: [PATCH] feat: rename hostRules.platform to hostRules.hostType (#3768) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactors hostRules to use field “hostType” instead of “platform”. hostType can include datasources like npm, maven, pypi, etc. --- lib/config/cli.js | 1 + lib/config/definitions.js | 10 ++++ lib/config/env.js | 4 +- lib/config/migration.js | 22 ++++---- lib/datasource/cargo/index.js | 2 +- lib/datasource/docker/index.js | 2 +- lib/datasource/github/index.js | 2 +- lib/datasource/go/index.js | 2 +- lib/datasource/hex/index.js | 2 +- lib/datasource/maven/index.js | 2 +- lib/datasource/npm/get.js | 2 +- lib/datasource/nuget/v2.js | 2 +- lib/datasource/nuget/v3.js | 6 +-- lib/datasource/packagist/index.js | 2 +- lib/datasource/pypi/index.js | 4 +- lib/datasource/rubygems/get.js | 2 +- lib/datasource/terraform/index.js | 2 +- lib/manager/composer/artifacts.js | 6 +-- lib/manager/gomod/artifacts.js | 2 +- lib/manager/npm/post-update/index.js | 4 +- lib/platform/azure/azure-got-wrapper.js | 4 +- lib/platform/azure/index.js | 2 +- .../bitbucket-server/bb-got-wrapper.ts | 4 +- lib/platform/bitbucket-server/index.ts | 6 +-- lib/platform/bitbucket/bb-got-wrapper.ts | 2 +- lib/platform/bitbucket/index.ts | 2 +- lib/platform/github/gh-got-wrapper.js | 2 +- lib/platform/github/index.js | 5 +- lib/platform/gitlab/gl-got-wrapper.js | 2 +- lib/platform/gitlab/index.js | 6 +-- lib/platform/index.js | 2 +- lib/util/got/host-rules.js | 4 +- lib/util/host-rules.ts | 52 ++++++++----------- lib/workers/pr/changelog/source-github.js | 2 +- renovate-schema.json | 15 +++++- test/config/__snapshots__/env.spec.js.snap | 4 +- .../__snapshots__/migration.spec.js.snap | 1 + test/config/cli.spec.js | 4 +- test/config/migration.spec.js | 9 ++++ .../__snapshots__/pypi.spec.js.snap | 8 +-- .../platform/__snapshots__/index.spec.js.snap | 2 +- test/platform/azure/azure-got-wrapper.spec.js | 2 +- test/platform/bitbucket-server/index.spec.ts | 2 +- .../platform/bitbucket/bb-got-wrapper.spec.ts | 2 +- test/platform/bitbucket/index.spec.ts | 2 +- test/platform/github/index.spec.js | 4 +- .../__snapshots__/host-rules.spec.js.snap | 8 +-- test/util/host-rules.spec.js | 36 ++++++------- test/workers/global/index.spec.js | 2 +- test/workers/pr/changelog/index.spec.js | 6 +-- website/docs/configuration-options.md | 4 +- website/docs/docker.md | 2 +- website/docs/java.md | 4 +- website/docs/nuget.md | 2 +- 54 files changed, 162 insertions(+), 133 deletions(-) diff --git a/lib/config/cli.js b/lib/config/cli.js index e2145f0edf..e8edc40c95 100644 --- a/lib/config/cli.js +++ b/lib/config/cli.js @@ -23,6 +23,7 @@ function getConfig(input) { .replace('--expose-env=true', '--trust-level=high') .replace('--expose-env', '--trust-level=high') .replace('--renovate-fork', '--include-forks') + .replace('"platform":"', '"hostType":"') ); const options = configDefinitions.getOptions(); diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 677aeda4c3..2fccee6f5f 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -1687,6 +1687,16 @@ const options = [ cli: 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', description: 'Table column definitions for use in PR tables', diff --git a/lib/config/env.js b/lib/config/env.js index a86d32403b..5fc7f9e017 100644 --- a/lib/config/env.js +++ b/lib/config/env.js @@ -42,14 +42,14 @@ function getConfig(env) { if (env.GITHUB_COM_TOKEN) { config.hostRules.push({ endpoint: 'https://api.github.com/', - platform: 'github', + hostType: 'github', token: env.GITHUB_COM_TOKEN, }); } if (env.DOCKER_USERNAME && env.DOCKER_PASSWORD) { config.hostRules.push({ - platform: 'docker', + hostType: 'docker', username: env.DOCKER_USERNAME, password: env.DOCKER_PASSWORD, }); diff --git a/lib/config/migration.js b/lib/config/migration.js index 1a6b49bb21..33b4c009c0 100644 --- a/lib/config/migration.js +++ b/lib/config/migration.js @@ -25,7 +25,7 @@ const removedOptions = [ ]; // Returns a migrated config -function migrateConfig(config) { +function migrateConfig(config, parentKey) { try { if (!optionTypes) { optionTypes = {}; @@ -50,7 +50,7 @@ function migrateConfig(config) { if (is.array(val)) { migratedConfig.packageRules = migratedConfig.packageRules || []; const migratedPathRules = migratedConfig.pathRules.map( - p => migrateConfig(p).migratedConfig + p => migrateConfig(p, key).migratedConfig ); migratedConfig.packageRules = migratedPathRules.concat( migratedConfig.packageRules @@ -74,6 +74,10 @@ function migrateConfig(config) { isMigrated = true; migratedConfig.gitFs = 'https'; } + } else if (parentKey === 'hostRules' && key === 'platform') { + isMigrated = true; + migratedConfig.hostType = val; + delete migratedConfig.platform; } else if (key === 'packageFiles' && is.array(val)) { isMigrated = true; const fileList = []; @@ -82,7 +86,7 @@ function migrateConfig(config) { fileList.push(packageFile.packageFile); if (Object.keys(packageFile).length > 1) { migratedConfig.packageRules = migratedConfig.packageRules || []; - const payload = migrateConfig(packageFile).migratedConfig; + const payload = migrateConfig(packageFile, key).migratedConfig; for (const subrule of payload.packageRules || []) { subrule.paths = [packageFile.packageFile]; migratedConfig.packageRules.push(subrule); @@ -105,7 +109,7 @@ function migrateConfig(config) { } else if (depTypes.includes(key)) { isMigrated = true; migratedConfig.packageRules = migratedConfig.packageRules || []; - const depTypePackageRule = migrateConfig(val).migratedConfig; + const depTypePackageRule = migrateConfig(val, key).migratedConfig; depTypePackageRule.depTypeList = [key]; delete depTypePackageRule.packageRules; migratedConfig.packageRules.push(depTypePackageRule); @@ -229,7 +233,7 @@ function migrateConfig(config) { isMigrated = true; migratedConfig.packageRules = migratedConfig.packageRules || []; migratedConfig.packageRules = migratedConfig.packageRules.concat( - migratedConfig.packages.map(p => migrateConfig(p).migratedConfig) + migratedConfig.packages.map(p => migrateConfig(p, key).migratedConfig) ); delete migratedConfig.packages; } else if (key === 'excludedPackageNames') { @@ -340,7 +344,7 @@ function migrateConfig(config) { const depTypeName = depType.depType; if (depTypeName) { migratedConfig.packageRules = migratedConfig.packageRules || []; - const newPackageRule = migrateConfig(depType).migratedConfig; + const newPackageRule = migrateConfig(depType, key).migratedConfig; delete newPackageRule.depType; newPackageRule.depTypeList = [depTypeName]; migratedConfig.packageRules.push(newPackageRule); @@ -372,14 +376,14 @@ function migrateConfig(config) { if (!Object.keys(migratedConfig.node).length) { delete migratedConfig.node; } else { - const subMigrate = migrateConfig(migratedConfig.node); + const subMigrate = migrateConfig(migratedConfig.node, key); migratedConfig.node = subMigrate.migratedConfig; } } else if (is.array(val)) { const newArray = []; for (const item of migratedConfig[key]) { if (is.object(item) && !is.array(item)) { - const arrMigrate = migrateConfig(item); + const arrMigrate = migrateConfig(item, key); newArray.push(arrMigrate.migratedConfig); if (arrMigrate.isMigrated) { isMigrated = true; @@ -390,7 +394,7 @@ function migrateConfig(config) { } migratedConfig[key] = newArray; } else if (is.object(val)) { - const subMigrate = migrateConfig(migratedConfig[key]); + const subMigrate = migrateConfig(migratedConfig[key], key); if (subMigrate.isMigrated) { isMigrated = true; migratedConfig[key] = subMigrate.migratedConfig; diff --git a/lib/datasource/cargo/index.js b/lib/datasource/cargo/index.js index 47a74f1fb5..f23a15cc64 100644 --- a/lib/datasource/cargo/index.js +++ b/lib/datasource/cargo/index.js @@ -36,7 +36,7 @@ async function getPkgReleases({ lookupName }) { const crateUrl = baseUrl + path; try { let res = await got(crateUrl, { - platform: 'cargo', + hostType: 'cargo', }); if (!res || !res.body) { logger.warn( diff --git a/lib/datasource/docker/index.js b/lib/datasource/docker/index.js index d67add8414..e5ccc6acc6 100644 --- a/lib/datasource/docker/index.js +++ b/lib/datasource/docker/index.js @@ -51,7 +51,7 @@ async function getAuthHeaders(registry, repository) { ); 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) { const auth = Buffer.from(`${opts.username}:${opts.password}`).toString( 'base64' diff --git a/lib/datasource/github/index.js b/lib/datasource/github/index.js index bc345a7bd5..4fcde592aa 100644 --- a/lib/datasource/github/index.js +++ b/lib/datasource/github/index.js @@ -16,7 +16,7 @@ async function fetchJSONFile(repo, fileName) { : 'application/vnd.github.v3+json', }, json: true, - platform: 'github', + hostType: 'github', }; let res; try { diff --git a/lib/datasource/go/index.js b/lib/datasource/go/index.js index f76ad4bac5..c1d541a026 100644 --- a/lib/datasource/go/index.js +++ b/lib/datasource/go/index.js @@ -25,7 +25,7 @@ async function getDatasource(name) { const pkgUrl = `https://${name}?go-get=1`; try { const res = (await got(pkgUrl, { - platform: 'go', + hostType: 'go', })).body; const sourceMatch = res.match( new RegExp(`<meta name="go-source" content="${name}\\s+([^\\s]+)`) diff --git a/lib/datasource/hex/index.js b/lib/datasource/hex/index.js index fc78696fe8..96f3d6cd7c 100644 --- a/lib/datasource/hex/index.js +++ b/lib/datasource/hex/index.js @@ -7,7 +7,7 @@ module.exports = { function getHostOpts() { return { json: true, - platform: 'hex', + hostType: 'hex', }; } diff --git a/lib/datasource/maven/index.js b/lib/datasource/maven/index.js index 1b1e2d0547..f1c66efd3e 100644 --- a/lib/datasource/maven/index.js +++ b/lib/datasource/maven/index.js @@ -136,7 +136,7 @@ async function downloadFileProtocol(pkgUrl) { async function downloadHttpProtocol(pkgUrl) { let raw; try { - raw = await got(pkgUrl, { platform: 'maven' }); + raw = await got(pkgUrl, { hostType: 'maven' }); } catch (err) { if (isNotFoundError(err)) { logger.debug(`Url not found ${pkgUrl}`); diff --git a/lib/datasource/npm/get.js b/lib/datasource/npm/get.js index c2de383486..be2c2794b9 100644 --- a/lib/datasource/npm/get.js +++ b/lib/datasource/npm/get.js @@ -132,7 +132,7 @@ async function getDependency(name) { if (res.repository && res.repository.url) { const extraBaseUrls = []; // istanbul ignore next - hostRules.hosts({ platform: 'github' }).forEach(host => { + hostRules.hosts({ hostType: 'github' }).forEach(host => { extraBaseUrls.push(host, `gist.${host}`); }); // Massage www out of github URL diff --git a/lib/datasource/nuget/v2.js b/lib/datasource/nuget/v2.js index 7021db5f7d..d959e1a4e3 100644 --- a/lib/datasource/nuget/v2.js +++ b/lib/datasource/nuget/v2.js @@ -15,7 +15,7 @@ async function getPkgReleases(feedUrl, pkgName) { let pkgUrlList = `${feedUrl}/FindPackagesById()?id=%27${pkgName}%27&$select=Version,IsLatestVersion,ProjectUrl`; do { - const pkgVersionsListRaw = await got(pkgUrlList, { platform: 'nuget' }); + const pkgVersionsListRaw = await got(pkgUrlList, { hostType: 'nuget' }); if (pkgVersionsListRaw.statusCode !== 200) { logger.debug( { dependency: pkgName, pkgVersionsListRaw }, diff --git a/lib/datasource/nuget/v3.js b/lib/datasource/nuget/v3.js index a43313f53a..6068ab2009 100644 --- a/lib/datasource/nuget/v3.js +++ b/lib/datasource/nuget/v3.js @@ -29,7 +29,7 @@ async function getQueryUrl(url) { } try { - const servicesIndexRaw = await got(url, { json: true, platform: 'nuget' }); + const servicesIndexRaw = await got(url, { json: true, hostType: 'nuget' }); if (servicesIndexRaw.statusCode !== 200) { logger.debug( { dependency: url, servicesIndexRaw }, @@ -72,7 +72,7 @@ async function getPkgReleases(registryUrl, feedUrl, pkgName) { try { const pkgUrlListRaw = await got(queryUrl, { json: true, - platform: 'nuget', + hostType: 'nuget', }); if (pkgUrlListRaw.statusCode !== 200) { 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`; let metaresult; try { - metaresult = await got(nugetOrgApi, { platform: 'nuget' }); + metaresult = await got(nugetOrgApi, { hostType: 'nuget' }); } catch (err) /* istanbul ignore next */ { logger.debug( `Cannot fetch metadata for ${pkgName} using popped version ${lastVersion}` diff --git a/lib/datasource/packagist/index.js b/lib/datasource/packagist/index.js index b6ff94a387..a6a3a98069 100644 --- a/lib/datasource/packagist/index.js +++ b/lib/datasource/packagist/index.js @@ -13,7 +13,7 @@ module.exports = { function getHostOpts(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) { const auth = Buffer.from(`${opts.username}:${opts.password}`).toString( 'base64' diff --git a/lib/datasource/pypi/index.js b/lib/datasource/pypi/index.js index 8520ce1239..e4ad311790 100644 --- a/lib/datasource/pypi/index.js +++ b/lib/datasource/pypi/index.js @@ -56,7 +56,7 @@ async function getDependency(depName, hostUrl, compatibility) { const dependency = {}; const rep = await got(url.parse(lookupUrl), { json: true, - platform: 'pypi', + hostType: 'pypi', }); const dep = rep && rep.body; if (!dep) { @@ -105,7 +105,7 @@ async function getSimpleDependency(depName, hostUrl) { const dependency = {}; const response = await got(url.parse(lookupUrl), { json: false, - platform: 'pypi', + hostType: 'pypi', }); const dep = response && response.body; if (!dep) { diff --git a/lib/datasource/rubygems/get.js b/lib/datasource/rubygems/get.js index ca25bc202b..efce817185 100644 --- a/lib/datasource/rubygems/get.js +++ b/lib/datasource/rubygems/get.js @@ -31,7 +31,7 @@ const processError = ({ err, ...rest }) => { }; const getHeaders = () => { - return { platform: 'rubygems' }; + return { hostType: 'rubygems' }; }; const fetch = async ({ dependency, registry, path }) => { diff --git a/lib/datasource/terraform/index.js b/lib/datasource/terraform/index.js index 1603303fff..b9c7b83bc4 100644 --- a/lib/datasource/terraform/index.js +++ b/lib/datasource/terraform/index.js @@ -52,7 +52,7 @@ async function getPkgReleases({ lookupName, registryUrls }) { try { const res = (await got(pkgUrl, { json: true, - platform: 'terraform', + hostType: 'terraform', })).body; const returnedName = res.namespace + '/' + res.name + '/' + res.provider; if (returnedName !== repository) { diff --git a/lib/manager/composer/artifacts.js b/lib/manager/composer/artifacts.js index 7fad82bdc2..fccb140f05 100644 --- a/lib/manager/composer/artifacts.js +++ b/lib/manager/composer/artifacts.js @@ -40,7 +40,7 @@ async function getArtifacts( } let authJson = {}; let credentials = hostRules.find({ - platform: 'github', + hostType: 'github', host: 'api.github.com', }); // istanbul ignore if @@ -50,7 +50,7 @@ async function getArtifacts( }; } credentials = hostRules.find({ - platform: 'gitlab', + hostType: 'gitlab', host: 'gitlab.com', }); // istanbul ignore if @@ -66,7 +66,7 @@ async function getArtifacts( if (regUrl.url) { const { host } = URL.parse(regUrl.url); const hostRule = hostRules.find({ - platform: 'packagist', + hostType: 'packagist', host, }); // istanbul ignore else diff --git a/lib/manager/gomod/artifacts.js b/lib/manager/gomod/artifacts.js index cfdbe02b2a..3407eecfa9 100644 --- a/lib/manager/gomod/artifacts.js +++ b/lib/manager/gomod/artifacts.js @@ -62,7 +62,7 @@ async function getArtifacts( cmd += `-w ${cwd} `; cmd += `renovate/go `; const credentials = hostRules.find({ - platform: 'github', + hostType: 'github', host: 'api.github.com', }); if (credentials && credentials.token) { diff --git a/lib/manager/npm/post-update/index.js b/lib/manager/npm/post-update/index.js index b0b12c7b2e..a466b4b905 100644 --- a/lib/manager/npm/post-update/index.js +++ b/lib/manager/npm/post-update/index.js @@ -304,7 +304,7 @@ async function writeUpdatedPackageFiles(config) { delete massagedFile.engines; delete massagedFile.scripts; try { - const { token } = hostRules.find({ platform: config.platform }); + const { token } = hostRules.find({ hostType: config.platform }); for (const upgrade of config.upgrades) { if (upgrade.gitRef && upgrade.packageFile === packageFile.name) { massagedFile[upgrade.depType][upgrade.depName] = massagedFile[ @@ -377,7 +377,7 @@ async function getAdditionalFiles(config, packageFiles) { let token = ''; try { - ({ token } = hostRules.find({ platform: config.platform })); + ({ token } = hostRules.find({ hostType: config.platform })); token += '@'; } catch (err) { logger.warn({ err }, 'Error getting token for packageFile'); diff --git a/lib/platform/azure/azure-got-wrapper.js b/lib/platform/azure/azure-got-wrapper.js index 10733e9978..24ee067a3a 100644 --- a/lib/platform/azure/azure-got-wrapper.js +++ b/lib/platform/azure/azure-got-wrapper.js @@ -1,7 +1,7 @@ const azure = require('azure-devops-node-api'); const hostRules = require('../../util/host-rules'); -const platform = 'azure'; +const hostType = 'azure'; let endpoint; module.exports = { @@ -12,7 +12,7 @@ module.exports = { }; function azureObj() { - const config = hostRules.find({ platform, endpoint }); + const config = hostRules.find({ hostType, endpoint }); if (!(config && config.token)) { throw new Error(`No token found for azure`); } diff --git a/lib/platform/azure/index.js b/lib/platform/azure/index.js index 70dd1cc8b2..68da0559a1 100644 --- a/lib/platform/azure/index.js +++ b/lib/platform/azure/index.js @@ -8,7 +8,7 @@ const GitStorage = require('../git/storage'); let config = {}; const defaults = { - platform: 'azure', + hostType: 'azure', }; module.exports = { diff --git a/lib/platform/bitbucket-server/bb-got-wrapper.ts b/lib/platform/bitbucket-server/bb-got-wrapper.ts index 066de5393c..9e6f04d5ec 100644 --- a/lib/platform/bitbucket-server/bb-got-wrapper.ts +++ b/lib/platform/bitbucket-server/bb-got-wrapper.ts @@ -5,7 +5,7 @@ import { IGotApiOptions, IGotApi } from '../common'; let cache: Renovate.IDict<got.Response<any>> = {}; -const platform = 'bitbucket-server'; +const hostType = 'bitbucket-server'; let endpoint: string; 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, json: true, basic: false, - ...hostRules.find({ platform, host }), + ...hostRules.find({ hostType, host }), ...options, }; const url = URL.resolve(endpoint, path); diff --git a/lib/platform/bitbucket-server/index.ts b/lib/platform/bitbucket-server/index.ts index 8adea7fc0c..7ca97a5b8c 100644 --- a/lib/platform/bitbucket-server/index.ts +++ b/lib/platform/bitbucket-server/index.ts @@ -6,8 +6,6 @@ import * as utils from './utils'; import * as hostRules from '../../util/host-rules'; import GitStorage from '../git/storage'; -const platform = 'bitbucket-server'; - interface BbsConfig { baseBranch: string; bbUseDefaultReviewers: boolean; @@ -25,7 +23,7 @@ interface BbsConfig { let config: BbsConfig = {} as any; const defaults: any = { - platform: 'bitbucket-server', + hostType: 'bitbucket-server', }; export function initPlatform({ @@ -105,7 +103,7 @@ export async function initRepo({ 2 )}")` ); - const opts = hostRules.find({ platform }, { endpoint }); + const opts = hostRules.find({ hostType: defaults.hostType, endpoint }); api.reset(); const [projectKey, repositorySlug] = repository.split('/'); diff --git a/lib/platform/bitbucket/bb-got-wrapper.ts b/lib/platform/bitbucket/bb-got-wrapper.ts index bf816eb83e..1169071381 100644 --- a/lib/platform/bitbucket/bb-got-wrapper.ts +++ b/lib/platform/bitbucket/bb-got-wrapper.ts @@ -16,7 +16,7 @@ async function get(path: string, options: IGotApiOptions & got.GotJSONOptions) { timeout: 60 * 1000, json: true, basic: false, - ...hostRules.find({ platform: 'bitbucket', host }), + ...hostRules.find({ hostType: 'bitbucket', host }), ...options, }; const url = URL.resolve(endpoint, path); diff --git a/lib/platform/bitbucket/index.ts b/lib/platform/bitbucket/index.ts index 578187bd8c..78aba1a215 100644 --- a/lib/platform/bitbucket/index.ts +++ b/lib/platform/bitbucket/index.ts @@ -70,7 +70,7 @@ export async function initRepo({ localDir: string; }) { logger.debug(`initRepo("${repository}")`); - const opts = hostRules.find({ platform: 'bitbucket' }); + const opts = hostRules.find({ hostType: 'bitbucket' }); api.reset(); config = {} as any; // TODO: get in touch with @rarkins about lifting up the caching into the app layer diff --git a/lib/platform/github/gh-got-wrapper.js b/lib/platform/github/gh-got-wrapper.js index 64f33f85c4..0b0705f5b7 100644 --- a/lib/platform/github/gh-got-wrapper.js +++ b/lib/platform/github/gh-got-wrapper.js @@ -17,7 +17,7 @@ async function get(path, options, retries = 5) { const opts = { // TODO: Move to configurable host rules, or use utils/got timeout: 60 * 1000, - ...hostRules.find({ platform: 'github', host }), + ...hostRules.find({ hostType: 'github', host }), ...options, }; delete opts.endpoint; diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js index e3373ecfce..3040d3b20f 100644 --- a/lib/platform/github/index.js +++ b/lib/platform/github/index.js @@ -19,7 +19,7 @@ const defaultConfigFile = configFileNames[0]; let config = {}; const defaults = { - platform: 'github', + hostType: 'github', 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 cleanRepo(); const opts = hostRules.find({ - platform: 'github', + hostType: 'github', }); config.isGhe = opts.endpoint && !opts.endpoint.startsWith('https://api.github.com'); config.renovateUsername = renovateUsername; config.localDir = localDir; - config.platform = 'github'; config.repository = repository; [config.repositoryOwner, config.repositoryName] = repository.split('/'); config.gitPrivateKey = gitPrivateKey; diff --git a/lib/platform/gitlab/gl-got-wrapper.js b/lib/platform/gitlab/gl-got-wrapper.js index 9d4a90add7..2090b39123 100644 --- a/lib/platform/gitlab/gl-got-wrapper.js +++ b/lib/platform/gitlab/gl-got-wrapper.js @@ -13,7 +13,7 @@ async function get(path, options, retries = 5) { const opts = { // TODO: Move to configurable host rules, or use utils/got timeout: 60 * 1000, - ...hostRules.find({ platform: 'gitlab', host }), + ...hostRules.find({ hostType: 'gitlab', host }), ...options, }; const url = URL.resolve(endpoint, path); diff --git a/lib/platform/gitlab/index.js b/lib/platform/gitlab/index.js index 837efc11b0..2d08910cc9 100644 --- a/lib/platform/gitlab/index.js +++ b/lib/platform/gitlab/index.js @@ -7,7 +7,7 @@ const GitStorage = require('../git/storage'); let config = {}; const defaults = { - platform: 'gitlab', + hostType: 'gitlab', endpoint: 'https://gitlab.com/api/v4/', }; @@ -72,8 +72,8 @@ function initPlatform({ endpoint, token }) { get.setEndpoint(res.endpoint); defaults.endpoint = res.endpoint; } else { - logger.info('Using default GitLab endpoint: ' + res.endpoint); res.endpoint = defaults.endpoint; + logger.info('Using default GitLab endpoint: ' + res.endpoint); } // TODO: Add a connection check that endpoint/token combination are valid return res; @@ -139,7 +139,7 @@ async function initRepo({ repository, gitFs, localDir }) { logger.debug('Enabling Git FS'); const { host, protocol } = URL.parse(defaults.endpoint); const opts = hostRules.find({ - platform: 'gitlab', + hostType: 'gitlab', host, }); const url = GitStorage.getUrl({ diff --git a/lib/platform/index.js b/lib/platform/index.js index 884f446b45..5ffa7708c5 100644 --- a/lib/platform/index.js +++ b/lib/platform/index.js @@ -37,7 +37,7 @@ async function initPlatform(config) { token = base64(`${config.username}:${config.password}`); } const platformRule = { - platform: returnConfig.platform, + hostType: returnConfig.platform, endpoint: returnConfig.endpoint, token, username: returnConfig.username, diff --git a/lib/util/got/host-rules.js b/lib/util/got/host-rules.js index 0586916e70..9afc87f47f 100644 --- a/lib/util/got/host-rules.js +++ b/lib/util/got/host-rules.js @@ -10,13 +10,13 @@ module.exports = got.create({ timeout: 60 * 1000, }, handler: (options, next) => { - const { platform, ...opts } = options; + const { hostType, ...opts } = options; if (!options.hostname) { return next(opts); } const hostRule = hostRules.find({ host: options.hostname, - platform, + hostType, }); if (!hostRule) { return next(opts); diff --git a/lib/util/host-rules.ts b/lib/util/host-rules.ts index 44b3624f42..86427874b1 100644 --- a/lib/util/host-rules.ts +++ b/lib/util/host-rules.ts @@ -1,13 +1,5 @@ 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 export interface IPlatformConfig { [prop: string]: any; @@ -19,31 +11,31 @@ export interface IPlatformConfig { interface IDict<T> { [key: string]: T; } -const platforms: IDict<IPlatformConfig> = {}; +const hostTypes: IDict<IPlatformConfig> = {}; const hostsOnly: IDict<IPlatformConfig> = {}; export function update(params: IPlatformConfig) { - const { platform } = params; - if (!platform) { + const { hostType } = params; + if (!hostType) { if (params.endpoint) { const { host } = URL.parse(params.endpoint); hostsOnly[host!] = params; return true; } 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 { endpoint } = config; if (!endpoint) { // istanbul ignore if - if (platform === 'docker') { - platforms.docker = params; + if (hostType === 'docker') { + hostTypes.docker = params; return true; } throw new Error( - `Failed to configure platform '${platform}': no endpoint defined` + `Failed to configure hostType '${hostType}': no endpoint defined` ); } config.endpoint = endpoint.replace(/[^/]$/, '$&/'); @@ -54,42 +46,42 @@ export function update(params: IPlatformConfig) { host = host || (endpoint && URL.parse('http://' + endpoint).host); if (!host) { 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'); - platforms[platform][host] = { ...platforms[platform][host], ...config }; + hostTypes[hostType][host] = { ...hostTypes[hostType][host], ...config }; return true; } export function find( { - platform, + hostType, host, endpoint, - }: { platform: string; host?: string; endpoint?: string }, + }: { hostType: string; host?: string; endpoint?: string }, overrides?: IPlatformConfig ) { const massagedHost = host || (endpoint ? URL.parse(endpoint).host : undefined); - if (!platforms[platform]) { + if (!hostTypes[hostType]) { if (massagedHost && hostsOnly[massagedHost]) { return merge(hostsOnly[massagedHost], overrides); } return merge(null, overrides); } // istanbul ignore if - if (platform === 'docker') { - if (platforms.docker.platform === 'docker') { - return merge(platforms.docker, overrides); + if (hostType === 'docker') { + if (hostTypes.docker.hostType === 'docker') { + return merge(hostTypes.docker, overrides); } - return merge(platforms.docker[massagedHost!], overrides); + return merge(hostTypes.docker[massagedHost!], overrides); } 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; if (configs.length === 1) { [config] = configs; @@ -97,8 +89,8 @@ export function find( return merge(config, overrides); } -export function hosts({ platform }: { platform: string }) { - return Object.keys({ ...platforms[platform] }); +export function hosts({ hostType }: { hostType: string }) { + return Object.keys({ ...hostTypes[hostType] }); } function merge(config: IPlatformConfig | null, overrides?: IPlatformConfig) { @@ -115,5 +107,5 @@ function merge(config: IPlatformConfig | null, overrides?: IPlatformConfig) { } export function clear() { - Object.keys(platforms).forEach(key => delete platforms[key]); + Object.keys(hostTypes).forEach(key => delete hostTypes[key]); } diff --git a/lib/workers/pr/changelog/source-github.js b/lib/workers/pr/changelog/source-github.js index a9870c86ca..f5f7488787 100644 --- a/lib/workers/pr/changelog/source-github.js +++ b/lib/workers/pr/changelog/source-github.js @@ -56,7 +56,7 @@ async function getChangeLogJSON({ const { protocol, host, pathname } = URL.parse(sourceUrl); const githubBaseURL = `${protocol}//${host}/`; const config = hostRules.find({ - platform: 'github', + hostType: 'github', host: host === 'github.com' ? 'api.github.com' : host, }); if (!config) { diff --git a/renovate-schema.json b/renovate-schema.json index eecf5bb8bc..89af15ae90 100644 --- a/renovate-schema.json +++ b/renovate-schema.json @@ -1159,7 +1159,20 @@ }, "hostRules": { "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": { "description": "Table column definitions for use in PR tables", diff --git a/test/config/__snapshots__/env.spec.js.snap b/test/config/__snapshots__/env.spec.js.snap index 035f17cdf4..aa4282aec6 100644 --- a/test/config/__snapshots__/env.spec.js.snap +++ b/test/config/__snapshots__/env.spec.js.snap @@ -42,7 +42,7 @@ Object { "hostRules": Array [ Object { "endpoint": "https://api.github.com/", - "platform": "github", + "hostType": "github", "token": "a github.com token", }, ], @@ -78,8 +78,8 @@ exports[`config/env .getConfig(env) supports docker username/password 1`] = ` Object { "hostRules": Array [ Object { + "hostType": "docker", "password": "some-password", - "platform": "docker", "username": "some-username", }, ], diff --git a/test/config/__snapshots__/migration.spec.js.snap b/test/config/__snapshots__/migration.spec.js.snap index 762ab39e60..e1cca575cd 100644 --- a/test/config/__snapshots__/migration.spec.js.snap +++ b/test/config/__snapshots__/migration.spec.js.snap @@ -121,6 +121,7 @@ Object { "patch": Object { "automerge": true, }, + "platform": "github", "postUpdateOptions": Array [ "gomodTidy", ], diff --git a/test/config/cli.spec.js b/test/config/cli.spec.js index 57862e7979..9f59b361f7 100644 --- a/test/config/cli.spec.js +++ b/test/config/cli.spec.js @@ -76,13 +76,13 @@ describe('config/cli', () => { }); it('parses json lists correctly', () => { 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({ hostRules: [ { host: 'docker.io', - platform: 'docker', + hostType: 'docker', username: 'user', password: 'password', }, diff --git a/test/config/migration.spec.js b/test/config/migration.spec.js index 58bb1bab37..3a9f8d60cb 100644 --- a/test/config/migration.spec.js +++ b/test/config/migration.spec.js @@ -7,6 +7,14 @@ describe('config/migration', () => { const config = { endpoints: [{}], enabled: true, + platform: 'github', + hostRules: [ + { + platform: 'docker', + username: 'some-username', + password: 'some-password', + }, + ], extends: [':js-app', 'config:library'], maintainYarnLock: true, onboarding: 'false', @@ -99,6 +107,7 @@ describe('config/migration', () => { expect(migratedConfig.depTypes).not.toBeDefined(); expect(migratedConfig.automerge).toEqual(false); expect(migratedConfig.packageRules).toHaveLength(7); + expect(migratedConfig.hostRules).toHaveLength(1); }); it('migrates before and after schedules', () => { const config = { diff --git a/test/datasource/__snapshots__/pypi.spec.js.snap b/test/datasource/__snapshots__/pypi.spec.js.snap index 607b5894e6..af721ded89 100644 --- a/test/datasource/__snapshots__/pypi.spec.js.snap +++ b/test/datasource/__snapshots__/pypi.spec.js.snap @@ -180,8 +180,8 @@ Array [ "slashes": true, }, Object { + "hostType": "pypi", "json": true, - "platform": "pypi", }, ], ] @@ -205,8 +205,8 @@ Array [ "slashes": true, }, Object { + "hostType": "pypi", "json": true, - "platform": "pypi", }, ], ] @@ -230,8 +230,8 @@ Array [ "slashes": true, }, Object { + "hostType": "pypi", "json": true, - "platform": "pypi", }, ], Array [ @@ -250,8 +250,8 @@ Array [ "slashes": true, }, Object { + "hostType": "pypi", "json": true, - "platform": "pypi", }, ], ] diff --git a/test/platform/__snapshots__/index.spec.js.snap b/test/platform/__snapshots__/index.spec.js.snap index 3bb3dbf79f..8a1a81343a 100644 --- a/test/platform/__snapshots__/index.spec.js.snap +++ b/test/platform/__snapshots__/index.spec.js.snap @@ -141,8 +141,8 @@ Object { "hostRules": Array [ Object { "endpoint": "https://api.bitbucket.org/", + "hostType": "bitbucket", "password": "123", - "platform": "bitbucket", "token": "YWJjOjEyMw==", "username": "abc", }, diff --git a/test/platform/azure/azure-got-wrapper.spec.js b/test/platform/azure/azure-got-wrapper.spec.js index 6e414c2022..780284ab24 100644 --- a/test/platform/azure/azure-got-wrapper.spec.js +++ b/test/platform/azure/azure-got-wrapper.spec.js @@ -15,7 +15,7 @@ describe('platform/azure/azure-got-wrapper', () => { }); it('should set token and endpoint', async () => { hostRules.update({ - platform: 'azure', + hostType: 'azure', token: 'token', endpoint: 'https://dev.azure.com/renovate12345', }); diff --git a/test/platform/bitbucket-server/index.spec.ts b/test/platform/bitbucket-server/index.spec.ts index 30cbb322b7..f8992eade7 100644 --- a/test/platform/bitbucket-server/index.spec.ts +++ b/test/platform/bitbucket-server/index.spec.ts @@ -66,7 +66,7 @@ describe('platform/bitbucket-server', () => { ? 'https://stash.renovatebot.com/vcs/' : 'https://stash.renovatebot.com'; hostRules.find.mockReturnValue({ - platform: 'bitbucket-server', + hostType: 'bitbucket-server', endpoint, username: 'abc', password: '123', diff --git a/test/platform/bitbucket/bb-got-wrapper.spec.ts b/test/platform/bitbucket/bb-got-wrapper.spec.ts index cd62ebd784..4e337fc8ea 100644 --- a/test/platform/bitbucket/bb-got-wrapper.spec.ts +++ b/test/platform/bitbucket/bb-got-wrapper.spec.ts @@ -15,7 +15,7 @@ describe('platform/gl-got-wrapper', () => { // clean up hostRules hostRules.clear(); hostRules.update({ - platform: 'bitbucket', + hostType: 'bitbucket', endpoint: 'https://api.bitbucket.org', token: 'token', }); diff --git a/test/platform/bitbucket/index.spec.ts b/test/platform/bitbucket/index.spec.ts index d61ce742c6..5edb826614 100644 --- a/test/platform/bitbucket/index.spec.ts +++ b/test/platform/bitbucket/index.spec.ts @@ -40,7 +40,7 @@ describe('platform/bitbucket', () => { // clean up hostRules hostRules.clear(); hostRules.find.mockReturnValue({ - platform: 'bitbucket', + hostType: 'bitbucket', endpoint: 'https://bitbucket.org', username: 'abc', password: '123', diff --git a/test/platform/github/index.spec.js b/test/platform/github/index.spec.js index 76206b1133..3dd49e202a 100644 --- a/test/platform/github/index.spec.js +++ b/test/platform/github/index.spec.js @@ -15,7 +15,7 @@ describe('platform/github', () => { hostRules = require('../../../lib/util/host-rules'); delete global.gitAuthor; hostRules.find.mockReturnValue({ - platform: 'github', + hostType: 'github', endpoint: 'https://api.github.com', token: 'abc123', }); @@ -1673,7 +1673,7 @@ describe('platform/github', () => { }); it('returns not-updated pr body for GHE', async () => { hostRules.find.mockReturnValue({ - platform: 'github', + hostType: 'github', endpoint: 'https://github.company.com', token: 'abc123', }); diff --git a/test/util/__snapshots__/host-rules.spec.js.snap b/test/util/__snapshots__/host-rules.spec.js.snap index 03060ad866..89d0a5b35e 100644 --- a/test/util/__snapshots__/host-rules.spec.js.snap +++ b/test/util/__snapshots__/host-rules.spec.js.snap @@ -3,8 +3,8 @@ exports[`util/host-rules find() allows overrides 1`] = ` Object { "endpoint": "endpoint/", + "hostType": "github", "other": "data", - "platform": "github", "token": "secret", } `; @@ -24,7 +24,7 @@ Object { exports[`util/host-rules find() matches on endpoint 1`] = ` Object { "endpoint": "https://nuget.local/api/", - "platform": "nuget", + "hostType": "nuget", "token": "abc", } `; @@ -32,7 +32,7 @@ Object { exports[`util/host-rules find() matches on endpoint subresource 1`] = ` Object { "endpoint": "https://nuget.local/api/", - "platform": "nuget", + "hostType": "nuget", "token": "abc", } `; @@ -41,8 +41,8 @@ exports[`util/host-rules find() needs exact host matches 1`] = ` Object { "endpoint": "endpoint/", "host": "nuget.org", + "hostType": "nuget", "password": "p4$$w0rd", - "platform": "nuget", "username": "root", } `; diff --git a/test/util/host-rules.spec.js b/test/util/host-rules.spec.js index 1b9118711c..8fd2c6cba6 100644 --- a/test/util/host-rules.spec.js +++ b/test/util/host-rules.spec.js @@ -5,22 +5,22 @@ describe('util/host-rules', () => { clear(); }); describe('update()', () => { - it('throws if no platform ', () => { + it('throws if no hostType ', () => { 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 ', () => { - expect(() => update({ platform: 'azure' })).toThrow( - `Failed to configure platform 'azure': no endpoint defined` + expect(() => update({ hostType: 'azure' })).toThrow( + `Failed to configure hostType 'azure': no endpoint defined` ); }); it('throws if invalid endpoint ', () => { expect(() => - update({ platform: 'azure', endpoint: '/some/path' }) + update({ hostType: 'azure', endpoint: '/some/path' }) ).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', () => { @@ -35,7 +35,7 @@ describe('util/host-rules', () => { describe('find()', () => { it('allows overrides', () => { update({ - platform: 'github', + hostType: 'github', endpoint: 'endpoint', token: 'token', other: 'data', @@ -45,49 +45,49 @@ describe('util/host-rules', () => { other: null, foo: undefined, }; - expect(find({ platform: 'github' }, overrides)).toMatchSnapshot(); + expect(find({ hostType: 'github' }, overrides)).toMatchSnapshot(); expect( - find({ platform: 'github', host: 'api.github.com' }, overrides) + find({ hostType: 'github', host: 'api.github.com' }, overrides) ).toMatchSnapshot(); expect( - find({ platform: 'github', host: 'example.com' }, overrides) + find({ hostType: 'github', host: 'example.com' }, overrides) ).toMatchSnapshot(); }); it('needs exact host matches', () => { update({ - platform: 'nuget', + hostType: 'nuget', endpoint: 'endpoint', host: 'nuget.org', username: 'root', password: 'p4$$w0rd', }); - expect(find({ platform: 'nuget', host: 'nuget.org' })).toMatchSnapshot(); + expect(find({ hostType: 'nuget', host: 'nuget.org' })).toMatchSnapshot(); expect( - find({ platform: 'nuget', host: 'not.nuget.org' }) + find({ hostType: 'nuget', host: 'not.nuget.org' }) ).toMatchSnapshot(); expect( - find({ platform: 'nuget', host: 'not-nuget.org' }) + find({ hostType: 'nuget', host: 'not-nuget.org' }) ).toMatchSnapshot(); }); it('matches on endpoint', () => { update({ - platform: 'nuget', + hostType: 'nuget', endpoint: 'https://nuget.local/api', token: 'abc', }); expect( - find({ platform: 'nuget', endpoint: 'https://nuget.local/api' }) + find({ hostType: 'nuget', endpoint: 'https://nuget.local/api' }) ).toMatchSnapshot(); }); it('matches on endpoint subresource', () => { update({ - platform: 'nuget', + hostType: 'nuget', endpoint: 'https://nuget.local/api', token: 'abc', }); expect( find({ - platform: 'nuget', + hostType: 'nuget', endpoint: 'https://nuget.local/api/sub-resource', }) ).toMatchSnapshot(); diff --git a/test/workers/global/index.spec.js b/test/workers/global/index.spec.js index 040d745c7a..d2299cc21e 100644 --- a/test/workers/global/index.spec.js +++ b/test/workers/global/index.spec.js @@ -36,7 +36,7 @@ describe('lib/workers/global', () => { repositories: ['a', 'b'], hostRules: [ { - platform: 'docker', + hostType: 'docker', host: 'docker.io', username: 'some-user', password: 'some-password', diff --git a/test/workers/pr/changelog/index.spec.js b/test/workers/pr/changelog/index.spec.js index 845dda2fa9..3be01f79bd 100644 --- a/test/workers/pr/changelog/index.spec.js +++ b/test/workers/pr/changelog/index.spec.js @@ -36,7 +36,7 @@ describe('workers/pr/changelog', () => { ghGot.mockClear(); hostRules.clear(); hostRules.update({ - platform: 'github', + hostType: 'github', endpoint: 'https://api.github.com/', }); await global.renovateCache.rmAll(); @@ -156,7 +156,7 @@ describe('workers/pr/changelog', () => { }); it('supports github enterprise and github.com changelog', async () => { hostRules.update({ - platform: 'github', + hostType: 'github', token: 'super_secret', endpoint: 'https://github-enterprise.example.com/', }); @@ -168,7 +168,7 @@ describe('workers/pr/changelog', () => { }); it('supports github enterprise and github enterprise changelog', async () => { hostRules.update({ - platform: 'github', + hostType: 'github', endpoint: 'https://github-enterprise.example.com/', }); process.env.GITHUB_ENDPOINT = ''; diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md index f3e52b0c07..4be7d8c997 100644 --- a/website/docs/configuration-options.md +++ b/website/docs/configuration-options.md @@ -325,7 +325,7 @@ Example for configuring `docker` auth: { "hostRules": [ { - "platform": "docker", + "hostType": "docker", "username": "<some-username>", "password": "<some-password>" } @@ -333,6 +333,8 @@ Example for configuring `docker` auth: } ``` +### hostType + ## 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. diff --git a/website/docs/docker.md b/website/docs/docker.md index 5eb574d364..45d1939bb6 100644 --- a/website/docs/docker.md +++ b/website/docs/docker.md @@ -99,7 +99,7 @@ If you are running your own Renovate bot, add this to your `config.js`: module.exports = { hostRules: [ { - platform: 'docker', + hostType: 'docker', username: '<your-username>', password: '<your-password>', }, diff --git a/website/docs/java.md b/website/docs/java.md index 2828d228eb..6e32ddc3ce 100644 --- a/website/docs/java.md +++ b/website/docs/java.md @@ -44,12 +44,12 @@ Here is an example configuration to work with custom Artifactory servers using a "enabled": true }, "hostRules": [{ - "platform": "maven", + "hostType": "maven", "endpoint": "https://artifactoryurl1/", "username": "artifactoryusername", "password": "artifactorypassword" }, { - "platform": "maven", + "hostType": "maven", "endpoint": "https://artifactoryurl2/", "username": "artifactoryusername", "password": "artifactorypassword" diff --git a/website/docs/nuget.md b/website/docs/nuget.md index 42e2803276..e8fa1b9224 100644 --- a/website/docs/nuget.md +++ b/website/docs/nuget.md @@ -47,7 +47,7 @@ Credentials for authenticated/private feeds can be provided via host rules in th ```json "hostRules": [ { - "platform": "nuget", + "hostType": "nuget", "endpoint": "http://example1.com/nuget", "username": "root", "password": "p4$$w0rd" -- GitLab