mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-24 14:34:21 +00:00
0583e54718
* refactor(constants): add a platform family capability table Every consumer of `detectPlatform` carried its own mapping from the detected platform to a tags datasource or a web UI path, and the seven `*_API_USING_HOST_TYPES` arrays were checked one by one to produce that platform in the first place. Introduce `PLATFORM_FAMILIES`, one record keyed by family holding the host types, the hostnames which identify the family outright, the tags datasource, the API base URL derivation and the web UI path to a directory at the default branch. A family is a group of platforms, so the ids are checked against `PlatformId`: a family which is not a platform is a compile error. Not every platform is a family, because codecommit, gerrit, local and scm-manager are never recognized from a URL. `detectPlatform` loops the table for both its hostname and its hostType matching, and the consumers look their answers up: - `github-actions` and `pre-commit` read `tagsDatasource` instead of importing the tags datasource classes. - The PR body reads `webDirPath` instead of special-casing Bitbucket and Bitbucket Server. `apiBaseUrl` has no consumer yet; the changelog sources pick it up in the next commit. `lib/util/http/auth.ts` and `lib/util/http/host-rules.ts` still read six of the old arrays by name, so those stay as aliases of the table and are migrated in a follow-up. `AZURE_API_USING_HOST_TYPES` had no other consumer and is dropped. Behaviour changes: none. `detectPlatform` now tests every known hostname before its name heuristics instead of interleaving the two, which is equivalent because the hostname lists are pairwise disjoint and no known hostname contains the name of another family. * Apply suggestion from @secustor
146 lines
4.0 KiB
TypeScript
146 lines
4.0 KiB
TypeScript
import { isNumber } from '@sindresorhus/is';
|
|
import JSON5 from 'json5';
|
|
import { parse as jsoncWeaverParse } from 'jsonc-weaver';
|
|
import type { JsonValue } from 'type-fest';
|
|
import { GlobalConfig } from '../config/global.ts';
|
|
import { InheritConfig, NOT_PRESENT } from '../config/inherit.ts';
|
|
import type { GlobalInheritableConfig } from '../config/types.ts';
|
|
import type { PlatformFamilyId } from '../constants/index.ts';
|
|
import { PLATFORM_FAMILIES } from '../constants/index.ts';
|
|
import { logger } from '../logger/index.ts';
|
|
import type { Nullish } from '../types/index.ts';
|
|
import * as hostRules from './host-rules.ts';
|
|
import { coerceObject } from './object.ts';
|
|
import { parseUrl } from './url.ts';
|
|
|
|
/**
|
|
* Tries to detect the `platform` from a url.
|
|
*
|
|
* @param url the url to detect `platform` from
|
|
* @returns matched `platform` if found, otherwise `null`
|
|
*/
|
|
export function detectPlatform(url: string): PlatformFamilyId | null {
|
|
const { hostname } = coerceObject(parseUrl(url));
|
|
if (hostname) {
|
|
// Azure DevOps kept serving organizations from their Visual Studio Team
|
|
// Services hostnames, which no other family can claim.
|
|
if (hostname.endsWith('.visualstudio.com')) {
|
|
return 'azure';
|
|
}
|
|
|
|
for (const [family, { knownHosts }] of Object.entries(PLATFORM_FAMILIES)) {
|
|
if (knownHosts.includes(hostname)) {
|
|
return family as PlatformFamilyId;
|
|
}
|
|
}
|
|
|
|
// Anything else is matched by name, so a self-hosted instance which was
|
|
// named after its vendor is recognized without a hostRule. Bitbucket is
|
|
// tested first because a self-hosted Bitbucket is always Data Center.
|
|
if (hostname.includes('bitbucket')) {
|
|
return 'bitbucket-server';
|
|
}
|
|
if (hostname.includes('forgejo')) {
|
|
return 'forgejo';
|
|
}
|
|
if (hostname.includes('gitea')) {
|
|
return 'gitea';
|
|
}
|
|
if (hostname.includes('github')) {
|
|
return 'github';
|
|
}
|
|
if (hostname.includes('gitlab')) {
|
|
return 'gitlab';
|
|
}
|
|
}
|
|
|
|
const hostType = hostRules.hostType({ url });
|
|
|
|
if (!hostType) {
|
|
return null;
|
|
}
|
|
|
|
for (const [family, { apiUsingHostTypes }] of Object.entries(
|
|
PLATFORM_FAMILIES,
|
|
)) {
|
|
if (apiUsingHostTypes.includes(hostType)) {
|
|
return family as PlatformFamilyId;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function noLeadingAtSymbol(input: string): string {
|
|
return input.startsWith('@') ? input.slice(1) : input;
|
|
}
|
|
|
|
export function parseJson(
|
|
content: Nullish<string>,
|
|
filename: string,
|
|
): JsonValue {
|
|
if (!content) {
|
|
return null;
|
|
}
|
|
|
|
if (filename.endsWith('.jsonc')) {
|
|
return parseJsonc(content);
|
|
}
|
|
|
|
if (filename.endsWith('.json5')) {
|
|
return JSON5.parse(content);
|
|
}
|
|
|
|
return parseJsonWithFallback(content, filename);
|
|
}
|
|
|
|
export function parseJsonWithFallback(
|
|
content: string,
|
|
context: string,
|
|
): JsonValue {
|
|
let parsedJson: JsonValue;
|
|
|
|
try {
|
|
parsedJson = parseJsonc(content);
|
|
} catch {
|
|
// warn if json5 format used in json
|
|
parsedJson = JSON5.parse(content);
|
|
logger.warn(
|
|
{ context },
|
|
'File contents are invalid JSONC but parse using JSON5. Support for this will be removed in a future release so please change to a support .json5 file name or ensure correct JSON syntax.',
|
|
);
|
|
}
|
|
|
|
return parsedJson;
|
|
}
|
|
|
|
export function parseJsonc(content: string): JsonValue {
|
|
return jsoncWeaverParse(content);
|
|
}
|
|
|
|
/**
|
|
* Use only if an option is inherited + globalOnly
|
|
* For globalOnly options use GlobalConfig.get
|
|
*/
|
|
export function getInheritedOrGlobal<Key extends keyof GlobalInheritableConfig>(
|
|
key: Key,
|
|
): GlobalInheritableConfig[Key] {
|
|
const inheritedValue = InheritConfig.get(key);
|
|
const globalValue = GlobalConfig.get(key);
|
|
if (inheritedValue !== NOT_PRESENT) {
|
|
// Don't allow inherited config to make `onboardingAutoCloseAge` a higher value than our global setting
|
|
if (
|
|
key === 'onboardingAutoCloseAge' &&
|
|
isNumber(inheritedValue) &&
|
|
isNumber(globalValue) &&
|
|
globalValue < inheritedValue
|
|
) {
|
|
return globalValue;
|
|
}
|
|
|
|
return inheritedValue;
|
|
}
|
|
|
|
return globalValue;
|
|
}
|