renovate 44.171.0 → 44.171.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/instrumentation/reporting.js +5 -1
- package/dist/instrumentation/reporting.js.map +1 -1
- package/dist/modules/datasource/common.d.ts +4 -0
- package/dist/modules/datasource/common.js +16 -1
- package/dist/modules/datasource/common.js.map +1 -1
- package/dist/modules/datasource/crate/index.js +4 -1
- package/dist/modules/datasource/crate/index.js.map +1 -1
- package/dist/modules/datasource/custom/index.js +5 -1
- package/dist/modules/datasource/custom/index.js.map +1 -1
- package/dist/modules/datasource/custom/utils.js +2 -1
- package/dist/modules/datasource/custom/utils.js.map +1 -1
- package/dist/modules/datasource/docker/common.js +1 -1
- package/dist/modules/datasource/git-refs/base.js +2 -1
- package/dist/modules/datasource/git-refs/base.js.map +1 -1
- package/dist/modules/datasource/index.js +20 -10
- package/dist/modules/datasource/index.js.map +1 -1
- package/dist/modules/datasource/metadata.js +36 -9
- package/dist/modules/datasource/metadata.js.map +1 -1
- package/dist/modules/manager/bun/extract.js +7 -2
- package/dist/modules/manager/bun/extract.js.map +1 -1
- package/dist/modules/manager/fingerprint.generated.js +4 -4
- package/dist/modules/manager/fingerprint.generated.js.map +1 -1
- package/dist/modules/manager/npm/extract/index.js +3 -2
- package/dist/modules/manager/npm/extract/index.js.map +1 -1
- package/dist/modules/manager/npm/extract/post/monorepo.js +6 -3
- package/dist/modules/manager/npm/extract/post/monorepo.js.map +1 -1
- package/dist/modules/manager/npm/npmrc.js +162 -11
- package/dist/modules/manager/npm/npmrc.js.map +1 -1
- package/dist/modules/manager/npmrc.js +35 -0
- package/dist/modules/manager/npmrc.js.map +1 -0
- package/dist/modules/manager/pep621/processors/uv.js +9 -3
- package/dist/modules/manager/pep621/processors/uv.js.map +1 -1
- package/dist/modules/manager/pipenv/artifacts.js +16 -5
- package/dist/modules/manager/pipenv/artifacts.js.map +1 -1
- package/dist/util/cache/package/index.js +7 -4
- package/dist/util/cache/package/index.js.map +1 -1
- package/dist/util/cache/repository/http-cache.js +10 -0
- package/dist/util/cache/repository/http-cache.js.map +1 -1
- package/dist/util/cache/sanitize-key.js +63 -0
- package/dist/util/cache/sanitize-key.js.map +1 -0
- package/dist/util/git/auth.js +22 -2
- package/dist/util/git/auth.js.map +1 -1
- package/dist/util/git/index.d.ts +2 -0
- package/dist/util/git/index.js +1 -1
- package/dist/util/git/index.js.map +1 -1
- package/dist/util/host-rules.d.ts +33 -2
- package/dist/util/host-rules.js +237 -12
- package/dist/util/host-rules.js.map +1 -1
- package/dist/util/http/cache/abstract-http-cache-provider.js +17 -0
- package/dist/util/http/cache/abstract-http-cache-provider.js.map +1 -1
- package/dist/util/http/cache/memory-http-cache-provider.js +1 -0
- package/dist/util/http/cache/memory-http-cache-provider.js.map +1 -1
- package/dist/util/http/cache/persisted-headers.js +27 -0
- package/dist/util/http/cache/persisted-headers.js.map +1 -0
- package/dist/util/http/cache/repository-http-cache-provider.js +7 -4
- package/dist/util/http/cache/repository-http-cache-provider.js.map +1 -1
- package/dist/util/http/host-rules.js +2 -15
- package/dist/util/http/host-rules.js.map +1 -1
- package/dist/util/http/http.js +1 -1
- package/dist/util/jsonata.js +1 -1
- package/dist/util/merge-confidence/index.js +1 -1
- package/dist/util/url.d.ts +38 -0
- package/dist/util/url.js +100 -2
- package/dist/util/url.js.map +1 -1
- package/dist/workers/repository/cache.js +9 -1
- package/dist/workers/repository/cache.js.map +1 -1
- package/dist/workers/repository/init/merge.js +1 -1
- package/dist/workers/repository/init/merge.js.map +1 -1
- package/dist/workers/repository/onboarding/branch/rebase.js +1 -1
- package/dist/workers/repository/onboarding/pr/index.js +1 -1
- package/dist/workers/repository/process/extract-update.js +53 -5
- package/dist/workers/repository/process/extract-update.js.map +1 -1
- package/dist/workers/repository/process/fetch.js +2 -1
- package/dist/workers/repository/process/fetch.js.map +1 -1
- package/dist/workers/repository/process/lookup/digest.js +8 -4
- package/dist/workers/repository/process/lookup/digest.js.map +1 -1
- package/dist/workers/repository/process/lookup/index.js +13 -8
- package/dist/workers/repository/process/lookup/index.js.map +1 -1
- package/dist/workers/repository/update/branch/index.js +5 -3
- package/dist/workers/repository/update/branch/index.js.map +1 -1
- package/dist/workers/repository/updates/branch-name.js +5 -4
- package/dist/workers/repository/updates/branch-name.js.map +1 -1
- package/dist/workers/repository/updates/flatten.js +2 -2
- package/dist/workers/repository/updates/flatten.js.map +1 -1
- package/dist/workers/repository/updates/generate.js +5 -4
- package/dist/workers/repository/updates/generate.js.map +1 -1
- package/package.json +2 -2
- package/renovate-schema.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { prettier } from "../expose.js";
|
|
2
|
+
import { sanitizeValue } from "../logger/utils.js";
|
|
2
3
|
import { getProblems, logger } from "../logger/index.js";
|
|
3
4
|
import { writeSystemFile } from "../util/fs/index.js";
|
|
4
5
|
import { getS3Client, parseS3Url } from "../util/s3.js";
|
|
@@ -35,8 +36,11 @@ function finalizeReport() {
|
|
|
35
36
|
} else report.problems.push(problem);
|
|
36
37
|
}
|
|
37
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Returns the report as JSON, sanitized like a log record.
|
|
41
|
+
*/
|
|
38
42
|
async function getReportBody(config) {
|
|
39
|
-
const json = JSON.stringify(report);
|
|
43
|
+
const json = JSON.stringify(sanitizeValue(report));
|
|
40
44
|
if (!config.reportFormatting) return json;
|
|
41
45
|
return prettier().format(json, { parser: "json" });
|
|
42
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporting.js","names":[],"sources":["../../lib/instrumentation/reporting.ts"],"sourcesContent":["import type { PutObjectCommandInput } from '@aws-sdk/client-s3';\nimport { PutObjectCommand } from '@aws-sdk/client-s3';\nimport { isNullOrUndefined, isUndefined } from '@sindresorhus/is';\nimport type { RenovateConfig } from '../config/types.ts';\nimport { prettier } from '../expose.ts';\nimport { getProblems, logger } from '../logger/index.ts';\nimport type { BranchCache } from '../util/cache/repository/types.ts';\nimport { writeSystemFile } from '../util/fs/index.ts';\nimport { getS3Client, parseS3Url } from '../util/s3.ts';\nimport type { ExtractResult } from '../workers/repository/process/extract-update.ts';\nimport type { LibYearsWithStatus, Report } from './types.ts';\n\nconst report: Report = {\n problems: [],\n repositories: {},\n};\n\n/**\n * Reset the report\n * Should only be used for testing\n */\nexport function resetReport(): void {\n report.problems = [];\n report.repositories = {};\n}\n\nexport function addBranchStats(\n config: RenovateConfig,\n branchesInformation: Partial<BranchCache>[],\n): void {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n coerceRepo(config.repository!);\n report.repositories[config.repository!].branches = branchesInformation;\n}\n\nexport function addExtractionStats(\n config: RenovateConfig,\n extractResult: ExtractResult,\n): void {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n coerceRepo(config.repository!);\n report.repositories[config.repository!].packageFiles =\n extractResult.packageFiles;\n}\n\nexport function addLibYears(\n config: RenovateConfig,\n libYearsWithDepCount: LibYearsWithStatus,\n): void {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n coerceRepo(config.repository!);\n report.repositories[config.repository!].libYearsWithStatus =\n libYearsWithDepCount;\n}\n\nexport function finalizeReport(): void {\n const allProblems = structuredClone(getProblems());\n for (const problem of allProblems) {\n const repository = problem.repository;\n delete problem.repository;\n\n // if the problem can be connected to a repository add it their else add to the root list\n if (repository) {\n coerceRepo(repository);\n report.repositories[repository].problems.push(problem);\n } else {\n report.problems.push(problem);\n }\n }\n}\n\nasync function getReportBody(config: RenovateConfig): Promise<string> {\n const json = JSON.stringify(report);\n if (!config.reportFormatting) {\n return json;\n }\n return prettier().format(json, { parser: 'json' });\n}\n\nexport async function exportStats(config: RenovateConfig): Promise<void> {\n try {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n if (config.reportType === 'logging') {\n logger.info({ report }, 'Printing report');\n return;\n }\n\n if (config.reportType === 'file') {\n const path = config.reportPath!;\n await writeSystemFile(path, await getReportBody(config));\n logger.debug({ path }, 'Writing report');\n return;\n }\n\n // v8 ignore else -- TODO: add test #40625\n if (config.reportType === 's3') {\n const s3Url = parseS3Url(config.reportPath!);\n if (isNullOrUndefined(s3Url)) {\n logger.warn(\n { reportPath: config.reportPath },\n 'Failed to parse s3 URL',\n );\n return;\n }\n\n const s3Params: PutObjectCommandInput = {\n Bucket: s3Url.Bucket,\n Key: s3Url.Key,\n Body: await getReportBody(config),\n ContentType: 'application/json',\n };\n\n const client = getS3Client(config.s3Endpoint, config.s3PathStyle);\n const command = new PutObjectCommand(s3Params);\n await client.send(command);\n }\n } catch (err) {\n logger.warn({ err }, 'Reporting.exportStats() - failure');\n }\n}\n\nexport function getReport(): Report {\n return structuredClone(report);\n}\n\nfunction coerceRepo(repository: string): void {\n if (!isUndefined(report.repositories[repository])) {\n return;\n }\n\n report.repositories[repository] = {\n problems: [],\n branches: [],\n packageFiles: {},\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"reporting.js","names":[],"sources":["../../lib/instrumentation/reporting.ts"],"sourcesContent":["import type { PutObjectCommandInput } from '@aws-sdk/client-s3';\nimport { PutObjectCommand } from '@aws-sdk/client-s3';\nimport { isNullOrUndefined, isUndefined } from '@sindresorhus/is';\nimport type { RenovateConfig } from '../config/types.ts';\nimport { prettier } from '../expose.ts';\nimport { getProblems, logger } from '../logger/index.ts';\nimport { sanitizeValue } from '../logger/utils.ts';\nimport type { BranchCache } from '../util/cache/repository/types.ts';\nimport { writeSystemFile } from '../util/fs/index.ts';\nimport { getS3Client, parseS3Url } from '../util/s3.ts';\nimport type { ExtractResult } from '../workers/repository/process/extract-update.ts';\nimport type { LibYearsWithStatus, Report } from './types.ts';\n\nconst report: Report = {\n problems: [],\n repositories: {},\n};\n\n/**\n * Reset the report\n * Should only be used for testing\n */\nexport function resetReport(): void {\n report.problems = [];\n report.repositories = {};\n}\n\nexport function addBranchStats(\n config: RenovateConfig,\n branchesInformation: Partial<BranchCache>[],\n): void {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n coerceRepo(config.repository!);\n report.repositories[config.repository!].branches = branchesInformation;\n}\n\nexport function addExtractionStats(\n config: RenovateConfig,\n extractResult: ExtractResult,\n): void {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n coerceRepo(config.repository!);\n report.repositories[config.repository!].packageFiles =\n extractResult.packageFiles;\n}\n\nexport function addLibYears(\n config: RenovateConfig,\n libYearsWithDepCount: LibYearsWithStatus,\n): void {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n coerceRepo(config.repository!);\n report.repositories[config.repository!].libYearsWithStatus =\n libYearsWithDepCount;\n}\n\nexport function finalizeReport(): void {\n const allProblems = structuredClone(getProblems());\n for (const problem of allProblems) {\n const repository = problem.repository;\n delete problem.repository;\n\n // if the problem can be connected to a repository add it their else add to the root list\n if (repository) {\n coerceRepo(repository);\n report.repositories[repository].problems.push(problem);\n } else {\n report.problems.push(problem);\n }\n }\n}\n\n/**\n * Returns the report as JSON, sanitized like a log record.\n */\nasync function getReportBody(config: RenovateConfig): Promise<string> {\n const json = JSON.stringify(sanitizeValue(report));\n if (!config.reportFormatting) {\n return json;\n }\n return prettier().format(json, { parser: 'json' });\n}\n\nexport async function exportStats(config: RenovateConfig): Promise<void> {\n try {\n if (isNullOrUndefined(config.reportType)) {\n return;\n }\n\n if (config.reportType === 'logging') {\n logger.info({ report }, 'Printing report');\n return;\n }\n\n if (config.reportType === 'file') {\n const path = config.reportPath!;\n await writeSystemFile(path, await getReportBody(config));\n logger.debug({ path }, 'Writing report');\n return;\n }\n\n // v8 ignore else -- TODO: add test #40625\n if (config.reportType === 's3') {\n const s3Url = parseS3Url(config.reportPath!);\n if (isNullOrUndefined(s3Url)) {\n logger.warn(\n { reportPath: config.reportPath },\n 'Failed to parse s3 URL',\n );\n return;\n }\n\n const s3Params: PutObjectCommandInput = {\n Bucket: s3Url.Bucket,\n Key: s3Url.Key,\n Body: await getReportBody(config),\n ContentType: 'application/json',\n };\n\n const client = getS3Client(config.s3Endpoint, config.s3PathStyle);\n const command = new PutObjectCommand(s3Params);\n await client.send(command);\n }\n } catch (err) {\n logger.warn({ err }, 'Reporting.exportStats() - failure');\n }\n}\n\nexport function getReport(): Report {\n return structuredClone(report);\n}\n\nfunction coerceRepo(repository: string): void {\n if (!isUndefined(report.repositories[repository])) {\n return;\n }\n\n report.repositories[repository] = {\n problems: [],\n branches: [],\n packageFiles: {},\n };\n}\n"],"mappings":";;;;;;;;AAaA,MAAM,SAAiB;CACrB,UAAU,CAAC;CACX,cAAc,CAAC;AACjB;AAWA,SAAgB,eACd,QACA,qBACM;CACN,IAAI,kBAAkB,OAAO,UAAU,GACrC;CAGF,WAAW,OAAO,UAAW;CAC7B,OAAO,aAAa,OAAO,WAAY,CAAC,WAAW;AACrD;AAEA,SAAgB,mBACd,QACA,eACM;CACN,IAAI,kBAAkB,OAAO,UAAU,GACrC;CAGF,WAAW,OAAO,UAAW;CAC7B,OAAO,aAAa,OAAO,WAAY,CAAC,eACtC,cAAc;AAClB;AAEA,SAAgB,YACd,QACA,sBACM;CACN,IAAI,kBAAkB,OAAO,UAAU,GACrC;CAGF,WAAW,OAAO,UAAW;CAC7B,OAAO,aAAa,OAAO,WAAY,CAAC,qBACtC;AACJ;AAEA,SAAgB,iBAAuB;CACrC,MAAM,cAAc,gBAAgB,YAAY,CAAC;CACjD,KAAK,MAAM,WAAW,aAAa;EACjC,MAAM,aAAa,QAAQ;EAC3B,OAAO,QAAQ;EAGf,IAAI,YAAY;GACd,WAAW,UAAU;GACrB,OAAO,aAAa,WAAW,CAAC,SAAS,KAAK,OAAO;EACvD,OACE,OAAO,SAAS,KAAK,OAAO;CAEhC;AACF;;;;AAKA,eAAe,cAAc,QAAyC;CACpE,MAAM,OAAO,KAAK,UAAU,cAAc,MAAM,CAAC;CACjD,IAAI,CAAC,OAAO,kBACV,OAAO;CAET,OAAO,SAAS,CAAC,CAAC,OAAO,MAAM,EAAE,QAAQ,OAAO,CAAC;AACnD;AAEA,eAAsB,YAAY,QAAuC;CACvE,IAAI;EACF,IAAI,kBAAkB,OAAO,UAAU,GACrC;EAGF,IAAI,OAAO,eAAe,WAAW;GACnC,OAAO,KAAK,EAAE,OAAO,GAAG,iBAAiB;GACzC;EACF;EAEA,IAAI,OAAO,eAAe,QAAQ;GAChC,MAAM,OAAO,OAAO;GACpB,MAAM,gBAAgB,MAAM,MAAM,cAAc,MAAM,CAAC;GACvD,OAAO,MAAM,EAAE,KAAK,GAAG,gBAAgB;GACvC;EACF;;EAGA,IAAI,OAAO,eAAe,MAAM;GAC9B,MAAM,QAAQ,WAAW,OAAO,UAAW;GAC3C,IAAI,kBAAkB,KAAK,GAAG;IAC5B,OAAO,KACL,EAAE,YAAY,OAAO,WAAW,GAChC,wBACF;IACA;GACF;GAEA,MAAM,WAAkC;IACtC,QAAQ,MAAM;IACd,KAAK,MAAM;IACX,MAAM,MAAM,cAAc,MAAM;IAChC,aAAa;GACf;GAEA,MAAM,SAAS,YAAY,OAAO,YAAY,OAAO,WAAW;GAChE,MAAM,UAAU,IAAI,iBAAiB,QAAQ;GAC7C,MAAM,OAAO,KAAK,OAAO;EAC3B;CACF,SAAS,KAAK;EACZ,OAAO,KAAK,EAAE,IAAI,GAAG,mCAAmC;CAC1D;AACF;AAMA,SAAS,WAAW,YAA0B;CAC5C,IAAI,CAAC,YAAY,OAAO,aAAa,WAAW,GAC9C;CAGF,OAAO,aAAa,cAAc;EAChC,UAAU,CAAC;EACX,UAAU,CAAC;EACX,cAAc,CAAC;CACjB;AACF"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { DatasourceApi, GetPkgReleasesConfig, ReleaseResult } from "./types.js";
|
|
2
2
|
//#region lib/modules/datasource/common.d.ts
|
|
3
3
|
export declare function getDatasourceFor(datasource: string): DatasourceApi | null;
|
|
4
|
+
/**
|
|
5
|
+
* Returns the host type the requests of `datasource` use, such as `custom` for `custom.<name>`, or `null` when there is no such datasource.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getDatasourceHostType(datasource: string): string | null;
|
|
4
8
|
export declare function getDefaultVersioning(datasourceName: string | undefined): string;
|
|
5
9
|
export declare function isGetPkgReleasesConfig(input: unknown): input is GetPkgReleasesConfig;
|
|
6
10
|
export declare function applyVersionCompatibility(releaseResult: ReleaseResult, versionCompatibility: string | undefined, currentCompatibility: string | undefined): ReleaseResult;
|
|
@@ -11,6 +11,21 @@ function getDatasourceFor(datasource) {
|
|
|
11
11
|
if (datasource?.startsWith("custom.")) return getDatasourceFor(CustomDatasource.id);
|
|
12
12
|
return api.get(datasource) ?? null;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* The host types of the datasources whose requests use another host type than their id.
|
|
16
|
+
*/
|
|
17
|
+
const datasourceHostTypes = {
|
|
18
|
+
"sbt-package": "sbt",
|
|
19
|
+
"sbt-plugin": "sbt"
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Returns the host type the requests of `datasource` use, such as `custom` for `custom.<name>`, or `null` when there is no such datasource.
|
|
23
|
+
*/
|
|
24
|
+
function getDatasourceHostType(datasource) {
|
|
25
|
+
const id = getDatasourceFor(datasource)?.id;
|
|
26
|
+
if (!id) return null;
|
|
27
|
+
return datasourceHostTypes[id] ?? id;
|
|
28
|
+
}
|
|
14
29
|
function getDefaultVersioning(datasourceName) {
|
|
15
30
|
if (!datasourceName) return defaultVersioning.id;
|
|
16
31
|
const datasource = getDatasourceFor(datasourceName);
|
|
@@ -249,6 +264,6 @@ function applyConstraintsFiltering(releaseResult, config) {
|
|
|
249
264
|
return releaseResult;
|
|
250
265
|
}
|
|
251
266
|
//#endregion
|
|
252
|
-
export { applyConstraintsFiltering, applyExtractVersion, applyVersionCompatibility, filterValidVersions, getDatasourceFor, getDefaultVersioning, isGetPkgReleasesConfig, sortAndRemoveDuplicates };
|
|
267
|
+
export { applyConstraintsFiltering, applyExtractVersion, applyVersionCompatibility, filterValidVersions, getDatasourceFor, getDatasourceHostType, getDefaultVersioning, isGetPkgReleasesConfig, sortAndRemoveDuplicates };
|
|
253
268
|
|
|
254
269
|
//# sourceMappingURL=common.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","names":["datasources","allVersioning.get"],"sources":["../../../lib/modules/datasource/common.ts"],"sourcesContent":["import {\n isNonEmptyArray,\n isNonEmptyStringAndNotWhitespace,\n} from '@sindresorhus/is';\nimport { logger } from '../../logger/index.ts';\nimport {\n type ConstraintName,\n isAdditionalConstraintName,\n} from '../../util/exec/types.ts';\nimport { filterMap } from '../../util/filter-map.ts';\nimport { regEx } from '../../util/regex.ts';\nimport * as allVersioning from '../versioning/index.ts';\nimport { defaultVersioning } from '../versioning/index.ts';\nimport datasources from './api.ts';\nimport { CustomDatasource } from './custom/index.ts';\nimport type {\n DatasourceApi,\n GetPkgReleasesConfig,\n ReleaseResult,\n} from './types.ts';\n\nexport function getDatasourceFor(datasource: string): DatasourceApi | null {\n if (datasource?.startsWith('custom.')) {\n return getDatasourceFor(CustomDatasource.id);\n }\n return datasources.get(datasource) ?? null;\n}\n\nexport function getDefaultVersioning(\n datasourceName: string | undefined,\n): string {\n if (!datasourceName) {\n return defaultVersioning.id;\n }\n\n const datasource = getDatasourceFor(datasourceName);\n\n if (!datasource) {\n logger.warn({ datasourceName }, 'Missing datasource!');\n return defaultVersioning.id;\n }\n\n if (!datasource.defaultVersioning) {\n return defaultVersioning.id;\n }\n\n return datasource.defaultVersioning;\n}\n\nexport function isGetPkgReleasesConfig(\n input: unknown,\n): input is GetPkgReleasesConfig {\n return (\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).datasource,\n ) &&\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).packageName,\n )\n );\n}\n\nexport function applyVersionCompatibility(\n releaseResult: ReleaseResult,\n versionCompatibility: string | undefined,\n currentCompatibility: string | undefined,\n): ReleaseResult {\n if (!versionCompatibility) {\n return releaseResult;\n }\n\n const versionCompatibilityRegEx = regEx(versionCompatibility);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const regexResult = versionCompatibilityRegEx.exec(release.version);\n if (!regexResult?.groups?.version) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match regex',\n );\n return null;\n }\n if (regexResult?.groups?.compatibility !== currentCompatibility) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match compatibility',\n );\n return null;\n }\n logger.trace(\n {\n releaseVersion: release.version,\n versionCompatibility,\n version: regexResult.groups.version,\n compatibility: regexResult.groups.compatibility,\n },\n 'versionCompatibility: matches',\n );\n release.versionOrig ??= release.version;\n release.version = regexResult.groups.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyExtractVersion(\n releaseResult: ReleaseResult,\n extractVersion: string | undefined,\n): ReleaseResult {\n if (!extractVersion) {\n return releaseResult;\n }\n\n const extractVersionRegEx = regEx(extractVersion);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const version = extractVersionRegEx.exec(release.version)?.groups?.version;\n if (!version) {\n return null;\n }\n\n release.versionOrig = release.version;\n release.version = version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function filterValidVersions<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = filterMap(releaseResult.releases, (release) =>\n versioning.isVersion(release.version) ? release : null,\n );\n\n return releaseResult;\n}\n\nexport function sortAndRemoveDuplicates<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = releaseResult.releases.sort((a, b) =>\n versioning.sortVersions(a.version, b.version),\n );\n\n // Once releases are sorted, deduplication is straightforward and efficient\n let previousVersion: string | null = null;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n if (previousVersion === release.version) {\n return null;\n }\n previousVersion = release.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyConstraintsFiltering<\n Config extends Pick<\n GetPkgReleasesConfig,\n | 'constraintsFiltering'\n | 'constraintsVersioning'\n | 'versioning'\n | 'datasource'\n | 'constraints'\n | 'packageName'\n >,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n if (config?.constraintsFiltering !== 'strict') {\n for (const release of releaseResult.releases) {\n delete release.constraints;\n }\n\n return releaseResult;\n }\n\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n const configConstraints = config.constraints;\n const filteredReleases: string[] = [];\n const startingLength = releaseResult.releases.length;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n logger.trace(\n {\n release,\n versioning: versioningName,\n },\n `applyConstraintsFiltering(${release.version})`,\n );\n const releaseConstraints = release.constraints;\n delete release.constraints;\n\n logger.trace(\n {\n release,\n versioning: versioningName,\n configConstraints: configConstraints ?? 'undefined',\n releaseConstraints: releaseConstraints ?? 'undefined',\n },\n `applyConstraintsFiltering(${release.version}): checking constraints`,\n );\n if (!configConstraints || !releaseConstraints) {\n return release;\n }\n\n for (const [name, configConstraint] of Object.entries(\n configConstraints,\n ) as [ConstraintName, string][]) {\n let constraintVersioningName = versioningName;\n if (\n isAdditionalConstraintName(name) &&\n config.constraintsVersioning?.[name]\n ) {\n const val = config.constraintsVersioning[name];\n logger.once.debug(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${config.packageName}, ${name}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n logger.trace(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${release.version}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n constraintVersioningName = val;\n }\n const constraintVersioning = allVersioning.get(constraintVersioningName);\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n constraintName: name,\n constraint: configConstraint,\n },\n `applyConstraintsFiltering(${release.version}) for constraint ${name}`,\n );\n\n const isValid = constraintVersioning.isValid(configConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): versioning.isValid(${configConstraint})=${isValid}`,\n );\n if (!isValid) {\n logger.once.warn(\n {\n packageName: config.packageName,\n constraint: configConstraint,\n versioning: constraintVersioningName,\n },\n 'Invalid constraint used with strict constraintsFiltering',\n );\n continue;\n }\n\n const constraint = releaseConstraints[name];\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraints[${name}]=${JSON.stringify(constraint)}`,\n );\n if (!isNonEmptyArray(constraint)) {\n // A release with no constraints is OK\n continue;\n }\n\n let satisfiesConstraints = false;\n for (const releaseConstraint of constraint) {\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraint=${releaseConstraint}`,\n );\n if (!releaseConstraint) {\n satisfiesConstraints = true;\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Undefined release constraint',\n );\n break;\n }\n\n const isValidConstraintVersion =\n constraintVersioning.isValid(releaseConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): constraintVersioning.isValid(${releaseConstraint})=${isValidConstraintVersion}`,\n );\n const isValidVersion = versioning.isValid(releaseConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.isValid(${releaseConstraint})=${isValidVersion}`,\n );\n if (!isValidVersion || !isValidConstraintVersion) {\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Invalid release constraint',\n );\n break;\n }\n\n const isEqual = configConstraint === releaseConstraint;\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): ${configConstraint} === ${releaseConstraint}=${isEqual}`,\n );\n if (isEqual) {\n satisfiesConstraints = true;\n break;\n }\n\n const isSubset = constraintVersioning.subset?.(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.subset?.(${configConstraint}, ${releaseConstraint})=${isSubset}`,\n );\n if (isSubset) {\n satisfiesConstraints = true;\n break;\n }\n\n const doesMatchConfig = constraintVersioning.matches(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${configConstraint}, ${releaseConstraint})=${doesMatchConfig}`,\n );\n const doesMatchRelease = constraintVersioning.matches(\n releaseConstraint,\n configConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${releaseConstraint}, ${configConstraint})=${doesMatchRelease}`,\n );\n if (doesMatchConfig || doesMatchRelease) {\n satisfiesConstraints = true;\n break;\n }\n }\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): satisfiesConstraints=${satisfiesConstraints}`,\n );\n if (!satisfiesConstraints) {\n filteredReleases.push(release.version);\n return null;\n }\n }\n\n return release;\n });\n\n if (filteredReleases.length) {\n const count = filteredReleases.length;\n const packageName = config.packageName;\n const releases = filteredReleases.join(', ');\n logger.debug(\n {\n datasource: config.datasource,\n packageName: config.packageName,\n },\n `Filtered out ${count} non-matching releases out of ${startingLength} total for ${packageName} due to constraintsFiltering=strict: ${releases}`,\n );\n }\n\n return releaseResult;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"common.js","names":["datasources","allVersioning.get"],"sources":["../../../lib/modules/datasource/common.ts"],"sourcesContent":["import {\n isNonEmptyArray,\n isNonEmptyStringAndNotWhitespace,\n} from '@sindresorhus/is';\nimport { logger } from '../../logger/index.ts';\nimport {\n type ConstraintName,\n isAdditionalConstraintName,\n} from '../../util/exec/types.ts';\nimport { filterMap } from '../../util/filter-map.ts';\nimport { regEx } from '../../util/regex.ts';\nimport * as allVersioning from '../versioning/index.ts';\nimport { defaultVersioning } from '../versioning/index.ts';\nimport datasources from './api.ts';\nimport { CustomDatasource } from './custom/index.ts';\nimport type {\n DatasourceApi,\n GetPkgReleasesConfig,\n ReleaseResult,\n} from './types.ts';\n\nexport function getDatasourceFor(datasource: string): DatasourceApi | null {\n if (datasource?.startsWith('custom.')) {\n return getDatasourceFor(CustomDatasource.id);\n }\n return datasources.get(datasource) ?? null;\n}\n\n/**\n * The host types of the datasources whose requests use another host type than their id.\n */\nconst datasourceHostTypes: Record<string, string> = {\n 'sbt-package': 'sbt',\n 'sbt-plugin': 'sbt',\n};\n\n/**\n * Returns the host type the requests of `datasource` use, such as `custom` for `custom.<name>`, or `null` when there is no such datasource.\n */\nexport function getDatasourceHostType(datasource: string): string | null {\n const id = getDatasourceFor(datasource)?.id;\n if (!id) {\n return null;\n }\n return datasourceHostTypes[id] ?? id;\n}\n\nexport function getDefaultVersioning(\n datasourceName: string | undefined,\n): string {\n if (!datasourceName) {\n return defaultVersioning.id;\n }\n\n const datasource = getDatasourceFor(datasourceName);\n\n if (!datasource) {\n logger.warn({ datasourceName }, 'Missing datasource!');\n return defaultVersioning.id;\n }\n\n if (!datasource.defaultVersioning) {\n return defaultVersioning.id;\n }\n\n return datasource.defaultVersioning;\n}\n\nexport function isGetPkgReleasesConfig(\n input: unknown,\n): input is GetPkgReleasesConfig {\n return (\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).datasource,\n ) &&\n isNonEmptyStringAndNotWhitespace(\n (input as GetPkgReleasesConfig).packageName,\n )\n );\n}\n\nexport function applyVersionCompatibility(\n releaseResult: ReleaseResult,\n versionCompatibility: string | undefined,\n currentCompatibility: string | undefined,\n): ReleaseResult {\n if (!versionCompatibility) {\n return releaseResult;\n }\n\n const versionCompatibilityRegEx = regEx(versionCompatibility);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const regexResult = versionCompatibilityRegEx.exec(release.version);\n if (!regexResult?.groups?.version) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match regex',\n );\n return null;\n }\n if (regexResult?.groups?.compatibility !== currentCompatibility) {\n logger.trace(\n { releaseVersion: release.version, versionCompatibility },\n 'versionCompatibility: Does not match compatibility',\n );\n return null;\n }\n logger.trace(\n {\n releaseVersion: release.version,\n versionCompatibility,\n version: regexResult.groups.version,\n compatibility: regexResult.groups.compatibility,\n },\n 'versionCompatibility: matches',\n );\n release.versionOrig ??= release.version;\n release.version = regexResult.groups.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyExtractVersion(\n releaseResult: ReleaseResult,\n extractVersion: string | undefined,\n): ReleaseResult {\n if (!extractVersion) {\n return releaseResult;\n }\n\n const extractVersionRegEx = regEx(extractVersion);\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n const version = extractVersionRegEx.exec(release.version)?.groups?.version;\n if (!version) {\n return null;\n }\n\n release.versionOrig = release.version;\n release.version = version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function filterValidVersions<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = filterMap(releaseResult.releases, (release) =>\n versioning.isVersion(release.version) ? release : null,\n );\n\n return releaseResult;\n}\n\nexport function sortAndRemoveDuplicates<\n Config extends Pick<GetPkgReleasesConfig, 'versioning' | 'datasource'>,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n releaseResult.releases = releaseResult.releases.sort((a, b) =>\n versioning.sortVersions(a.version, b.version),\n );\n\n // Once releases are sorted, deduplication is straightforward and efficient\n let previousVersion: string | null = null;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n if (previousVersion === release.version) {\n return null;\n }\n previousVersion = release.version;\n return release;\n });\n\n return releaseResult;\n}\n\nexport function applyConstraintsFiltering<\n Config extends Pick<\n GetPkgReleasesConfig,\n | 'constraintsFiltering'\n | 'constraintsVersioning'\n | 'versioning'\n | 'datasource'\n | 'constraints'\n | 'packageName'\n >,\n>(releaseResult: ReleaseResult, config: Config): ReleaseResult {\n if (config?.constraintsFiltering !== 'strict') {\n for (const release of releaseResult.releases) {\n delete release.constraints;\n }\n\n return releaseResult;\n }\n\n const versioningName =\n config.versioning ?? getDefaultVersioning(config.datasource);\n const versioning = allVersioning.get(versioningName);\n\n const configConstraints = config.constraints;\n const filteredReleases: string[] = [];\n const startingLength = releaseResult.releases.length;\n releaseResult.releases = filterMap(releaseResult.releases, (release) => {\n logger.trace(\n {\n release,\n versioning: versioningName,\n },\n `applyConstraintsFiltering(${release.version})`,\n );\n const releaseConstraints = release.constraints;\n delete release.constraints;\n\n logger.trace(\n {\n release,\n versioning: versioningName,\n configConstraints: configConstraints ?? 'undefined',\n releaseConstraints: releaseConstraints ?? 'undefined',\n },\n `applyConstraintsFiltering(${release.version}): checking constraints`,\n );\n if (!configConstraints || !releaseConstraints) {\n return release;\n }\n\n for (const [name, configConstraint] of Object.entries(\n configConstraints,\n ) as [ConstraintName, string][]) {\n let constraintVersioningName = versioningName;\n if (\n isAdditionalConstraintName(name) &&\n config.constraintsVersioning?.[name]\n ) {\n const val = config.constraintsVersioning[name];\n logger.once.debug(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${config.packageName}, ${name}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n logger.trace(\n { packageName: config.packageName, release },\n `applyConstraintsFiltering(${release.version}): overriding constraintsVersioning from ${constraintVersioningName} to ${val}`,\n );\n constraintVersioningName = val;\n }\n const constraintVersioning = allVersioning.get(constraintVersioningName);\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n constraintName: name,\n constraint: configConstraint,\n },\n `applyConstraintsFiltering(${release.version}) for constraint ${name}`,\n );\n\n const isValid = constraintVersioning.isValid(configConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): versioning.isValid(${configConstraint})=${isValid}`,\n );\n if (!isValid) {\n logger.once.warn(\n {\n packageName: config.packageName,\n constraint: configConstraint,\n versioning: constraintVersioningName,\n },\n 'Invalid constraint used with strict constraintsFiltering',\n );\n continue;\n }\n\n const constraint = releaseConstraints[name];\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraints[${name}]=${JSON.stringify(constraint)}`,\n );\n if (!isNonEmptyArray(constraint)) {\n // A release with no constraints is OK\n continue;\n }\n\n let satisfiesConstraints = false;\n for (const releaseConstraint of constraint) {\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): releaseConstraint=${releaseConstraint}`,\n );\n if (!releaseConstraint) {\n satisfiesConstraints = true;\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Undefined release constraint',\n );\n break;\n }\n\n const isValidConstraintVersion =\n constraintVersioning.isValid(releaseConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): constraintVersioning.isValid(${releaseConstraint})=${isValidConstraintVersion}`,\n );\n const isValidVersion = versioning.isValid(releaseConstraint);\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.isValid(${releaseConstraint})=${isValidVersion}`,\n );\n if (!isValidVersion || !isValidConstraintVersion) {\n logger.once.debug(\n {\n packageName: config.packageName,\n versioning: constraintVersioningName,\n constraint: releaseConstraint,\n },\n 'Invalid release constraint',\n );\n break;\n }\n\n const isEqual = configConstraint === releaseConstraint;\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): ${configConstraint} === ${releaseConstraint}=${isEqual}`,\n );\n if (isEqual) {\n satisfiesConstraints = true;\n break;\n }\n\n const isSubset = constraintVersioning.subset?.(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.subset?.(${configConstraint}, ${releaseConstraint})=${isSubset}`,\n );\n if (isSubset) {\n satisfiesConstraints = true;\n break;\n }\n\n const doesMatchConfig = constraintVersioning.matches(\n configConstraint,\n releaseConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${configConstraint}, ${releaseConstraint})=${doesMatchConfig}`,\n );\n const doesMatchRelease = constraintVersioning.matches(\n releaseConstraint,\n configConstraint,\n );\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n configConstraint,\n releaseConstraint,\n },\n `applyConstraintsFiltering(${release.version}): versioning.matches(${releaseConstraint}, ${configConstraint})=${doesMatchRelease}`,\n );\n if (doesMatchConfig || doesMatchRelease) {\n satisfiesConstraints = true;\n break;\n }\n }\n\n logger.trace(\n {\n release,\n versioning: constraintVersioningName,\n },\n `applyConstraintsFiltering(${release.version}): satisfiesConstraints=${satisfiesConstraints}`,\n );\n if (!satisfiesConstraints) {\n filteredReleases.push(release.version);\n return null;\n }\n }\n\n return release;\n });\n\n if (filteredReleases.length) {\n const count = filteredReleases.length;\n const packageName = config.packageName;\n const releases = filteredReleases.join(', ');\n logger.debug(\n {\n datasource: config.datasource,\n packageName: config.packageName,\n },\n `Filtered out ${count} non-matching releases out of ${startingLength} total for ${packageName} due to constraintsFiltering=strict: ${releases}`,\n );\n }\n\n return releaseResult;\n}\n"],"mappings":"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"}
|
|
@@ -305,7 +305,10 @@ var CrateDatasource = class CrateDatasource extends Datasource {
|
|
|
305
305
|
}, `Cloning private cargo registry`);
|
|
306
306
|
const git = createSimpleGit({
|
|
307
307
|
config: { maxConcurrentProcesses: 1 },
|
|
308
|
-
...isHttpUrl(registryFetchUrl) && { authentication: {
|
|
308
|
+
...isHttpUrl(registryFetchUrl) && { authentication: {
|
|
309
|
+
hostTypes: [CrateDatasource.id],
|
|
310
|
+
url: registryFetchUrl
|
|
311
|
+
} }
|
|
309
312
|
});
|
|
310
313
|
try {
|
|
311
314
|
await git.clone(registryFetchUrl, clonePath, { "--depth": 1 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["cargoVersioning.id","memCache.get","HttpError","packageCache.get","packageCache.set"],"sources":["../../../../lib/modules/datasource/crate/index.ts"],"sourcesContent":["import { isBoolean } from '@sindresorhus/is';\nimport upath from 'upath';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { privateCacheDir, readCacheFile } from '../../../util/fs/index.ts';\nimport { createSimpleGit } from '../../../util/git/index.ts';\nimport { toSha256 } from '../../../util/hash.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { acquireLock } from '../../../util/mutex.ts';\nimport { newlineRegex, regEx } from '../../../util/regex.ts';\nimport { Json } from '../../../util/schema-utils/index.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport { isHttpUrl, joinUrlParts, parseUrl } from '../../../util/url.ts';\nimport * as cargoVersioning from '../../versioning/cargo/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport type { CrateMetadata } from './schema.ts';\nimport {\n CrateMetadataResponse,\n RegistryConfig,\n ReleaseTimestamp,\n} from './schema.ts';\nimport type { CrateRecord, RegistryFlavor, RegistryInfo } from './types.ts';\n\ntype CloneResult =\n | {\n err: Error;\n clonePath?: undefined;\n }\n | {\n clonePath: string;\n err?: undefined;\n };\n\nexport class CrateDatasource extends Datasource {\n static readonly id = 'crate';\n\n constructor() {\n super(CrateDatasource.id);\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['sparse+https://index.crates.io/'];\n }\n\n override defaultVersioning = cargoVersioning.id;\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `repository` field in the results.';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from `pubtime` field from crates.io index if available, or `version.created_at` field from crates.io API otherwise.';\n\n private async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore if -- should never happen */\n if (!registryUrl) {\n logger.warn(\n 'crate datasource: No registryUrl specified, cannot perform getReleases',\n );\n return null;\n }\n\n const registryInfo = await CrateDatasource.fetchRegistryInfo({\n packageName,\n registryUrl,\n });\n if (!registryInfo) {\n logger.debug(`Could not fetch registry info from ${registryUrl}`);\n return null;\n }\n\n const dependencyUrl = CrateDatasource.getDependencyUrl(\n registryInfo,\n packageName,\n );\n\n const payload = await this.fetchCrateRecordsPayload(\n registryInfo,\n packageName,\n );\n const lines = payload\n .split(newlineRegex) // break into lines\n .map((line) => line.trim()) // remove whitespace\n .filter((line) => line.length !== 0) // remove empty lines\n .map((line) => JSON.parse(line) as CrateRecord); // parse\n\n const metadata = await this.getCrateMetadata(registryInfo, packageName);\n\n const result: ReleaseResult = {\n dependencyUrl,\n releases: [],\n };\n\n if (metadata?.homepage) {\n result.homepage = metadata.homepage;\n }\n\n if (metadata?.repository) {\n result.sourceUrl = metadata.repository;\n }\n\n result.releases = lines\n .map((line) => {\n const versionOrig = line.vers;\n const version = versionOrig.replace(regEx(/\\+.*$/), '');\n const release: Release = { version };\n\n if (versionOrig !== version) {\n release.versionOrig = versionOrig;\n }\n\n if (line.yanked) {\n release.isDeprecated = true;\n }\n\n if (line.rust_version) {\n release.constraints = { rust: [line.rust_version] };\n }\n\n if (line.pubtime) {\n release.releaseTimestamp = asTimestamp(line.pubtime);\n }\n\n return release;\n })\n .filter((release) => release.version);\n if (!result.releases.length) {\n return null;\n }\n\n return result;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}`,\n key: buildCacheKey(config.registryUrl, config.packageName),\n cacheable: CrateDatasource.isCratesIo(config.registryUrl),\n fallback: true,\n },\n () => this._getReleases(config),\n );\n }\n\n /** Returns the memory cache key of the registry's config.json. */\n private static registryConfigCacheKey(rawUrl: string): string {\n return buildCacheKey('crate-datasource', 'registry-config', rawUrl);\n }\n\n /** Returns the memory cache key of the unsupported read API marker. */\n private static apiUnsupportedCacheKey(api: string): string {\n return buildCacheKey('crate-datasource', 'registry-api-unsupported', api);\n }\n\n /**\n * Fetches the registry's config.json which provides the API base URL\n * and download URL template.\n * See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration\n */\n private async fetchRegistryConfig(\n info: RegistryInfo,\n ): Promise<RegistryConfig | null> {\n const cacheKey = CrateDatasource.registryConfigCacheKey(info.rawUrl);\n const cached = memCache.get<RegistryConfig>(cacheKey);\n if (cached) {\n return cached;\n }\n\n if (info.clonePath) {\n try {\n const configPath = upath.join(info.clonePath, 'config.json');\n const content = await readCacheFile(configPath, 'utf8');\n const parsed = Json.pipe(RegistryConfig).parse(content);\n memCache.set(cacheKey, parsed);\n return parsed;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not read config.json from cloned registry',\n );\n }\n } else {\n try {\n const configUrl = joinUrlParts(info.rawUrl, 'config.json');\n const { body } = await this.http.getJson(configUrl, RegistryConfig);\n memCache.set(cacheKey, body);\n return body;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not fetch registry config.json',\n );\n }\n }\n\n return null;\n }\n\n /**\n * The registry web API specification only defines publish, yank, unyank,\n * owners, search and login endpoints, see\n * https://doc.rust-lang.org/cargo/reference/registry-web-api.html.\n * `GET api/v1/crates/<name>` and `GET api/v1/crates/<name>/<version>` are\n * crates.io extensions. Registries which mirror the crates.io index keep\n * `api` pointing at crates.io and are used without probing. Any other\n * registry is probed once and remembered as unsupported when it answers\n * 404, since private registries (Artifactory, CodeArtifact, ...) advertise\n * an `api` URL for publishing only.\n */\n private static isCratesIoApi(api: string): boolean {\n return parseUrl(api)?.hostname === 'crates.io';\n }\n\n private static isNotFound(err: unknown): boolean {\n return err instanceof HttpError && err.response?.statusCode === 404;\n }\n\n /**\n * The marker is keyed by the `api` URL, since the missing endpoints are a\n * property of the API server, not of the index that points to it.\n */\n private async isReadApiUnsupported(api: string): Promise<boolean> {\n if (CrateDatasource.isCratesIoApi(api)) {\n return false;\n }\n\n const memKey = CrateDatasource.apiUnsupportedCacheKey(api);\n const cached = memCache.get<boolean>(memKey);\n if (isBoolean(cached)) {\n return cached;\n }\n\n const persisted = await packageCache.get<boolean>(\n 'datasource-crate-registry-api',\n api,\n );\n const unsupported = persisted === true;\n memCache.set(memKey, unsupported);\n return unsupported;\n }\n\n private async markReadApiUnsupported(\n registryUrl: string,\n api: string,\n ): Promise<void> {\n logger.debug(\n { registryUrl, api },\n 'Registry does not implement the crates.io read API, skipping crate metadata and release timestamp lookups',\n );\n memCache.set(CrateDatasource.apiUnsupportedCacheKey(api), true);\n await packageCache.set('datasource-crate-registry-api', api, true, 24 * 60);\n }\n\n private async _getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n const registryConfig = await this.fetchRegistryConfig(info);\n if (!registryConfig?.api) {\n return null;\n }\n\n const { api } = registryConfig;\n if (await this.isReadApiUnsupported(api)) {\n return null;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n\n // The `?include=` suffix is required to avoid unnecessary database queries\n // on the crates.io server. This lets us work around the regular request\n // throttling of one request per second.\n const crateUrl = `${apiBaseUrl}crates/${packageName}?include=`;\n\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'downloading crate metadata',\n );\n\n try {\n const { body } = await this.http.getJson(crateUrl, CrateMetadataResponse);\n return body.crate;\n } catch (err) {\n // The index lookup preceding this call found the crate, so a 404 means\n // the registry does not implement the endpoint at all\n if (\n !CrateDatasource.isCratesIoApi(api) &&\n CrateDatasource.isNotFound(err)\n ) {\n await this.markReadApiUnsupported(info.rawUrl, api);\n return null;\n }\n logger.debug(\n { err, packageName, registryUrl: info.rawUrl },\n 'failed to download crate metadata',\n );\n }\n\n return null;\n }\n\n public getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}-metadata`,\n key: buildCacheKey(info.rawUrl, packageName),\n cacheable: info.flavor === 'crates.io',\n ttlMinutes: 24 * 60, // 24 hours\n },\n () => this._getCrateMetadata(info, packageName),\n );\n }\n\n public async fetchCrateRecordsPayload(\n info: RegistryInfo,\n packageName: string,\n ): Promise<string> {\n if (info.clonePath) {\n const path = upath.join(\n info.clonePath,\n ...CrateDatasource.getIndexSuffix(packageName),\n );\n return readCacheFile(path, 'utf8');\n }\n\n // sparse index\n const packageSuffix = CrateDatasource.getIndexSuffix(\n packageName.toLowerCase(),\n );\n const crateUrl = joinUrlParts(info.rawUrl, ...packageSuffix);\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'fetching crate records from sparse index',\n );\n try {\n return (await this.http.getText(crateUrl)).body;\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n /**\n * Computes the dependency URL for a crate, given\n * registry information\n */\n private static getDependencyUrl(\n info: RegistryInfo,\n packageName: string,\n ): string {\n switch (info.flavor) {\n case 'crates.io':\n return `https://crates.io/crates/${packageName}`;\n case 'cloudsmith': {\n // input: https://dl.cloudsmith.io/basic/$org/$repo/cargo/index.git\n const tokens = info.url.pathname.split('/');\n const org = tokens[2];\n const repo = tokens[3];\n return `https://cloudsmith.io/~${org}/repos/${repo}/packages/detail/cargo/${packageName}`;\n }\n default:\n return `${info.url}/${packageName}`;\n }\n }\n\n /**\n * Given a Git URL, computes a semi-human-readable name for a folder in which to\n * clone the repository.\n */\n private static cacheDirFromUrl(url: URL): string {\n const proto = url.protocol.replace(regEx(/:$/), '');\n const host = url.hostname;\n const hash = toSha256(url.pathname).substring(0, 7);\n\n return `crate-registry-${proto}-${host}-${hash}`;\n }\n\n private static isSparseRegistry(url: string): boolean {\n const parsed = parseUrl(url);\n if (!parsed) {\n return false;\n }\n return parsed.protocol.startsWith('sparse+');\n }\n\n /**\n * Fetches information about a registry, by url.\n * If no url is given, assumes crates.io.\n * If an url is given, assumes it's a valid Git repository\n * url and clones it to cache.\n */\n private static async fetchRegistryInfo({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<RegistryInfo | null> {\n /* v8 ignore next -- should never happen */\n if (!registryUrl) {\n return null;\n }\n\n const isSparseRegistry = CrateDatasource.isSparseRegistry(registryUrl);\n const registryFetchUrl = isSparseRegistry\n ? registryUrl.replace(regEx(/^sparse\\+/), '')\n : registryUrl;\n\n const url = parseUrl(registryFetchUrl);\n if (!url) {\n logger.debug(`Could not parse registry URL ${registryFetchUrl}`);\n return null;\n }\n\n let flavor: RegistryFlavor;\n if (url.hostname === 'index.crates.io') {\n flavor = 'crates.io';\n } else if (url.hostname === 'dl.cloudsmith.io') {\n flavor = 'cloudsmith';\n } else {\n flavor = 'other';\n }\n\n const registry: RegistryInfo = {\n flavor,\n rawUrl: registryFetchUrl,\n url,\n };\n\n if (!isSparseRegistry) {\n if (\n registry.flavor !== 'crates.io' &&\n !GlobalConfig.get('allowCustomCrateGitRegistries')\n ) {\n logger.warn(\n 'crate datasource: allowCustomCrateGitRegistries=true is required for git-cloning registries other than crates.io, bailing out',\n );\n return null;\n }\n const cacheKey = buildCacheKey(\n 'crate-datasource',\n 'registry-clone-path',\n registryFetchUrl,\n );\n const lockKey = registryFetchUrl;\n\n const executionTimeout = GlobalConfig.get('executionTimeout') * 60 * 1000;\n const gitTimeout = GlobalConfig.get('gitTimeout') || executionTimeout;\n const releaseLock = await acquireLock(\n lockKey,\n 'crate-registry',\n gitTimeout,\n );\n try {\n const cached = memCache.get<CloneResult>(cacheKey);\n\n if (cached?.err) {\n logger.warn(\n { err: cached.err, packageName, registryFetchUrl },\n 'Previous git clone failed, bailing out.',\n );\n return null;\n }\n\n if (cached?.clonePath) {\n registry.clonePath = cached.clonePath;\n return registry;\n }\n\n const clonePath = upath.join(\n privateCacheDir(),\n CrateDatasource.cacheDirFromUrl(url),\n );\n\n const result = await CrateDatasource.clone(\n registryFetchUrl,\n clonePath,\n packageName,\n );\n\n memCache.set(cacheKey, result);\n\n if (result.err) {\n logger.warn(\n { err: result.err, packageName, registryFetchUrl },\n 'Git clone failed, bailing out.',\n );\n return null;\n }\n\n registry.clonePath = result.clonePath;\n } finally {\n releaseLock();\n }\n }\n\n return registry;\n }\n\n private static async clone(\n registryFetchUrl: string,\n clonePath: string,\n packageName: string,\n ): Promise<CloneResult> {\n logger.info(\n { clonePath, registryFetchUrl },\n `Cloning private cargo registry`,\n );\n\n const git = createSimpleGit({\n config: { maxConcurrentProcesses: 1 },\n ...(isHttpUrl(registryFetchUrl) && {\n authentication: { hostTypes: [CrateDatasource.id] },\n }),\n });\n\n try {\n await git.clone(registryFetchUrl, clonePath, {\n '--depth': 1,\n });\n return { clonePath };\n } catch (err) {\n if (\n err.message.includes(\n 'fatal: dumb http transport does not support shallow capabilities',\n )\n ) {\n logger.info(\n { packageName, registryFetchUrl },\n 'failed to shallow clone git registry, doing full clone',\n );\n try {\n await git.clone(registryFetchUrl, clonePath);\n return { clonePath };\n } catch (err) {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n } else {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n }\n }\n\n private static isCratesIo(registryUrl: string | undefined): boolean {\n if (!registryUrl) {\n return false;\n }\n const normalized = registryUrl.replace(regEx(/^sparse\\+/), '');\n const parsed = parseUrl(normalized);\n return parsed?.hostname === 'index.crates.io';\n }\n\n public static getIndexSuffix(packageName: string): string[] {\n const len = packageName.length;\n\n if (len === 1) {\n return ['1', packageName];\n }\n if (len === 2) {\n return ['2', packageName];\n }\n if (len === 3) {\n return ['3', packageName[0], packageName];\n }\n\n return [packageName.slice(0, 2), packageName.slice(2, 4), packageName];\n }\n\n private async _postprocessRelease(\n { packageName, registryUrl }: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n if (release.releaseTimestamp) {\n return release;\n }\n\n // Look up the registry config from cache (populated during getReleases)\n const rawUrl = registryUrl?.replace(regEx(/^sparse\\+/), '');\n if (!rawUrl) {\n return release;\n }\n const config = memCache.get<RegistryConfig>(\n CrateDatasource.registryConfigCacheKey(rawUrl),\n );\n if (!config?.api) {\n return release;\n }\n\n const { api } = config;\n if (await this.isReadApiUnsupported(api)) {\n return release;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n const url = `${apiBaseUrl}crates/${packageName}/${release.versionOrig ?? release.version}`;\n logger.trace(\n { url, packageName, version: release.version, registryUrl },\n 'fetching crate release timestamp',\n );\n // Getting release timestamp could become unnecessary if the manual backfill of `pubtime` mentioned in\n // https://github.com/rust-lang/cargo/issues/15491 is done for all packages.\n try {\n const { body: releaseTimestamp } = await this.http.getJson(\n url,\n { cacheProvider: memCacheProvider },\n ReleaseTimestamp,\n );\n release.releaseTimestamp = releaseTimestamp;\n } catch (err) {\n if (\n CrateDatasource.isCratesIoApi(api) ||\n !CrateDatasource.isNotFound(err)\n ) {\n throw err;\n }\n await this.markReadApiUnsupported(rawUrl, api);\n }\n return release;\n }\n\n override postprocessRelease(\n config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n return withCache(\n {\n namespace: `datasource-crate`,\n key: buildCacheKey(\n 'postprocessRelease',\n config.registryUrl,\n config.packageName,\n release.version,\n ),\n ttlMinutes: 7 * 24 * 60,\n cacheable: CrateDatasource.isCratesIo(config.registryUrl ?? undefined),\n },\n () => this._postprocessRelease(config, release),\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA6CA,IAAa,kBAAb,MAAa,wBAAwB,WAAW;CAC9C,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,gBAAgB,EAAE;CAC1B;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,iCAAiC;CAC3C;CAEA,oBAA6BA;CAE7B,mBAAqC;CACrC,gBACE;CAEF,0BAA4C;CAC5C,uBACE;CAEF,MAAc,aAAa,EACzB,aACA,eACmD;;EAEnD,IAAI,CAAC,aAAa;GAChB,OAAO,KACL,wEACF;GACA,OAAO;EACT;EAEA,MAAM,eAAe,MAAM,gBAAgB,kBAAkB;GAC3D;GACA;EACF,CAAC;EACD,IAAI,CAAC,cAAc;GACjB,OAAO,MAAM,sCAAsC,aAAa;GAChE,OAAO;EACT;EAEA,MAAM,gBAAgB,gBAAgB,iBACpC,cACA,WACF;EAMA,MAAM,SAAQ,MAJQ,KAAK,yBACzB,cACA,WACF,EAAA,CAEG,MAAM,YAAY,CAAC,CACnB,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,QAAQ,SAAS,KAAK,WAAW,CAAC,CAAC,CACnC,KAAK,SAAS,KAAK,MAAM,IAAI,CAAgB;EAEhD,MAAM,WAAW,MAAM,KAAK,iBAAiB,cAAc,WAAW;EAEtE,MAAM,SAAwB;GAC5B;GACA,UAAU,CAAC;EACb;EAEA,IAAI,UAAU,UACZ,OAAO,WAAW,SAAS;EAG7B,IAAI,UAAU,YACZ,OAAO,YAAY,SAAS;EAG9B,OAAO,WAAW,MACf,KAAK,SAAS;GACb,MAAM,cAAc,KAAK;GACzB,MAAM,UAAU,YAAY,QAAQ,MAAM,OAAO,GAAG,EAAE;GACtD,MAAM,UAAmB,EAAE,QAAQ;GAEnC,IAAI,gBAAgB,SAClB,QAAQ,cAAc;GAGxB,IAAI,KAAK,QACP,QAAQ,eAAe;GAGzB,IAAI,KAAK,cACP,QAAQ,cAAc,EAAE,MAAM,CAAC,KAAK,YAAY,EAAE;GAGpD,IAAI,KAAK,SACP,QAAQ,mBAAmB,YAAY,KAAK,OAAO;GAGrD,OAAO;EACT,CAAC,CAAC,CACD,QAAQ,YAAY,QAAQ,OAAO;EACtC,IAAI,CAAC,OAAO,SAAS,QACnB,OAAO;EAGT,OAAO;CACT;CAEA,YAAY,QAA0D;EACpE,OAAO,UACL;GACE,WAAW,cAAc,gBAAgB;GACzC,KAAK,cAAc,OAAO,aAAa,OAAO,WAAW;GACzD,WAAW,gBAAgB,WAAW,OAAO,WAAW;GACxD,UAAU;EACZ,SACM,KAAK,aAAa,MAAM,CAChC;CACF;;CAGA,OAAe,uBAAuB,QAAwB;EAC5D,OAAO,cAAc,oBAAoB,mBAAmB,MAAM;CACpE;;CAGA,OAAe,uBAAuB,KAAqB;EACzD,OAAO,cAAc,oBAAoB,4BAA4B,GAAG;CAC1E;;;;;;CAOA,MAAc,oBACZ,MACgC;EAChC,MAAM,WAAW,gBAAgB,uBAAuB,KAAK,MAAM;EACnE,MAAM,SAASC,IAA6B,QAAQ;EACpD,IAAI,QACF,OAAO;EAGT,IAAI,KAAK,WACP,IAAI;GACF,MAAM,aAAa,MAAM,KAAK,KAAK,WAAW,aAAa;GAC3D,MAAM,UAAU,MAAM,cAAc,YAAY,MAAM;GACtD,MAAM,SAAS,KAAK,KAAK,cAAc,CAAC,CAAC,MAAM,OAAO;GACtD,IAAa,UAAU,MAAM;GAC7B,OAAO;EACT,QAAQ;GACN,OAAO,MACL,EAAE,aAAa,KAAK,OAAO,GAC3B,iDACF;EACF;OAEA,IAAI;GACF,MAAM,YAAY,aAAa,KAAK,QAAQ,aAAa;GACzD,MAAM,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,WAAW,cAAc;GAClE,IAAa,UAAU,IAAI;GAC3B,OAAO;EACT,QAAQ;GACN,OAAO,MACL,EAAE,aAAa,KAAK,OAAO,GAC3B,sCACF;EACF;EAGF,OAAO;CACT;;;;;;;;;;;;CAaA,OAAe,cAAc,KAAsB;EACjD,OAAO,SAAS,GAAG,CAAC,EAAE,aAAa;CACrC;CAEA,OAAe,WAAW,KAAuB;EAC/C,OAAO,eAAeC,gBAAa,IAAI,UAAU,eAAe;CAClE;;;;;CAMA,MAAc,qBAAqB,KAA+B;EAChE,IAAI,gBAAgB,cAAc,GAAG,GACnC,OAAO;EAGT,MAAM,SAAS,gBAAgB,uBAAuB,GAAG;EACzD,MAAM,SAASD,IAAsB,MAAM;EAC3C,IAAI,UAAU,MAAM,GAClB,OAAO;EAOT,MAAM,cAAc,MAJIE,MACtB,iCACA,GACF,MACkC;EAClC,IAAa,QAAQ,WAAW;EAChC,OAAO;CACT;CAEA,MAAc,uBACZ,aACA,KACe;EACf,OAAO,MACL;GAAE;GAAa;EAAI,GACnB,2GACF;EACA,IAAa,gBAAgB,uBAAuB,GAAG,GAAG,IAAI;EAC9D,MAAMC,MAAiB,iCAAiC,KAAK,MAAM,IAAO;CAC5E;CAEA,MAAc,kBACZ,MACA,aAC+B;EAC/B,MAAM,iBAAiB,MAAM,KAAK,oBAAoB,IAAI;EAC1D,IAAI,CAAC,gBAAgB,KACnB,OAAO;EAGT,MAAM,EAAE,QAAQ;EAChB,IAAI,MAAM,KAAK,qBAAqB,GAAG,GACrC,OAAO;EAQT,MAAM,WAAW,GALE,aAAa,KAAK,SAKR,EAAE,SAAS,YAAY;EAEpD,OAAO,MACL;GAAE;GAAU;GAAa,aAAa,KAAK;EAAO,GAClD,4BACF;EAEA,IAAI;GACF,MAAM,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,UAAU,qBAAqB;GACxE,OAAO,KAAK;EACd,SAAS,KAAK;GAGZ,IACE,CAAC,gBAAgB,cAAc,GAAG,KAClC,gBAAgB,WAAW,GAAG,GAC9B;IACA,MAAM,KAAK,uBAAuB,KAAK,QAAQ,GAAG;IAClD,OAAO;GACT;GACA,OAAO,MACL;IAAE;IAAK;IAAa,aAAa,KAAK;GAAO,GAC7C,mCACF;EACF;EAEA,OAAO;CACT;CAEA,iBACE,MACA,aAC+B;EAC/B,OAAO,UACL;GACE,WAAW,cAAc,gBAAgB,GAAG;GAC5C,KAAK,cAAc,KAAK,QAAQ,WAAW;GAC3C,WAAW,KAAK,WAAW;GAC3B,YAAY;EACd,SACM,KAAK,kBAAkB,MAAM,WAAW,CAChD;CACF;CAEA,MAAa,yBACX,MACA,aACiB;EACjB,IAAI,KAAK,WAAW;GAClB,MAAM,OAAO,MAAM,KACjB,KAAK,WACL,GAAG,gBAAgB,eAAe,WAAW,CAC/C;GACA,OAAO,cAAc,MAAM,MAAM;EACnC;EAGA,MAAM,gBAAgB,gBAAgB,eACpC,YAAY,YAAY,CAC1B;EACA,MAAM,WAAW,aAAa,KAAK,QAAQ,GAAG,aAAa;EAC3D,OAAO,MACL;GAAE;GAAU;GAAa,aAAa,KAAK;EAAO,GAClD,0CACF;EACA,IAAI;GACF,QAAQ,MAAM,KAAK,KAAK,QAAQ,QAAQ,EAAA,CAAG;EAC7C,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;CACF;;;;;CAMA,OAAe,iBACb,MACA,aACQ;EACR,QAAQ,KAAK,QAAb;GACE,KAAK,aACH,OAAO,4BAA4B;GACrC,KAAK,cAAc;IAEjB,MAAM,SAAS,KAAK,IAAI,SAAS,MAAM,GAAG;IAG1C,OAAO,0BAFK,OAAO,GAEkB,SADxB,OAAO,GAC+B,yBAAyB;GAC9E;GACA,SACE,OAAO,GAAG,KAAK,IAAI,GAAG;EAC1B;CACF;;;;;CAMA,OAAe,gBAAgB,KAAkB;EAK/C,OAAO,kBAJO,IAAI,SAAS,QAAQ,MAAM,IAAI,GAAG,EAInB,EAAE,GAHlB,IAAI,SAGsB,GAF1B,SAAS,IAAI,QAAQ,CAAC,CAAC,UAAU,GAAG,CAEJ;CAC/C;CAEA,OAAe,iBAAiB,KAAsB;EACpD,MAAM,SAAS,SAAS,GAAG;EAC3B,IAAI,CAAC,QACH,OAAO;EAET,OAAO,OAAO,SAAS,WAAW,SAAS;CAC7C;;;;;;;CAQA,aAAqB,kBAAkB,EACrC,aACA,eACkD;;EAElD,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,mBAAmB,gBAAgB,iBAAiB,WAAW;EACrE,MAAM,mBAAmB,mBACrB,YAAY,QAAQ,MAAM,WAAW,GAAG,EAAE,IAC1C;EAEJ,MAAM,MAAM,SAAS,gBAAgB;EACrC,IAAI,CAAC,KAAK;GACR,OAAO,MAAM,gCAAgC,kBAAkB;GAC/D,OAAO;EACT;EAEA,IAAI;EACJ,IAAI,IAAI,aAAa,mBACnB,SAAS;OACJ,IAAI,IAAI,aAAa,oBAC1B,SAAS;OAET,SAAS;EAGX,MAAM,WAAyB;GAC7B;GACA,QAAQ;GACR;EACF;EAEA,IAAI,CAAC,kBAAkB;GACrB,IACE,SAAS,WAAW,eACpB,CAAC,aAAa,IAAI,+BAA+B,GACjD;IACA,OAAO,KACL,+HACF;IACA,OAAO;GACT;GACA,MAAM,WAAW,cACf,oBACA,uBACA,gBACF;GACA,MAAM,UAAU;GAEhB,MAAM,mBAAmB,aAAa,IAAI,kBAAkB,IAAI,KAAK;GACrE,MAAM,aAAa,aAAa,IAAI,YAAY,KAAK;GACrD,MAAM,cAAc,MAAM,YACxB,SACA,kBACA,UACF;GACA,IAAI;IACF,MAAM,SAASH,IAA0B,QAAQ;IAEjD,IAAI,QAAQ,KAAK;KACf,OAAO,KACL;MAAE,KAAK,OAAO;MAAK;MAAa;KAAiB,GACjD,yCACF;KACA,OAAO;IACT;IAEA,IAAI,QAAQ,WAAW;KACrB,SAAS,YAAY,OAAO;KAC5B,OAAO;IACT;IAEA,MAAM,YAAY,MAAM,KACtB,gBAAgB,GAChB,gBAAgB,gBAAgB,GAAG,CACrC;IAEA,MAAM,SAAS,MAAM,gBAAgB,MACnC,kBACA,WACA,WACF;IAEA,IAAa,UAAU,MAAM;IAE7B,IAAI,OAAO,KAAK;KACd,OAAO,KACL;MAAE,KAAK,OAAO;MAAK;MAAa;KAAiB,GACjD,gCACF;KACA,OAAO;IACT;IAEA,SAAS,YAAY,OAAO;GAC9B,UAAU;IACR,YAAY;GACd;EACF;EAEA,OAAO;CACT;CAEA,aAAqB,MACnB,kBACA,WACA,aACsB;EACtB,OAAO,KACL;GAAE;GAAW;EAAiB,GAC9B,gCACF;EAEA,MAAM,MAAM,gBAAgB;GAC1B,QAAQ,EAAE,wBAAwB,EAAE;GACpC,GAAI,UAAU,gBAAgB,KAAK,EACjC,gBAAgB,EAAE,WAAW,CAAC,gBAAgB,EAAE,EAAE,EACpD;EACF,CAAC;EAED,IAAI;GACF,MAAM,IAAI,MAAM,kBAAkB,WAAW,EAC3C,WAAW,EACb,CAAC;GACD,OAAO,EAAE,UAAU;EACrB,SAAS,KAAK;GACZ,IACE,IAAI,QAAQ,SACV,kEACF,GACA;IACA,OAAO,KACL;KAAE;KAAa;IAAiB,GAChC,wDACF;IACA,IAAI;KACF,MAAM,IAAI,MAAM,kBAAkB,SAAS;KAC3C,OAAO,EAAE,UAAU;IACrB,SAAS,KAAK;KACZ,OAAO,KACL;MAAE;MAAK;MAAa;KAAiB,GACrC,6BACF;KACA,OAAO,EAAE,IAAI;IACf;GACF,OAAO;IACL,OAAO,KACL;KAAE;KAAK;KAAa;IAAiB,GACrC,6BACF;IACA,OAAO,EAAE,IAAI;GACf;EACF;CACF;CAEA,OAAe,WAAW,aAA0C;EAClE,IAAI,CAAC,aACH,OAAO;EAET,MAAM,aAAa,YAAY,QAAQ,MAAM,WAAW,GAAG,EAAE;EAE7D,OADe,SAAS,UACZ,CAAC,EAAE,aAAa;CAC9B;CAEA,OAAc,eAAe,aAA+B;EAC1D,MAAM,MAAM,YAAY;EAExB,IAAI,QAAQ,GACV,OAAO,CAAC,KAAK,WAAW;EAE1B,IAAI,QAAQ,GACV,OAAO,CAAC,KAAK,WAAW;EAE1B,IAAI,QAAQ,GACV,OAAO;GAAC;GAAK,YAAY;GAAI;EAAW;EAG1C,OAAO;GAAC,YAAY,MAAM,GAAG,CAAC;GAAG,YAAY,MAAM,GAAG,CAAC;GAAG;EAAW;CACvE;CAEA,MAAc,oBACZ,EAAE,aAAa,eACf,SACmC;EACnC,IAAI,QAAQ,kBACV,OAAO;EAIT,MAAM,SAAS,aAAa,QAAQ,MAAM,WAAW,GAAG,EAAE;EAC1D,IAAI,CAAC,QACH,OAAO;EAET,MAAM,SAASA,IACb,gBAAgB,uBAAuB,MAAM,CAC/C;EACA,IAAI,CAAC,QAAQ,KACX,OAAO;EAGT,MAAM,EAAE,QAAQ;EAChB,IAAI,MAAM,KAAK,qBAAqB,GAAG,GACrC,OAAO;EAIT,MAAM,MAAM,GADO,aAAa,KAAK,SACb,EAAE,SAAS,YAAY,GAAG,QAAQ,eAAe,QAAQ;EACjF,OAAO,MACL;GAAE;GAAK;GAAa,SAAS,QAAQ;GAAS;EAAY,GAC1D,kCACF;EAGA,IAAI;GACF,MAAM,EAAE,MAAM,qBAAqB,MAAM,KAAK,KAAK,QACjD,KACA,EAAE,eAAe,iBAAiB,GAClC,gBACF;GACA,QAAQ,mBAAmB;EAC7B,SAAS,KAAK;GACZ,IACE,gBAAgB,cAAc,GAAG,KACjC,CAAC,gBAAgB,WAAW,GAAG,GAE/B,MAAM;GAER,MAAM,KAAK,uBAAuB,QAAQ,GAAG;EAC/C;EACA,OAAO;CACT;CAEA,mBACE,QACA,SACmC;EACnC,OAAO,UACL;GACE,WAAW;GACX,KAAK,cACH,sBACA,OAAO,aACP,OAAO,aACP,QAAQ,OACV;GACA,YAAY;GACZ,WAAW,gBAAgB,WAAW,OAAO,eAAe,KAAA,CAAS;EACvE,SACM,KAAK,oBAAoB,QAAQ,OAAO,CAChD;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["cargoVersioning.id","memCache.get","HttpError","packageCache.get","packageCache.set"],"sources":["../../../../lib/modules/datasource/crate/index.ts"],"sourcesContent":["import { isBoolean } from '@sindresorhus/is';\nimport upath from 'upath';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport * as packageCache from '../../../util/cache/package/index.ts';\nimport { buildCacheKey } from '../../../util/cache/package/key.ts';\nimport { withCache } from '../../../util/cache/package/with-cache.ts';\nimport { privateCacheDir, readCacheFile } from '../../../util/fs/index.ts';\nimport { createSimpleGit } from '../../../util/git/index.ts';\nimport { toSha256 } from '../../../util/hash.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport { HttpError } from '../../../util/http/index.ts';\nimport { acquireLock } from '../../../util/mutex.ts';\nimport { newlineRegex, regEx } from '../../../util/regex.ts';\nimport { Json } from '../../../util/schema-utils/index.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport { isHttpUrl, joinUrlParts, parseUrl } from '../../../util/url.ts';\nimport * as cargoVersioning from '../../versioning/cargo/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n GetReleasesConfig,\n PostprocessReleaseConfig,\n PostprocessReleaseResult,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport type { CrateMetadata } from './schema.ts';\nimport {\n CrateMetadataResponse,\n RegistryConfig,\n ReleaseTimestamp,\n} from './schema.ts';\nimport type { CrateRecord, RegistryFlavor, RegistryInfo } from './types.ts';\n\ntype CloneResult =\n | {\n err: Error;\n clonePath?: undefined;\n }\n | {\n clonePath: string;\n err?: undefined;\n };\n\nexport class CrateDatasource extends Datasource {\n static readonly id = 'crate';\n\n constructor() {\n super(CrateDatasource.id);\n }\n\n override getDefaultRegistryUrls(_packageName: string): string[] {\n return ['sparse+https://index.crates.io/'];\n }\n\n override defaultVersioning = cargoVersioning.id;\n\n override readonly sourceUrlSupport = 'package';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `repository` field in the results.';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The release timestamp is determined from `pubtime` field from crates.io index if available, or `version.created_at` field from crates.io API otherwise.';\n\n private async _getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n /* v8 ignore if -- should never happen */\n if (!registryUrl) {\n logger.warn(\n 'crate datasource: No registryUrl specified, cannot perform getReleases',\n );\n return null;\n }\n\n const registryInfo = await CrateDatasource.fetchRegistryInfo({\n packageName,\n registryUrl,\n });\n if (!registryInfo) {\n logger.debug(`Could not fetch registry info from ${registryUrl}`);\n return null;\n }\n\n const dependencyUrl = CrateDatasource.getDependencyUrl(\n registryInfo,\n packageName,\n );\n\n const payload = await this.fetchCrateRecordsPayload(\n registryInfo,\n packageName,\n );\n const lines = payload\n .split(newlineRegex) // break into lines\n .map((line) => line.trim()) // remove whitespace\n .filter((line) => line.length !== 0) // remove empty lines\n .map((line) => JSON.parse(line) as CrateRecord); // parse\n\n const metadata = await this.getCrateMetadata(registryInfo, packageName);\n\n const result: ReleaseResult = {\n dependencyUrl,\n releases: [],\n };\n\n if (metadata?.homepage) {\n result.homepage = metadata.homepage;\n }\n\n if (metadata?.repository) {\n result.sourceUrl = metadata.repository;\n }\n\n result.releases = lines\n .map((line) => {\n const versionOrig = line.vers;\n const version = versionOrig.replace(regEx(/\\+.*$/), '');\n const release: Release = { version };\n\n if (versionOrig !== version) {\n release.versionOrig = versionOrig;\n }\n\n if (line.yanked) {\n release.isDeprecated = true;\n }\n\n if (line.rust_version) {\n release.constraints = { rust: [line.rust_version] };\n }\n\n if (line.pubtime) {\n release.releaseTimestamp = asTimestamp(line.pubtime);\n }\n\n return release;\n })\n .filter((release) => release.version);\n if (!result.releases.length) {\n return null;\n }\n\n return result;\n }\n\n getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}`,\n key: buildCacheKey(config.registryUrl, config.packageName),\n cacheable: CrateDatasource.isCratesIo(config.registryUrl),\n fallback: true,\n },\n () => this._getReleases(config),\n );\n }\n\n /** Returns the memory cache key of the registry's config.json. */\n private static registryConfigCacheKey(rawUrl: string): string {\n return buildCacheKey('crate-datasource', 'registry-config', rawUrl);\n }\n\n /** Returns the memory cache key of the unsupported read API marker. */\n private static apiUnsupportedCacheKey(api: string): string {\n return buildCacheKey('crate-datasource', 'registry-api-unsupported', api);\n }\n\n /**\n * Fetches the registry's config.json which provides the API base URL\n * and download URL template.\n * See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration\n */\n private async fetchRegistryConfig(\n info: RegistryInfo,\n ): Promise<RegistryConfig | null> {\n const cacheKey = CrateDatasource.registryConfigCacheKey(info.rawUrl);\n const cached = memCache.get<RegistryConfig>(cacheKey);\n if (cached) {\n return cached;\n }\n\n if (info.clonePath) {\n try {\n const configPath = upath.join(info.clonePath, 'config.json');\n const content = await readCacheFile(configPath, 'utf8');\n const parsed = Json.pipe(RegistryConfig).parse(content);\n memCache.set(cacheKey, parsed);\n return parsed;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not read config.json from cloned registry',\n );\n }\n } else {\n try {\n const configUrl = joinUrlParts(info.rawUrl, 'config.json');\n const { body } = await this.http.getJson(configUrl, RegistryConfig);\n memCache.set(cacheKey, body);\n return body;\n } catch {\n logger.debug(\n { registryUrl: info.rawUrl },\n 'Could not fetch registry config.json',\n );\n }\n }\n\n return null;\n }\n\n /**\n * The registry web API specification only defines publish, yank, unyank,\n * owners, search and login endpoints, see\n * https://doc.rust-lang.org/cargo/reference/registry-web-api.html.\n * `GET api/v1/crates/<name>` and `GET api/v1/crates/<name>/<version>` are\n * crates.io extensions. Registries which mirror the crates.io index keep\n * `api` pointing at crates.io and are used without probing. Any other\n * registry is probed once and remembered as unsupported when it answers\n * 404, since private registries (Artifactory, CodeArtifact, ...) advertise\n * an `api` URL for publishing only.\n */\n private static isCratesIoApi(api: string): boolean {\n return parseUrl(api)?.hostname === 'crates.io';\n }\n\n private static isNotFound(err: unknown): boolean {\n return err instanceof HttpError && err.response?.statusCode === 404;\n }\n\n /**\n * The marker is keyed by the `api` URL, since the missing endpoints are a\n * property of the API server, not of the index that points to it.\n */\n private async isReadApiUnsupported(api: string): Promise<boolean> {\n if (CrateDatasource.isCratesIoApi(api)) {\n return false;\n }\n\n const memKey = CrateDatasource.apiUnsupportedCacheKey(api);\n const cached = memCache.get<boolean>(memKey);\n if (isBoolean(cached)) {\n return cached;\n }\n\n const persisted = await packageCache.get<boolean>(\n 'datasource-crate-registry-api',\n api,\n );\n const unsupported = persisted === true;\n memCache.set(memKey, unsupported);\n return unsupported;\n }\n\n private async markReadApiUnsupported(\n registryUrl: string,\n api: string,\n ): Promise<void> {\n logger.debug(\n { registryUrl, api },\n 'Registry does not implement the crates.io read API, skipping crate metadata and release timestamp lookups',\n );\n memCache.set(CrateDatasource.apiUnsupportedCacheKey(api), true);\n await packageCache.set('datasource-crate-registry-api', api, true, 24 * 60);\n }\n\n private async _getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n const registryConfig = await this.fetchRegistryConfig(info);\n if (!registryConfig?.api) {\n return null;\n }\n\n const { api } = registryConfig;\n if (await this.isReadApiUnsupported(api)) {\n return null;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n\n // The `?include=` suffix is required to avoid unnecessary database queries\n // on the crates.io server. This lets us work around the regular request\n // throttling of one request per second.\n const crateUrl = `${apiBaseUrl}crates/${packageName}?include=`;\n\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'downloading crate metadata',\n );\n\n try {\n const { body } = await this.http.getJson(crateUrl, CrateMetadataResponse);\n return body.crate;\n } catch (err) {\n // The index lookup preceding this call found the crate, so a 404 means\n // the registry does not implement the endpoint at all\n if (\n !CrateDatasource.isCratesIoApi(api) &&\n CrateDatasource.isNotFound(err)\n ) {\n await this.markReadApiUnsupported(info.rawUrl, api);\n return null;\n }\n logger.debug(\n { err, packageName, registryUrl: info.rawUrl },\n 'failed to download crate metadata',\n );\n }\n\n return null;\n }\n\n public getCrateMetadata(\n info: RegistryInfo,\n packageName: string,\n ): Promise<CrateMetadata | null> {\n return withCache(\n {\n namespace: `datasource-${CrateDatasource.id}-metadata`,\n key: buildCacheKey(info.rawUrl, packageName),\n cacheable: info.flavor === 'crates.io',\n ttlMinutes: 24 * 60, // 24 hours\n },\n () => this._getCrateMetadata(info, packageName),\n );\n }\n\n public async fetchCrateRecordsPayload(\n info: RegistryInfo,\n packageName: string,\n ): Promise<string> {\n if (info.clonePath) {\n const path = upath.join(\n info.clonePath,\n ...CrateDatasource.getIndexSuffix(packageName),\n );\n return readCacheFile(path, 'utf8');\n }\n\n // sparse index\n const packageSuffix = CrateDatasource.getIndexSuffix(\n packageName.toLowerCase(),\n );\n const crateUrl = joinUrlParts(info.rawUrl, ...packageSuffix);\n logger.trace(\n { crateUrl, packageName, registryUrl: info.rawUrl },\n 'fetching crate records from sparse index',\n );\n try {\n return (await this.http.getText(crateUrl)).body;\n } catch (err) {\n this.handleGenericErrors(err);\n }\n }\n\n /**\n * Computes the dependency URL for a crate, given\n * registry information\n */\n private static getDependencyUrl(\n info: RegistryInfo,\n packageName: string,\n ): string {\n switch (info.flavor) {\n case 'crates.io':\n return `https://crates.io/crates/${packageName}`;\n case 'cloudsmith': {\n // input: https://dl.cloudsmith.io/basic/$org/$repo/cargo/index.git\n const tokens = info.url.pathname.split('/');\n const org = tokens[2];\n const repo = tokens[3];\n return `https://cloudsmith.io/~${org}/repos/${repo}/packages/detail/cargo/${packageName}`;\n }\n default:\n return `${info.url}/${packageName}`;\n }\n }\n\n /**\n * Given a Git URL, computes a semi-human-readable name for a folder in which to\n * clone the repository.\n */\n private static cacheDirFromUrl(url: URL): string {\n const proto = url.protocol.replace(regEx(/:$/), '');\n const host = url.hostname;\n const hash = toSha256(url.pathname).substring(0, 7);\n\n return `crate-registry-${proto}-${host}-${hash}`;\n }\n\n private static isSparseRegistry(url: string): boolean {\n const parsed = parseUrl(url);\n if (!parsed) {\n return false;\n }\n return parsed.protocol.startsWith('sparse+');\n }\n\n /**\n * Fetches information about a registry, by url.\n * If no url is given, assumes crates.io.\n * If an url is given, assumes it's a valid Git repository\n * url and clones it to cache.\n */\n private static async fetchRegistryInfo({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<RegistryInfo | null> {\n /* v8 ignore next -- should never happen */\n if (!registryUrl) {\n return null;\n }\n\n const isSparseRegistry = CrateDatasource.isSparseRegistry(registryUrl);\n const registryFetchUrl = isSparseRegistry\n ? registryUrl.replace(regEx(/^sparse\\+/), '')\n : registryUrl;\n\n const url = parseUrl(registryFetchUrl);\n if (!url) {\n logger.debug(`Could not parse registry URL ${registryFetchUrl}`);\n return null;\n }\n\n let flavor: RegistryFlavor;\n if (url.hostname === 'index.crates.io') {\n flavor = 'crates.io';\n } else if (url.hostname === 'dl.cloudsmith.io') {\n flavor = 'cloudsmith';\n } else {\n flavor = 'other';\n }\n\n const registry: RegistryInfo = {\n flavor,\n rawUrl: registryFetchUrl,\n url,\n };\n\n if (!isSparseRegistry) {\n if (\n registry.flavor !== 'crates.io' &&\n !GlobalConfig.get('allowCustomCrateGitRegistries')\n ) {\n logger.warn(\n 'crate datasource: allowCustomCrateGitRegistries=true is required for git-cloning registries other than crates.io, bailing out',\n );\n return null;\n }\n const cacheKey = buildCacheKey(\n 'crate-datasource',\n 'registry-clone-path',\n registryFetchUrl,\n );\n const lockKey = registryFetchUrl;\n\n const executionTimeout = GlobalConfig.get('executionTimeout') * 60 * 1000;\n const gitTimeout = GlobalConfig.get('gitTimeout') || executionTimeout;\n const releaseLock = await acquireLock(\n lockKey,\n 'crate-registry',\n gitTimeout,\n );\n try {\n const cached = memCache.get<CloneResult>(cacheKey);\n\n if (cached?.err) {\n logger.warn(\n { err: cached.err, packageName, registryFetchUrl },\n 'Previous git clone failed, bailing out.',\n );\n return null;\n }\n\n if (cached?.clonePath) {\n registry.clonePath = cached.clonePath;\n return registry;\n }\n\n const clonePath = upath.join(\n privateCacheDir(),\n CrateDatasource.cacheDirFromUrl(url),\n );\n\n const result = await CrateDatasource.clone(\n registryFetchUrl,\n clonePath,\n packageName,\n );\n\n memCache.set(cacheKey, result);\n\n if (result.err) {\n logger.warn(\n { err: result.err, packageName, registryFetchUrl },\n 'Git clone failed, bailing out.',\n );\n return null;\n }\n\n registry.clonePath = result.clonePath;\n } finally {\n releaseLock();\n }\n }\n\n return registry;\n }\n\n private static async clone(\n registryFetchUrl: string,\n clonePath: string,\n packageName: string,\n ): Promise<CloneResult> {\n logger.info(\n { clonePath, registryFetchUrl },\n `Cloning private cargo registry`,\n );\n\n const git = createSimpleGit({\n config: { maxConcurrentProcesses: 1 },\n ...(isHttpUrl(registryFetchUrl) && {\n // the URL as well, for the credentials registered from it, which only apply to this registry\n authentication: {\n hostTypes: [CrateDatasource.id],\n url: registryFetchUrl,\n },\n }),\n });\n\n try {\n await git.clone(registryFetchUrl, clonePath, {\n '--depth': 1,\n });\n return { clonePath };\n } catch (err) {\n if (\n err.message.includes(\n 'fatal: dumb http transport does not support shallow capabilities',\n )\n ) {\n logger.info(\n { packageName, registryFetchUrl },\n 'failed to shallow clone git registry, doing full clone',\n );\n try {\n await git.clone(registryFetchUrl, clonePath);\n return { clonePath };\n } catch (err) {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n } else {\n logger.warn(\n { err, packageName, registryFetchUrl },\n 'failed cloning git registry',\n );\n return { err };\n }\n }\n }\n\n private static isCratesIo(registryUrl: string | undefined): boolean {\n if (!registryUrl) {\n return false;\n }\n const normalized = registryUrl.replace(regEx(/^sparse\\+/), '');\n const parsed = parseUrl(normalized);\n return parsed?.hostname === 'index.crates.io';\n }\n\n public static getIndexSuffix(packageName: string): string[] {\n const len = packageName.length;\n\n if (len === 1) {\n return ['1', packageName];\n }\n if (len === 2) {\n return ['2', packageName];\n }\n if (len === 3) {\n return ['3', packageName[0], packageName];\n }\n\n return [packageName.slice(0, 2), packageName.slice(2, 4), packageName];\n }\n\n private async _postprocessRelease(\n { packageName, registryUrl }: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n if (release.releaseTimestamp) {\n return release;\n }\n\n // Look up the registry config from cache (populated during getReleases)\n const rawUrl = registryUrl?.replace(regEx(/^sparse\\+/), '');\n if (!rawUrl) {\n return release;\n }\n const config = memCache.get<RegistryConfig>(\n CrateDatasource.registryConfigCacheKey(rawUrl),\n );\n if (!config?.api) {\n return release;\n }\n\n const { api } = config;\n if (await this.isReadApiUnsupported(api)) {\n return release;\n }\n\n const apiBaseUrl = joinUrlParts(api, 'api/v1/');\n const url = `${apiBaseUrl}crates/${packageName}/${release.versionOrig ?? release.version}`;\n logger.trace(\n { url, packageName, version: release.version, registryUrl },\n 'fetching crate release timestamp',\n );\n // Getting release timestamp could become unnecessary if the manual backfill of `pubtime` mentioned in\n // https://github.com/rust-lang/cargo/issues/15491 is done for all packages.\n try {\n const { body: releaseTimestamp } = await this.http.getJson(\n url,\n { cacheProvider: memCacheProvider },\n ReleaseTimestamp,\n );\n release.releaseTimestamp = releaseTimestamp;\n } catch (err) {\n if (\n CrateDatasource.isCratesIoApi(api) ||\n !CrateDatasource.isNotFound(err)\n ) {\n throw err;\n }\n await this.markReadApiUnsupported(rawUrl, api);\n }\n return release;\n }\n\n override postprocessRelease(\n config: PostprocessReleaseConfig,\n release: Release,\n ): Promise<PostprocessReleaseResult> {\n return withCache(\n {\n namespace: `datasource-crate`,\n key: buildCacheKey(\n 'postprocessRelease',\n config.registryUrl,\n config.packageName,\n release.version,\n ),\n ttlMinutes: 7 * 24 * 60,\n cacheable: CrateDatasource.isCratesIo(config.registryUrl ?? undefined),\n },\n () => this._postprocessRelease(config, release),\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA6CA,IAAa,kBAAb,MAAa,wBAAwB,WAAW;CAC9C,OAAgB,KAAK;CAErB,cAAc;EACZ,MAAM,gBAAgB,EAAE;CAC1B;CAEA,uBAAgC,cAAgC;EAC9D,OAAO,CAAC,iCAAiC;CAC3C;CAEA,oBAA6BA;CAE7B,mBAAqC;CACrC,gBACE;CAEF,0BAA4C;CAC5C,uBACE;CAEF,MAAc,aAAa,EACzB,aACA,eACmD;;EAEnD,IAAI,CAAC,aAAa;GAChB,OAAO,KACL,wEACF;GACA,OAAO;EACT;EAEA,MAAM,eAAe,MAAM,gBAAgB,kBAAkB;GAC3D;GACA;EACF,CAAC;EACD,IAAI,CAAC,cAAc;GACjB,OAAO,MAAM,sCAAsC,aAAa;GAChE,OAAO;EACT;EAEA,MAAM,gBAAgB,gBAAgB,iBACpC,cACA,WACF;EAMA,MAAM,SAAQ,MAJQ,KAAK,yBACzB,cACA,WACF,EAAA,CAEG,MAAM,YAAY,CAAC,CACnB,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,QAAQ,SAAS,KAAK,WAAW,CAAC,CAAC,CACnC,KAAK,SAAS,KAAK,MAAM,IAAI,CAAgB;EAEhD,MAAM,WAAW,MAAM,KAAK,iBAAiB,cAAc,WAAW;EAEtE,MAAM,SAAwB;GAC5B;GACA,UAAU,CAAC;EACb;EAEA,IAAI,UAAU,UACZ,OAAO,WAAW,SAAS;EAG7B,IAAI,UAAU,YACZ,OAAO,YAAY,SAAS;EAG9B,OAAO,WAAW,MACf,KAAK,SAAS;GACb,MAAM,cAAc,KAAK;GACzB,MAAM,UAAU,YAAY,QAAQ,MAAM,OAAO,GAAG,EAAE;GACtD,MAAM,UAAmB,EAAE,QAAQ;GAEnC,IAAI,gBAAgB,SAClB,QAAQ,cAAc;GAGxB,IAAI,KAAK,QACP,QAAQ,eAAe;GAGzB,IAAI,KAAK,cACP,QAAQ,cAAc,EAAE,MAAM,CAAC,KAAK,YAAY,EAAE;GAGpD,IAAI,KAAK,SACP,QAAQ,mBAAmB,YAAY,KAAK,OAAO;GAGrD,OAAO;EACT,CAAC,CAAC,CACD,QAAQ,YAAY,QAAQ,OAAO;EACtC,IAAI,CAAC,OAAO,SAAS,QACnB,OAAO;EAGT,OAAO;CACT;CAEA,YAAY,QAA0D;EACpE,OAAO,UACL;GACE,WAAW,cAAc,gBAAgB;GACzC,KAAK,cAAc,OAAO,aAAa,OAAO,WAAW;GACzD,WAAW,gBAAgB,WAAW,OAAO,WAAW;GACxD,UAAU;EACZ,SACM,KAAK,aAAa,MAAM,CAChC;CACF;;CAGA,OAAe,uBAAuB,QAAwB;EAC5D,OAAO,cAAc,oBAAoB,mBAAmB,MAAM;CACpE;;CAGA,OAAe,uBAAuB,KAAqB;EACzD,OAAO,cAAc,oBAAoB,4BAA4B,GAAG;CAC1E;;;;;;CAOA,MAAc,oBACZ,MACgC;EAChC,MAAM,WAAW,gBAAgB,uBAAuB,KAAK,MAAM;EACnE,MAAM,SAASC,IAA6B,QAAQ;EACpD,IAAI,QACF,OAAO;EAGT,IAAI,KAAK,WACP,IAAI;GACF,MAAM,aAAa,MAAM,KAAK,KAAK,WAAW,aAAa;GAC3D,MAAM,UAAU,MAAM,cAAc,YAAY,MAAM;GACtD,MAAM,SAAS,KAAK,KAAK,cAAc,CAAC,CAAC,MAAM,OAAO;GACtD,IAAa,UAAU,MAAM;GAC7B,OAAO;EACT,QAAQ;GACN,OAAO,MACL,EAAE,aAAa,KAAK,OAAO,GAC3B,iDACF;EACF;OAEA,IAAI;GACF,MAAM,YAAY,aAAa,KAAK,QAAQ,aAAa;GACzD,MAAM,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,WAAW,cAAc;GAClE,IAAa,UAAU,IAAI;GAC3B,OAAO;EACT,QAAQ;GACN,OAAO,MACL,EAAE,aAAa,KAAK,OAAO,GAC3B,sCACF;EACF;EAGF,OAAO;CACT;;;;;;;;;;;;CAaA,OAAe,cAAc,KAAsB;EACjD,OAAO,SAAS,GAAG,CAAC,EAAE,aAAa;CACrC;CAEA,OAAe,WAAW,KAAuB;EAC/C,OAAO,eAAeC,gBAAa,IAAI,UAAU,eAAe;CAClE;;;;;CAMA,MAAc,qBAAqB,KAA+B;EAChE,IAAI,gBAAgB,cAAc,GAAG,GACnC,OAAO;EAGT,MAAM,SAAS,gBAAgB,uBAAuB,GAAG;EACzD,MAAM,SAASD,IAAsB,MAAM;EAC3C,IAAI,UAAU,MAAM,GAClB,OAAO;EAOT,MAAM,cAAc,MAJIE,MACtB,iCACA,GACF,MACkC;EAClC,IAAa,QAAQ,WAAW;EAChC,OAAO;CACT;CAEA,MAAc,uBACZ,aACA,KACe;EACf,OAAO,MACL;GAAE;GAAa;EAAI,GACnB,2GACF;EACA,IAAa,gBAAgB,uBAAuB,GAAG,GAAG,IAAI;EAC9D,MAAMC,MAAiB,iCAAiC,KAAK,MAAM,IAAO;CAC5E;CAEA,MAAc,kBACZ,MACA,aAC+B;EAC/B,MAAM,iBAAiB,MAAM,KAAK,oBAAoB,IAAI;EAC1D,IAAI,CAAC,gBAAgB,KACnB,OAAO;EAGT,MAAM,EAAE,QAAQ;EAChB,IAAI,MAAM,KAAK,qBAAqB,GAAG,GACrC,OAAO;EAQT,MAAM,WAAW,GALE,aAAa,KAAK,SAKR,EAAE,SAAS,YAAY;EAEpD,OAAO,MACL;GAAE;GAAU;GAAa,aAAa,KAAK;EAAO,GAClD,4BACF;EAEA,IAAI;GACF,MAAM,EAAE,SAAS,MAAM,KAAK,KAAK,QAAQ,UAAU,qBAAqB;GACxE,OAAO,KAAK;EACd,SAAS,KAAK;GAGZ,IACE,CAAC,gBAAgB,cAAc,GAAG,KAClC,gBAAgB,WAAW,GAAG,GAC9B;IACA,MAAM,KAAK,uBAAuB,KAAK,QAAQ,GAAG;IAClD,OAAO;GACT;GACA,OAAO,MACL;IAAE;IAAK;IAAa,aAAa,KAAK;GAAO,GAC7C,mCACF;EACF;EAEA,OAAO;CACT;CAEA,iBACE,MACA,aAC+B;EAC/B,OAAO,UACL;GACE,WAAW,cAAc,gBAAgB,GAAG;GAC5C,KAAK,cAAc,KAAK,QAAQ,WAAW;GAC3C,WAAW,KAAK,WAAW;GAC3B,YAAY;EACd,SACM,KAAK,kBAAkB,MAAM,WAAW,CAChD;CACF;CAEA,MAAa,yBACX,MACA,aACiB;EACjB,IAAI,KAAK,WAAW;GAClB,MAAM,OAAO,MAAM,KACjB,KAAK,WACL,GAAG,gBAAgB,eAAe,WAAW,CAC/C;GACA,OAAO,cAAc,MAAM,MAAM;EACnC;EAGA,MAAM,gBAAgB,gBAAgB,eACpC,YAAY,YAAY,CAC1B;EACA,MAAM,WAAW,aAAa,KAAK,QAAQ,GAAG,aAAa;EAC3D,OAAO,MACL;GAAE;GAAU;GAAa,aAAa,KAAK;EAAO,GAClD,0CACF;EACA,IAAI;GACF,QAAQ,MAAM,KAAK,KAAK,QAAQ,QAAQ,EAAA,CAAG;EAC7C,SAAS,KAAK;GACZ,KAAK,oBAAoB,GAAG;EAC9B;CACF;;;;;CAMA,OAAe,iBACb,MACA,aACQ;EACR,QAAQ,KAAK,QAAb;GACE,KAAK,aACH,OAAO,4BAA4B;GACrC,KAAK,cAAc;IAEjB,MAAM,SAAS,KAAK,IAAI,SAAS,MAAM,GAAG;IAG1C,OAAO,0BAFK,OAAO,GAEkB,SADxB,OAAO,GAC+B,yBAAyB;GAC9E;GACA,SACE,OAAO,GAAG,KAAK,IAAI,GAAG;EAC1B;CACF;;;;;CAMA,OAAe,gBAAgB,KAAkB;EAK/C,OAAO,kBAJO,IAAI,SAAS,QAAQ,MAAM,IAAI,GAAG,EAInB,EAAE,GAHlB,IAAI,SAGsB,GAF1B,SAAS,IAAI,QAAQ,CAAC,CAAC,UAAU,GAAG,CAEJ;CAC/C;CAEA,OAAe,iBAAiB,KAAsB;EACpD,MAAM,SAAS,SAAS,GAAG;EAC3B,IAAI,CAAC,QACH,OAAO;EAET,OAAO,OAAO,SAAS,WAAW,SAAS;CAC7C;;;;;;;CAQA,aAAqB,kBAAkB,EACrC,aACA,eACkD;;EAElD,IAAI,CAAC,aACH,OAAO;EAGT,MAAM,mBAAmB,gBAAgB,iBAAiB,WAAW;EACrE,MAAM,mBAAmB,mBACrB,YAAY,QAAQ,MAAM,WAAW,GAAG,EAAE,IAC1C;EAEJ,MAAM,MAAM,SAAS,gBAAgB;EACrC,IAAI,CAAC,KAAK;GACR,OAAO,MAAM,gCAAgC,kBAAkB;GAC/D,OAAO;EACT;EAEA,IAAI;EACJ,IAAI,IAAI,aAAa,mBACnB,SAAS;OACJ,IAAI,IAAI,aAAa,oBAC1B,SAAS;OAET,SAAS;EAGX,MAAM,WAAyB;GAC7B;GACA,QAAQ;GACR;EACF;EAEA,IAAI,CAAC,kBAAkB;GACrB,IACE,SAAS,WAAW,eACpB,CAAC,aAAa,IAAI,+BAA+B,GACjD;IACA,OAAO,KACL,+HACF;IACA,OAAO;GACT;GACA,MAAM,WAAW,cACf,oBACA,uBACA,gBACF;GACA,MAAM,UAAU;GAEhB,MAAM,mBAAmB,aAAa,IAAI,kBAAkB,IAAI,KAAK;GACrE,MAAM,aAAa,aAAa,IAAI,YAAY,KAAK;GACrD,MAAM,cAAc,MAAM,YACxB,SACA,kBACA,UACF;GACA,IAAI;IACF,MAAM,SAASH,IAA0B,QAAQ;IAEjD,IAAI,QAAQ,KAAK;KACf,OAAO,KACL;MAAE,KAAK,OAAO;MAAK;MAAa;KAAiB,GACjD,yCACF;KACA,OAAO;IACT;IAEA,IAAI,QAAQ,WAAW;KACrB,SAAS,YAAY,OAAO;KAC5B,OAAO;IACT;IAEA,MAAM,YAAY,MAAM,KACtB,gBAAgB,GAChB,gBAAgB,gBAAgB,GAAG,CACrC;IAEA,MAAM,SAAS,MAAM,gBAAgB,MACnC,kBACA,WACA,WACF;IAEA,IAAa,UAAU,MAAM;IAE7B,IAAI,OAAO,KAAK;KACd,OAAO,KACL;MAAE,KAAK,OAAO;MAAK;MAAa;KAAiB,GACjD,gCACF;KACA,OAAO;IACT;IAEA,SAAS,YAAY,OAAO;GAC9B,UAAU;IACR,YAAY;GACd;EACF;EAEA,OAAO;CACT;CAEA,aAAqB,MACnB,kBACA,WACA,aACsB;EACtB,OAAO,KACL;GAAE;GAAW;EAAiB,GAC9B,gCACF;EAEA,MAAM,MAAM,gBAAgB;GAC1B,QAAQ,EAAE,wBAAwB,EAAE;GACpC,GAAI,UAAU,gBAAgB,KAAK,EAEjC,gBAAgB;IACd,WAAW,CAAC,gBAAgB,EAAE;IAC9B,KAAK;GACP,EACF;EACF,CAAC;EAED,IAAI;GACF,MAAM,IAAI,MAAM,kBAAkB,WAAW,EAC3C,WAAW,EACb,CAAC;GACD,OAAO,EAAE,UAAU;EACrB,SAAS,KAAK;GACZ,IACE,IAAI,QAAQ,SACV,kEACF,GACA;IACA,OAAO,KACL;KAAE;KAAa;IAAiB,GAChC,wDACF;IACA,IAAI;KACF,MAAM,IAAI,MAAM,kBAAkB,SAAS;KAC3C,OAAO,EAAE,UAAU;IACrB,SAAS,KAAK;KACZ,OAAO,KACL;MAAE;MAAK;MAAa;KAAiB,GACrC,6BACF;KACA,OAAO,EAAE,IAAI;IACf;GACF,OAAO;IACL,OAAO,KACL;KAAE;KAAK;KAAa;IAAiB,GACrC,6BACF;IACA,OAAO,EAAE,IAAI;GACf;EACF;CACF;CAEA,OAAe,WAAW,aAA0C;EAClE,IAAI,CAAC,aACH,OAAO;EAET,MAAM,aAAa,YAAY,QAAQ,MAAM,WAAW,GAAG,EAAE;EAE7D,OADe,SAAS,UACZ,CAAC,EAAE,aAAa;CAC9B;CAEA,OAAc,eAAe,aAA+B;EAC1D,MAAM,MAAM,YAAY;EAExB,IAAI,QAAQ,GACV,OAAO,CAAC,KAAK,WAAW;EAE1B,IAAI,QAAQ,GACV,OAAO,CAAC,KAAK,WAAW;EAE1B,IAAI,QAAQ,GACV,OAAO;GAAC;GAAK,YAAY;GAAI;EAAW;EAG1C,OAAO;GAAC,YAAY,MAAM,GAAG,CAAC;GAAG,YAAY,MAAM,GAAG,CAAC;GAAG;EAAW;CACvE;CAEA,MAAc,oBACZ,EAAE,aAAa,eACf,SACmC;EACnC,IAAI,QAAQ,kBACV,OAAO;EAIT,MAAM,SAAS,aAAa,QAAQ,MAAM,WAAW,GAAG,EAAE;EAC1D,IAAI,CAAC,QACH,OAAO;EAET,MAAM,SAASA,IACb,gBAAgB,uBAAuB,MAAM,CAC/C;EACA,IAAI,CAAC,QAAQ,KACX,OAAO;EAGT,MAAM,EAAE,QAAQ;EAChB,IAAI,MAAM,KAAK,qBAAqB,GAAG,GACrC,OAAO;EAIT,MAAM,MAAM,GADO,aAAa,KAAK,SACb,EAAE,SAAS,YAAY,GAAG,QAAQ,eAAe,QAAQ;EACjF,OAAO,MACL;GAAE;GAAK;GAAa,SAAS,QAAQ;GAAS;EAAY,GAC1D,kCACF;EAGA,IAAI;GACF,MAAM,EAAE,MAAM,qBAAqB,MAAM,KAAK,KAAK,QACjD,KACA,EAAE,eAAe,iBAAiB,GAClC,gBACF;GACA,QAAQ,mBAAmB;EAC7B,SAAS,KAAK;GACZ,IACE,gBAAgB,cAAc,GAAG,KACjC,CAAC,gBAAgB,WAAW,GAAG,GAE/B,MAAM;GAER,MAAM,KAAK,uBAAuB,QAAQ,GAAG;EAC/C;EACA,OAAO;CACT;CAEA,mBACE,QACA,SACmC;EACnC,OAAO,UACL;GACE,WAAW;GACX,KAAK,cACH,sBACA,OAAO,aACP,OAAO,aACP,QAAQ,OACV;GACA,YAAY;GACZ,WAAW,gBAAgB,WAAW,OAAO,eAAe,KAAA,CAAS;EACvE,SACM,KAAK,oBAAoB,QAAQ,OAAO,CAChD;CACF;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logger } from "../../../logger/index.js";
|
|
2
|
+
import { withoutUrlCredentials } from "../../../util/url.js";
|
|
2
3
|
import { getExpression } from "../../../util/jsonata.js";
|
|
3
4
|
import { Datasource } from "../datasource.js";
|
|
4
5
|
import { fetchers } from "./formats/index.js";
|
|
@@ -55,7 +56,10 @@ var CustomDatasource = class CustomDatasource extends Datasource {
|
|
|
55
56
|
}
|
|
56
57
|
try {
|
|
57
58
|
const parsed = ReleaseResultZod.parse(data);
|
|
58
|
-
|
|
59
|
+
const result = structuredClone(parsed);
|
|
60
|
+
const { registryUrl } = getReleasesConfig;
|
|
61
|
+
if (registryUrl && result.releases.length) result.registryUrl = withoutUrlCredentials(registryUrl);
|
|
62
|
+
return result;
|
|
59
63
|
} catch (err) {
|
|
60
64
|
logger.debug({ err }, `Response has failed validation`);
|
|
61
65
|
logger.trace({ data }, "Response that has failed validation");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/datasource/custom/index.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { getExpression } from '../../../util/jsonata.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n ReleaseResult,\n} from '../types.ts';\nimport { fetchers } from './formats/index.ts';\nimport { ReleaseResultZod } from './schema.ts';\nimport { getCustomConfig } from './utils.ts';\n\nexport class CustomDatasource extends Datasource {\n static readonly id = 'custom';\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n constructor() {\n super(CustomDatasource.id);\n }\n\n async getReleases(\n getReleasesConfig: GetReleasesConfig,\n ): Promise<ReleaseResult | null> {\n const config = getCustomConfig(getReleasesConfig);\n if (isNullOrUndefined(config)) {\n return null;\n }\n\n const { defaultRegistryUrlTemplate, transformTemplates, format } = config;\n\n const fetcher = fetchers[format];\n const isLocalRegistry = defaultRegistryUrlTemplate.startsWith('file://');\n\n let data: unknown;\n try {\n if (isLocalRegistry) {\n data = await fetcher.readFile(\n defaultRegistryUrlTemplate.replace('file://', ''),\n );\n } else {\n data = await fetcher.fetch(this.http, defaultRegistryUrlTemplate);\n }\n } catch (e) {\n this.handleHttpErrors(e);\n return null;\n }\n\n logger.trace(\n { data },\n `Custom datasource API fetcher '${format}' received data. Starting transformation.`,\n );\n\n for (const transformTemplate of transformTemplates) {\n const expression = getExpression(transformTemplate);\n\n if (expression instanceof Error) {\n logger.once.warn(\n { errorMessage: expression.message, transformTemplate },\n 'Invalid JSONata expression',\n );\n return null;\n }\n\n try {\n const modifiedData = await expression.evaluate(data);\n\n logger.trace(\n { before: data, after: modifiedData },\n `Custom datasource transformed data.`,\n );\n\n data = modifiedData;\n } catch (err) {\n logger.once.warn(\n { err, transformTemplate },\n 'Error while evaluating JSONata expression',\n );\n return null;\n }\n }\n\n try {\n const parsed = ReleaseResultZod.parse(data);\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/datasource/custom/index.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { getExpression } from '../../../util/jsonata.ts';\nimport { withoutUrlCredentials } from '../../../util/url.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n ReleaseResult,\n} from '../types.ts';\nimport { fetchers } from './formats/index.ts';\nimport { ReleaseResultZod } from './schema.ts';\nimport { getCustomConfig } from './utils.ts';\n\nexport class CustomDatasource extends Datasource {\n static readonly id = 'custom';\n\n override supportsCustomRegistry(_packageName: string): boolean {\n return true;\n }\n\n constructor() {\n super(CustomDatasource.id);\n }\n\n async getReleases(\n getReleasesConfig: GetReleasesConfig,\n ): Promise<ReleaseResult | null> {\n const config = getCustomConfig(getReleasesConfig);\n if (isNullOrUndefined(config)) {\n return null;\n }\n\n const { defaultRegistryUrlTemplate, transformTemplates, format } = config;\n\n const fetcher = fetchers[format];\n const isLocalRegistry = defaultRegistryUrlTemplate.startsWith('file://');\n\n let data: unknown;\n try {\n if (isLocalRegistry) {\n data = await fetcher.readFile(\n defaultRegistryUrlTemplate.replace('file://', ''),\n );\n } else {\n data = await fetcher.fetch(this.http, defaultRegistryUrlTemplate);\n }\n } catch (e) {\n this.handleHttpErrors(e);\n return null;\n }\n\n logger.trace(\n { data },\n `Custom datasource API fetcher '${format}' received data. Starting transformation.`,\n );\n\n for (const transformTemplate of transformTemplates) {\n const expression = getExpression(transformTemplate);\n\n if (expression instanceof Error) {\n logger.once.warn(\n { errorMessage: expression.message, transformTemplate },\n 'Invalid JSONata expression',\n );\n return null;\n }\n\n try {\n const modifiedData = await expression.evaluate(data);\n\n logger.trace(\n { before: data, after: modifiedData },\n `Custom datasource transformed data.`,\n );\n\n data = modifiedData;\n } catch (err) {\n logger.once.warn(\n { err, transformTemplate },\n 'Error while evaluating JSONata expression',\n );\n return null;\n }\n }\n\n try {\n const parsed = ReleaseResultZod.parse(data);\n const result: ReleaseResult = structuredClone(parsed);\n const { registryUrl } = getReleasesConfig;\n // a URL template keeps its credentials until it is compiled\n // set only with releases, as `getRegistryReleases()` does, so that an empty result stays recognisable as one\n if (registryUrl && result.releases.length) {\n result.registryUrl = withoutUrlCredentials(registryUrl);\n }\n return result;\n } catch (err) {\n logger.debug({ err }, `Response has failed validation`);\n logger.trace({ data }, 'Response that has failed validation');\n return null;\n }\n }\n\n override getDigest(\n _cfg: DigestConfig,\n _newValue?: string,\n ): Promise<string | null> {\n // Return null here to support setting a digest: value can be provided digest in getReleases\n return Promise.resolve(null);\n }\n}\n"],"mappings":";;;;;;;;;AAcA,IAAa,mBAAb,MAAa,yBAAyB,WAAW;CAC/C,OAAgB,KAAK;CAErB,uBAAgC,cAA+B;EAC7D,OAAO;CACT;CAEA,cAAc;EACZ,MAAM,iBAAiB,EAAE;CAC3B;CAEA,MAAM,YACJ,mBAC+B;EAC/B,MAAM,SAAS,gBAAgB,iBAAiB;EAChD,IAAI,kBAAkB,MAAM,GAC1B,OAAO;EAGT,MAAM,EAAE,4BAA4B,oBAAoB,WAAW;EAEnE,MAAM,UAAU,SAAS;EACzB,MAAM,kBAAkB,2BAA2B,WAAW,SAAS;EAEvE,IAAI;EACJ,IAAI;GACF,IAAI,iBACF,OAAO,MAAM,QAAQ,SACnB,2BAA2B,QAAQ,WAAW,EAAE,CAClD;QAEA,OAAO,MAAM,QAAQ,MAAM,KAAK,MAAM,0BAA0B;EAEpE,SAAS,GAAG;GACV,KAAK,iBAAiB,CAAC;GACvB,OAAO;EACT;EAEA,OAAO,MACL,EAAE,KAAK,GACP,kCAAkC,OAAO,0CAC3C;EAEA,KAAK,MAAM,qBAAqB,oBAAoB;GAClD,MAAM,aAAa,cAAc,iBAAiB;GAElD,IAAI,sBAAsB,OAAO;IAC/B,OAAO,KAAK,KACV;KAAE,cAAc,WAAW;KAAS;IAAkB,GACtD,4BACF;IACA,OAAO;GACT;GAEA,IAAI;IACF,MAAM,eAAe,MAAM,WAAW,SAAS,IAAI;IAEnD,OAAO,MACL;KAAE,QAAQ;KAAM,OAAO;IAAa,GACpC,qCACF;IAEA,OAAO;GACT,SAAS,KAAK;IACZ,OAAO,KAAK,KACV;KAAE;KAAK;IAAkB,GACzB,2CACF;IACA,OAAO;GACT;EACF;EAEA,IAAI;GACF,MAAM,SAAS,iBAAiB,MAAM,IAAI;GAC1C,MAAM,SAAwB,gBAAgB,MAAM;GACpD,MAAM,EAAE,gBAAgB;GAGxB,IAAI,eAAe,OAAO,SAAS,QACjC,OAAO,cAAc,sBAAsB,WAAW;GAExD,OAAO;EACT,SAAS,KAAK;GACZ,OAAO,MAAM,EAAE,IAAI,GAAG,gCAAgC;GACtD,OAAO,MAAM,EAAE,KAAK,GAAG,qCAAqC;GAC5D,OAAO;EACT;CACF;CAEA,UACE,MACA,WACwB;EAExB,OAAO,QAAQ,QAAQ,IAAI;CAC7B;AACF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { coerceArray } from "../../../util/array.js";
|
|
2
2
|
import { logger } from "../../../logger/index.js";
|
|
3
|
+
import { detachUrlCredentials } from "../../../util/host-rules.js";
|
|
3
4
|
import { compile } from "../../../util/template/index.js";
|
|
4
5
|
import { isNonEmptyString, isNullOrUndefined } from "@sindresorhus/is";
|
|
5
6
|
//#region lib/modules/datasource/custom/utils.ts
|
|
@@ -18,7 +19,7 @@ function massageCustomDatasourceConfig(customDatasourceName, { customDatasources
|
|
|
18
19
|
logger.debug("No registry url provided by extraction nor datasource configuration");
|
|
19
20
|
return null;
|
|
20
21
|
}
|
|
21
|
-
const registryUrl = compile(registryUrlTemplate, templateInput);
|
|
22
|
+
const registryUrl = detachUrlCredentials(compile(registryUrlTemplate, templateInput), ["custom"]);
|
|
22
23
|
const transformTemplates = coerceArray(customDatasource.transformTemplates);
|
|
23
24
|
const transform = [];
|
|
24
25
|
for (const transformTemplate of transformTemplates) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["template.compile"],"sources":["../../../../lib/modules/datasource/custom/utils.ts"],"sourcesContent":["import { isNonEmptyString, isNullOrUndefined } from '@sindresorhus/is';\nimport type { CustomDatasourceConfig } from '../../../config/types.ts';\nimport { logger } from '../../../logger/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport * as template from '../../../util/template/index.ts';\nimport type { GetReleasesConfig } from '../types.ts';\n\nexport function massageCustomDatasourceConfig(\n customDatasourceName: string,\n {\n customDatasources,\n packageName,\n currentValue,\n registryUrl: defaultRegistryUrl,\n }: GetReleasesConfig,\n): Required<CustomDatasourceConfig> | null {\n const customDatasource = customDatasources?.[customDatasourceName];\n if (isNullOrUndefined(customDatasource)) {\n logger.debug(\n `No custom datasource config provided while ${packageName} has been requested`,\n );\n return null;\n }\n const templateInput = { packageName, currentValue };\n\n const registryUrlTemplate =\n defaultRegistryUrl ?? customDatasource.defaultRegistryUrlTemplate;\n if (isNullOrUndefined(registryUrlTemplate)) {\n logger.debug(\n 'No registry url provided by extraction nor datasource configuration',\n );\n return null;\n }\n const registryUrl = template.compile(registryUrlTemplate, templateInput);\n\n const transformTemplates = coerceArray(customDatasource.transformTemplates);\n const transform: string[] = [];\n for (const transformTemplate of transformTemplates) {\n const templated = template.compile(transformTemplate, templateInput);\n transform.push(templated);\n }\n\n logger.trace({ transform }, `Custom datasource compiled data.`);\n\n return {\n format: customDatasource.format ?? 'json',\n defaultRegistryUrlTemplate: registryUrl,\n transformTemplates: transform,\n };\n}\n\nexport function getCustomConfig(\n getReleasesConfig: GetReleasesConfig,\n): Required<CustomDatasourceConfig> | null {\n const customDatasourceName = getReleasesConfig.datasource?.replace(\n 'custom.',\n '',\n );\n\n if (!isNonEmptyString(customDatasourceName)) {\n logger.debug(\n `No datasource has been supplied while looking up ${getReleasesConfig.packageName}`,\n );\n return null;\n }\n\n return massageCustomDatasourceConfig(customDatasourceName, getReleasesConfig);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","names":["template.compile"],"sources":["../../../../lib/modules/datasource/custom/utils.ts"],"sourcesContent":["import { isNonEmptyString, isNullOrUndefined } from '@sindresorhus/is';\nimport type { CustomDatasourceConfig } from '../../../config/types.ts';\nimport { logger } from '../../../logger/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { detachUrlCredentials } from '../../../util/host-rules.ts';\nimport * as template from '../../../util/template/index.ts';\nimport type { GetReleasesConfig } from '../types.ts';\n\nexport function massageCustomDatasourceConfig(\n customDatasourceName: string,\n {\n customDatasources,\n packageName,\n currentValue,\n registryUrl: defaultRegistryUrl,\n }: GetReleasesConfig,\n): Required<CustomDatasourceConfig> | null {\n const customDatasource = customDatasources?.[customDatasourceName];\n if (isNullOrUndefined(customDatasource)) {\n logger.debug(\n `No custom datasource config provided while ${packageName} has been requested`,\n );\n return null;\n }\n const templateInput = { packageName, currentValue };\n\n const registryUrlTemplate =\n defaultRegistryUrl ?? customDatasource.defaultRegistryUrlTemplate;\n if (isNullOrUndefined(registryUrlTemplate)) {\n logger.debug(\n 'No registry url provided by extraction nor datasource configuration',\n );\n return null;\n }\n // the credentials of a URL template are detached from the URL it compiles, the one which is requested with the `custom` host type\n const registryUrl = detachUrlCredentials(\n template.compile(registryUrlTemplate, templateInput),\n ['custom'],\n );\n\n const transformTemplates = coerceArray(customDatasource.transformTemplates);\n const transform: string[] = [];\n for (const transformTemplate of transformTemplates) {\n const templated = template.compile(transformTemplate, templateInput);\n transform.push(templated);\n }\n\n logger.trace({ transform }, `Custom datasource compiled data.`);\n\n return {\n format: customDatasource.format ?? 'json',\n defaultRegistryUrlTemplate: registryUrl,\n transformTemplates: transform,\n };\n}\n\nexport function getCustomConfig(\n getReleasesConfig: GetReleasesConfig,\n): Required<CustomDatasourceConfig> | null {\n const customDatasourceName = getReleasesConfig.datasource?.replace(\n 'custom.',\n '',\n );\n\n if (!isNonEmptyString(customDatasourceName)) {\n logger.debug(\n `No datasource has been supplied while looking up ${getReleasesConfig.packageName}`,\n );\n return null;\n }\n\n return massageCustomDatasourceConfig(customDatasourceName, getReleasesConfig);\n}\n"],"mappings":";;;;;;AAQA,SAAgB,8BACd,sBACA,EACE,mBACA,aACA,cACA,aAAa,sBAE0B;CACzC,MAAM,mBAAmB,oBAAoB;CAC7C,IAAI,kBAAkB,gBAAgB,GAAG;EACvC,OAAO,MACL,8CAA8C,YAAY,oBAC5D;EACA,OAAO;CACT;CACA,MAAM,gBAAgB;EAAE;EAAa;CAAa;CAElD,MAAM,sBACJ,sBAAsB,iBAAiB;CACzC,IAAI,kBAAkB,mBAAmB,GAAG;EAC1C,OAAO,MACL,qEACF;EACA,OAAO;CACT;CAEA,MAAM,cAAc,qBAClBA,QAAiB,qBAAqB,aAAa,GACnD,CAAC,QAAQ,CACX;CAEA,MAAM,qBAAqB,YAAY,iBAAiB,kBAAkB;CAC1E,MAAM,YAAsB,CAAC;CAC7B,KAAK,MAAM,qBAAqB,oBAAoB;EAClD,MAAM,YAAYA,QAAiB,mBAAmB,aAAa;EACnE,UAAU,KAAK,SAAS;CAC1B;CAEA,OAAO,MAAM,EAAE,UAAU,GAAG,kCAAkC;CAE9D,OAAO;EACL,QAAQ,iBAAiB,UAAU;EACnC,4BAA4B;EAC5B,oBAAoB;CACtB;AACF;AAEA,SAAgB,gBACd,mBACyC;CACzC,MAAM,uBAAuB,kBAAkB,YAAY,QACzD,WACA,EACF;CAEA,IAAI,CAAC,iBAAiB,oBAAoB,GAAG;EAC3C,OAAO,MACL,oDAAoD,kBAAkB,aACxE;EACA,OAAO;CACT;CAEA,OAAO,8BAA8B,sBAAsB,iBAAiB;AAC9E"}
|
|
@@ -5,9 +5,9 @@ import { coerceArray } from "../../../util/array.js";
|
|
|
5
5
|
import { addSecretForSanitizing } from "../../../util/sanitize.js";
|
|
6
6
|
import { logger } from "../../../logger/index.js";
|
|
7
7
|
import { ensureTrailingSlash, parseUrl, trimTrailingSlash } from "../../../util/url.js";
|
|
8
|
+
import { toSha256 } from "../../../util/hash.js";
|
|
8
9
|
import { find } from "../../../util/host-rules.js";
|
|
9
10
|
import { detectPlatform } from "../../../util/common.js";
|
|
10
|
-
import { toSha256 } from "../../../util/hash.js";
|
|
11
11
|
import { ExternalHostError } from "../../../types/errors/external-host-error.js";
|
|
12
12
|
import { api } from "../../versioning/docker/index.js";
|
|
13
13
|
import { refusedHostMessage } from "../../../util/http/util.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { newlineRegex, regEx } from "../../../util/regex.js";
|
|
2
2
|
import { logger } from "../../../logger/index.js";
|
|
3
|
+
import { withoutUrlCredentials } from "../../../util/url.js";
|
|
3
4
|
import { Datasource } from "../datasource.js";
|
|
4
5
|
import { getRemoteUrlWithToken } from "../../../util/git/url.js";
|
|
5
6
|
import { createSimpleGit } from "../../../util/git/index.js";
|
|
@@ -75,7 +76,7 @@ var GitDatasource = class extends Datasource {
|
|
|
75
76
|
};
|
|
76
77
|
}
|
|
77
78
|
return {
|
|
78
|
-
sourceUrl: this.getSourceUrl(packageName),
|
|
79
|
+
sourceUrl: withoutUrlCredentials(this.getSourceUrl(packageName)),
|
|
79
80
|
releases: Object.values(releases)
|
|
80
81
|
};
|
|
81
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","names":[],"sources":["../../../../lib/modules/datasource/git-refs/base.ts"],"sourcesContent":["import { isTruthy } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { createSimpleGit } from '../../../util/git/index.ts';\nimport { getRemoteUrlWithToken } from '../../../util/git/url.ts';\nimport { newlineRegex, regEx } from '../../../util/regex.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport type { RawRefs } from './types.ts';\n\nconst refMatch = regEx(/(?<hash>.*?)\\s+refs\\/(?<type>.*?)\\/(?<value>.*)/);\nconst headMatch = regEx(/(?<hash>.*?)\\s+HEAD/);\n\nconst gitId = 'git';\n\n// TODO: extract to a separate directory structure (#10532)\nexport abstract class GitDatasource extends Datasource {\n static id = gitId;\n\n /**\n * The `refs/<type>/` kinds this datasource exposes as releases, and the only\n * ones a `newValue` is matched against by {@link GitDatasource.getDigest}.\n */\n protected abstract readonly refTypes: readonly string[];\n\n constructor(id: string) {\n super(id);\n }\n\n private async _getRawRefs({\n packageName,\n }: GetReleasesConfig): Promise<RawRefs[] | null> {\n const git = createSimpleGit({\n authentication: { hostTypes: [this.id] },\n });\n\n // fetch remote tags\n const lsRemote = await git.listRemote([\n getRemoteUrlWithToken(packageName, this.id),\n ]);\n if (!lsRemote) {\n return null;\n }\n\n const allRefs = lsRemote\n .trim()\n .split(newlineRegex)\n .map((line) => line.trim())\n .map((line) => {\n let match = refMatch.exec(line);\n if (match?.groups) {\n return {\n type: match.groups.type,\n value: match.groups.value,\n hash: match.groups.hash,\n };\n }\n match = headMatch.exec(line);\n if (match?.groups) {\n return {\n type: '',\n value: 'HEAD',\n hash: match.groups.hash,\n };\n }\n logger.trace(`malformed ref: ${line}`);\n return null;\n })\n .filter(isTruthy)\n .filter((ref) => ref.type !== 'pull');\n\n // For annotated tags, git ls-remote returns two entries:\n // 1. The tag object hash: refs/tags/v1.0.0\n // 2. The dereferenced commit hash: refs/tags/v1.0.0^{}\n // We need to use the dereferenced commit hash (^{}) for annotated tags\n // to match what `git submodule status` returns (the actual commit hash).\n // This prevents false-positive updates that result in empty commits.\n const dereferencedTags: Record<string, string> = {};\n for (const ref of allRefs) {\n if (ref.value.endsWith('^{}')) {\n // Store the commit hash for the base tag name (without ^{})\n dereferencedTags[ref.value.slice(0, -3)] = ref.hash;\n }\n }\n\n const refs = allRefs\n .filter((ref) => !ref.value.endsWith('^{}'))\n .map((ref) => {\n // For annotated tags, use the dereferenced commit hash\n const dereferencedHash = dereferencedTags[ref.value];\n if (dereferencedHash) {\n return { ...ref, hash: dereferencedHash };\n }\n return ref;\n });\n\n return refs;\n }\n\n getRawRefs(config: GetReleasesConfig): Promise<RawRefs[] | null> {\n return this.cached(\n {\n namespace: `datasource-${gitId}`,\n key: config.packageName,\n },\n () => this._getRawRefs(config),\n );\n }\n\n /**\n * The repository URL, without the `.git` suffix and the trailing slash that\n * a `packageName` may carry.\n */\n protected getSourceUrl(packageName: string): string {\n return packageName.replace(regEx(/\\.git$/), '').replace(regEx(/\\/$/), '');\n }\n\n /**\n * One release per distinct ref value of the datasource's\n * {@link GitDatasource.refTypes}. A value carried by several ref types, such\n * as a branch and a tag of the same name, keeps the hash of the first ref that\n * has it.\n */\n protected async getRefReleases({\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const rawRefs = await this.getRawRefs({ packageName });\n if (!rawRefs) {\n return null;\n }\n\n const releases: Record<string, Release> = {};\n for (const ref of rawRefs) {\n if (\n !this.refTypes.includes(ref.type) ||\n Object.hasOwn(releases, ref.value)\n ) {\n continue;\n }\n\n releases[ref.value] = {\n version: ref.value,\n gitRef: ref.value,\n newDigest: ref.hash,\n };\n }\n\n return {\n sourceUrl: this.getSourceUrl(packageName),\n releases: Object.values(releases),\n };\n }\n\n override async getDigest(\n { packageName }: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n const rawRefs = await this.getRawRefs({ packageName });\n if (!rawRefs) {\n return null;\n }\n\n if (!newValue) {\n const head = rawRefs.find(\n (rawRef) => rawRef.type === '' && rawRef.value === 'HEAD',\n );\n return head?.hash ?? null;\n }\n\n const ref = rawRefs.find(\n (rawRef) =>\n this.refTypes.includes(rawRef.type) && rawRef.value === newValue,\n );\n return ref?.hash ?? null;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"base.js","names":[],"sources":["../../../../lib/modules/datasource/git-refs/base.ts"],"sourcesContent":["import { isTruthy } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { createSimpleGit } from '../../../util/git/index.ts';\nimport { getRemoteUrlWithToken } from '../../../util/git/url.ts';\nimport { newlineRegex, regEx } from '../../../util/regex.ts';\nimport { withoutUrlCredentials } from '../../../util/url.ts';\nimport { Datasource } from '../datasource.ts';\nimport type {\n DigestConfig,\n GetReleasesConfig,\n Release,\n ReleaseResult,\n} from '../types.ts';\nimport type { RawRefs } from './types.ts';\n\nconst refMatch = regEx(/(?<hash>.*?)\\s+refs\\/(?<type>.*?)\\/(?<value>.*)/);\nconst headMatch = regEx(/(?<hash>.*?)\\s+HEAD/);\n\nconst gitId = 'git';\n\n// TODO: extract to a separate directory structure (#10532)\nexport abstract class GitDatasource extends Datasource {\n static id = gitId;\n\n /**\n * The `refs/<type>/` kinds this datasource exposes as releases, and the only\n * ones a `newValue` is matched against by {@link GitDatasource.getDigest}.\n */\n protected abstract readonly refTypes: readonly string[];\n\n constructor(id: string) {\n super(id);\n }\n\n private async _getRawRefs({\n packageName,\n }: GetReleasesConfig): Promise<RawRefs[] | null> {\n const git = createSimpleGit({\n authentication: { hostTypes: [this.id] },\n });\n\n // fetch remote tags\n const lsRemote = await git.listRemote([\n getRemoteUrlWithToken(packageName, this.id),\n ]);\n if (!lsRemote) {\n return null;\n }\n\n const allRefs = lsRemote\n .trim()\n .split(newlineRegex)\n .map((line) => line.trim())\n .map((line) => {\n let match = refMatch.exec(line);\n if (match?.groups) {\n return {\n type: match.groups.type,\n value: match.groups.value,\n hash: match.groups.hash,\n };\n }\n match = headMatch.exec(line);\n if (match?.groups) {\n return {\n type: '',\n value: 'HEAD',\n hash: match.groups.hash,\n };\n }\n logger.trace(`malformed ref: ${line}`);\n return null;\n })\n .filter(isTruthy)\n .filter((ref) => ref.type !== 'pull');\n\n // For annotated tags, git ls-remote returns two entries:\n // 1. The tag object hash: refs/tags/v1.0.0\n // 2. The dereferenced commit hash: refs/tags/v1.0.0^{}\n // We need to use the dereferenced commit hash (^{}) for annotated tags\n // to match what `git submodule status` returns (the actual commit hash).\n // This prevents false-positive updates that result in empty commits.\n const dereferencedTags: Record<string, string> = {};\n for (const ref of allRefs) {\n if (ref.value.endsWith('^{}')) {\n // Store the commit hash for the base tag name (without ^{})\n dereferencedTags[ref.value.slice(0, -3)] = ref.hash;\n }\n }\n\n const refs = allRefs\n .filter((ref) => !ref.value.endsWith('^{}'))\n .map((ref) => {\n // For annotated tags, use the dereferenced commit hash\n const dereferencedHash = dereferencedTags[ref.value];\n if (dereferencedHash) {\n return { ...ref, hash: dereferencedHash };\n }\n return ref;\n });\n\n return refs;\n }\n\n getRawRefs(config: GetReleasesConfig): Promise<RawRefs[] | null> {\n return this.cached(\n {\n namespace: `datasource-${gitId}`,\n key: config.packageName,\n },\n () => this._getRawRefs(config),\n );\n }\n\n /**\n * The repository URL, without the `.git` suffix and the trailing slash that\n * a `packageName` may carry.\n */\n protected getSourceUrl(packageName: string): string {\n return packageName.replace(regEx(/\\.git$/), '').replace(regEx(/\\/$/), '');\n }\n\n /**\n * One release per distinct ref value of the datasource's\n * {@link GitDatasource.refTypes}. A value carried by several ref types, such\n * as a branch and a tag of the same name, keeps the hash of the first ref that\n * has it.\n */\n protected async getRefReleases({\n packageName,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n const rawRefs = await this.getRawRefs({ packageName });\n if (!rawRefs) {\n return null;\n }\n\n const releases: Record<string, Release> = {};\n for (const ref of rawRefs) {\n if (\n !this.refTypes.includes(ref.type) ||\n Object.hasOwn(releases, ref.value)\n ) {\n continue;\n }\n\n releases[ref.value] = {\n version: ref.value,\n gitRef: ref.value,\n newDigest: ref.hash,\n };\n }\n\n return {\n // the result is cached, while `packageName` may carry the credentials the refs are listed with\n sourceUrl: withoutUrlCredentials(this.getSourceUrl(packageName)),\n releases: Object.values(releases),\n };\n }\n\n override async getDigest(\n { packageName }: DigestConfig,\n newValue?: string,\n ): Promise<string | null> {\n const rawRefs = await this.getRawRefs({ packageName });\n if (!rawRefs) {\n return null;\n }\n\n if (!newValue) {\n const head = rawRefs.find(\n (rawRef) => rawRef.type === '' && rawRef.value === 'HEAD',\n );\n return head?.hash ?? null;\n }\n\n const ref = rawRefs.find(\n (rawRef) =>\n this.refTypes.includes(rawRef.type) && rawRef.value === newValue,\n );\n return ref?.hash ?? null;\n }\n}\n"],"mappings":";;;;;;;;AAeA,MAAM,WAAW,MAAM,iDAAiD;AACxE,MAAM,YAAY,MAAM,qBAAqB;AAE7C,MAAM,QAAQ;AAGd,IAAsB,gBAAtB,cAA4C,WAAW;CACrD,OAAO,KAAK;CAQZ,YAAY,IAAY;EACtB,MAAM,EAAE;CACV;CAEA,MAAc,YAAY,EACxB,eAC+C;EAM/C,MAAM,WAAW,MALL,gBAAgB,EAC1B,gBAAgB,EAAE,WAAW,CAAC,KAAK,EAAE,EAAE,EACzC,CAGyB,CAAC,CAAC,WAAW,CACpC,sBAAsB,aAAa,KAAK,EAAE,CAC5C,CAAC;EACD,IAAI,CAAC,UACH,OAAO;EAGT,MAAM,UAAU,SACb,KAAK,CAAC,CACN,MAAM,YAAY,CAAC,CACnB,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,KAAK,SAAS;GACb,IAAI,QAAQ,SAAS,KAAK,IAAI;GAC9B,IAAI,OAAO,QACT,OAAO;IACL,MAAM,MAAM,OAAO;IACnB,OAAO,MAAM,OAAO;IACpB,MAAM,MAAM,OAAO;GACrB;GAEF,QAAQ,UAAU,KAAK,IAAI;GAC3B,IAAI,OAAO,QACT,OAAO;IACL,MAAM;IACN,OAAO;IACP,MAAM,MAAM,OAAO;GACrB;GAEF,OAAO,MAAM,kBAAkB,MAAM;GACrC,OAAO;EACT,CAAC,CAAC,CACD,OAAO,QAAQ,CAAC,CAChB,QAAQ,QAAQ,IAAI,SAAS,MAAM;EAQtC,MAAM,mBAA2C,CAAC;EAClD,KAAK,MAAM,OAAO,SAChB,IAAI,IAAI,MAAM,SAAS,KAAK,GAE1B,iBAAiB,IAAI,MAAM,MAAM,GAAG,EAAE,KAAK,IAAI;EAenD,OAXa,QACV,QAAQ,QAAQ,CAAC,IAAI,MAAM,SAAS,KAAK,CAAC,CAAC,CAC3C,KAAK,QAAQ;GAEZ,MAAM,mBAAmB,iBAAiB,IAAI;GAC9C,IAAI,kBACF,OAAO;IAAE,GAAG;IAAK,MAAM;GAAiB;GAE1C,OAAO;EACT,CAEQ;CACZ;CAEA,WAAW,QAAsD;EAC/D,OAAO,KAAK,OACV;GACE,WAAW,cAAc;GACzB,KAAK,OAAO;EACd,SACM,KAAK,YAAY,MAAM,CAC/B;CACF;;;;;CAMA,aAAuB,aAA6B;EAClD,OAAO,YAAY,QAAQ,MAAM,QAAQ,GAAG,EAAE,CAAC,CAAC,QAAQ,MAAM,KAAK,GAAG,EAAE;CAC1E;;;;;;;CAQA,MAAgB,eAAe,EAC7B,eACmD;EACnD,MAAM,UAAU,MAAM,KAAK,WAAW,EAAE,YAAY,CAAC;EACrD,IAAI,CAAC,SACH,OAAO;EAGT,MAAM,WAAoC,CAAC;EAC3C,KAAK,MAAM,OAAO,SAAS;GACzB,IACE,CAAC,KAAK,SAAS,SAAS,IAAI,IAAI,KAChC,OAAO,OAAO,UAAU,IAAI,KAAK,GAEjC;GAGF,SAAS,IAAI,SAAS;IACpB,SAAS,IAAI;IACb,QAAQ,IAAI;IACZ,WAAW,IAAI;GACjB;EACF;EAEA,OAAO;GAEL,WAAW,sBAAsB,KAAK,aAAa,WAAW,CAAC;GAC/D,UAAU,OAAO,OAAO,QAAQ;EAClC;CACF;CAEA,MAAe,UACb,EAAE,eACF,UACwB;EACxB,MAAM,UAAU,MAAM,KAAK,WAAW,EAAE,YAAY,CAAC;EACrD,IAAI,CAAC,SACH,OAAO;EAGT,IAAI,CAAC,UAIH,OAHa,QAAQ,MAClB,WAAW,OAAO,SAAS,MAAM,OAAO,UAAU,MAE3C,CAAC,EAAE,QAAQ;EAOvB,OAJY,QAAQ,MACjB,WACC,KAAK,SAAS,SAAS,OAAO,IAAI,KAAK,OAAO,UAAU,QAEnD,CAAC,EAAE,QAAQ;CACtB;AACF"}
|
|
@@ -6,10 +6,11 @@ import { safeStringify } from "../../util/stringify.js";
|
|
|
6
6
|
import { logger } from "../../logger/index.js";
|
|
7
7
|
import { clone } from "../../util/clone.js";
|
|
8
8
|
import { buildCacheKey } from "../../util/cache/package/key.js";
|
|
9
|
-
import { trimTrailingSlash } from "../../util/url.js";
|
|
9
|
+
import { trimTrailingSlash, withoutUrlCredentials } from "../../util/url.js";
|
|
10
10
|
import { ATTR_RENOVATE_DATASOURCE, ATTR_RENOVATE_PACKAGE_NAME, ATTR_RENOVATE_REGISTRY_URL } from "../../instrumentation/types.js";
|
|
11
11
|
import { DatasourceCacheStats } from "../../util/stats.js";
|
|
12
12
|
import { instrument } from "../../instrumentation/index.js";
|
|
13
|
+
import { detachUrlCredentials } from "../../util/host-rules.js";
|
|
13
14
|
import { ExternalHostError } from "../../types/errors/external-host-error.js";
|
|
14
15
|
import { filterMap } from "../../util/filter-map.js";
|
|
15
16
|
import { get as get$1 } from "../versioning/index.js";
|
|
@@ -17,9 +18,9 @@ import { get as get$2, set as set$1 } from "../../util/cache/package/index.js";
|
|
|
17
18
|
import { AsyncResult, Result } from "../../util/result.js";
|
|
18
19
|
import { resolveRegistryUrl, setNpmrc } from "./npm/npmrc.js";
|
|
19
20
|
import "./npm/index.js";
|
|
20
|
-
import { addMetaData } from "./metadata.js";
|
|
21
|
+
import { addMetaData, stripMetadataUrlCredentials } from "./metadata.js";
|
|
21
22
|
import api from "./api.js";
|
|
22
|
-
import { applyConstraintsFiltering, applyExtractVersion, applyVersionCompatibility, filterValidVersions, getDatasourceFor, isGetPkgReleasesConfig, sortAndRemoveDuplicates } from "./common.js";
|
|
23
|
+
import { applyConstraintsFiltering, applyExtractVersion, applyVersionCompatibility, filterValidVersions, getDatasourceFor, getDatasourceHostType, isGetPkgReleasesConfig, sortAndRemoveDuplicates } from "./common.js";
|
|
23
24
|
import { isNonEmptyArray, isString, isTruthy } from "@sindresorhus/is";
|
|
24
25
|
import { dequal } from "dequal";
|
|
25
26
|
import { ATTR_CODE_FUNCTION_NAME } from "@opentelemetry/semantic-conventions";
|
|
@@ -93,6 +94,7 @@ async function getRegistryReleases(datasource, config, registryUrl) {
|
|
|
93
94
|
} });
|
|
94
95
|
if (res?.releases.length) res.registryUrl ??= registryUrl;
|
|
95
96
|
if (!res) return null;
|
|
97
|
+
stripMetadataUrlCredentials(res);
|
|
96
98
|
let cache = false;
|
|
97
99
|
if (cacheForced) cache = true;
|
|
98
100
|
else if (cacheEnabled && !res.isPrivate) cache = true;
|
|
@@ -192,8 +194,15 @@ async function mergeRegistries(config, datasource, registryUrls) {
|
|
|
192
194
|
});
|
|
193
195
|
return combinedRes;
|
|
194
196
|
}
|
|
195
|
-
function massageRegistryUrls(registryUrls) {
|
|
196
|
-
|
|
197
|
+
function massageRegistryUrls(datasource, registryUrls) {
|
|
198
|
+
const hostTypes = [getDatasourceHostType(datasource.id)].filter(isTruthy);
|
|
199
|
+
return registryUrls.filter(isTruthy).map((url) => isCustomUrlTemplate(hostTypes, url) ? url : detachUrlCredentials(url, hostTypes)).map(trimTrailingSlash);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Whether `url` requested with `hostTypes` is a URL template of the custom datasource, such as `https://host/{{packageName}}/versions.json`.
|
|
203
|
+
*/
|
|
204
|
+
function isCustomUrlTemplate(hostTypes, url) {
|
|
205
|
+
return hostTypes.includes("custom") && url.includes("{{");
|
|
197
206
|
}
|
|
198
207
|
function resolveRegistryUrls(datasource, packageName, { defaultRegistryUrls, registryUrls, additionalRegistryUrls }) {
|
|
199
208
|
const customRegistrySupport = datasource.supportsCustomRegistry(packageName);
|
|
@@ -201,17 +210,17 @@ function resolveRegistryUrls(datasource, packageName, { defaultRegistryUrls, reg
|
|
|
201
210
|
if (!customRegistrySupport) {
|
|
202
211
|
if (isNonEmptyArray(registryUrls) || isNonEmptyArray(defaultRegistryUrls) || isNonEmptyArray(additionalRegistryUrls)) logger.warn({
|
|
203
212
|
datasource: datasource.id,
|
|
204
|
-
registryUrls,
|
|
205
|
-
defaultRegistryUrls,
|
|
206
|
-
additionalRegistryUrls
|
|
213
|
+
registryUrls: registryUrls?.filter(isTruthy).map(withoutUrlCredentials),
|
|
214
|
+
defaultRegistryUrls: defaultRegistryUrls?.filter(isTruthy).map(withoutUrlCredentials),
|
|
215
|
+
additionalRegistryUrls: additionalRegistryUrls?.filter(isTruthy).map(withoutUrlCredentials)
|
|
207
216
|
}, "Custom registries are not allowed for this datasource and will be ignored");
|
|
208
217
|
return coerceArray(datasourceDefaultRegistryUrls);
|
|
209
218
|
}
|
|
210
219
|
const customUrls = registryUrls?.filter(isTruthy);
|
|
211
|
-
if (isNonEmptyArray(customUrls)) return massageRegistryUrls(customUrls);
|
|
220
|
+
if (isNonEmptyArray(customUrls)) return massageRegistryUrls(datasource, customUrls);
|
|
212
221
|
const defaultUrls = isNonEmptyArray(defaultRegistryUrls) ? defaultRegistryUrls : datasourceDefaultRegistryUrls;
|
|
213
222
|
if (!isNonEmptyArray(defaultUrls)) return [];
|
|
214
|
-
return massageRegistryUrls([...defaultUrls, ...coerceArray(additionalRegistryUrls)]);
|
|
223
|
+
return massageRegistryUrls(datasource, [...defaultUrls, ...coerceArray(additionalRegistryUrls)]);
|
|
215
224
|
}
|
|
216
225
|
function applyReplacements(config) {
|
|
217
226
|
if (config.replacementName && config.replacementVersion) return {
|
|
@@ -262,6 +271,7 @@ async function fetchReleases(config) {
|
|
|
262
271
|
}
|
|
263
272
|
if (!dep || dequal(dep, { releases: [] })) return null;
|
|
264
273
|
addMetaData(dep, datasourceName, config.packageName);
|
|
274
|
+
stripMetadataUrlCredentials(dep);
|
|
265
275
|
dep = {
|
|
266
276
|
...dep,
|
|
267
277
|
...applyReplacements(config)
|