Skip to content
Merged
32 changes: 30 additions & 2 deletions script/tool/lib/src/update_dependency_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class UpdateDependencyCommand extends PackageLoopingCommand {
allowed: <String>[
_AndroidDependencyType.gradle,
_AndroidDependencyType.androidGradlePlugin,
_AndroidDependencyType.kotlinGradlePlugin,
_AndroidDependencyType.compileSdk,
_AndroidDependencyType.compileSdkForExamples,
],
Expand All @@ -53,6 +54,8 @@ class UpdateDependencyCommand extends PackageLoopingCommand {
'Updates Gradle version used in plugin example apps.',
_AndroidDependencyType.androidGradlePlugin:
'Updates AGP version used in plugin example apps.',
_AndroidDependencyType.kotlinGradlePlugin:
'Updates KGP version used in plugin example apps.',
_AndroidDependencyType.compileSdk:
'Updates compileSdk version used to compile plugins.',
_AndroidDependencyType.compileSdkForExamples:
Expand Down Expand Up @@ -155,6 +158,19 @@ A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) mus
3. If present, the third number must have a single digit''');
throw ToolExit(_exitInvalidTargetVersion);
}
} else if (_targetAndroidDependency ==
_AndroidDependencyType.kotlinGradlePlugin) {
final RegExp validKgpVersionPattern = RegExp(r'^\d\.\d\.\d{1,2}$');
final bool isValidKgpVersion =
validKgpVersionPattern.stringMatch(version) == version;
if (!isValidKgpVersion) {
printError('''
A version with a valid format (3 numbers separated by 2 periods) must be provided.
1. The first number must have one digit
2. The second number must have one digit
3. The third number must have one or two digits''');
throw ToolExit(_exitInvalidTargetVersion);
}
} else if (_targetAndroidDependency ==
_AndroidDependencyType.compileSdk ||
_targetAndroidDependency ==
Expand Down Expand Up @@ -266,7 +282,8 @@ A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) mus
_targetAndroidDependency ==
_AndroidDependencyType.compileSdkForExamples ||
_targetAndroidDependency ==
_AndroidDependencyType.androidGradlePlugin) {
_AndroidDependencyType.androidGradlePlugin ||
_targetAndroidDependency == _AndroidDependencyType.kotlinGradlePlugin) {
return _runForAndroidDependencyOnExamples(package);
}

Expand Down Expand Up @@ -334,7 +351,17 @@ A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) mus
r'^\s*id\s+"com\.android\.application"\s+version\s+"(\d{1,2}\.\d{1,2}(?:\.\d)?)"\s+apply\s+false\s*$',
multiLine: true);
newDependencyVersionEntry =
' id "com.android.application" version "$_targetVersion" apply false';
'id "com.android.application" version "$_targetVersion" apply false';
} else if (_targetAndroidDependency ==
_AndroidDependencyType.kotlinGradlePlugin) {
if (androidDirectory.childFile('settings.gradle').existsSync()) {
filesToUpdate.add(androidDirectory.childFile('settings.gradle'));
}
dependencyVersionPattern = RegExp(
r'^\s*id\s+"org\.jetbrains\.kotlin\.android"\s+version\s+"(\d\.\d\.\d{1,2})"\s+apply\s+false\s*$',
multiLine: true);
newDependencyVersionEntry =
' id "org.jetbrains.kotlin.android" version "$_targetVersion" apply false';
} else {
printError(
'Target Android dependency $_targetAndroidDependency is unrecognized.');
Expand Down Expand Up @@ -525,6 +552,7 @@ enum _PubDependencyType { normal, dev }
class _AndroidDependencyType {
static const String gradle = 'gradle';
static const String androidGradlePlugin = 'androidGradlePlugin';
static const String kotlinGradlePlugin = 'kotlinGradlePlugin';
static const String compileSdk = 'compileSdk';
static const String compileSdkForExamples = 'compileSdkForExamples';
}
170 changes: 158 additions & 12 deletions script/tool/test/update_dependency_command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,18 @@ dev_dependencies:
'8.12.12'
];

const String invalidGradleAgpVersionError = '''
A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) must be provided.
1. The first number must have one or two digits
2. The second number must have one or two digits
3. If present, the third number must have a single digit''';

const String invalidKgpVersionError = '''
A version with a valid format (3 numbers separated by 2 periods) must be provided.
1. The first number must have one digit
2. The second number must have one digit
3. The third number must have one or two digits''';

group('gradle', () {
for (final String gradleVersion in invalidGradleAgpVersionsFormat) {
test('throws because gradleVersion: $gradleVersion is invalid',
Expand All @@ -633,11 +645,7 @@ dev_dependencies:
expect(
output,
containsAllInOrder(<Matcher>[
contains('''
A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) must be provided.
1. The first number must have one or two digits
2. The second number must have one or two digits
3. If present, the third number must have a single digit'''),
contains(invalidGradleAgpVersionError),
]),
);
});
Expand Down Expand Up @@ -925,11 +933,7 @@ distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
expect(
output,
containsAllInOrder(<Matcher>[
contains('''
A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) must be provided.
1. The first number must have one or two digits
2. The second number must have one or two digits
3. If present, the third number must have a single digit'''),
contains(invalidGradleAgpVersionError),
]),
);
});
Expand Down Expand Up @@ -994,7 +998,7 @@ plugins {

expect(
updatedGradleSettingsContents,
contains(r' id "com.android.application" version '
contains(r'id "com.android.application" version '
'"$newAgpVersion" apply false'));
});

Expand Down Expand Up @@ -1037,10 +1041,152 @@ plugins {

expect(
updatedGradleSettingsContents,
contains(r' id "com.android.application" version '
contains(r'id "com.android.application" version '
'"$newAgpVersion" apply false'));
});
});
group('kgp', () {
final List<String> invalidKgpVersionsFormat = <String>[
'81',
'81.1',
'8.123',
'8.12.12',
'8.12.1',
];

for (final String kgpVersion in invalidKgpVersionsFormat) {
test('throws because kgpVersion: $kgpVersion is invalid', () async {
Error? commandError;
final List<String> output = await runCapturingPrint(runner, <String>[
'update-dependency',
'--android-dependency',
'kotlinGradlePlugin',
'--version',
kgpVersion,
], errorHandler: (Error e) {
commandError = e;
});

expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains(invalidKgpVersionError),
]),
);
});
}

test('skips if example app does not run on Android', () async {
final RepositoryPackage package =
createFakePlugin('fake_plugin', packagesDir);

final List<String> output = await runCapturingPrint(runner, <String>[
'update-dependency',
'--packages',
package.displayName,
'--android-dependency',
'kotlinGradlePlugin',
'--version',
'2.2.20',
], errorHandler: (Error e) {
print((e as ToolExit).stackTrace);
});

expect(
output,
containsAllInOrder(<Matcher>[
contains('SKIPPING: No example apps run on Android.'),
]),
);
});

test('succeeds if example app has android/settings.gradle structure',
() async {
final RepositoryPackage package = createFakePlugin(
'fake_plugin', packagesDir,
extraFiles: <String>['example/android/settings.gradle']);
const String newKgpVersion = '2.2.20';

final File gradleSettingsFile = package.directory
.childDirectory('example')
.childDirectory('android')
.childFile('settings.gradle');

gradleSettingsFile.writeAsStringSync(r'''
...
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
...
id "org.jetbrains.kotlin.android" version "2.2.20" apply false
...
}
...
''');

await runCapturingPrint(runner, <String>[
'update-dependency',
'--packages',
package.displayName,
'--android-dependency',
'kotlinGradlePlugin',
'--version',
newKgpVersion,
]);

final String updatedGradleSettingsContents =
gradleSettingsFile.readAsStringSync();

expect(
updatedGradleSettingsContents,
contains(r' id "org.jetbrains.kotlin.android" version '
'"$newKgpVersion" apply false'));
});

test('succeeds if one example app runs on Android and another does not',
() async {
final RepositoryPackage package = createFakePlugin(
'fake_plugin', packagesDir,
examples: <String>['example_1', 'example_2'],
extraFiles: <String>['example/example_2/android/settings.gradle']);
const String newKgpVersion = '2.2.20';

final File gradleSettingsFile = package.directory
.childDirectory('example')
.childDirectory('example_2')
.childDirectory('android')
.childFile('settings.gradle');

gradleSettingsFile.writeAsStringSync(r'''
...
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
...
id "org.jetbrains.kotlin.android" version "2.2.20" apply false
...
}
...
''');

await runCapturingPrint(runner, <String>[
'update-dependency',
'--packages',
package.displayName,
'--android-dependency',
'kotlinGradlePlugin',
'--version',
newKgpVersion,
]);

final String updatedGradleSettingsContents =
gradleSettingsFile.readAsStringSync();

expect(
updatedGradleSettingsContents,
contains(r' id "org.jetbrains.kotlin.android" version '
'"$newKgpVersion" apply false'));
});
});

group('compileSdk/compileSdkForExamples', () {
// Tests if the compileSdk version is updated for the provided
Expand Down