Skip to content

Commit ee60cae

Browse files
authored
Tool for tagging sdk versions in the repository (#4661)
1 parent 486d5a6 commit ee60cae

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
4+
/// Tool for finding all tagged versions of the dart sdk, and in turn tag this
5+
/// repository with `SDK-$version` for each of these.
6+
library;
7+
8+
import 'dart:io';
9+
10+
import 'package:args/args.dart';
11+
import 'package:path/path.dart' as p;
12+
import 'package:pub_semver/pub_semver.dart';
13+
14+
Future<void> main(List<String> args) async {
15+
final argParser =
16+
ArgParser()
17+
..addFlag(
18+
'create',
19+
help: 'Create the missing tags, otherwise only list them',
20+
negatable: false,
21+
)
22+
..addFlag(
23+
'push',
24+
help: 'Push missing sdk tags to remote',
25+
negatable: false,
26+
)
27+
..addOption('sdk-dir');
28+
final ArgResults argResults;
29+
try {
30+
argResults = argParser.parse(args);
31+
} on FormatException catch (e) {
32+
stderr.writeln('${e.message}\n${argParser.usage}');
33+
stderr.writeln('''
34+
Will find all tagged sdk versions, and tag the corresponding revision in this
35+
repository with `--create`.
36+
And can push these tags to the remote with `--push`.
37+
38+
Usage: create_version_tags_from_sdk [--create] [--push] [--sdk-dir <path>]
39+
''');
40+
exit(-1);
41+
}
42+
final create = argResults.flag('create');
43+
final push = argResults.flag('push');
44+
45+
Directory? tempDir;
46+
String sdkDir;
47+
try {
48+
if (argResults.option('sdk-dir') == null) {
49+
tempDir = Directory.systemTemp.createTempSync();
50+
final cloneResult = Process.runSync('git', [
51+
'clone',
52+
// Using a treeless clone is faster up-front, but slower for
53+
// showing a specific revision.
54+
// We assume we only miss a few tags.
55+
'--filter=tree:0',
56+
'-n',
57+
'https://github.com/dart-lang/sdk',
58+
], workingDirectory: tempDir.path);
59+
if (cloneResult.exitCode != 0) {
60+
throw Exception(
61+
'Failed to clone sdk ${cloneResult.stderr} ${cloneResult.stdout}',
62+
);
63+
}
64+
sdkDir = p.join(tempDir.path, 'sdk');
65+
} else {
66+
sdkDir = argResults.option('sdk-dir')!;
67+
}
68+
69+
final sdkTags =
70+
(Process.runSync('git', [
71+
'ls-remote',
72+
'--tags',
73+
'--refs',
74+
'origin',
75+
], workingDirectory: sdkDir).stdout
76+
as String)
77+
.split('\n')
78+
.where((line) => line.isNotEmpty)
79+
.map((line) => line.split('\t')[1])
80+
.map((x) => x.substring('refs/tags/'.length))
81+
.where((x) {
82+
try {
83+
Version.parse(x);
84+
} on FormatException {
85+
return false;
86+
}
87+
return true;
88+
})
89+
.toSet();
90+
final alreadyTagged =
91+
(Process.runSync('git', [
92+
'ls-remote',
93+
'--tags',
94+
'--refs',
95+
'origin',
96+
], workingDirectory: Directory.current.path).stdout
97+
as String)
98+
.split('\n')
99+
.where((line) => line.isNotEmpty)
100+
.map((line) => line.split('\t')[1])
101+
.map((x) => x.substring('refs/tags/'.length))
102+
.where((x) => x.startsWith('SDK-'))
103+
.map((x) => x.substring('SDK-'.length))
104+
.toSet();
105+
final missing = sdkTags.difference(alreadyTagged);
106+
var createdTagCount = 0;
107+
var pushedTagCount = 0;
108+
109+
if (missing.isNotEmpty) {
110+
for (final sdkTag in missing) {
111+
final version = Version.parse(sdkTag);
112+
if (
113+
// Old versions of the sdk had no pub or no DEPS file.
114+
version <= (Version.parse('1.11.3')) ||
115+
// These version seems to have a broken DEPS file.
116+
version == Version.parse('1.12.0-dev.5.6') ||
117+
version == Version.parse('1.12.0-dev.5.7')) {
118+
continue;
119+
}
120+
final depsResult = Process.runSync('git', [
121+
'show',
122+
'$sdkTag:DEPS',
123+
], workingDirectory: sdkDir);
124+
if (depsResult.exitCode != 0) {
125+
stderr.writeln(
126+
'Failed to get deps for $sdkTag ${depsResult.stderr} '
127+
'${depsResult.stdout}',
128+
);
129+
continue;
130+
}
131+
132+
// Could use `gclient getdep -r sdk/third_party/pkg/pub` instead of a
133+
// regexp. But for some versions that seems to not work well.
134+
// The regexp
135+
var pubRev = RegExp(
136+
'"pub_rev": "([^"]*)"',
137+
).firstMatch(depsResult.stdout as String)?.group(1);
138+
if (pubRev == null || pubRev.isEmpty) {
139+
stderr.writeln('Failed to get pub rev for $sdkTag ');
140+
continue;
141+
}
142+
if (pubRev.startsWith('@')) {
143+
pubRev = pubRev.substring(1);
144+
}
145+
146+
stdout.writeln('$sdkTag uses pub: $pubRev');
147+
if (create) {
148+
final tagResult = Process.runSync('git', [
149+
'tag',
150+
'SDK-$sdkTag',
151+
pubRev,
152+
'-a',
153+
'-f',
154+
'-m',
155+
'SDK $sdkTag',
156+
], workingDirectory: Directory.current.path);
157+
if (tagResult.exitCode != 0) {
158+
stderr.writeln(
159+
'Failed to tag sdk ${tagResult.stderr} ${tagResult.stdout}',
160+
);
161+
continue;
162+
}
163+
createdTagCount++;
164+
}
165+
if (push) {
166+
final pushResult = Process.runSync('git', [
167+
'push',
168+
'origin',
169+
// Don't run any hooks before pushing.
170+
'--no-verify',
171+
'SDK-$sdkTag',
172+
], workingDirectory: Directory.current.path);
173+
if (pushResult.exitCode != 0) {
174+
stderr.writeln(
175+
'Failed to push sdk ${pushResult.stderr} ${pushResult.stdout}',
176+
);
177+
continue;
178+
}
179+
pushedTagCount++;
180+
}
181+
}
182+
}
183+
if (!create) {
184+
stdout.writeln('Would have created $createdTagCount tags');
185+
} else {
186+
stdout.writeln('Created $createdTagCount tags');
187+
}
188+
if (push) {
189+
stdout.writeln('Pushed $pushedTagCount tags');
190+
}
191+
} finally {
192+
tempDir?.deleteSync(recursive: true);
193+
}
194+
}

0 commit comments

Comments
 (0)