Protect flutter analyze --suggestions from erroring on missing AGP value. (#137719)
Fixes #137600
Protect flutter analyze --suggestions from null error when AGP value is missing
Update template with a reference to new agp definition location
Look for AGP version being set in settings.gradle (change to templates happened in dbe0ccd885 (diff-20537fb84ee37894a3f3d9723a06bcf2674290ee25aa83332c2524a1f7546a6d)
This commit is contained in:
parent
969a8750a5
commit
4d21a026e5
@ -71,19 +71,31 @@ const String maxKnownAgpVersion = '8.3';
|
||||
// compatible Java version.
|
||||
const String oldestDocumentedJavaAgpCompatibilityVersion = '4.2';
|
||||
|
||||
// Constant used in [_buildAndroidGradlePluginRegExp] and
|
||||
// [_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'"
|
||||
// Parentheticals are use to group which helps with version extraction.
|
||||
// "...build:gradle:(...)" where group(1) should be the version string.
|
||||
final RegExp _androidGradlePluginRegExp =
|
||||
RegExp(r'com\.android\.tools\.build:gradle:(\d+\.\d+\.\d+)');
|
||||
// ?<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+)');
|
||||
|
||||
// AGP can be defined in settings.gradle.
|
||||
// Expected content:
|
||||
// "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+)"',
|
||||
multiLine: true);
|
||||
|
||||
// Expected content format (with lines above and below).
|
||||
// Version can have 2 or 3 numbers.
|
||||
// 'distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip'
|
||||
// '^\s*' protects against commented out lines.
|
||||
final RegExp distributionUrlRegex =
|
||||
RegExp(r'^\s*distributionUrl\s*=\s*.*\.zip', multiLine: true);
|
||||
RegExp(r'^\s*distributionUrl\s*=\s*.*\.zip', multiLine: true);
|
||||
|
||||
// Modified version of the gradle distribution url match designed to only match
|
||||
// gradle.org urls so that we can guarantee any modifications to the url
|
||||
@ -199,7 +211,7 @@ String getGradleVersionForAndroidPlugin(Directory directory, Logger logger) {
|
||||
return templateDefaultGradleVersion;
|
||||
}
|
||||
final String buildFileContent = buildFile.readAsStringSync();
|
||||
final Iterable<Match> pluginMatches = _androidGradlePluginRegExp.allMatches(buildFileContent);
|
||||
final Iterable<Match> pluginMatches = _buildAndroidGradlePluginRegExp.allMatches(buildFileContent);
|
||||
if (pluginMatches.isEmpty) {
|
||||
logger.printTrace("$buildFile doesn't provide an AGP version, assuming Gradle version: $templateDefaultGradleVersion");
|
||||
return templateDefaultGradleVersion;
|
||||
@ -309,8 +321,9 @@ 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] file within
|
||||
/// the project's Android directory ([androidDirectory]).
|
||||
/// The Android plugin version is specified in the [build.gradle] or
|
||||
/// [settings.gradle] file within the project's
|
||||
/// Android directory ([androidDirectory]).
|
||||
String? getAgpVersion(Directory androidDirectory, Logger logger) {
|
||||
final File buildFile = androidDirectory.childFile('build.gradle');
|
||||
if (!buildFile.existsSync()) {
|
||||
@ -318,15 +331,34 @@ String? getAgpVersion(Directory androidDirectory, Logger logger) {
|
||||
return null;
|
||||
}
|
||||
final String buildFileContent = buildFile.readAsStringSync();
|
||||
final Iterable<Match> pluginMatches =
|
||||
_androidGradlePluginRegExp.allMatches(buildFileContent);
|
||||
if (pluginMatches.isEmpty) {
|
||||
logger.printTrace("$buildFile doesn't provide an AGP version");
|
||||
final RegExpMatch? buildMatch =
|
||||
_buildAndroidGradlePluginRegExp.firstMatch(buildFileContent);
|
||||
if (buildMatch != null) {
|
||||
final String? androidPluginVersion =
|
||||
buildMatch.namedGroup(_versionGroupName);
|
||||
logger.printTrace('$buildFile provides AGP version: $androidPluginVersion');
|
||||
return androidPluginVersion;
|
||||
}
|
||||
logger.printTrace(
|
||||
"$buildFile doesn't provide an AGP version. Checking settings.");
|
||||
final File settingsFile = androidDirectory.childFile('settings.gradle');
|
||||
if (!settingsFile.existsSync()) {
|
||||
logger.printTrace('$settingsFile does not exist.');
|
||||
return null;
|
||||
}
|
||||
final String? androidPluginVersion = pluginMatches.first.group(1);
|
||||
logger.printTrace('$buildFile provides AGP version: $androidPluginVersion');
|
||||
return androidPluginVersion;
|
||||
final String settingsFileContent = settingsFile.readAsStringSync();
|
||||
final RegExpMatch? settingsMatch =
|
||||
_settingsAndroidGradlePluginRegExp.firstMatch(settingsFileContent);
|
||||
|
||||
if (settingsMatch != null) {
|
||||
final String? androidPluginVersion =
|
||||
settingsMatch.namedGroup(_versionGroupName);
|
||||
logger.printTrace(
|
||||
'$settingsFile provides AGP version: $androidPluginVersion');
|
||||
return androidPluginVersion;
|
||||
}
|
||||
logger.printTrace("$settingsFile doesn't provide an AGP version.");
|
||||
return null;
|
||||
}
|
||||
|
||||
String _formatParseWarning(String content) {
|
||||
|
@ -608,15 +608,20 @@ class AndroidProject extends FlutterProjectPlatform {
|
||||
final bool compatibleGradleAgp = gradle.validateGradleAndAgp(globals.logger,
|
||||
gradleV: gradleVersion, agpV: agpVersion);
|
||||
|
||||
final bool compatibleJavaGradle = gradle.validateJavaAndGradle(globals.logger,
|
||||
javaV: javaVersion, gradleV: gradleVersion);
|
||||
final bool compatibleJavaGradle = gradle.validateJavaAndGradle(
|
||||
globals.logger,
|
||||
javaV: javaVersion,
|
||||
gradleV: gradleVersion);
|
||||
|
||||
// Begin description formatting.
|
||||
if (!compatibleGradleAgp) {
|
||||
final String gradleDescription = agpVersion != null
|
||||
? 'Update Gradle to at least "${gradle.getGradleVersionFor(agpVersion)}".'
|
||||
: '';
|
||||
description = '''
|
||||
Incompatible Gradle/AGP versions. \n
|
||||
Gradle Version: $gradleVersion, AGP Version: $agpVersion
|
||||
Update Gradle to at least "${gradle.getGradleVersionFor(agpVersion!)}".\n
|
||||
$gradleDescription\n
|
||||
See the link below for more information:
|
||||
$gradleAgpCompatUrl
|
||||
''';
|
||||
|
@ -6,6 +6,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// AGP version is set in settings.gradle.
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// AGP version is set in settings.gradle.
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
@ -469,6 +469,51 @@ allprojects {
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('returns the AGP version when in settings', () 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
|
||||
}
|
||||
}
|
||||
|
||||
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',
|
||||
);
|
||||
});
|
||||
|
||||
group('validates gradle/agp versions', () {
|
||||
final List<GradleAgpTestData> testData = <GradleAgpTestData>[
|
||||
// Values too new *these need to be updated* when
|
||||
|
@ -659,6 +659,48 @@ dependencies {
|
||||
androidSdk: androidSdk,
|
||||
);
|
||||
});
|
||||
group('_', () {
|
||||
final FakeProcessManager processManager;
|
||||
final Java java;
|
||||
final AndroidStudio androidStudio;
|
||||
final FakeAndroidSdkWithDir androidSdk;
|
||||
final FileSystem fileSystem = getFileSystemForPlatform();
|
||||
java = FakeJava(version: Version(11, 0, 2));
|
||||
processManager = FakeProcessManager.empty();
|
||||
androidStudio = FakeAndroidStudio();
|
||||
androidSdk =
|
||||
FakeAndroidSdkWithDir(fileSystem.currentDirectory);
|
||||
fileSystem.currentDirectory
|
||||
.childDirectory(androidStudio.javaPath!)
|
||||
.createSync();
|
||||
_testInMemory(
|
||||
'null agp only',
|
||||
() async {
|
||||
const String gradleV = '7.0.3';
|
||||
final FlutterProject? project = await configureGradleAgpForTest(
|
||||
gradleV: gradleV,
|
||||
agpV: '',
|
||||
);
|
||||
final CompatibilityResult value =
|
||||
await project!.android.hasValidJavaGradleAgpVersions();
|
||||
expect(value.success, isFalse);
|
||||
// Should not have the valid string.
|
||||
expect(
|
||||
value.description,
|
||||
isNot(
|
||||
contains(RegExp(AndroidProject.validJavaGradleAgpString))));
|
||||
// On gradle/agp error print help url null value for agp.
|
||||
expect(value.description,
|
||||
contains(RegExp(AndroidProject.gradleAgpCompatUrl)));
|
||||
expect(value.description, contains(RegExp(gradleV)));
|
||||
expect(value.description, contains(RegExp('null')));
|
||||
},
|
||||
java: java,
|
||||
androidStudio: androidStudio,
|
||||
processManager: processManager,
|
||||
androidSdk: androidSdk,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('language', () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user