mirror of
https://github.com/flutter/packages.git
synced 2025-06-09 22:35:33 +08:00

Standardizes all first-party copyrights on a single year, as is done in flutter/flutter and flutter/engine. All code now uses 2013, which is the earliest year that was in any existing copyright notice. The script checks now enforce the exact format of first-party licenses and copyrights. Fixes flutter/flutter#78448
238 lines
8.2 KiB
Dart
238 lines
8.2 KiB
Dart
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:meta/meta.dart';
|
|
import 'package:file/file.dart';
|
|
import 'package:git/git.dart';
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
import 'package:pubspec_parse/pubspec_parse.dart';
|
|
|
|
import 'common.dart';
|
|
|
|
const String _kBaseSha = 'base-sha';
|
|
|
|
enum NextVersionType {
|
|
BREAKING_MAJOR,
|
|
MAJOR_NULLSAFETY_PRE_RELEASE,
|
|
MINOR_NULLSAFETY_PRE_RELEASE,
|
|
MINOR,
|
|
PATCH,
|
|
RELEASE,
|
|
}
|
|
|
|
Version getNextNullSafetyPreRelease(Version current, Version next) {
|
|
String nextNullsafetyPrerelease = 'nullsafety';
|
|
if (current.isPreRelease &&
|
|
current.preRelease.first is String &&
|
|
current.preRelease.first == 'nullsafety') {
|
|
if (current.preRelease.length == 1) {
|
|
nextNullsafetyPrerelease = 'nullsafety.1';
|
|
} else if (current.preRelease.length == 2 &&
|
|
current.preRelease.last is int) {
|
|
nextNullsafetyPrerelease = 'nullsafety.${current.preRelease.last + 1}';
|
|
}
|
|
}
|
|
return Version(
|
|
next.major,
|
|
next.minor,
|
|
next.patch,
|
|
pre: nextNullsafetyPrerelease,
|
|
);
|
|
}
|
|
|
|
@visibleForTesting
|
|
Map<Version, NextVersionType> getAllowedNextVersions(
|
|
Version masterVersion, Version headVersion) {
|
|
final Version nextNullSafetyMajor =
|
|
getNextNullSafetyPreRelease(masterVersion, masterVersion.nextMajor);
|
|
final Version nextNullSafetyMinor =
|
|
getNextNullSafetyPreRelease(masterVersion, masterVersion.nextMinor);
|
|
final Map<Version, NextVersionType> allowedNextVersions =
|
|
<Version, NextVersionType>{
|
|
masterVersion.nextMajor: NextVersionType.BREAKING_MAJOR,
|
|
nextNullSafetyMajor: NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE,
|
|
nextNullSafetyMinor: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE,
|
|
masterVersion.nextMinor: NextVersionType.MINOR,
|
|
masterVersion.nextPatch: NextVersionType.PATCH,
|
|
};
|
|
|
|
if (masterVersion.major < 1 && headVersion.major < 1) {
|
|
int nextBuildNumber = -1;
|
|
if (masterVersion.build.isEmpty) {
|
|
nextBuildNumber = 1;
|
|
} else {
|
|
final int currentBuildNumber = masterVersion.build.first;
|
|
nextBuildNumber = currentBuildNumber + 1;
|
|
}
|
|
final Version preReleaseVersion = Version(
|
|
masterVersion.major,
|
|
masterVersion.minor,
|
|
masterVersion.patch,
|
|
build: nextBuildNumber.toString(),
|
|
);
|
|
allowedNextVersions.clear();
|
|
allowedNextVersions[masterVersion.nextMajor] = NextVersionType.RELEASE;
|
|
allowedNextVersions[masterVersion.nextMinor] =
|
|
NextVersionType.BREAKING_MAJOR;
|
|
allowedNextVersions[masterVersion.nextPatch] = NextVersionType.MINOR;
|
|
allowedNextVersions[preReleaseVersion] = NextVersionType.PATCH;
|
|
|
|
final Version nextNullSafetyMajor =
|
|
getNextNullSafetyPreRelease(masterVersion, masterVersion.nextMinor);
|
|
final Version nextNullSafetyMinor =
|
|
getNextNullSafetyPreRelease(masterVersion, masterVersion.nextPatch);
|
|
|
|
allowedNextVersions[nextNullSafetyMajor] =
|
|
NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE;
|
|
allowedNextVersions[nextNullSafetyMinor] =
|
|
NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE;
|
|
}
|
|
return allowedNextVersions;
|
|
}
|
|
|
|
class VersionCheckCommand extends PluginCommand {
|
|
VersionCheckCommand(
|
|
Directory packagesDir,
|
|
FileSystem fileSystem, {
|
|
ProcessRunner processRunner = const ProcessRunner(),
|
|
GitDir gitDir,
|
|
}) : super(packagesDir, fileSystem,
|
|
processRunner: processRunner, gitDir: gitDir);
|
|
|
|
@override
|
|
final String name = 'version-check';
|
|
|
|
@override
|
|
final String description =
|
|
'Checks if the versions of the plugins have been incremented per pub specification.\n'
|
|
'Also checks if the latest version in CHANGELOG matches the version in pubspec.\n\n'
|
|
'This command requires "pub" and "flutter" to be in your path.';
|
|
|
|
@override
|
|
Future<Null> run() async {
|
|
checkSharding();
|
|
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();
|
|
|
|
final List<String> changedPubspecs =
|
|
await gitVersionFinder.getChangedPubSpecs();
|
|
|
|
final String baseSha = argResults[_kBaseSha];
|
|
for (final String pubspecPath in changedPubspecs) {
|
|
try {
|
|
final File pubspecFile = fileSystem.file(pubspecPath);
|
|
if (!pubspecFile.existsSync()) {
|
|
continue;
|
|
}
|
|
final Pubspec pubspec = Pubspec.parse(pubspecFile.readAsStringSync());
|
|
if (pubspec.publishTo == 'none') {
|
|
continue;
|
|
}
|
|
|
|
final Version masterVersion =
|
|
await gitVersionFinder.getPackageVersion(pubspecPath, baseSha);
|
|
final Version headVersion =
|
|
await gitVersionFinder.getPackageVersion(pubspecPath, 'HEAD');
|
|
if (headVersion == null) {
|
|
continue; // Example apps don't have versions
|
|
}
|
|
|
|
final Map<Version, NextVersionType> allowedNextVersions =
|
|
getAllowedNextVersions(masterVersion, headVersion);
|
|
|
|
if (!allowedNextVersions.containsKey(headVersion)) {
|
|
final String error = '$pubspecPath incorrectly updated version.\n'
|
|
'HEAD: $headVersion, master: $masterVersion.\n'
|
|
'Allowed versions: $allowedNextVersions';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
|
|
bool isPlatformInterface = pubspec.name.endsWith("_platform_interface");
|
|
if (isPlatformInterface &&
|
|
allowedNextVersions[headVersion] ==
|
|
NextVersionType.BREAKING_MAJOR) {
|
|
final String error = '$pubspecPath breaking change detected.\n'
|
|
'Breaking changes to platform interfaces are strongly discouraged.\n';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
} on io.ProcessException {
|
|
print('Unable to find pubspec in master for $pubspecPath.'
|
|
' Safe to ignore if the project is new.');
|
|
}
|
|
}
|
|
|
|
await for (Directory plugin in getPlugins()) {
|
|
await _checkVersionsMatch(plugin);
|
|
}
|
|
|
|
print('No version check errors found!');
|
|
}
|
|
|
|
Future<void> _checkVersionsMatch(Directory plugin) async {
|
|
// get version from pubspec
|
|
final String packageName = plugin.basename;
|
|
print('-----------------------------------------');
|
|
print(
|
|
'Checking the first version listed in CHANGELOG.MD matches the version in pubspec.yaml for $packageName.');
|
|
|
|
final Pubspec pubspec = _tryParsePubspec(plugin);
|
|
if (pubspec == null) {
|
|
final String error = 'Cannot parse version from pubspec.yaml';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
final Version fromPubspec = pubspec.version;
|
|
|
|
// get first version from CHANGELOG
|
|
final File changelog = plugin.childFile('CHANGELOG.md');
|
|
final List<String> lines = changelog.readAsLinesSync();
|
|
String firstLineWithText;
|
|
final Iterator iterator = lines.iterator;
|
|
while (iterator.moveNext()) {
|
|
if ((iterator.current as String).trim().isNotEmpty) {
|
|
firstLineWithText = iterator.current;
|
|
break;
|
|
}
|
|
}
|
|
// Remove all leading mark down syntax from the version line.
|
|
final String versionString = firstLineWithText.split(' ').last;
|
|
Version fromChangeLog = Version.parse(versionString);
|
|
if (fromChangeLog == null) {
|
|
final String error =
|
|
'Cannot find version on the first line of ${plugin.path}/CHANGELOG.md';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
|
|
if (fromPubspec != fromChangeLog) {
|
|
final String error = '''
|
|
versions for $packageName in CHANGELOG.md and pubspec.yaml do not match.
|
|
The version in pubspec.yaml is $fromPubspec.
|
|
The first version listed in CHANGELOG.md is $fromChangeLog.
|
|
''';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
print('${packageName} passed version check');
|
|
}
|
|
|
|
Pubspec _tryParsePubspec(Directory package) {
|
|
final File pubspecFile = package.childFile('pubspec.yaml');
|
|
|
|
try {
|
|
Pubspec pubspec = Pubspec.parse(pubspecFile.readAsStringSync());
|
|
if (pubspec == null) {
|
|
final String error =
|
|
'Failed to parse `pubspec.yaml` at ${pubspecFile.path}';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
return pubspec;
|
|
} on Exception catch (exception) {
|
|
final String error =
|
|
'Failed to parse `pubspec.yaml` at ${pubspecFile.path}: $exception}';
|
|
printErrorAndExit(errorMessage: error);
|
|
}
|
|
return null;
|
|
}
|
|
}
|