add version to pubspec.yaml (#16857)
Uses the `version` property from the `pubspec.yaml` file to set the corresponding fields in the `local.properties` file respectively in the `Generated.xcconfig` file.
The `--build-name` and `--build-number` options have changed. Now they trump the `version` property from the `pubspec.yaml` file.
If the `version` property is not set and the `--build-name` and `--build-number` options are not provided, the build command will not change the `local.properties` / `Generated.xcconfig` file.
diff --git a/packages/flutter_tools/test/android/gradle_test.dart b/packages/flutter_tools/test/android/gradle_test.dart
index 5da37d5..c03af96 100644
--- a/packages/flutter_tools/test/android/gradle_test.dart
+++ b/packages/flutter_tools/test/android/gradle_test.dart
@@ -2,16 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
+
import 'package:flutter_tools/src/android/gradle.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
+import 'package:flutter_tools/src/cache.dart';
import 'package:test/test.dart';
import '../src/common.dart';
+import '../src/context.dart';
void main() {
group('gradle build', () {
- test('do not crash if there is no Android SDK', () {
+ test('do not crash if there is no Android SDK', () async {
Exception shouldBeToolExit;
try {
// We'd like to always set androidSdk to null and test updateLocalProperties. But that's
@@ -21,7 +25,7 @@
// This test is written to fail if our bots get Android SDKs in the future: shouldBeToolExit
// will be null and our expectation would fail. That would remind us to make these tests
// hermetic before adding Android SDKs to the bots.
- updateLocalProperties();
+ await updateLocalProperties();
} on Exception catch (e) {
shouldBeToolExit = e;
}
@@ -126,4 +130,181 @@
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
});
});
+
+ group('Gradle local.properties', () {
+ Directory temp;
+
+ setUp(() {
+ Cache.disableLocking();
+ temp = fs.systemTempDirectory.createTempSync('flutter_tools');
+ });
+
+ tearDown(() {
+ temp.deleteSync(recursive: true);
+ });
+
+ Future<String> createMinimalProject(String manifest) async {
+ final Directory directory = temp.childDirectory('android_project');
+ final File manifestFile = directory.childFile('pubspec.yaml');
+ manifestFile.createSync(recursive: true);
+ manifestFile.writeAsStringSync(manifest);
+
+ return directory.path;
+ }
+
+ String propertyFor(String key, File file) {
+ return file
+ .readAsLinesSync()
+ .where((String line) => line.startsWith('$key='))
+ .map((String line) => line.split('=')[1])
+ .first;
+ }
+
+ Future<void> checkBuildVersion({
+ String manifest,
+ BuildInfo buildInfo,
+ String expectedBuildName,
+ String expectedBuildNumber,
+ }) async {
+ final String projectPath = await createMinimalProject(manifest);
+
+ try {
+ await updateLocalProperties(projectPath: projectPath, buildInfo: buildInfo);
+
+ final String propertiesPath = fs.path.join(projectPath, 'android', 'local.properties');
+ final File localPropertiesFile = fs.file(propertiesPath);
+
+ expect(propertyFor('flutter.versionName', localPropertiesFile), expectedBuildName);
+ expect(propertyFor('flutter.versionCode', localPropertiesFile), expectedBuildNumber);
+ } on Exception {
+ // Android SDK not found, skip test
+ }
+ }
+
+ testUsingContext('extract build name and number from pubspec.yaml', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: '1',
+ );
+ });
+
+ testUsingContext('extract build name from pubspec.yaml', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: null,
+ );
+ });
+
+ testUsingContext('allow build info to override build name', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2');
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '1',
+ );
+ });
+
+ testUsingContext('allow build info to override build number', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: '3',
+ );
+ });
+
+ testUsingContext('allow build info to override build name and number', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '3',
+ );
+ });
+
+ testUsingContext('allow build info to override build name and set number', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '3',
+ );
+ });
+
+ testUsingContext('allow build info to set build name and number', () async {
+ const String manifest = '''
+name: test
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '3',
+ );
+ });
+ });
}
diff --git a/packages/flutter_tools/test/flutter_manifest_test.dart b/packages/flutter_tools/test/flutter_manifest_test.dart
index 75be31c..91c42cc 100644
--- a/packages/flutter_tools/test/flutter_manifest_test.dart
+++ b/packages/flutter_tools/test/flutter_manifest_test.dart
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
+
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
@@ -359,6 +361,118 @@
final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest);
expect(flutterManifest.isEmpty, false);
});
+
+ Future<void> checkManifestVersion({
+ String manifest,
+ String expectedAppVersion,
+ String expectedBuildName,
+ int expectedBuildNumber,
+ }) async {
+ final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest);
+ expect(flutterManifest.appVersion, expectedAppVersion);
+ expect(flutterManifest.buildName, expectedBuildName);
+ expect(flutterManifest.buildNumber, expectedBuildNumber);
+ }
+
+ test('parses major.minor.patch+build version clause', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+2
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ await checkManifestVersion(
+ manifest: manifest,
+ expectedAppVersion: '1.0.0+2',
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: 2,
+ );
+ });
+
+ test('parses major.minor+build version clause', () async {
+ const String manifest = '''
+name: test
+version: 1.0+2
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ await checkManifestVersion(
+ manifest: manifest,
+ expectedAppVersion: '1.0+2',
+ expectedBuildName: '1.0',
+ expectedBuildNumber: 2,
+ );
+ });
+
+ test('parses major+build version clause', () async {
+ const String manifest = '''
+name: test
+version: 1+2
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ await checkManifestVersion(
+ manifest: manifest,
+ expectedAppVersion: '1+2',
+ expectedBuildName: '1',
+ expectedBuildNumber: 2,
+ );
+ });
+
+ test('parses major version clause', () async {
+ const String manifest = '''
+name: test
+version: 1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ await checkManifestVersion(
+ manifest: manifest,
+ expectedAppVersion: '1',
+ expectedBuildName: '1',
+ expectedBuildNumber: null,
+ );
+ });
+
+ test('parses empty version clause', () async {
+ const String manifest = '''
+name: test
+version:
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ await checkManifestVersion(
+ manifest: manifest,
+ expectedAppVersion: null,
+ expectedBuildName: null,
+ expectedBuildNumber: null,
+ );
+ });
+ test('parses no version clause', () async {
+ const String manifest = '''
+name: test
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ await checkManifestVersion(
+ manifest: manifest,
+ expectedAppVersion: null,
+ expectedBuildName: null,
+ expectedBuildNumber: null,
+ );
+ });
});
group('FlutterManifest with MemoryFileSystem', () {
@@ -371,8 +485,7 @@
flutter:
''';
- final FlutterManifest flutterManifest = await FlutterManifest
- .createFromString(manifest);
+ final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest);
expect(flutterManifest.isEmpty, false);
}
diff --git a/packages/flutter_tools/test/ios/xcodeproj_test.dart b/packages/flutter_tools/test/ios/xcodeproj_test.dart
index dd75f93..95f74ba 100644
--- a/packages/flutter_tools/test/ios/xcodeproj_test.dart
+++ b/packages/flutter_tools/test/ios/xcodeproj_test.dart
@@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
+
import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/build_info.dart';
+import 'package:flutter_tools/src/bundle.dart' as bundle;
+import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
@@ -277,14 +281,14 @@
});
}
- testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () {
+ testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () async {
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, any)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
const BuildInfo buildInfo = const BuildInfo(BuildMode.debug, null,
previewDart2: true,
targetPlatform: TargetPlatform.ios,
);
- updateGeneratedXcodeProperties(
+ await updateGeneratedXcodeProperties(
projectPath: 'path/to/project',
buildInfo: buildInfo,
previewDart2: true,
@@ -297,14 +301,14 @@
expect(contents.contains('ARCHS=armv7'), isTrue);
});
- testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () {
+ testUsingOsxContext('sets ARCHS=armv7 when armv7 local engine is set', () async {
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, any)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile'));
const BuildInfo buildInfo = const BuildInfo(BuildMode.debug, null,
previewDart2: true,
targetPlatform: TargetPlatform.ios,
);
- updateGeneratedXcodeProperties(
+ await updateGeneratedXcodeProperties(
projectPath: 'path/to/project',
buildInfo: buildInfo,
previewDart2: true,
@@ -317,6 +321,185 @@
expect(contents.contains('ARCHS=arm64'), isTrue);
});
});
+
+ group('Xcode Generated.xcconfig', () {
+ Directory temp;
+
+ setUp(() {
+ Cache.disableLocking();
+ temp = fs.systemTempDirectory.createTempSync('flutter_tools');
+ });
+
+ tearDown(() {
+ temp.deleteSync(recursive: true);
+ });
+
+ Future<String> createMinimalProject(String manifest) async {
+ final Directory directory = temp.childDirectory('ios_project');
+ final File manifestFile = directory.childFile('pubspec.yaml');
+ manifestFile.createSync(recursive: true);
+ manifestFile.writeAsStringSync(manifest);
+
+ return directory.path;
+ }
+
+ String propertyFor(String key, File file) {
+ final List<String> properties = file
+ .readAsLinesSync()
+ .where((String line) => line.startsWith('$key='))
+ .map((String line) => line.split('=')[1])
+ .toList();
+ return properties.isEmpty ? null : properties.first;
+ }
+
+ Future<void> checkBuildVersion({
+ String manifest,
+ BuildInfo buildInfo,
+ String expectedBuildName,
+ String expectedBuildNumber,
+ }) async {
+ final String projectPath = await createMinimalProject(manifest);
+
+ await updateGeneratedXcodeProperties(
+ projectPath: projectPath,
+ buildInfo: buildInfo,
+ targetOverride: bundle.defaultMainPath,
+ previewDart2: false,
+ );
+
+ final String propertiesPath = fs.path.join(projectPath, 'ios', 'Flutter', 'Generated.xcconfig');
+ final File localPropertiesFile = fs.file(propertiesPath);
+
+ expect(propertyFor('FLUTTER_BUILD_NAME', localPropertiesFile), expectedBuildName);
+ expect(propertyFor('FLUTTER_BUILD_NUMBER', localPropertiesFile), expectedBuildNumber);
+ }
+
+ testUsingContext('extract build name and number from pubspec.yaml', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: '1',
+ );
+ });
+
+ testUsingContext('extract build name from pubspec.yaml', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: null,
+ );
+ });
+
+ testUsingContext('allow build info to override build name', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2');
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '1',
+ );
+ });
+
+ testUsingContext('allow build info to override build number', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.0',
+ expectedBuildNumber: '3',
+ );
+ });
+
+ testUsingContext('allow build info to override build name and number', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0+1
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '3',
+ );
+ });
+
+ testUsingContext('allow build info to override build name and set number', () async {
+ const String manifest = '''
+name: test
+version: 1.0.0
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '3',
+ );
+ });
+
+ testUsingContext('allow build info to set build name and number', () async {
+ const String manifest = '''
+name: test
+dependencies:
+ flutter:
+ sdk: flutter
+flutter:
+''';
+ const BuildInfo buildInfo = const BuildInfo(BuildMode.release, null, buildName: '1.0.2', buildNumber: 3);
+ await checkBuildVersion(
+ manifest: manifest,
+ buildInfo: buildInfo,
+ expectedBuildName: '1.0.2',
+ expectedBuildNumber: '3',
+ );
+ });
+ });
}
Platform fakePlatform(String name) {
diff --git a/packages/flutter_tools/test/project_test.dart b/packages/flutter_tools/test/project_test.dart
index 632018d..8955187 100644
--- a/packages/flutter_tools/test/project_test.dart
+++ b/packages/flutter_tools/test/project_test.dart
@@ -20,23 +20,23 @@
group('ensure ready for platform-specific tooling', () {
testInMemory('does nothing, if project is not created', () async {
final FlutterProject project = someProject();
- project.ensureReadyForPlatformSpecificTooling();
+ await project.ensureReadyForPlatformSpecificTooling();
expect(project.directory.existsSync(), isFalse);
});
testInMemory('does nothing in plugin or package root project', () async {
final FlutterProject project = aPluginProject();
- project.ensureReadyForPlatformSpecificTooling();
+ await project.ensureReadyForPlatformSpecificTooling();
expect(project.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isFalse);
expect(project.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isFalse);
});
testInMemory('injects plugins', () async {
final FlutterProject project = aProjectWithIos();
- project.ensureReadyForPlatformSpecificTooling();
+ await project.ensureReadyForPlatformSpecificTooling();
expect(project.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isTrue);
});
testInMemory('generates Xcode configuration', () async {
final FlutterProject project = aProjectWithIos();
- project.ensureReadyForPlatformSpecificTooling();
+ await project.ensureReadyForPlatformSpecificTooling();
expect(project.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isTrue);
});
});