UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

281 lines (280 loc) • 10.4 kB
import { getEnv } from "../../../util/env.js"; import { logger } from "../../../logger/index.js"; import { coerceArray } from "../../../util/array.js"; import { LooseArray, LooseRecord, Toml, withDepType } from "../../../util/schema-utils/index.js"; import { id, isValid } from "../../versioning/pep440/index.js"; import "../../versioning/git/index.js"; import { id as id$1, isValid as isValid$1 } from "../../versioning/poetry/index.js"; import { parseGitUrl } from "../../../util/git/url.js"; import { uniq } from "../../../util/uniq.js"; import { GitRefsDatasource } from "../../datasource/git-refs/index.js"; import { GitTagsDatasource } from "../../datasource/git-tags/index.js"; import { GithubTagsDatasource } from "../../datasource/github-tags/index.js"; import { GitlabTagsDatasource } from "../../datasource/gitlab-tags/index.js"; import { normalizePythonDepName } from "../../datasource/pypi/common.js"; import { PypiDatasource } from "../../datasource/pypi/index.js"; import { depTypes, pep508ToPackageDependency } from "../pep621/utils.js"; import { DependencyGroup, ProjectSection } from "../pep621/schema.js"; import { z } from "zod/v4"; import merge from "deepmerge"; //#region lib/modules/manager/poetry/schema.ts const PoetryOptionalDependencyMixin = z.object({ optional: z.boolean().optional().catch(false) }).transform(({ optional }) => optional ? { depType: "extras" } : {}); const PoetryPathDependency = z.object({ path: z.string(), version: z.string().optional().catch(void 0) }).transform(({ version }) => { const dep = { datasource: PypiDatasource.id, skipReason: "path-dependency" }; if (version) dep.currentValue = version; return dep; }).and(PoetryOptionalDependencyMixin); const PoetryGitDependency = z.object({ git: z.string(), tag: z.string().optional().catch(void 0), version: z.string().optional().catch(void 0), branch: z.string().optional().catch(void 0), rev: z.string().optional().catch(void 0) }).transform(({ git, tag, version, branch, rev }) => { if (tag) { const { source, owner, name } = parseGitUrl(git); const repo = `${owner}/${name}`; if (source === "github.com") return { datasource: GithubTagsDatasource.id, currentValue: tag, packageName: repo }; else if (source === "gitlab.com") return { datasource: GitlabTagsDatasource.id, currentValue: tag, packageName: repo }; else return { datasource: GitTagsDatasource.id, currentValue: tag, packageName: git }; } if (rev) return { datasource: GitRefsDatasource.id, currentValue: branch, currentDigest: rev, replaceString: rev, packageName: git }; return { datasource: GitRefsDatasource.id, currentValue: version, packageName: git, skipReason: "git-dependency" }; }).and(PoetryOptionalDependencyMixin); const PoetryPypiDependency = z.union([z.object({ version: z.string().optional(), source: z.string().optional() }).transform(({ version: currentValue, source }) => { const managerData = source ? { sourceName: source.toLowerCase() } : {}; if (!currentValue) return { datasource: PypiDatasource.id, managerData }; return { datasource: PypiDatasource.id, managerData: { ...managerData, nestedVersion: true }, currentValue }; }).and(PoetryOptionalDependencyMixin), z.string().transform((version) => ({ datasource: PypiDatasource.id, currentValue: version, managerData: { nestedVersion: false } }))]); const PoetryArrayDependency = z.array(z.unknown()).transform(() => ({ datasource: PypiDatasource.id, skipReason: "multiple-constraint-dep" })); const PoetryDependency = z.union([ PoetryPathDependency, PoetryGitDependency, PoetryPypiDependency, PoetryArrayDependency ]); const PoetryDependencies = LooseRecord(z.string(), PoetryDependency.transform((dep) => { if (dep.skipReason) return dep; if (dep.datasource === GitRefsDatasource.id && dep.currentDigest) { dep.versioning = "git"; return dep; } // istanbul ignore if: normaly should not happen if (!dep.currentValue) { dep.skipReason = "unspecified-version"; return dep; } if (isValid(dep.currentValue)) { dep.versioning = id; return dep; } if (isValid$1(dep.currentValue)) { dep.versioning = id$1; return dep; } dep.skipReason = "invalid-version"; return dep; })).transform((record) => { const deps = []; for (const [depName, dep] of Object.entries(record)) { dep.depName = depName; if (!dep.packageName) { const packageName = normalizePythonDepName(depName); if (depName !== packageName) dep.packageName = packageName; } deps.push(dep); } return deps; }); const PoetryGroupDependencies = LooseRecord(z.string(), z.object({ dependencies: PoetryDependencies }).transform(({ dependencies }) => dependencies)).transform((record) => { const deps = []; for (const [name, val] of Object.entries(record)) for (const dep of Object.values(val)) { dep.depType = name; deps.push(dep); } return deps; }); const PoetrySourceOrder = [ "default", "primary", "secondary", "supplemental", "explicit" ]; const PoetrySources = LooseArray(z.object({ name: z.string().toLowerCase(), url: z.string().optional(), priority: z.enum(PoetrySourceOrder).default("primary") }), { onError: ({ error: err }) => { logger.debug({ err }, "Poetry: error parsing sources array"); } }).transform((sources) => { const pypiUrl = getEnv().PIP_INDEX_URL ?? "https://pypi.org/pypi/"; const result = []; let overridesPyPi = false; let hasDefaultSource = false; let hasPrimarySource = false; for (const source of sources) { if (source.name === "pypi") { source.url = pypiUrl; overridesPyPi = true; } if (!source.url) continue; if (source.priority === "default") hasDefaultSource = true; else if (source.priority === "primary") hasPrimarySource = true; result.push(source); } if (sources.length && !hasDefaultSource && !overridesPyPi) result.push({ name: "pypi", priority: hasPrimarySource ? "secondary" : "default", url: pypiUrl }); result.sort((a, b) => PoetrySourceOrder.indexOf(a.priority) - PoetrySourceOrder.indexOf(b.priority)); return result; }).catch([]); const PoetrySection = z.object({ version: z.string().optional().catch(void 0), dependencies: withDepType(PoetryDependencies, "dependencies", false).optional(), "dev-dependencies": withDepType(PoetryDependencies, "dev-dependencies").optional(), group: PoetryGroupDependencies.optional(), source: PoetrySources }); const BuildSystemRequires = LooseArray(z.string().nonempty().transform((val) => pep508ToPackageDependency(depTypes.buildSystemRequires, val)).refine((dep) => dep !== null)).catch([]); const PoetryPyProject = Toml.pipe(z.object({ project: ProjectSection.optional().catch(void 0), tool: z.object({ poetry: PoetrySection }).optional().catch(void 0), "dependency-groups": DependencyGroup(depTypes.dependencyGroups).catch([]), "build-system": z.object({ "build-backend": z.string().refine((buildBackend) => buildBackend === "poetry.masonry.api" || buildBackend === "poetry.core.masonry.api"), requires: BuildSystemRequires }).transform(({ requires }) => { return { poetryRequirement: requires.find(({ depName }) => depName === "poetry" || depName === "poetry_core" || depName === "poetry-core")?.currentValue, requires }; }).optional().catch(void 0) }).transform((pyproject) => { const { project, tool, "build-system": buildSystem, "dependency-groups": dependencyGroups } = pyproject; const deps = []; const projectDependencies = coerceArray(project?.dependencies); const projectOptionalDependencies = coerceArray(project?.["optional-dependencies"]); const projectDepsByName = {}; for (const dep of [ ...projectDependencies, ...dependencyGroups, ...projectOptionalDependencies ]) projectDepsByName[dep.depName] = dep; if (buildSystem?.requires) deps.push(...buildSystem.requires); const poetryDependencies = coerceArray(tool?.poetry?.dependencies); const poetryDevDependencies = coerceArray(tool?.poetry?.["dev-dependencies"]); const poetryGroupDependencies = coerceArray(tool?.poetry?.group); for (const poetryDep of [ ...poetryDependencies, ...poetryDevDependencies, ...poetryGroupDependencies ]) { const depName = poetryDep.depName; const projectDep = depName && projectDepsByName[depName]; if (projectDep) { const mergedDep = merge(poetryDep, projectDep); if (projectDep.currentValue && poetryDep.currentValue) mergedDep.skipReason = "invalid-dependency-specification"; if (mergedDep.skipReason === "unspecified-version") if (poetryDep.skipReason === "unspecified-version") mergedDep.skipReason = projectDep.skipReason; else mergedDep.skipReason = poetryDep.skipReason; projectDepsByName[depName] = mergedDep; } else deps.push(poetryDep); } deps.push(...Object.values(projectDepsByName)); const packageFileContent = { deps, packageFileVersion: tool?.poetry?.version }; const sourceUrls = tool?.poetry?.source; if (sourceUrls) { for (const dep of deps) if (dep.managerData?.sourceName) { const sourceUrl = sourceUrls.find(({ name }) => name === dep.managerData?.sourceName); if (sourceUrl?.url) dep.registryUrls = [sourceUrl.url]; } const sourceUrlsFiltered = sourceUrls.filter(({ priority }) => priority !== "explicit"); if (sourceUrlsFiltered.length) packageFileContent.registryUrls = uniq(sourceUrlsFiltered.map(({ url }) => url)); } return { packageFileContent, poetryRequirement: buildSystem?.poetryRequirement }; })); const poetryConstraint = { "1.0": "<1.1.0", "1.1": "<1.3.0", "2.0": ">=1.3.0 <1.4.0" }; const Lockfile = Toml.pipe(z.object({ package: LooseArray(z.object({ name: z.string(), version: z.string() }).transform(({ name, version }) => [name, version])).transform((entries) => Object.fromEntries(entries)).catch({}), metadata: z.object({ "lock-version": z.string().transform((lockVersion) => poetryConstraint[lockVersion]).optional().catch(void 0), "python-versions": z.string().optional().catch(void 0) }).transform(({ "lock-version": poetryConstraint, "python-versions": pythonVersions }) => ({ poetryConstraint, pythonVersions })).catch({ poetryConstraint: void 0, pythonVersions: void 0 }) })).transform(({ package: lock, metadata: { poetryConstraint, pythonVersions } }) => ({ lock, poetryConstraint, pythonVersions })); //#endregion export { Lockfile, PoetryPyProject }; //# sourceMappingURL=schema.js.map