Skip to content

Commit 3d5e965

Browse files
stuartmorgan-gnploi
authored andcommitted
[tool] Move Android lint checks (flutter#3816)
Moves the checks for Android warning configuration from `lint-android`, where it made sense to put them at the time, to the new `check-gradle`, which is a newer command specifically for validating that our Gradle files are following best practices. Makes minor changes to the Pigeon platform test projects to make them conform to the checks, since they are now included in the run. The changes shouldn't actually change the behavior of the Pigeon tests.
1 parent 7de6c1a commit 3d5e965

File tree

9 files changed

+370
-253
lines changed

9 files changed

+370
-253
lines changed

packages/pigeon/platform_tests/alternate_language_test_plugin/android/build.gradle

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,3 @@ android {
5757
testImplementation "org.mockito:mockito-core:5.1.1"
5858
}
5959
}
60-
61-
project.getTasks().withType(JavaCompile){
62-
options.compilerArgs.addAll(["-Xlint:all", "-Werror"])
63-
}

packages/pigeon/platform_tests/alternate_language_test_plugin/example/android/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,11 @@ subprojects {
2929
task clean(type: Delete) {
3030
delete rootProject.buildDir
3131
}
32+
33+
gradle.projectsEvaluated {
34+
project(":alternate_language_test_plugin") {
35+
tasks.withType(JavaCompile) {
36+
options.compilerArgs << "-Xlint:all" << "-Werror"
37+
}
38+
}
39+
}

packages/pigeon/platform_tests/test_plugin/android/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ android {
5858
}
5959
}
6060

61+
lintOptions {
62+
checkAllWarnings true
63+
warningsAsErrors true
64+
disable 'AndroidGradlePluginVersion', 'InvalidPackage', 'GradleDependency'
65+
}
66+
6167
dependencies {
6268
testImplementation 'junit:junit:4.+'
6369
testImplementation "io.mockk:mockk:1.13.5"

packages/pigeon/platform_tests/test_plugin/example/android/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,11 @@ subprojects {
2929
task clean(type: Delete) {
3030
delete rootProject.buildDir
3131
}
32+
33+
gradle.projectsEvaluated {
34+
project(":test_plugin") {
35+
tasks.withType(JavaCompile) {
36+
options.compilerArgs << "-Xlint:all" << "-Werror"
37+
}
38+
}
39+
}

script/tool/lib/src/common/repository_package.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,19 @@ class RepositoryPackage {
151151
.map((FileSystemEntity entity) =>
152152
RepositoryPackage(entity as Directory));
153153
}
154+
155+
/// Returns the package that this package is a part of, if any.
156+
///
157+
/// Currently this is limited to checking up two directories, since that
158+
/// covers all the example structures currently used.
159+
RepositoryPackage? getEnclosingPackage() {
160+
final Directory parent = directory.parent;
161+
if (isPackage(parent)) {
162+
return RepositoryPackage(parent);
163+
}
164+
if (isPackage(parent.parent)) {
165+
return RepositoryPackage(parent.parent);
166+
}
167+
return null;
168+
}
154169
}

script/tool/lib/src/gradle_check_command.dart

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:file/file.dart';
66

77
import 'common/core.dart';
88
import 'common/package_looping_command.dart';
9+
import 'common/plugin_utils.dart';
910
import 'common/repository_package.dart';
1011

1112
/// A command to enforce gradle file conventions and best practices.
@@ -84,6 +85,8 @@ class GradleCheckCommand extends PackageLoopingCommand {
8485
.childFile('AndroidManifest.xml');
8586
}
8687

88+
bool _isCommented(String line) => line.trim().startsWith('//');
89+
8790
/// Validates the build.gradle file for a plugin
8891
/// (some_plugin/android/build.gradle).
8992
bool _validatePluginBuildGradle(RepositoryPackage package, File gradleFile) {
@@ -101,6 +104,9 @@ class GradleCheckCommand extends PackageLoopingCommand {
101104
if (!_validateSourceCompatibilityVersion(lines)) {
102105
succeeded = false;
103106
}
107+
if (!_validateGradleDrivenLintConfig(package, lines)) {
108+
succeeded = false;
109+
}
104110
return succeeded;
105111
}
106112

@@ -110,9 +116,16 @@ class GradleCheckCommand extends PackageLoopingCommand {
110116
RepositoryPackage package, File gradleFile) {
111117
print('${indentation}Validating '
112118
'${getRelativePosixPath(gradleFile, from: package.directory)}.');
113-
// TODO(stuartmorgan): Move the -Xlint validation from lint_android_command
114-
// to here.
115-
return true;
119+
final String contents = gradleFile.readAsStringSync();
120+
final List<String> lines = contents.split('\n');
121+
122+
// This is tracked as a variable rather than a sequence of &&s so that all
123+
// failures are reported at once, not just the first one.
124+
bool succeeded = true;
125+
if (!_validateJavacLintConfig(package, lines)) {
126+
succeeded = false;
127+
}
128+
return succeeded;
116129
}
117130

118131
/// Validates the app-level build.gradle for an example app (e.g.,
@@ -193,11 +206,9 @@ build.gradle "namespace" must match the "package" attribute in AndroidManifest.x
193206
/// lead to compile errors that show up for clients, but not in CI).
194207
bool _validateSourceCompatibilityVersion(List<String> gradleLines) {
195208
if (!gradleLines.any((String line) =>
196-
line.contains('languageVersion') &&
197-
!line.trim().startsWith('//')) &&
209+
line.contains('languageVersion') && !_isCommented(line)) &&
198210
!gradleLines.any((String line) =>
199-
line.contains('sourceCompatibility') &&
200-
!line.trim().startsWith('//'))) {
211+
line.contains('sourceCompatibility') && !_isCommented(line))) {
201212
const String errorMessage = '''
202213
build.gradle must set an explicit Java compatibility version.
203214
@@ -225,4 +236,75 @@ for more details.''';
225236
}
226237
return true;
227238
}
239+
240+
/// Returns whether the given gradle content is configured to enable all
241+
/// Gradle-driven lints (those checked by ./gradlew lint) and treat them as
242+
/// errors.
243+
bool _validateGradleDrivenLintConfig(
244+
RepositoryPackage package, List<String> gradleLines) {
245+
final List<String> gradleBuildContents = package
246+
.platformDirectory(FlutterPlatform.android)
247+
.childFile('build.gradle')
248+
.readAsLinesSync();
249+
if (!gradleBuildContents.any((String line) =>
250+
line.contains('checkAllWarnings true') && !_isCommented(line)) ||
251+
!gradleBuildContents.any((String line) =>
252+
line.contains('warningsAsErrors true') && !_isCommented(line))) {
253+
printError('${indentation}This package is not configured to enable all '
254+
'Gradle-driven lint warnings and treat them as errors. '
255+
'Please add the following to the lintOptions section of '
256+
'android/build.gradle:');
257+
print('''
258+
checkAllWarnings true
259+
warningsAsErrors true
260+
''');
261+
return false;
262+
}
263+
return true;
264+
}
265+
266+
/// Validates whether the given [example]'s gradle content is configured to
267+
/// build its plugin target with javac lints enabled and treated as errors,
268+
/// if the enclosing package is a plugin.
269+
///
270+
/// This can only be called on example packages. (Plugin packages should not
271+
/// be configured this way, since it would affect clients.)
272+
///
273+
/// If [example]'s enclosing package is not a plugin package, this just
274+
/// returns true.
275+
bool _validateJavacLintConfig(
276+
RepositoryPackage example, List<String> gradleLines) {
277+
final RepositoryPackage enclosingPackage = example.getEnclosingPackage()!;
278+
if (!pluginSupportsPlatform(platformAndroid, enclosingPackage,
279+
requiredMode: PlatformSupport.inline)) {
280+
return true;
281+
}
282+
final String enclosingPackageName = enclosingPackage.directory.basename;
283+
284+
// The check here is intentionally somewhat loose, to allow for the
285+
// possibility of variations (e.g., not using Xlint:all in some cases, or
286+
// passing other arguments).
287+
if (!(gradleLines.any((String line) =>
288+
line.contains('project(":$enclosingPackageName")')) &&
289+
gradleLines.any((String line) =>
290+
line.contains('options.compilerArgs') &&
291+
line.contains('-Xlint') &&
292+
line.contains('-Werror')))) {
293+
printError('The example '
294+
'"${getRelativePosixPath(example.directory, from: enclosingPackage.directory)}" '
295+
'is not configured to treat javac lints and warnings as errors. '
296+
'Please add the following to its build.gradle:');
297+
print('''
298+
gradle.projectsEvaluated {
299+
project(":$enclosingPackageName") {
300+
tasks.withType(JavaCompile) {
301+
options.compilerArgs << "-Xlint:all" << "-Werror"
302+
}
303+
}
304+
}
305+
''');
306+
return false;
307+
}
308+
return true;
309+
}
228310
}

script/tool/lib/src/lint_android_command.dart

Lines changed: 2 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,6 @@ class LintAndroidCommand extends PackageLoopingCommand {
3838
'Plugin does not have an Android implementation.');
3939
}
4040

41-
bool failed = false;
42-
43-
// Ensure that the plugin has a strict Gradle-driven lint configuration, so
44-
// that this test actually catches most issues.
45-
if (!_mainGradleHasLintConfig(package)) {
46-
failed = true;
47-
printError('This plugin is not configured to enable all Gradle-driven '
48-
'lint warnings and treat them as errors. '
49-
'Please add the following to the lintOptions section of '
50-
'android/build.gradle:');
51-
print('''
52-
checkAllWarnings true
53-
warningsAsErrors true
54-
''');
55-
}
56-
5741
for (final RepositoryPackage example in package.getExamples()) {
5842
final GradleProject project = GradleProject(example,
5943
processRunner: processRunner, platform: platform);
@@ -75,62 +59,10 @@ class LintAndroidCommand extends PackageLoopingCommand {
7559
// inline, and the rest have to be checked via the CI-uploaded artifact.
7660
final int exitCode = await project.runCommand('$packageName:lintDebug');
7761
if (exitCode != 0) {
78-
failed = true;
62+
return PackageResult.fail();
7963
}
80-
81-
// In addition to running the Gradle-driven lint step, also ensure that
82-
// the example project is configured to build with javac lints enabled and
83-
// treated as errors.
84-
if (!_exampleGradleHasJavacLintConfig(example, packageName)) {
85-
failed = true;
86-
printError('The example '
87-
'"${getRelativePosixPath(example.directory, from: package.directory)}" '
88-
'is not configured to treat javac lints and warnings as errors. '
89-
'Please add the following to its build.gradle:');
90-
print('''
91-
gradle.projectsEvaluated {
92-
project(":${package.directory.basename}") {
93-
tasks.withType(JavaCompile) {
94-
options.compilerArgs << "-Xlint:all" << "-Werror"
95-
}
9664
}
97-
}
98-
''');
99-
}
100-
}
101-
102-
return failed ? PackageResult.fail() : PackageResult.success();
103-
}
104-
105-
/// Returns whether the plugin project is configured to enable all Gradle
106-
/// lints and treat them as errors.
107-
bool _mainGradleHasLintConfig(RepositoryPackage package) {
108-
final List<String> gradleBuildContents = package
109-
.platformDirectory(FlutterPlatform.android)
110-
.childFile('build.gradle')
111-
.readAsLinesSync();
112-
return gradleBuildContents
113-
.any((String line) => line.contains('checkAllWarnings true')) &&
114-
gradleBuildContents
115-
.any((String line) => line.contains('warningsAsErrors true'));
116-
}
11765

118-
/// Returns whether the example project is configured to build with javac
119-
/// lints enabled and treated as errors.
120-
bool _exampleGradleHasJavacLintConfig(
121-
RepositoryPackage example, String pluginPackageName) {
122-
final List<String> gradleBuildContents = example
123-
.platformDirectory(FlutterPlatform.android)
124-
.childFile('build.gradle')
125-
.readAsLinesSync();
126-
// The check here is intentionally somewhat loose, to allow for the
127-
// possibility of variations (e.g., not using Xlint:all in some cases, or
128-
// passing other arguments).
129-
return gradleBuildContents.any(
130-
(String line) => line.contains('project(":$pluginPackageName")')) &&
131-
gradleBuildContents.any((String line) =>
132-
line.contains('options.compilerArgs') &&
133-
line.contains('-Xlint') &&
134-
line.contains('-Werror'));
66+
return PackageResult.success();
13567
}
13668
}

0 commit comments

Comments
 (0)