1*53c12298Saleqsioimport chalk from 'chalk';
2*53c12298Saleqsioimport { readFile, writeFile } from 'fs-extra';
3*53c12298Saleqsioimport * as path from 'path';
4*53c12298Saleqsioimport terminalLink from 'terminal-link';
5*53c12298Saleqsio
6*53c12298Saleqsioimport { EXPO_DIR } from '../Constants';
7*53c12298Saleqsioimport logger from '../Logger';
8*53c12298Saleqsioimport { AndroidProjectDependenciesUpdates } from './types';
9*53c12298Saleqsioimport { addColorBasedOnSemverDiff, calculateSemverDiff } from './utils';
10*53c12298Saleqsio
11*53c12298Saleqsiofunction replaceVersionInGradleFile(
12*53c12298Saleqsio  body: string,
13*53c12298Saleqsio  {
14*53c12298Saleqsio    oldVersion,
15*53c12298Saleqsio    newVersion,
16*53c12298Saleqsio    fullName,
17*53c12298Saleqsio    group,
18*53c12298Saleqsio    name,
19*53c12298Saleqsio  }: {
20*53c12298Saleqsio    oldVersion: string;
21*53c12298Saleqsio    newVersion: string;
22*53c12298Saleqsio    fullName: string;
23*53c12298Saleqsio    name: string;
24*53c12298Saleqsio    group: string;
25*53c12298Saleqsio  }
26*53c12298Saleqsio): string {
27*53c12298Saleqsio  let modifiedBody = body;
28*53c12298Saleqsio
29*53c12298Saleqsio  const regexVersionVariable = new RegExp(`${fullName}:\\\${?(\\w+)}?`, 'ig');
30*53c12298Saleqsio
31*53c12298Saleqsio  // 'de.kevcodez:pubg-api-wrapper:$myVar'
32*53c12298Saleqsio  // 'de.kevcodez:pubg-api-wrapper:${myVar}'
33*53c12298Saleqsio  const versionWithVariableMatches = regexVersionVariable.exec(modifiedBody);
34*53c12298Saleqsio  if (versionWithVariableMatches?.length === 2) {
35*53c12298Saleqsio    const variableName = versionWithVariableMatches[1];
36*53c12298Saleqsio
37*53c12298Saleqsio    const regexVariableDefinition = new RegExp(
38*53c12298Saleqsio      `(${variableName}(\\s+)?=(\\s+)?('|")${oldVersion}('|"))`,
39*53c12298Saleqsio      'ig'
40*53c12298Saleqsio    );
41*53c12298Saleqsio
42*53c12298Saleqsio    regexVariableDefinition
43*53c12298Saleqsio      .exec(modifiedBody)
44*53c12298Saleqsio      ?.filter((it) => it.includes(oldVersion))
45*53c12298Saleqsio      .forEach((match) => {
46*53c12298Saleqsio        modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion));
47*53c12298Saleqsio      });
48*53c12298Saleqsio
49*53c12298Saleqsio    // val PUBG_API_WRAPPER by extra("0.8.1")
50*53c12298Saleqsio    // eslint-disable-next-line no-useless-escape
51*53c12298Saleqsio    const regexKotlinValExtra = new RegExp(`${variableName}.+\(("|')${oldVersion}("|')\)`);
52*53c12298Saleqsio    regexKotlinValExtra
53*53c12298Saleqsio      .exec(modifiedBody)
54*53c12298Saleqsio      ?.filter((it) => it.includes(oldVersion))
55*53c12298Saleqsio      .forEach((match) => {
56*53c12298Saleqsio        modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion));
57*53c12298Saleqsio      });
58*53c12298Saleqsio  }
59*53c12298Saleqsio
60*53c12298Saleqsio  // compile 'de.kevcodez:pubg-api-wrapper:1.0.0'
61*53c12298Saleqsio  const regexVersionInline = new RegExp(`${fullName}:${oldVersion}`, 'g');
62*53c12298Saleqsio  regexVersionInline
63*53c12298Saleqsio    .exec(modifiedBody)
64*53c12298Saleqsio    ?.filter((it) => it.includes(`${fullName}:${oldVersion}`))
65*53c12298Saleqsio    .forEach((match) => {
66*53c12298Saleqsio      modifiedBody = modifiedBody.replace(match, `${fullName}:${newVersion}`);
67*53c12298Saleqsio    });
68*53c12298Saleqsio
69*53c12298Saleqsio  // id 'com.github.ben-manes.versions' version "0.21.0"
70*53c12298Saleqsio  // id("com.github.ben-manes.versions") version "0.22.0"
71*53c12298Saleqsio  const regexPluginVersionWithPrefix = new RegExp(
72*53c12298Saleqsio    `${group}("|')\\)?(\\s+)?version(\\s+)?("|')${oldVersion}("|')`
73*53c12298Saleqsio  );
74*53c12298Saleqsio  regexPluginVersionWithPrefix
75*53c12298Saleqsio    .exec(modifiedBody)
76*53c12298Saleqsio    ?.filter((it) => it.includes(oldVersion)) // filter out all groups not containing version
77*53c12298Saleqsio    .forEach((match) => {
78*53c12298Saleqsio      modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion));
79*53c12298Saleqsio    });
80*53c12298Saleqsio
81*53c12298Saleqsio  // compile group: 'de.kevcodez.pubg', name: 'pubg-api-wrapper', version: '0.8.1'
82*53c12298Saleqsio  const regexDependencyWithVersionPrefix = new RegExp(
83*53c12298Saleqsio    `${name}('|"),(\\s+)?version:(\\s+)('|")${oldVersion}('|")`
84*53c12298Saleqsio  );
85*53c12298Saleqsio  regexDependencyWithVersionPrefix
86*53c12298Saleqsio    .exec(modifiedBody)
87*53c12298Saleqsio    ?.filter((it) => it.includes(oldVersion))
88*53c12298Saleqsio    .forEach((match) => {
89*53c12298Saleqsio      modifiedBody = modifiedBody.replace(match, match.replace(oldVersion, newVersion));
90*53c12298Saleqsio    });
91*53c12298Saleqsio
92*53c12298Saleqsio  return modifiedBody;
93*53c12298Saleqsio}
94*53c12298Saleqsio
95*53c12298Saleqsioasync function readGradleFiles(
96*53c12298Saleqsio  updates: AndroidProjectDependenciesUpdates[]
97*53c12298Saleqsio): Promise<Record<string, string>> {
98*53c12298Saleqsio  const buildFiles = (
99*53c12298Saleqsio    await Promise.all(
100*53c12298Saleqsio      updates.map(async ({ report: { gradleFilePath } }) => [
101*53c12298Saleqsio        gradleFilePath,
102*53c12298Saleqsio        await readFile(gradleFilePath, 'utf-8'),
103*53c12298Saleqsio      ])
104*53c12298Saleqsio    )
105*53c12298Saleqsio  ).reduce<Record<string, string>>((acc, [filePath, content]) => {
106*53c12298Saleqsio    acc[filePath] = content;
107*53c12298Saleqsio    return acc;
108*53c12298Saleqsio  }, {});
109*53c12298Saleqsio
110*53c12298Saleqsio  return buildFiles;
111*53c12298Saleqsio}
112*53c12298Saleqsio
113*53c12298Saleqsioasync function writeGradleFiles(gradleFiles: Record<string, string>) {
114*53c12298Saleqsio  await Promise.all(
115*53c12298Saleqsio    Object.entries(gradleFiles).map(
116*53c12298Saleqsio      async ([filePath, content]) => await writeFile(filePath, content)
117*53c12298Saleqsio    )
118*53c12298Saleqsio  );
119*53c12298Saleqsio}
120*53c12298Saleqsio
121*53c12298Saleqsioexport async function updateGradleDependencies(
122*53c12298Saleqsio  updatesList: AndroidProjectDependenciesUpdates[]
123*53c12298Saleqsio): Promise<void> {
124*53c12298Saleqsio  logger.log(chalk.white.bold(`\nUpdating gradle files.`));
125*53c12298Saleqsio  const buildFiles = await readGradleFiles(updatesList);
126*53c12298Saleqsio  for (const updates of updatesList) {
127*53c12298Saleqsio    if (updates.updates.length === 0) {
128*53c12298Saleqsio      continue;
129*53c12298Saleqsio    }
130*53c12298Saleqsio
131*53c12298Saleqsio    logger.log(
132*53c12298Saleqsio      `\n�� Updating %s native dependencies in file: %s`,
133*53c12298Saleqsio      chalk.blue(updates.report.projectName),
134*53c12298Saleqsio      terminalLink(
135*53c12298Saleqsio        chalk.italic.grey(path.relative(EXPO_DIR, updates.report.gradleFilePath)),
136*53c12298Saleqsio        updates.report.gradleFilePath
137*53c12298Saleqsio      )
138*53c12298Saleqsio    );
139*53c12298Saleqsio
140*53c12298Saleqsio    let buildFile = buildFiles[updates.report.gradleFilePath];
141*53c12298Saleqsio    for (const singleUpdate of updates.updates) {
142*53c12298Saleqsio      logger.log(
143*53c12298Saleqsio        `  ▶︎ ${chalk.blueBright(singleUpdate.fullName)}:${
144*53c12298Saleqsio          singleUpdate.oldVersion
145*53c12298Saleqsio        } ➡️  ${addColorBasedOnSemverDiff(
146*53c12298Saleqsio          singleUpdate.newVersion,
147*53c12298Saleqsio          calculateSemverDiff(singleUpdate.oldVersion, singleUpdate.newVersion)
148*53c12298Saleqsio        )}`
149*53c12298Saleqsio      );
150*53c12298Saleqsio      buildFile = replaceVersionInGradleFile(buildFile, singleUpdate);
151*53c12298Saleqsio    }
152*53c12298Saleqsio    buildFiles[updates.report.gradleFilePath] = buildFile;
153*53c12298Saleqsio  }
154*53c12298Saleqsio
155*53c12298Saleqsio  await writeGradleFiles(buildFiles);
156*53c12298Saleqsio}
157