From 31bb29e1029c6be85acdf56dd4a5419222347491 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sat, 13 May 2023 13:53:19 -0400 Subject: [PATCH 1/4] Add tooling check --- script/tool/lib/src/gradle_check_command.dart | 31 ++++++ .../tool/test/gradle_check_command_test.dart | 102 +++++++++++++++++- 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/script/tool/lib/src/gradle_check_command.dart b/script/tool/lib/src/gradle_check_command.dart index 09a9d7a55f2..7876fbee163 100644 --- a/script/tool/lib/src/gradle_check_command.dart +++ b/script/tool/lib/src/gradle_check_command.dart @@ -3,12 +3,16 @@ // found in the LICENSE file. import 'package:file/file.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'common/core.dart'; import 'common/package_looping_command.dart'; import 'common/plugin_utils.dart'; import 'common/repository_package.dart'; +/// The lowest `ext.kotlin_version` that example apps are allowed to use. +final Version _minKotlinVersion = Version(1, 7, 10); + /// A command to enforce gradle file conventions and best practices. class GradleCheckCommand extends PackageLoopingCommand { /// Creates an instance of the gradle check command. @@ -125,6 +129,9 @@ class GradleCheckCommand extends PackageLoopingCommand { if (!_validateJavacLintConfig(package, lines)) { succeeded = false; } + if (!_validateKotlinVersion(package, lines)) { + succeeded = false; + } return succeeded; } @@ -347,4 +354,28 @@ gradle.projectsEvaluated { } return true; } + + /// Validates whether the given [example] has its Kotlin version set to at + /// least a minimum value, if it is set at all. + bool _validateKotlinVersion( + RepositoryPackage example, List gradleLines) { + final RepositoryPackage enclosingPackage = example.getEnclosingPackage()!; + + final RegExp kotlinVersionRegex = + RegExp(r"ext\.kotlin_version\s*=\s*'([\d.]+)'"); + RegExpMatch? match; + if (gradleLines.any((String line) { + match = kotlinVersionRegex.firstMatch(line); + return match != null; + })) { + final Version version = Version.parse(match!.group(1)!); + if (version < _minKotlinVersion) { + printError('build.gradle sets "ext.kotlin_version" to "$version". The ' + 'minimum Kotlin version that can be specified is ' + '$_minKotlinVersion, for compatibility with modern dependencies.'); + return false; + } + } + return true; + } } diff --git a/script/tool/test/gradle_check_command_test.dart b/script/tool/test/gradle_check_command_test.dart index 68581c7a639..2b359fcea7e 100644 --- a/script/tool/test/gradle_check_command_test.dart +++ b/script/tool/test/gradle_check_command_test.dart @@ -123,6 +123,7 @@ dependencies { RepositoryPackage package, { required String pluginName, required bool warningsConfigured, + String? kotlinVersion, }) { final File buildGradle = package .platformDirectory(FlutterPlatform.android) @@ -140,6 +141,7 @@ gradle.projectsEvaluated { '''; buildGradle.writeAsStringSync(''' buildscript { + ${kotlinVersion == null ? '' : "ext.kotlin_version = '$kotlinVersion'"} repositories { google() mavenCentral() @@ -228,9 +230,12 @@ dependencies { bool includeNamespace = true, bool commentNamespace = false, bool warningsConfigured = true, + String? kotlinVersion, }) { writeFakeExampleTopLevelBuildGradle(package, - pluginName: pluginName, warningsConfigured: warningsConfigured); + pluginName: pluginName, + warningsConfigured: warningsConfigured, + kotlinVersion: kotlinVersion); writeFakeExampleAppBuildGradle(package, includeNamespace: includeNamespace, commentNamespace: commentNamespace); } @@ -644,4 +649,99 @@ dependencies { ], )); }); + + group('Kotlin version check', () { + test('passes if not set', () async { + const String packageName = 'a_package'; + final RepositoryPackage package = + createFakePackage('a_package', packagesDir); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, pluginName: packageName); + writeFakeManifest(example, isApp: true); + + final List output = + await runCapturingPrint(runner, ['gradle-check']); + + expect( + output, + containsAllInOrder([ + contains('Validating android/build.gradle'), + ]), + ); + }); + + test('passes if at the minimum allowed version', () async { + const String packageName = 'a_package'; + final RepositoryPackage package = + createFakePackage('a_package', packagesDir); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, + pluginName: packageName, kotlinVersion: '1.7.10'); + writeFakeManifest(example, isApp: true); + + final List output = + await runCapturingPrint(runner, ['gradle-check']); + + expect( + output, + containsAllInOrder([ + contains('Validating android/build.gradle'), + ]), + ); + }); + + test('passes if above the minimum allowed version', () async { + const String packageName = 'a_package'; + final RepositoryPackage package = + createFakePackage('a_package', packagesDir); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, + pluginName: packageName, kotlinVersion: '99.99.0'); + writeFakeManifest(example, isApp: true); + + final List output = + await runCapturingPrint(runner, ['gradle-check']); + + expect( + output, + containsAllInOrder([ + contains('Validating android/build.gradle'), + ]), + ); + }); + + test('fails if below the minimum allowed version', () async { + const String packageName = 'a_package'; + final RepositoryPackage package = + createFakePackage('a_package', packagesDir); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, + pluginName: packageName, kotlinVersion: '1.6.21'); + writeFakeManifest(example, isApp: true); + + Error? commandError; + final List output = await runCapturingPrint( + runner, ['gradle-check'], errorHandler: (Error e) { + commandError = e; + }); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('build.gradle sets "ext.kotlin_version" to "1.6.21". The ' + 'minimum Kotlin version that can be specified is 1.7.10, for ' + 'compatibility with modern dependencies.'), + ]), + ); + }); + }); } From 0747f43709d5fe26b08d04e4f9b00b54977434c3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sat, 13 May 2023 13:56:31 -0400 Subject: [PATCH 2/4] Fix violations --- packages/animations/example/android/build.gradle | 2 +- packages/dynamic_layouts/example/android/build.gradle | 2 +- packages/flutter_markdown/example/android/build.gradle | 2 +- packages/go_router/example/android/build.gradle | 2 +- packages/rfw/example/hello/android/build.gradle | 2 +- packages/rfw/example/local/android/build.gradle | 2 +- packages/rfw/example/remote/android/build.gradle | 2 +- .../shared_preferences/example/android/build.gradle | 2 +- .../shared_preferences_android/example/android/build.gradle | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/animations/example/android/build.gradle b/packages/animations/example/android/build.gradle index 4b30292ebe1..ce647a433bd 100644 --- a/packages/animations/example/android/build.gradle +++ b/packages/animations/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/dynamic_layouts/example/android/build.gradle b/packages/dynamic_layouts/example/android/build.gradle index 4b30292ebe1..ce647a433bd 100644 --- a/packages/dynamic_layouts/example/android/build.gradle +++ b/packages/dynamic_layouts/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/flutter_markdown/example/android/build.gradle b/packages/flutter_markdown/example/android/build.gradle index 4b30292ebe1..ce647a433bd 100644 --- a/packages/flutter_markdown/example/android/build.gradle +++ b/packages/flutter_markdown/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/go_router/example/android/build.gradle b/packages/go_router/example/android/build.gradle index 96e940b06ea..586557f0afc 100644 --- a/packages/go_router/example/android/build.gradle +++ b/packages/go_router/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/rfw/example/hello/android/build.gradle b/packages/rfw/example/hello/android/build.gradle index ff27ef813e9..586557f0afc 100644 --- a/packages/rfw/example/hello/android/build.gradle +++ b/packages/rfw/example/hello/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/rfw/example/local/android/build.gradle b/packages/rfw/example/local/android/build.gradle index ff27ef813e9..586557f0afc 100644 --- a/packages/rfw/example/local/android/build.gradle +++ b/packages/rfw/example/local/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/rfw/example/remote/android/build.gradle b/packages/rfw/example/remote/android/build.gradle index ff27ef813e9..586557f0afc 100644 --- a/packages/rfw/example/remote/android/build.gradle +++ b/packages/rfw/example/remote/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/shared_preferences/shared_preferences/example/android/build.gradle b/packages/shared_preferences/shared_preferences/example/android/build.gradle index 4b30292ebe1..ce647a433bd 100644 --- a/packages/shared_preferences/shared_preferences/example/android/build.gradle +++ b/packages/shared_preferences/shared_preferences/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() diff --git a/packages/shared_preferences/shared_preferences_android/example/android/build.gradle b/packages/shared_preferences/shared_preferences_android/example/android/build.gradle index c11ef06c4e3..f6f6475fb39 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/build.gradle +++ b/packages/shared_preferences/shared_preferences_android/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() From 5c86692769c23c9b69a115622fc26ac062a06091 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sat, 13 May 2023 14:12:08 -0400 Subject: [PATCH 3/4] Analysis fix --- script/tool/lib/src/gradle_check_command.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/tool/lib/src/gradle_check_command.dart b/script/tool/lib/src/gradle_check_command.dart index 7876fbee163..009a94de367 100644 --- a/script/tool/lib/src/gradle_check_command.dart +++ b/script/tool/lib/src/gradle_check_command.dart @@ -359,8 +359,6 @@ gradle.projectsEvaluated { /// least a minimum value, if it is set at all. bool _validateKotlinVersion( RepositoryPackage example, List gradleLines) { - final RepositoryPackage enclosingPackage = example.getEnclosingPackage()!; - final RegExp kotlinVersionRegex = RegExp(r"ext\.kotlin_version\s*=\s*'([\d.]+)'"); RegExpMatch? match; From 4123b5767366c04a34e0bc140ae45835e2cd2c04 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 15 May 2023 10:51:28 -0400 Subject: [PATCH 4/4] Use a variable for tests --- script/tool/lib/src/gradle_check_command.dart | 8 +++++--- script/tool/test/gradle_check_command_test.dart | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/script/tool/lib/src/gradle_check_command.dart b/script/tool/lib/src/gradle_check_command.dart index 009a94de367..53da6405beb 100644 --- a/script/tool/lib/src/gradle_check_command.dart +++ b/script/tool/lib/src/gradle_check_command.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:file/file.dart'; +import 'package:meta/meta.dart'; import 'package:pub_semver/pub_semver.dart'; import 'common/core.dart'; @@ -11,7 +12,8 @@ import 'common/plugin_utils.dart'; import 'common/repository_package.dart'; /// The lowest `ext.kotlin_version` that example apps are allowed to use. -final Version _minKotlinVersion = Version(1, 7, 10); +@visibleForTesting +final Version minKotlinVersion = Version(1, 7, 10); /// A command to enforce gradle file conventions and best practices. class GradleCheckCommand extends PackageLoopingCommand { @@ -367,10 +369,10 @@ gradle.projectsEvaluated { return match != null; })) { final Version version = Version.parse(match!.group(1)!); - if (version < _minKotlinVersion) { + if (version < minKotlinVersion) { printError('build.gradle sets "ext.kotlin_version" to "$version". The ' 'minimum Kotlin version that can be specified is ' - '$_minKotlinVersion, for compatibility with modern dependencies.'); + '$minKotlinVersion, for compatibility with modern dependencies.'); return false; } } diff --git a/script/tool/test/gradle_check_command_test.dart b/script/tool/test/gradle_check_command_test.dart index 2b359fcea7e..28603d25cd1 100644 --- a/script/tool/test/gradle_check_command_test.dart +++ b/script/tool/test/gradle_check_command_test.dart @@ -680,7 +680,7 @@ dependencies { writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; writeFakeExampleBuildGradles(example, - pluginName: packageName, kotlinVersion: '1.7.10'); + pluginName: packageName, kotlinVersion: minKotlinVersion.toString()); writeFakeManifest(example, isApp: true); final List output = @@ -738,8 +738,8 @@ dependencies { output, containsAllInOrder([ contains('build.gradle sets "ext.kotlin_version" to "1.6.21". The ' - 'minimum Kotlin version that can be specified is 1.7.10, for ' - 'compatibility with modern dependencies.'), + 'minimum Kotlin version that can be specified is ' + '$minKotlinVersion, for compatibility with modern dependencies.'), ]), ); });