mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Update AGP version validation code to support KGP and kotlin build files. (#142357)
Addresses: https://github.com/flutter/flutter/issues/141410
This commit is contained in:
parent
f3ee371285
commit
e5a922fed4
@ -75,19 +75,25 @@ const String oldestDocumentedJavaAgpCompatibilityVersion = '4.2';
|
||||
// [_settingsAndroidGradlePluginRegExp] to identify the version section.
|
||||
const String _versionGroupName = 'version';
|
||||
|
||||
// AGP can be defined in build.gradle
|
||||
// Expected content:
|
||||
// "classpath 'com.android.tools.build:gradle:7.3.0'"
|
||||
// AGP can be defined in the dependencies block of [build.gradle] or [build.gradle.kts].
|
||||
// Expected content (covers both classpath and compileOnly cases):
|
||||
// Groovy DSL with single quotes - 'com.android.tools.build:gradle:{{agpVersion}}'
|
||||
// Groovy DSL with double quotes - "com.android.tools.build:gradle:{{agpVersion}}"
|
||||
// Kotlin DSL - ("com.android.tools.build.gradle:{{agpVersion}}")
|
||||
// ?<version> is used to name the version group which helps with extraction.
|
||||
final RegExp _buildAndroidGradlePluginRegExp =
|
||||
RegExp(r'com\.android\.tools\.build:gradle:(?<version>\d+\.\d+\.\d+)');
|
||||
final RegExp _androidGradlePluginRegExpFromDependencies = RegExp(
|
||||
r"""[^\/]*\s*((\bclasspath\b)|(\bcompileOnly\b))\s*\(?['"]com\.android\.tools\.build:gradle:(?<version>\d+(\.\d+){1,2})\)?""",
|
||||
multiLine: true);
|
||||
|
||||
// AGP can be defined in settings.gradle.
|
||||
// AGP can be defined in the plugins block of [build.gradle],
|
||||
// [build.gradle.kts], [settings.gradle], or [settings.gradle.kts].
|
||||
// Expected content:
|
||||
// "id "com.android.application" version "{{agpVersion}}""
|
||||
// Groovy DSL with single quotes - id 'com.android.application' version '{{agpVersion}}'
|
||||
// Groovy DSL with double quotes - id "com.android.application" version "{{agpVersion}}"
|
||||
// Kotlin DSL - id("com.android.application") version "{{agpVersion}}"
|
||||
// ?<version> is used to name the version group which helps with extraction.
|
||||
final RegExp _settingsAndroidGradlePluginRegExp = RegExp(
|
||||
r'^\s+id\s+"com.android.application"\s+version\s+"(?<version>\d+\.\d+\.\d+)"',
|
||||
final RegExp _androidGradlePluginRegExpFromId = RegExp(
|
||||
r"""[^\/]*s*id\s*\(?['"]com\.android\.application['"]\)?\s+version\s+['"](?<version>\d+(\.\d+){1,2})\)?""",
|
||||
multiLine: true);
|
||||
|
||||
// Expected content format (with lines above and below).
|
||||
@ -203,30 +209,17 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio
|
||||
/// Returns the Gradle version that the current Android plugin depends on when found,
|
||||
/// otherwise it returns a default version.
|
||||
///
|
||||
/// The Android plugin version is specified in the [build.gradle] file within
|
||||
/// The Android plugin version is specified in the [build.gradle],
|
||||
/// [build.gradle.kts], [settings.gradle], or [settings.gradle.kts] file within
|
||||
/// the project's Android directory.
|
||||
String getGradleVersionForAndroidPlugin(Directory directory, Logger logger) {
|
||||
const String buildFileName = 'build.gradle/build.gradle.kts';
|
||||
|
||||
File buildFile = directory.childFile('build.gradle');
|
||||
if (!buildFile.existsSync()) {
|
||||
buildFile = directory.childFile('build.gradle.kts');
|
||||
}
|
||||
|
||||
if (!buildFile.existsSync()) {
|
||||
final String? androidPluginVersion = getAgpVersion(directory, logger);
|
||||
if (androidPluginVersion == null) {
|
||||
logger.printTrace(
|
||||
"$buildFileName doesn't exist, assuming Gradle version: $templateDefaultGradleVersion");
|
||||
'AGP version cannot be determined, assuming Gradle version: $templateDefaultGradleVersion');
|
||||
return templateDefaultGradleVersion;
|
||||
}
|
||||
final String buildFileContent = buildFile.readAsStringSync();
|
||||
final Iterable<Match> pluginMatches = _buildAndroidGradlePluginRegExp.allMatches(buildFileContent);
|
||||
if (pluginMatches.isEmpty) {
|
||||
logger.printTrace("$buildFileName doesn't provide an AGP version, assuming Gradle version: $templateDefaultGradleVersion");
|
||||
return templateDefaultGradleVersion;
|
||||
}
|
||||
final String? androidPluginVersion = pluginMatches.first.group(1);
|
||||
logger.printTrace('$buildFileName provides AGP version: $androidPluginVersion');
|
||||
return getGradleVersionFor(androidPluginVersion ?? 'unknown');
|
||||
return getGradleVersionFor(androidPluginVersion);
|
||||
}
|
||||
|
||||
/// Returns the gradle file from the top level directory.
|
||||
@ -329,38 +322,51 @@ OS: Mac OS X 13.2.1 aarch64
|
||||
/// Returns the Android Gradle Plugin (AGP) version that the current project
|
||||
/// depends on when found, null otherwise.
|
||||
///
|
||||
/// The Android plugin version is specified in the [build.gradle] or
|
||||
/// [settings.gradle] file within the project's
|
||||
/// Android directory ([androidDirectory]).
|
||||
/// The Android plugin version is specified in the [build.gradle],
|
||||
/// [build.gradle.kts], [settings.gradle] or [settings.gradle.kts]
|
||||
/// file within the project's Android directory ([androidDirectory]).
|
||||
String? getAgpVersion(Directory androidDirectory, Logger logger) {
|
||||
File buildFile = androidDirectory.childFile('build.gradle');
|
||||
if (!buildFile.existsSync()) {
|
||||
buildFile = androidDirectory.childFile('build.gradle.kts');
|
||||
}
|
||||
|
||||
if (!buildFile.existsSync()) {
|
||||
logger.printTrace('Can not find build.gradle/build.gradle.kts in $androidDirectory');
|
||||
logger.printTrace(
|
||||
'Cannot find build.gradle/build.gradle.kts in $androidDirectory');
|
||||
return null;
|
||||
}
|
||||
final String buildFileContent = buildFile.readAsStringSync();
|
||||
final RegExpMatch? buildMatch =
|
||||
_buildAndroidGradlePluginRegExp.firstMatch(buildFileContent);
|
||||
if (buildMatch != null) {
|
||||
final RegExpMatch? buildMatchClasspath =
|
||||
_androidGradlePluginRegExpFromDependencies.firstMatch(buildFileContent);
|
||||
if (buildMatchClasspath != null) {
|
||||
final String? androidPluginVersion =
|
||||
buildMatch.namedGroup(_versionGroupName);
|
||||
logger.printTrace('$buildFile provides AGP version: $androidPluginVersion');
|
||||
buildMatchClasspath.namedGroup(_versionGroupName);
|
||||
logger.printTrace('$buildFile provides AGP version from classpath: $androidPluginVersion');
|
||||
return androidPluginVersion;
|
||||
}
|
||||
final RegExpMatch? buildMatchId =
|
||||
_androidGradlePluginRegExpFromId.firstMatch(buildFileContent);
|
||||
if (buildMatchId != null) {
|
||||
final String? androidPluginVersion =
|
||||
buildMatchId.namedGroup(_versionGroupName);
|
||||
logger.printTrace('$buildFile provides AGP version from plugin id: $androidPluginVersion');
|
||||
return androidPluginVersion;
|
||||
}
|
||||
|
||||
logger.printTrace(
|
||||
"$buildFile doesn't provide an AGP version. Checking settings.");
|
||||
final File settingsFile = androidDirectory.childFile('settings.gradle');
|
||||
File settingsFile = androidDirectory.childFile('settings.gradle');
|
||||
if (!settingsFile.existsSync()) {
|
||||
logger.printTrace('$settingsFile does not exist.');
|
||||
settingsFile = androidDirectory.childFile('settings.gradle.kts');
|
||||
}
|
||||
if (!settingsFile.existsSync()) {
|
||||
logger.printTrace(
|
||||
'Cannot find settings.gradle/settings.gradle.kts in $androidDirectory');
|
||||
return null;
|
||||
}
|
||||
final String settingsFileContent = settingsFile.readAsStringSync();
|
||||
final RegExpMatch? settingsMatch =
|
||||
_settingsAndroidGradlePluginRegExp.firstMatch(settingsFileContent);
|
||||
_androidGradlePluginRegExpFromId.firstMatch(settingsFileContent);
|
||||
|
||||
if (settingsMatch != null) {
|
||||
final String? androidPluginVersion =
|
||||
@ -385,7 +391,7 @@ String _formatParseWarning(String content) {
|
||||
//
|
||||
// Returns true if versions are compatible.
|
||||
// Null Gradle version or AGP version returns false.
|
||||
// If compatibility can not be evaluated returns false.
|
||||
// If compatibility cannot be evaluated returns false.
|
||||
// If versions are newer than the max known version a warning is logged and true
|
||||
// returned.
|
||||
//
|
||||
|
||||
@ -387,7 +387,9 @@ OS: Mac OS X 13.2.1 aarch64
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('returns the AGP version when set in Groovy', () async {
|
||||
testWithoutContext(
|
||||
'returns the AGP version when set in Groovy build file as classpath with single quotes and commented line',
|
||||
() async {
|
||||
const String expectedVersion = '7.3.0';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
@ -399,6 +401,8 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Decoy value to ensure we ignore commented out lines.
|
||||
// classpath 'com.android.application' version '6.1.0' apply false
|
||||
classpath 'com.android.tools.build:gradle:$expectedVersion'
|
||||
}
|
||||
}
|
||||
@ -417,7 +421,9 @@ allprojects {
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('returns the AGP version when set in Kotlin', () async {
|
||||
testWithoutContext(
|
||||
'returns the AGP version when set in Kotlin build file as classpath',
|
||||
() async {
|
||||
const String expectedVersion = '7.3.0';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
@ -447,7 +453,77 @@ allprojects {
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('prefers the AGP version when set in Groovy, ignores Kotlin', () async {
|
||||
|
||||
testWithoutContext(
|
||||
'returns the AGP version when set in Groovy build file as compileOnly with double quotes',
|
||||
() async {
|
||||
const String expectedVersion = '7.1.0';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
|
||||
dependencies {
|
||||
compileOnly "com.android.tools.build:gradle:$expectedVersion"
|
||||
}
|
||||
''');
|
||||
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
expectedVersion,
|
||||
);
|
||||
});
|
||||
testWithoutContext(
|
||||
'returns the AGP version when set in Kotlin build file as compileOnly',
|
||||
() async {
|
||||
const String expectedVersion = '7.1.0';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
|
||||
dependencies {
|
||||
compileOnly("com.android.tools.build:gradle:$expectedVersion")
|
||||
}
|
||||
''');
|
||||
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
expectedVersion,
|
||||
);
|
||||
});
|
||||
testWithoutContext(
|
||||
'returns the AGP version when set in Groovy build file as plugin',
|
||||
() async {
|
||||
const String expectedVersion = '6.8';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
androidDirectory.childFile('build.gradle').writeAsStringSync('''
|
||||
plugins {
|
||||
id 'com.android.application' version '$expectedVersion' apply false
|
||||
}
|
||||
''');
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
expectedVersion,
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext(
|
||||
'returns the AGP version when set in Kotlin build file as plugin',
|
||||
() async {
|
||||
const String expectedVersion = '7.2.0';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
|
||||
plugins {
|
||||
id("com.android.application") version "$expectedVersion" apply false
|
||||
}
|
||||
''');
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
expectedVersion,
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext(
|
||||
'prefers the AGP version when set in Groovy, ignores Kotlin', () async {
|
||||
const String versionInGroovy = '7.3.0';
|
||||
const String versionInKotlin = '7.4.2';
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
@ -554,48 +630,73 @@ allprojects {
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('returns the AGP version when in settings', () async {
|
||||
testWithoutContext('returns the AGP version when in Groovy settings as plugin',
|
||||
() async {
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
// File must exist and can not have agp defined.
|
||||
androidDirectory.childFile('build.gradle').writeAsStringSync(r'');
|
||||
androidDirectory.childFile('settings.gradle').writeAsStringSync(r'''
|
||||
pluginManagement {
|
||||
def flutterSdkPath = {
|
||||
def properties = new Properties()
|
||||
file("local.properties").withInputStream { properties.load(it) }
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
return flutterSdkPath
|
||||
}
|
||||
settings.ext.flutterSdkPath = flutterSdkPath()
|
||||
|
||||
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
|
||||
id 'dev.flutter.flutter-gradle-plugin' version '1.0.0' apply false
|
||||
id 'dev.flutter.flutter-plugin-loader' version '1.0.0'
|
||||
// Decoy value to ensure we ignore commented out lines.
|
||||
// id 'com.android.application' version '6.1.0' apply false
|
||||
id 'com.android.application' version '8.1.0' apply false
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
// Decoy value to ensure we ignore commented out lines.
|
||||
// id "com.android.application" version "6.1.0" apply false
|
||||
id "com.android.application" version "7.3.0" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
''');
|
||||
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
'7.3.0',
|
||||
'8.1.0',
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext(
|
||||
'returns the AGP version when in Kotlin settings as plugin', () async {
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
// File must exist and cannot have agp defined.
|
||||
androidDirectory.childFile('build.gradle.kts').writeAsStringSync(r'');
|
||||
androidDirectory.childFile('settings.gradle.kts').writeAsStringSync(r'''
|
||||
pluginManagement {
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
// Decoy value to ensure we ignore commented out lines.
|
||||
// id("com.android.application") version "6.1.0" apply false
|
||||
id("com.android.application") version "7.5.0" apply false
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
'7.5.0',
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext(
|
||||
'returns null when agp version is misconfigured',
|
||||
() async {
|
||||
final Directory androidDirectory = fileSystem.directory('/android')
|
||||
..createSync();
|
||||
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
|
||||
plugins {
|
||||
`java-gradle-plugin`
|
||||
`groovy`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// intentional typo
|
||||
compileOnl("com.android.tools.build:gradle:7.3.0")
|
||||
}
|
||||
''');
|
||||
|
||||
expect(
|
||||
getAgpVersion(androidDirectory, BufferLogger.test()),
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user