import chalk from 'chalk'; import { readFile, writeFile } from 'fs-extra'; import * as path from 'path'; import terminalLink from 'terminal-link'; import { EXPO_DIR } from '../Constants'; import logger from '../Logger'; import { AndroidProjectDependenciesUpdates } from './types'; import { addColorBasedOnSemverDiff, calculateSemverDiff } from './utils'; function replaceVersionInGradleFile( body: string, { oldVersion, newVersion, fullName, group, name, }: { oldVersion: string; newVersion: string; fullName: string; name: string; group: string; } ): string { let modifiedBody = body; const regexVersionVariable = new RegExp(`${fullName}:\\\${?(\\w+)}?`, 'ig'); // 'de.kevcodez:pubg-api-wrapper:$myVar' // 'de.kevcodez:pubg-api-wrapper:${myVar}' const versionWithVariableMatches = regexVersionVariable.exec(modifiedBody); if (versionWithVariableMatches?.length === 2) { const variableName = versionWithVariableMatches[1]; const regexVariableDefinition = new RegExp( `(${variableName}(\\s+)?=(\\s+)?('|")${oldVersion}('|"))`, 'ig' ); regexVariableDefinition .exec(modifiedBody) ?.filter((it) => it.includes(oldVersion)) .forEach((match) => { modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion)); }); // val PUBG_API_WRAPPER by extra("0.8.1") // eslint-disable-next-line no-useless-escape const regexKotlinValExtra = new RegExp(`${variableName}.+\(("|')${oldVersion}("|')\)`); regexKotlinValExtra .exec(modifiedBody) ?.filter((it) => it.includes(oldVersion)) .forEach((match) => { modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion)); }); } // compile 'de.kevcodez:pubg-api-wrapper:1.0.0' const regexVersionInline = new RegExp(`${fullName}:${oldVersion}`, 'g'); regexVersionInline .exec(modifiedBody) ?.filter((it) => it.includes(`${fullName}:${oldVersion}`)) .forEach((match) => { modifiedBody = modifiedBody.replace(match, `${fullName}:${newVersion}`); }); // id 'com.github.ben-manes.versions' version "0.21.0" // id("com.github.ben-manes.versions") version "0.22.0" const regexPluginVersionWithPrefix = new RegExp( `${group}("|')\\)?(\\s+)?version(\\s+)?("|')${oldVersion}("|')` ); regexPluginVersionWithPrefix .exec(modifiedBody) ?.filter((it) => it.includes(oldVersion)) // filter out all groups not containing version .forEach((match) => { modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion)); }); // compile group: 'de.kevcodez.pubg', name: 'pubg-api-wrapper', version: '0.8.1' const regexDependencyWithVersionPrefix = new RegExp( `${name}('|"),(\\s+)?version:(\\s+)('|")${oldVersion}('|")` ); regexDependencyWithVersionPrefix .exec(modifiedBody) ?.filter((it) => it.includes(oldVersion)) .forEach((match) => { modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion)); }); return modifiedBody; } async function readGradleFiles( updates: AndroidProjectDependenciesUpdates[] ): Promise> { const buildFiles = ( await Promise.all( updates.map(async ({ report: { gradleFilePath } }) => [ gradleFilePath, await readFile(gradleFilePath, 'utf-8'), ]) ) ).reduce>((acc, [filePath, content]) => { acc[filePath] = content; return acc; }, {}); return buildFiles; } async function writeGradleFiles(gradleFiles: Record) { await Promise.all( Object.entries(gradleFiles).map( async ([filePath, content]) => await writeFile(filePath, content) ) ); } export async function updateGradleDependencies( updatesList: AndroidProjectDependenciesUpdates[] ): Promise { logger.log(chalk.white.bold(`\nUpdating gradle files.`)); const buildFiles = await readGradleFiles(updatesList); for (const updates of updatesList) { if (updates.updates.length === 0) { continue; } logger.log( `\n📈 Updating %s native dependencies in file: %s`, chalk.blue(updates.report.projectName), terminalLink( chalk.italic.grey(path.relative(EXPO_DIR, updates.report.gradleFilePath)), updates.report.gradleFilePath ) ); let buildFile = buildFiles[updates.report.gradleFilePath]; for (const singleUpdate of updates.updates) { logger.log( ` ▶︎ ${chalk.blueBright(singleUpdate.fullName)}:${ singleUpdate.oldVersion } ➡️ ${addColorBasedOnSemverDiff( singleUpdate.newVersion, calculateSemverDiff(singleUpdate.oldVersion, singleUpdate.newVersion) )}` ); buildFile = replaceVersionInGradleFile(buildFile, singleUpdate); } buildFiles[updates.report.gradleFilePath] = buildFile; } await writeGradleFiles(buildFiles); }