Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[tool] Improve check version ci so that it enforces the version in CHANGELOG and pubspec matches. #3678

Merged
merged 45 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b6eb46d
version check
Mar 4, 2021
7ae7c82
tests
Mar 4, 2021
1918666
clea n
Mar 4, 2021
4618e63
enable version-check
Mar 4, 2021
d7d03ef
remove todo
Mar 4, 2021
98dd162
version check for all plugins
Mar 4, 2021
8bd1bb0
check version
Mar 4, 2021
7cac875
remove other tests
Mar 4, 2021
0fecf79
addtional log
Mar 4, 2021
e3a1bc5
chmod
Mar 4, 2021
d2a505c
try run all
Mar 4, 2021
f8f1ed0
update log
Mar 4, 2021
e1f64e9
remove todo
Mar 4, 2021
351d467
revert .cirrus change
Mar 4, 2021
071ccfc
refactor throw tool exit
Mar 5, 2021
025a910
review 1
Mar 8, 2021
3e9e74e
format
Mar 8, 2021
94566ee
allow empty lines
Mar 8, 2021
75c6e46
get changed plugins
Mar 8, 2021
697b4bf
fix typo
Mar 8, 2021
744b7d1
rename file and bug fixes
Mar 8, 2021
30b8677
auto get base sha and tests
Mar 8, 2021
3e0ccc6
remove sh script and add the script to cirrus
Mar 8, 2021
848b67f
add log to cirrus
Mar 8, 2021
d1e3428
make plugin_tools command a var
Mar 9, 2021
87e97a6
fix command name
Mar 9, 2021
cdabfdc
get branch name
Mar 9, 2021
680665b
rename to BRANCH
Mar 9, 2021
4ed9e7a
fix typo
Mar 9, 2021
1ff63da
fix typo
Mar 9, 2021
6469c21
add run-on-changed-packages option
Mar 9, 2021
19253b6
fix cirrus
Mar 9, 2021
6c47afa
fix typo
Mar 9, 2021
0bd32d2
revert unwanted changes
Mar 9, 2021
02de427
set branch
Mar 9, 2021
f1314f6
add export
Mar 9, 2021
e2c3a8e
review
Mar 9, 2021
7ece242
fix directory
Mar 10, 2021
6cd6f84
use cirrus branch
Mar 10, 2021
bc83daf
remove testing echo
Mar 10, 2021
9cfc0b9
revert device_info change
Mar 10, 2021
2bd1bfc
Merge branch 'master' into check_version
Mar 10, 2021
4f3e800
merge master
Mar 10, 2021
1ff0046
fix merge error
Mar 10, 2021
fa5240e
remove unnecessary channel swtich
Mar 10, 2021
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
9 changes: 8 additions & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ root_task_template: &ROOT_TASK_TEMPLATE
env:
INTEGRATION_TEST_PATH: "./packages/integration_test"
CHANNEL: "master" # Default to master when not explicitly set by a task.
PLUGIN_TOOLS: "dart run ./script/tool/lib/src/main.dart"
setup_script:
- flutter channel $CHANNEL
- flutter upgrade
- git fetch origin master # To set FETCH_HEAD for "git merge-base" to work
- cd script/tool
- pub get


# Light-workload Linux tasks.
Expand All @@ -24,10 +27,14 @@ task:
- name: plugin_tools_tests
script:
- cd script/tool
- pub get
- CIRRUS_BUILD_ID=null pub run test
- name: publishable
script:
- if [[ "$CIRRUS_BRANCH" == "master" ]]; then
- $PLUGIN_TOOLS version-check
- else
- $PLUGIN_TOOLS version-check --run-on-changed-packages
- fi
- ./script/check_publish.sh
- name: format
format_script: ./script/incremental_build.sh format --fail-on-change
Expand Down
3 changes: 0 additions & 3 deletions script/incremental_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,5 @@ else
else
echo running "${ACTIONS[@]}"
(cd "$REPO_DIR" && plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]})
echo "Running version check for changed packages"
# TODO(egarciad): Enable this check once in master.
# (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)")
fi
fi
143 changes: 142 additions & 1 deletion script/tool/lib/src/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import 'dart:io' as io;
import 'dart:math';

import 'package:args/command_runner.dart';
import 'package:colorize/colorize.dart';
import 'package:file/file.dart';
import 'package:git/git.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p;
import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart';

typedef void Print(Object object);
Expand Down Expand Up @@ -140,6 +144,13 @@ bool isLinuxPlugin(FileSystemEntity entity, FileSystem fileSystem) {
return pluginSupportsPlatform(kLinux, entity, fileSystem);
}

/// Throws a [ToolExit] with `exitCode` and log the `errorMessage` in red.
void printErrorAndExit({@required String errorMessage, int exitCode = 1}) {
final Colorize redError = Colorize(errorMessage)..red();
print(redError);
throw ToolExit(exitCode);
}

/// Error thrown when a command needs to exit with a non-zero exit code.
class ToolExit extends Error {
ToolExit(this.exitCode);
Expand All @@ -152,6 +163,7 @@ abstract class PluginCommand extends Command<Null> {
this.packagesDir,
this.fileSystem, {
this.processRunner = const ProcessRunner(),
this.gitDir,
}) {
argParser.addMultiOption(
_pluginsArg,
Expand Down Expand Up @@ -179,12 +191,23 @@ abstract class PluginCommand extends Command<Null> {
help: 'Exclude packages from this command.',
defaultsTo: <String>[],
);
argParser.addFlag(_runOnChangedPackagesArg,
help: 'Run the command on changed packages/plugins.\n'
'If the $_pluginsArg is specified, this flag is ignored.\n'
'The packages excluded with $_excludeArg is also excluded even if changed.\n'
'See $_kBaseSha if a custom base is needed to determine the diff.');
argParser.addOption(_kBaseSha,
help: 'The base sha used to determine git diff. \n'
'This is useful when $_runOnChangedPackagesArg is specified.\n'
'If not specified, merge-base is used as base sha.');
}

static const String _pluginsArg = 'plugins';
static const String _shardIndexArg = 'shardIndex';
static const String _shardCountArg = 'shardCount';
static const String _excludeArg = 'exclude';
static const String _runOnChangedPackagesArg = 'run-on-changed-packages';
static const String _kBaseSha = 'base-sha';

/// The directory containing the plugin packages.
final Directory packagesDir;
Expand All @@ -199,6 +222,11 @@ abstract class PluginCommand extends Command<Null> {
/// This can be overridden for testing.
final ProcessRunner processRunner;

/// The git directory to use. By default it uses the parent directory.
///
/// This can be mocked for testing.
final GitDir gitDir;

int _shardIndex;
int _shardCount;

Expand Down Expand Up @@ -273,9 +301,13 @@ abstract class PluginCommand extends Command<Null> {
/// "client library" package, which declares the API for the plugin, as
/// well as one or more platform-specific implementations.
Stream<Directory> _getAllPlugins() async* {
final Set<String> plugins = Set<String>.from(argResults[_pluginsArg]);
Set<String> plugins = Set<String>.from(argResults[_pluginsArg]);
final Set<String> excludedPlugins =
Set<String>.from(argResults[_excludeArg]);
final bool runOnChangedPackages = argResults[_runOnChangedPackagesArg];
if (plugins.isEmpty && runOnChangedPackages) {
plugins = await _getChangedPackages();
}

await for (FileSystemEntity entity
in packagesDir.list(followLinks: false)) {
Expand Down Expand Up @@ -363,6 +395,50 @@ abstract class PluginCommand extends Command<Null> {
(FileSystemEntity entity) => isFlutterPackage(entity, fileSystem))
.cast<Directory>();
}

/// Retrieve an instance of [GitVersionFinder] based on `_kBaseSha` and [gitDir].
///
/// Throws tool exit if [gitDir] nor root directory is a git directory.
Future<GitVersionFinder> retrieveVersionFinder() async {
final String rootDir = packagesDir.parent.absolute.path;
String baseSha = argResults[_kBaseSha];

GitDir baseGitDir = gitDir;
if (baseGitDir == null) {
if (!await GitDir.isGitDir(rootDir)) {
printErrorAndExit(
errorMessage: '$rootDir is not a valid Git repository.',
exitCode: 2);
}
baseGitDir = await GitDir.fromExisting(rootDir);
}

final GitVersionFinder gitVersionFinder =
GitVersionFinder(baseGitDir, baseSha);
return gitVersionFinder;
}

Future<Set<String>> _getChangedPackages() async {
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();

final List<String> allChangedFiles =
await gitVersionFinder.getChangedFiles();
final Set<String> packages = <String>{};
allChangedFiles.forEach((String path) {
final List<String> pathComponents = path.split('/');
final int packagesIndex =
pathComponents.indexWhere((String element) => element == 'packages');
if (packagesIndex != -1) {
packages.add(pathComponents[packagesIndex + 1]);
}
});
if (packages.isNotEmpty) {
final String changedPackages = packages.join(',');
print(changedPackages);
}
print('No changed packages.');
return packages;
}
}

/// A class used to run processes.
Expand Down Expand Up @@ -466,3 +542,68 @@ class ProcessRunner {
return 'ERROR: Unable to execute "$executable ${args.join(' ')}"$workdir.';
}
}

/// Finding diffs based on `baseGitDir` and `baseSha`.
class GitVersionFinder {
/// Constructor
GitVersionFinder(this.baseGitDir, this.baseSha);

/// The top level directory of the git repo.
///
/// That is where the .git/ folder exists.
final GitDir baseGitDir;

/// The base sha used to get diff.
final String baseSha;

static bool _isPubspec(String file) {
return file.trim().endsWith('pubspec.yaml');
}

/// Get a list of all the pubspec.yaml file that is changed.
Future<List<String>> getChangedPubSpecs() async {
return (await getChangedFiles()).where(_isPubspec).toList();
}

/// Get a list of all the changed files.
Future<List<String>> getChangedFiles() async {
final String baseSha = await _getBaseSha();
final io.ProcessResult changedFilesCommand = await baseGitDir
.runCommand(<String>['diff', '--name-only', '$baseSha', 'HEAD']);
print('Determine diff with base sha: $baseSha');
final String changedFilesStdout = changedFilesCommand.stdout.toString() ?? '';
if (changedFilesStdout.isEmpty) {
return <String>[];
}
final List<String> changedFiles = changedFilesStdout
.split('\n')
..removeWhere((element) => element.isEmpty);
return changedFiles.toList();
}

/// Get the package version specified in the pubspec file in `pubspecPath` and at the revision of `gitRef`.
Future<Version> getPackageVersion(String pubspecPath, String gitRef) async {
final io.ProcessResult gitShow =
await baseGitDir.runCommand(<String>['show', '$gitRef:$pubspecPath']);
final String fileContent = gitShow.stdout;
final String versionString = loadYaml(fileContent)['version'];
return versionString == null ? null : Version.parse(versionString);
}

Future<String> _getBaseSha() async {
if (baseSha != null && baseSha.isNotEmpty) {
return baseSha;
}

io.ProcessResult baseShaFromMergeBase = await baseGitDir.runCommand(
<String>['merge-base', '--fork-point', 'FETCH_HEAD', 'HEAD'],
throwOnError: false);
if (baseShaFromMergeBase == null ||
baseShaFromMergeBase.stderr != null ||
baseShaFromMergeBase.stdout == null) {
baseShaFromMergeBase = await baseGitDir
.runCommand(<String>['merge-base', 'FETCH_HEAD', 'HEAD']);
}
return (baseShaFromMergeBase.stdout as String).trim();
}
}
Loading