// Says whether a push to main brings release commits alone (exit 0) or // anything else (exit 1), for tool/pre-push, which then skips the checks: a // release commit changes an app's version and its texts of what's new alone // (tool/src/release/release_push.dart says why that is enough). Reads what // git hands a pre-push hook: the remote as the argument, a line per ref pushed // on stdin (local ref, local commit, remote ref, remote commit), and looks at // the commits pushed to main that no ref of that remote has yet, as // tool/check_signatures.sh does. import 'dart:convert'; import 'dart:io'; import 'src/release/log.dart'; import 'src/release/release_push.dart'; import 'src/release/version.dart'; Future main(List arguments) async { final remote = arguments.firstOrNull ?? 'origin'; final commits = <(Commit, List)>[]; var pushesMain = false; await for (final line in stdin.transform(utf8.decoder).transform(const LineSplitter())) { final fields = line.trim().split(RegExp(r'\s+')); if (fields.length != 4 || fields[2] != 'refs/heads/main') { continue; } final local = fields[1]; if (RegExp(r'^0+$').hasMatch(local)) { continue; } pushesMain = true; final log = await _git([ 'log', '--format=$logFormat', '--name-only', local, '--not', '--remotes=$remote', ]); for (final commit in parseLog(log)) { final diff = await _git([ 'show', '--format=', '--unified=0', commit.hash, '--', '*pubspec.yaml', ]); commits.add(( commit, [ for (final line in const LineSplitter().convert(diff)) if ((line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---')) line, ], )); } } if (pushesMain && onlyReleaseCommits(commits)) { stdout.writeln( '▸ Release commits alone (${commits.map((c) => c.$1.subject).join('; ')}): ' 'no checks needed.', ); exit(0); } exit(1); } Future _git(List arguments) async { final result = await Process.run('git', arguments); if (result.exitCode != 0) { stderr.writeln('git ${arguments.join(' ')}: ${result.stderr}'); exit(1); } return '${result.stdout}'; }