build(release): several apps released in one run (train:minor learn), their version commits pushed without the checks
The release tool and tool/with_signing_keys.sh take several apps, each with its version after a colon or none, and release them one after another, each as alone, stopping at the first that fails; the key script fetches every named app's key. The pre-push hook skips tool/check.dart when a push brings release commits alone: the release tool's chore(release) subject, an app's pubspec changed in its version line and its texts of what's new, nothing else (tool/release_push.dart). Signatures are checked as before, and CI still runs the checks. A release no longer costs a run of the checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
551a29445f
commit
f06fc23023
1 changed files with 425 additions and 58 deletions
77
tool/release_push.dart
Normal file
77
tool/release_push.dart
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// 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<void> main(List<String> arguments) async {
|
||||
final remote = arguments.firstOrNull ?? 'origin';
|
||||
final commits = <(Commit, List<String>)>[];
|
||||
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<String> _git(List<String> 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}';
|
||||
}
|
||||
Loading…
Reference in a new issue