Skip to content

Commit

Permalink
fix(android): bump Gradle wrapper version for 0.75 (#2124)
Browse files Browse the repository at this point in the history
  • Loading branch information
tido64 committed Jul 16, 2024
1 parent 33af66a commit cf8cb54
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 262 deletions.
96 changes: 96 additions & 0 deletions android/gradle-wrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// @ts-check
"use strict";

/**
* This script (and its dependencies) currently cannot be converted to ESM
* because it is consumed in `react-native.config.js`.
*/
const nodefs = require("node:fs");
const path = require("node:path");
const tty = require("node:tty");
const {
getPackageVersion,
readTextFile,
toVersionNumber,
v,
} = require("../scripts/helpers");

/**
* Configures Gradle wrapper as necessary before the Android app is built.
* @param {string} sourceDir
*/
function configureGradleWrapper(sourceDir, fs = nodefs) {
const androidCommands = ["build-android", "run-android"];
if (
process.env["RNTA_CONFIGURE_GRADLE_WRAPPER"] === "0" ||
!process.argv.some((arg) => androidCommands.includes(arg))
) {
return;
}

const gradleWrapperProperties = path.join(
sourceDir,
"gradle",
"wrapper",
"gradle-wrapper.properties"
);
if (!fs.existsSync(gradleWrapperProperties)) {
return;
}

const tag = tty.WriteStream.prototype.hasColors()
? "\u001B[33m\u001B[1mwarn\u001B[22m\u001B[39m"
: "warn";

try {
const props = readTextFile(gradleWrapperProperties, fs);
const re = /gradle-([.0-9]*?)-.*?\.zip/;
const m = props.match(re);
if (!m) {
return;
}

const gradleVersion = (() => {
const gradleVersion = toVersionNumber(m[1]);
const version = toVersionNumber(
getPackageVersion("react-native", sourceDir, fs)
);
if (version === 0 || version >= v(0, 76, 0)) {
if (gradleVersion < v(8, 9, 0)) {
return "8.9";
}
} else if (version >= v(0, 75, 0)) {
if (gradleVersion < v(8, 8, 0)) {
return "8.8";
}
} else if (version >= v(0, 74, 0)) {
if (gradleVersion < v(8, 6, 0)) {
return "8.6";
}
} else if (version >= v(0, 73, 0)) {
if (gradleVersion < v(8, 3, 0)) {
return "8.3";
}
} else if (version >= v(0, 72, 0)) {
if (gradleVersion < v(8, 1, 1)) {
return "8.1.1";
}
} else if (gradleVersion < v(7, 5, 1) || gradleVersion >= v(8, 0, 0)) {
return "7.6.4";
}
return undefined;
})();

if (gradleVersion) {
console.warn(tag, `Setting Gradle version ${gradleVersion}`);
fs.writeFileSync(
gradleWrapperProperties,
props.replace(re, `gradle-${gradleVersion}-bin.zip`)
);
}
} catch (_) {
console.warn(tag, "Failed to determine Gradle version");
}
}

exports.configureGradleWrapper = configureGradleWrapper;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"android/app/src",
"!android/app/src/test",
"android/autolink.mjs",
"android/gradle-wrapper.js",
"android/support/src",
"common",
"example/_gitignore",
Expand Down
73 changes: 1 addition & 72 deletions scripts/configure-projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
*/
const nodefs = require("node:fs");
const path = require("node:path");
const tty = require("node:tty");
const { generateAndroidManifest } = require("../android/android-manifest");
const { configureGradleWrapper } = require("../android/gradle-wrapper");
const {
findFile,
findNearest,
Expand Down Expand Up @@ -52,76 +52,6 @@ function cliPlatformIOSVersion() {
return getRNPackageVersion("@react-native-community/cli-platform-ios");
}

/**
* Configures Gradle wrapper as necessary before the Android app is built.
* @param {string} sourceDir
*/
function configureGradleWrapper(sourceDir, fs = nodefs) {
const androidCommands = ["build-android", "run-android"];
if (
process.env["RNTA_CONFIGURE_GRADLE_WRAPPER"] === "0" ||
!process.argv.some((arg) => androidCommands.includes(arg))
) {
return;
}

const gradleWrapperProperties = path.join(
sourceDir,
"gradle",
"wrapper",
"gradle-wrapper.properties"
);
if (!fs.existsSync(gradleWrapperProperties)) {
return;
}

const tag = tty.WriteStream.prototype.hasColors()
? "\u001B[33m\u001B[1mwarn\u001B[22m\u001B[39m"
: "warn";

try {
const props = readTextFile(gradleWrapperProperties, fs);
const re = /gradle-([.0-9]*?)-.*?\.zip/;
const m = props.match(re);
if (!m) {
return;
}

const gradleVersion = (() => {
const gradleVersion = toVersionNumber(m[1]);
const version = toVersionNumber(
getPackageVersion("react-native", sourceDir, fs)
);
if (version === 0 || version >= v(0, 74, 0)) {
if (gradleVersion < v(8, 6, 0)) {
return "8.6";
}
} else if (version >= v(0, 73, 0)) {
if (gradleVersion < v(8, 3, 0)) {
return "8.3";
}
} else if (version >= v(0, 72, 0)) {
if (gradleVersion < v(8, 1, 1)) {
return "8.1.1";
}
} else if (gradleVersion < v(7, 5, 1) || gradleVersion >= v(8, 0, 0)) {
return "7.6.4";
}
return undefined;
})();

if (gradleVersion) {
console.warn(tag, `Setting Gradle version ${gradleVersion}`);
fs.writeFileSync(
gradleWrapperProperties,
props.replace(re, `gradle-${gradleVersion}-bin.zip`)
);
}
} catch (_) {
console.warn(tag, "Failed to determine Gradle version");
}
}

/**
* @param {string | undefined} manifestPath
* @returns {string | undefined}
Expand Down Expand Up @@ -251,6 +181,5 @@ function configureProjects({ android, ios, windows }, fs = nodefs) {
exports.cliPlatformIOSVersion = cliPlatformIOSVersion;
exports.configureProjects = configureProjects;
exports.internalForTestingPurposesOnly = {
configureGradleWrapper,
getAndroidPackageName,
};
189 changes: 189 additions & 0 deletions test/android/gradle-wrapper.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { doesNotThrow, equal, fail, throws } from "node:assert/strict";
import * as nodefs from "node:fs";
import { afterEach, describe, it } from "node:test";
import { configureGradleWrapper } from "../../android/gradle-wrapper.js";

describe("configureGradleWrapper()", () => {
const args = process.argv;

afterEach(() => {
process.argv = args.slice();
delete process.env["RNTA_CONFIGURE_GRADLE_WRAPPER"];
});

it("only runs when targeting Android (unless disabled)", () => {
/** @type {typeof nodefs} */
const returnEarly = {
...nodefs,
existsSync: () => {
fail("Expected to return early");
},
readFileSync: () => {
fail("Expected to return early");
},
writeFileSync: () => {
fail("Expected to return early");
},
};

doesNotThrow(() => configureGradleWrapper("android", returnEarly));

process.argv.push("run-android");

throws(() => configureGradleWrapper("android", returnEarly));

process.argv[process.argv.length - 1] = "build-android";

throws(() => configureGradleWrapper("android", returnEarly));

process.env["RNTA_CONFIGURE_GRADLE_WRAPPER"] = "0";

doesNotThrow(() => configureGradleWrapper("android", returnEarly));
});

it("returns early if Gradle wrapper cannot be found", () => {
/** @type {typeof nodefs} */
const mockfs = {
...nodefs,
existsSync: () => false,
readFileSync: () => {
fail("Expected to return early");
},
writeFileSync: () => {
fail("Expected to return early");
},
};

process.argv.push("run-android");

doesNotThrow(() => configureGradleWrapper("android", mockfs));
});

it("returns early if Gradle wrapper cannot be read", () => {
/** @type {typeof nodefs} */
const mockfs = {
...nodefs,
existsSync: () => true,
readFileSync: () => {
fail("Expected to return early");
},
writeFileSync: () => {
/* noop */
},
};

process.argv.push("run-android");

doesNotThrow(() => configureGradleWrapper("android", mockfs));
});

it("returns early if Gradle wrapper cannot be determined", () => {
let written = "";
/** @type {typeof nodefs} */
const mockfs = {
...nodefs,
existsSync: () => true,
// @ts-expect-error Type 'string' is not assignable to type 'Buffer'
readFileSync: (p) => {
if (p.toString().endsWith("gradle-wrapper.properties")) {
return "";
}

fail(`Unexpected file read: ${p}`);
},
writeFileSync: (_, data) => {
// @ts-expect-error Type 'Uint8Array' is not assignable to type 'string'
written = data;
},
};

process.argv.push("run-android");

doesNotThrow(() => configureGradleWrapper("android", mockfs));
equal(written, "");
});

it("writes if Gradle version is too old", () => {
let written = "";
/** @type {(gradleVersion: string, rnVersion: string) => typeof nodefs} */
const mockfs = (gradleVersion, rnVersion) => ({
...nodefs,
existsSync: () => true,
// @ts-expect-error Type 'string' is not assignable to type 'Buffer'
readFileSync: (p) => {
if (p.toString().endsWith("gradle-wrapper.properties")) {
return `gradle-${gradleVersion}-bin.zip`;
} else if (p.toString().endsWith("package.json")) {
return JSON.stringify({ name: "react-native", version: rnVersion });
}

fail(`Unexpected file read: ${p}`);
},
writeFileSync: (_, data) => {
// @ts-expect-error Type 'Uint8Array' is not assignable to type 'string'
written = data;
},
});

process.argv.push("run-android");

const cases = [
["8.8", "0.76.0", "gradle-8.9-bin.zip"],
["8.7", "0.75.0", "gradle-8.8-bin.zip"],
["8.5", "0.74.0", "gradle-8.6-bin.zip"],
["8.2.1", "0.73.0", "gradle-8.3-bin.zip"],
["8.1", "0.72.0", "gradle-8.1.1-bin.zip"],
["8.0", "0.71.0", "gradle-7.6.4-bin.zip"],
["7.5", "0.71.0", "gradle-7.6.4-bin.zip"],
];
for (const [gradleVersion, rnVersion, expected] of cases) {
written = "";
const fs = mockfs(gradleVersion, rnVersion);
doesNotThrow(() => configureGradleWrapper("android", fs));
equal(written, expected);
}
});

it("skips writing if Gradle version is recent enough", () => {
let written = "";
/** @type {(gradleVersion: string, rnVersion: string) => typeof nodefs} */
const mockfs = (gradleVersion, rnVersion) => ({
...nodefs,
existsSync: () => true,
// @ts-expect-error Type 'string' is not assignable to type 'Buffer'
readFileSync: (p) => {
if (p.toString().endsWith("gradle-wrapper.properties")) {
return `gradle-${gradleVersion}-bin.zip`;
} else if (p.toString().endsWith("package.json")) {
return JSON.stringify({ name: "react-native", version: rnVersion });
}

fail(`Unexpected file read: ${p}`);
},
writeFileSync: (_, data) => {
// @ts-expect-error Type 'Uint8Array' is not assignable to type 'string'
written = data;
},
});

process.argv.push("run-android");

const cases = [
["8.9", "0.76.0"],
["8.9", "0.75.0"],
["8.7", "0.74.0"],
["8.7", "0.73.0"],
["8.7", "0.72.0"],
["8.6", "0.74.0"],
["8.3", "0.73.0"],
["8.1.1", "0.72.0"],
["7.6.4", "0.71.0"],
["7.5.1", "0.71.0"],
];
for (const [gradleVersion, rnVersion] of cases) {
const fs = mockfs(gradleVersion, rnVersion);
doesNotThrow(() => configureGradleWrapper("android", fs));
equal(written, "");
}
});
});
Loading

0 comments on commit cf8cb54

Please sign in to comment.