[various] Add targetCompatibility to build.gradle (#3825)

While current docs about `targetCompatibility` say that it defaults to `sourceCompatibility`, for older toolchains (AGP?) that is apparently not the case, and it's a build error to set `sourceCompatibility` without `targetCompatibility`.

This adds enforcement that it's set to `gradle-check`, and fixes all of the violations.

Fixes https://github.com/flutter/flutter/issues/125482
This commit is contained in:
stuartmorgan
2023-04-26 11:47:10 -07:00
committed by GitHub
parent dbab0528ef
commit 5ae8a1da2a
17 changed files with 85 additions and 20 deletions

View File

@ -101,7 +101,7 @@ class GradleCheckCommand extends PackageLoopingCommand {
if (!_validateNamespace(package, contents, isExample: false)) {
succeeded = false;
}
if (!_validateSourceCompatibilityVersion(lines)) {
if (!_validateCompatibilityVersions(lines)) {
succeeded = false;
}
if (!_validateGradleDrivenLintConfig(package, lines)) {
@ -204,18 +204,27 @@ build.gradle "namespace" must match the "package" attribute in AndroidManifest.x
/// Checks for a source compatibiltiy version, so that it's explicit rather
/// than using whatever the client's local toolchaing defaults to (which can
/// lead to compile errors that show up for clients, but not in CI).
bool _validateSourceCompatibilityVersion(List<String> gradleLines) {
if (!gradleLines.any((String line) =>
line.contains('languageVersion') && !_isCommented(line)) &&
!gradleLines.any((String line) =>
line.contains('sourceCompatibility') && !_isCommented(line))) {
bool _validateCompatibilityVersions(List<String> gradleLines) {
final bool hasLanguageVersion = gradleLines.any((String line) =>
line.contains('languageVersion') && !_isCommented(line));
final bool hasCompabilityVersions = gradleLines.any((String line) =>
line.contains('sourceCompatibility') && !_isCommented(line)) &&
// Newer toolchains default targetCompatibility to the same value as
// sourceCompatibility, but older toolchains require it to be set
// explicitly. The exact version cutoff (and of which piece of the
// toolchain; likely AGP) is unknown; for context see
// https://github.com/flutter/flutter/issues/125482
gradleLines.any((String line) =>
line.contains('targetCompatibility') && !_isCommented(line));
if (!hasLanguageVersion && !hasCompabilityVersions) {
const String errorMessage = '''
build.gradle must set an explicit Java compatibility version.
This can be done either via "sourceCompatibility":
This can be done either via "sourceCompatibility"/"targetCompatibility":
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

View File

@ -38,6 +38,7 @@ void main() {
RepositoryPackage package, {
bool includeLanguageVersion = false,
bool includeSourceCompat = false,
bool includeTargetCompat = false,
bool commentSourceLanguage = false,
bool includeNamespace = true,
bool commentNamespace = false,
@ -64,11 +65,10 @@ java {
}
''';
final String compileOptionsSection = '''
compileOptions {
${commentSourceLanguage ? '// ' : ''}sourceCompatibility JavaVersion.VERSION_1_8
}
''';
final String sourceCompat =
'${commentSourceLanguage ? '// ' : ''}sourceCompatibility JavaVersion.VERSION_1_8';
final String targetCompat =
'${commentSourceLanguage ? '// ' : ''}targetCompatibility JavaVersion.VERSION_1_8';
final String namespace =
"${commentNamespace ? '// ' : ''}namespace '$_defaultFakeNamespace'";
@ -94,7 +94,10 @@ android {
minSdkVersion 30
}
${warningsConfigured ? warningConfig : ''}
${includeSourceCompat ? compileOptionsSection : ''}
compileOptions {
${includeSourceCompat ? sourceCompat : ''}
${includeTargetCompat ? targetCompat : ''}
}
testOptions {
unitTests.includeAndroidResources = true
}
@ -280,12 +283,38 @@ dependencies {
);
});
test('passes when sourceCompatibility is specified', () async {
test(
'fails when sourceCompatibility is provided with out targetCompatibility',
() async {
final RepositoryPackage package =
createFakePlugin('a_plugin', packagesDir, examples: <String>[]);
writeFakePluginBuildGradle(package, includeSourceCompat: true);
writeFakeManifest(package);
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['gradle-check'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains(
'build.gradle must set an explicit Java compatibility version.'),
]),
);
});
test('passes when sourceCompatibility and targetCompatibility are specified',
() async {
final RepositoryPackage package =
createFakePlugin('a_plugin', packagesDir, examples: <String>[]);
writeFakePluginBuildGradle(package,
includeSourceCompat: true, includeTargetCompat: true);
writeFakeManifest(package);
final List<String> output =
await runCapturingPrint(runner, <String>['gradle-check']);
@ -339,7 +368,9 @@ dependencies {
final RepositoryPackage package =
createFakePlugin('a_plugin', packagesDir, examples: <String>[]);
writeFakePluginBuildGradle(package,
includeSourceCompat: true, commentSourceLanguage: true);
includeSourceCompat: true,
includeTargetCompat: true,
commentSourceLanguage: true);
writeFakeManifest(package);
Error? commandError;