import { logger } from '../../../logger/index.ts'; import { getSiblingFileName, localPathExists, readLocalFile, } from '../../../util/fs/index.ts'; import { regEx } from '../../../util/regex.ts'; import type { UpdateArtifact } from '../types.ts'; export const delimiters = ['"', "'"]; export function extractRubyVersion(txt: string): string | null { const rubyMatch = regEx(/^ruby\s+(?"[^"]+"|'[^']+')\s*$/gm).exec( txt, ); if (!rubyMatch?.groups) { return null; } const quotedVersion = rubyMatch.groups.version; return quotedVersion.substring(1, quotedVersion.length - 1); } export async function getRubyConstraint( updateArtifact: UpdateArtifact, ): Promise { const { packageFileName, config, newPackageFileContent } = updateArtifact; const { constraints = {} } = config; const { ruby } = constraints; if (ruby) { logger.debug('Using ruby constraint from config'); return ruby; } const rubyMatch = extractRubyVersion(newPackageFileContent); if (rubyMatch) { logger.debug('Using ruby version from gemfile'); return rubyMatch; } for (const file of ['.ruby-version', '.tool-versions']) { const rubyVersion = ( await readLocalFile(getSiblingFileName(packageFileName, file), 'utf8') )?.match(regEx(/^(?:ruby(?:-|\s+))?(?\d[\d.]*)/m))?.groups ?.version; if (rubyVersion) { logger.debug(`Using ruby version specified in ${file}`); return rubyVersion; } } const lockFile = await getLockFilePath(packageFileName); if (lockFile) { const rubyVersion = (await readLocalFile(lockFile, 'utf8'))?.match( regEx(/^ {3}ruby (?\d[\d.]*)(?:[a-z]|\s|$)/m), )?.groups?.version; if (rubyVersion) { logger.debug(`Using ruby version specified in lock file`); return rubyVersion; } } return null; } export function getBundlerConstraint( updateArtifact: Pick, existingLockFileContent: string, ): string | null { const { config } = updateArtifact; const { constraints = {} } = config; const { bundler } = constraints; if (bundler) { logger.debug('Using bundler constraint from config'); return bundler; } const bundledWith = regEx(/\nBUNDLED WITH\n\s+(?.*?)(?:\n|$)/).exec( existingLockFileContent, ); if (bundledWith) { logger.debug('Using bundler version specified in lockfile'); return bundledWith.groups!.version; } return null; } export async function getLockFilePath( packageFilePath: string, ): Promise { const lockFilePath = (await localPathExists(`${packageFilePath}.lock`)) ? `${packageFilePath}.lock` : `Gemfile.lock`; logger.debug(`Lockfile for ${packageFilePath} found in ${lockFilePath}`); return lockFilePath; }