import { isNonEmptyString, isString, isUndefined, isUrlString, } from '@sindresorhus/is'; import { regEx } from '../../../util/regex.ts'; import { CrateDatasource } from '../../datasource/crate/index.ts'; import { GitRefsDatasource } from '../../datasource/git-refs/index.ts'; import { GitTagsDatasource } from '../../datasource/git-tags/index.ts'; import { GithubReleasesDatasource } from '../../datasource/github-releases/index.ts'; import { GithubTagsDatasource } from '../../datasource/github-tags/index.ts'; import { GitlabReleasesDatasource } from '../../datasource/gitlab-releases/index.ts'; import { GoDatasource } from '../../datasource/go/index.ts'; import { NpmDatasource } from '../../datasource/npm/index.ts'; import { NugetDatasource } from '../../datasource/nuget/index.ts'; import { normalizePythonDepName } from '../../datasource/pypi/common.ts'; import { PypiDatasource } from '../../datasource/pypi/index.ts'; import { RubygemsDatasource } from '../../datasource/rubygems/index.ts'; import * as semverVersioning from '../../versioning/semver/index.ts'; import type { MiseToolOptions } from './schema.ts'; import type { BackendToolingConfig } from './types.ts'; /** * Create a tooling config for aqua backend * @link https://mise.jdx.dev/dev-tools/backends/aqua.html */ export function createAquaToolConfig( name: string, version: string, ): BackendToolingConfig { // mise supports http aqua package type but we cannot determine it from the tool name // An error will be thrown afterwards if the package type is http // ref: https://github.com/jdx/mise/blob/d1b9749d8f3e13ef705c1ea471d96c5935b79136/src/aqua/aqua_registry.rs#L39-L45 return { packageName: name, datasource: GithubTagsDatasource.id, // Trim the leading 'v' from both the current and extracted version currentValue: version.replace(regEx(/^v/), ''), extractVersion: '^v?(?.+)', }; } const cargoGitVersionRegex = regEx(/^(?tag|branch|rev):(?.+)$/); /** * Create a tooling config for cargo backend * @link https://mise.jdx.dev/dev-tools/backends/cargo.html */ export function createCargoToolConfig( name: string, version: string, ): BackendToolingConfig { if (!isUrlString(name)) { return { packageName: name, datasource: CrateDatasource.id, // A mise tool version is a concrete version, not a Cargo dependency requirement, // so the crate datasource default of cargo versioning does not apply versioning: semverVersioning.id, }; } // tag: branch: or rev: is required for git repository url // e.g. branch:main, tag:0.1.0, rev:abcdef const matchGroups = cargoGitVersionRegex.exec(version)?.groups; if (isUndefined(matchGroups)) { return { packageName: name, skipReason: 'invalid-version', }; } const { type, version: gitVersion } = matchGroups; switch (type as 'tag' | 'branch' | 'rev') { case 'tag': return { packageName: name, datasource: GitTagsDatasource.id, currentValue: gitVersion, }; case 'branch': return { packageName: name, datasource: GitRefsDatasource.id, currentValue: gitVersion, }; case 'rev': return { packageName: name, datasource: GitRefsDatasource.id, currentValue: gitVersion, }; } } /** * Create a tooling config for dotnet backend * @link https://mise.jdx.dev/dev-tools/backends/dotnet.html */ export function createDotnetToolConfig(name: string): BackendToolingConfig { return { packageName: name, datasource: NugetDatasource.id, }; } /** * Create a tooling config for gem backend * @link https://mise.jdx.dev/dev-tools/backends/gem.html */ export function createGemToolConfig(name: string): BackendToolingConfig { return { packageName: name, datasource: RubygemsDatasource.id, }; } /** * Create a tooling config for github backend * @link https://mise.jdx.dev/dev-tools/backends/github.html */ export function createGithubToolConfig( name: string, version: string, toolOptions: MiseToolOptions, ): BackendToolingConfig { let extractVersion: string | undefined = undefined; const prefix = toolOptions.version_prefix; if (isNonEmptyString(prefix)) { extractVersion = `^${RegExp.escape(prefix)}(?.+)`; } return { packageName: name, datasource: GithubReleasesDatasource.id, currentValue: version, ...(extractVersion && { extractVersion }), }; } /** * Create a tooling config for gitlab backend * @link https://mise.jdx.dev/dev-tools/backends/gitlab.html */ export function createGitlabToolConfig( name: string, version: string, toolOptions: MiseToolOptions, ): BackendToolingConfig { let extractVersion: string | undefined = undefined; const prefix = toolOptions.version_prefix; if (isNonEmptyString(prefix)) { extractVersion = `^${RegExp.escape(prefix)}(?.+)`; } return { packageName: name, datasource: GitlabReleasesDatasource.id, currentValue: version, ...(extractVersion && { extractVersion }), }; } /** * Create a tooling config for go backend * @link https://mise.jdx.dev/dev-tools/backends/go.html */ export function createGoToolConfig(name: string): BackendToolingConfig { return { packageName: name, datasource: GoDatasource.id, }; } /** * Create a tooling config for npm backend * @link https://mise.jdx.dev/dev-tools/backends/npm.html */ export function createNpmToolConfig(name: string): BackendToolingConfig { return { packageName: name, datasource: NpmDatasource.id, }; } const pipxGitHubRegex = regEx(/^git\+https:\/\/github\.com\/(?.+)\.git$/); /** * Create a tooling config for pipx backend * @link https://mise.jdx.dev/dev-tools/backends/pipx.html */ export function createPipxToolConfig(name: string): BackendToolingConfig { const isGitSyntax = name.startsWith('git+'); // Does not support zip file url // Avoid type narrowing to prevent type error if (!isGitSyntax && (isUrlString as (value: unknown) => boolean)(name)) { return { packageName: name, skipReason: 'unsupported-url', }; } if (isGitSyntax || name.includes('/')) { let repoName: string | undefined; if (isGitSyntax) { repoName = pipxGitHubRegex.exec(name)?.groups?.repo; // If the url is not a github repo, treat the version as a git ref if (isUndefined(repoName)) { return { packageName: name .replace(regEx(/^git\+/g), '') .replaceAll(regEx(/\.git$/g), ''), datasource: GitRefsDatasource.id, }; } } else { repoName = name; } return { packageName: repoName, datasource: GithubTagsDatasource.id, }; } return { packageName: normalizePythonDepName(name), datasource: PypiDatasource.id, }; } const spmGitHubRegex = regEx(/^https:\/\/github.com\/(?.+).git$/); /** * Create a tooling config for spm backend * @link https://mise.jdx.dev/dev-tools/backends/spm.html */ export function createSpmToolConfig(name: string): BackendToolingConfig { let repoName: string | undefined; // Avoid type narrowing to prevent type error if ((isUrlString as (value: unknown) => boolean)(name)) { repoName = spmGitHubRegex.exec(name)?.groups?.repo; // spm backend only supports github repos if (!repoName) { return { packageName: name, skipReason: 'unsupported-url', }; } } return { packageName: repoName ?? name, datasource: GithubReleasesDatasource.id, }; } /** * Create a tooling config for ubi backend * @link https://mise.jdx.dev/dev-tools/backends/ubi.html */ export function createUbiToolConfig( name: string, version: string, toolOptions: MiseToolOptions, ): BackendToolingConfig { let extractVersion: string | undefined = undefined; const hasVPrefix = version.startsWith('v'); const setsTagRegex = !hasVPrefix || isString(toolOptions.tag_regex); if (setsTagRegex) { // By default, use a regex that matches any tag let tagRegex = '.+'; // Filter versions by tag_regex if it is specified // ref: https://mise.jdx.dev/dev-tools/backends/ubi.html#ubi-uses-weird-versions if (isString(toolOptions.tag_regex)) { // Remove the leading '^' if it exists to avoid duplication tagRegex = toolOptions.tag_regex.replace(regEx(/^\^/), ''); if (!hasVPrefix) { // Remove the leading 'v?' if it exists to avoid duplication tagRegex = tagRegex.replace(regEx(/^v\??/), ''); } } // Trim the 'v' prefix if the current version does not have it extractVersion = `^${hasVPrefix ? '' : 'v?'}(?${tagRegex})`; } return { packageName: name, datasource: GithubReleasesDatasource.id, currentValue: version, ...(isString(extractVersion) ? { extractVersion } : {}), }; }