Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions script/tool/lib/src/gradle_check_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:collection/collection.dart';
import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:pub_semver/pub_semver.dart';
Expand Down Expand Up @@ -127,6 +128,9 @@ class GradleCheckCommand extends PackageLoopingCommand {
if (!_validateGradleDrivenLintConfig(package, lines)) {
succeeded = false;
}
if (!_validateCompileSdkUsage(package, lines)) {
succeeded = false;
}
return succeeded;
}

Expand Down Expand Up @@ -415,6 +419,47 @@ for more details.''';
return true;
}

bool _validateCompileSdkUsage(
RepositoryPackage package, List<String> gradleLines) {
final RegExp linePattern = RegExp(r'^\s*compileSdk');
final RegExp legacySettingPattern = RegExp(r'^\s*compileSdkVersion');
final String? compileSdkLine = gradleLines
.firstWhereOrNull((String line) => linePattern.hasMatch(line));
if (compileSdkLine == null) {
printError('${indentation}No compileSdk or compileSdkVersion found.');
return false;
}
if (legacySettingPattern.hasMatch(compileSdkLine)) {
printError('${indentation}Please replace the deprecated '
'"compileSdkVersion" setting with the newer "compileSdk"');
return false;
}
if (compileSdkLine.contains('flutter.compileSdkVersion')) {
final Pubspec pubspec = package.parsePubspec();
final VersionConstraint? flutterConstraint =
pubspec.environment['flutter'];
final Version? minFlutterVersion =
flutterConstraint != null && flutterConstraint is VersionRange
? flutterConstraint.min
: null;
if (minFlutterVersion == null) {
printError('${indentation}Unable to find a Flutter SDK version '
'constraint. Use of flutter.compileSdkVersion requires a minimum '
'Flutter version of 3.27');
return false;
}
if (minFlutterVersion < Version(3, 27, 0)) {
printError('${indentation}Use of flutter.compileSdkVersion requires a '
'minimum Flutter version of 3.27, but this package currently '
'supports $minFlutterVersion.\n'
"${indentation}Please update the package's minimum Flutter SDK "
'version to at least 3.27.');
return false;
}
}
return true;
}

/// Validates whether the given [example]'s gradle content is configured to
/// build its plugin target with javac lints enabled and treated as errors,
/// if the enclosing package is a plugin.
Expand Down
111 changes: 110 additions & 1 deletion script/tool/test/gradle_check_command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ void main() {
bool includeNamespace = true,
bool commentNamespace = false,
bool warningsConfigured = true,
bool useDeprecatedCompileSdkVersion = false,
String compileSdk = '33',
}) {
final File buildGradle = package
.platformDirectory(FlutterPlatform.android)
Expand Down Expand Up @@ -88,7 +90,7 @@ apply plugin: 'com.android.library'
${includeLanguageVersion ? javaSection : ''}
android {
${includeNamespace ? namespace : ''}
compileSdk 33
${useDeprecatedCompileSdkVersion ? 'compileSdkVersion' : 'compileSdk'} $compileSdk

defaultConfig {
minSdkVersion 30
Expand Down Expand Up @@ -989,4 +991,111 @@ dependencies {
);
});
});

group('compileSdk check', () {
test('passes if set to a number', () async {
const String packageName = 'a_package';
final RepositoryPackage package =
createFakePackage(packageName, packagesDir, isFlutter: true);
writeFakePluginBuildGradle(package,
includeLanguageVersion: true, compileSdk: '35');
writeFakeManifest(package);
final RepositoryPackage example = package.getExamples().first;
writeFakeExampleBuildGradles(example, pluginName: packageName);
writeFakeManifest(example, isApp: true);

final List<String> output =
await runCapturingPrint(runner, <String>['gradle-check']);

expect(
output,
containsAllInOrder(<Matcher>[
contains('Validating android/build.gradle'),
]),
);
});

test('passes if set to flutter.compileSdkVersion with Flutter 3.27+',
() async {
const String packageName = 'a_package';
final RepositoryPackage package = createFakePackage(
packageName, packagesDir,
isFlutter: true, flutterConstraint: '>=3.27.0');
writeFakePluginBuildGradle(package,
includeLanguageVersion: true,
compileSdk: 'flutter.compileSdkVersion');
writeFakeManifest(package);
final RepositoryPackage example = package.getExamples().first;
writeFakeExampleBuildGradles(example, pluginName: packageName);
writeFakeManifest(example, isApp: true);

final List<String> output =
await runCapturingPrint(runner, <String>['gradle-check']);

expect(
output,
containsAllInOrder(<Matcher>[
contains('Validating android/build.gradle'),
]),
);
});

test('fails if set to flutter.compileSdkVersion with Flutter <3.27',
() async {
const String packageName = 'a_package';
final RepositoryPackage package = createFakePackage(
packageName, packagesDir,
isFlutter: true, flutterConstraint: '>=3.24.0');
writeFakePluginBuildGradle(package,
includeLanguageVersion: true,
compileSdk: 'flutter.compileSdkVersion');
writeFakeManifest(package);
final RepositoryPackage example = package.getExamples().first;
writeFakeExampleBuildGradles(example, pluginName: packageName);
writeFakeManifest(example, isApp: true);

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('Use of flutter.compileSdkVersion requires a minimum '
'Flutter version of 3.27, but this package currently supports '
'3.24.0'),
]),
);
});

test('fails if uses the legacy key', () async {
const String packageName = 'a_package';
final RepositoryPackage package =
createFakePackage(packageName, packagesDir, isFlutter: true);
writeFakePluginBuildGradle(package,
includeLanguageVersion: true, useDeprecatedCompileSdkVersion: true);
writeFakeManifest(package);
final RepositoryPackage example = package.getExamples().first;
writeFakeExampleBuildGradles(example, pluginName: packageName);
writeFakeManifest(example, isApp: true);

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('Please replace the deprecated "compileSdkVersion" setting '
'with the newer "compileSdk"'),
]),
);
});
});
}