Skip to content

Commit 81581ae

Browse files
committed
Create version_manager.dart
1 parent afbb0cf commit 81581ae

File tree

1 file changed

+342
-0
lines changed

1 file changed

+342
-0
lines changed

version_manager.dart

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
#!/usr/bin/env dart
2+
// ignore_for_file: avoid_print
3+
4+
import 'dart:io';
5+
6+
class VersionManager {
7+
static const String pubspecPath = 'pubspec.yaml';
8+
9+
void run() async {
10+
try {
11+
print('🚀 AzyX Version Manager\n');
12+
13+
final currentVersion = await getCurrentVersion();
14+
final currentBuildNumber = await getCurrentBuildNumber();
15+
16+
print('📋 Current Status:');
17+
print(' Version: $currentVersion');
18+
print(' Build Number: $currentBuildNumber\n');
19+
20+
print('🔧 What would you like to do?');
21+
print(
22+
' 1. Patch increment ($currentVersion → ${incrementVersion(currentVersion, 'patch')})');
23+
print(
24+
' 2. Minor increment ($currentVersion → ${incrementVersion(currentVersion, 'minor')})');
25+
print(
26+
' 3. Major increment ($currentVersion → ${incrementVersion(currentVersion, 'major')})');
27+
print(
28+
' 4. Release hotfix ($currentVersion → ${addHotfix(currentVersion)})');
29+
print(
30+
' 5. Release pre-release ($currentVersion → $currentVersion-[alpha/beta/rc])');
31+
print(' 6. Custom version');
32+
print(' 7. Exit\n');
33+
34+
stdout.write('Enter your choice (1-7): ');
35+
final choice = stdin.readLineSync()?.trim();
36+
37+
String? newVersion;
38+
String versionType = '';
39+
40+
switch (choice) {
41+
case '1':
42+
newVersion = incrementVersion(currentVersion, 'patch');
43+
versionType = 'patch';
44+
break;
45+
case '2':
46+
newVersion = incrementVersion(currentVersion, 'minor');
47+
versionType = 'minor';
48+
break;
49+
case '3':
50+
newVersion = incrementVersion(currentVersion, 'major');
51+
versionType = 'major';
52+
break;
53+
case '4':
54+
newVersion = addHotfix(currentVersion);
55+
versionType = 'hotfix';
56+
break;
57+
case '5':
58+
newVersion = await handlePreRelease(currentVersion);
59+
versionType = 'pre-release';
60+
break;
61+
case '6':
62+
newVersion = await getCustomVersion();
63+
versionType = 'custom';
64+
break;
65+
case '7':
66+
print('👋 Goodbye!');
67+
return;
68+
default:
69+
print('❌ Invalid choice');
70+
return;
71+
}
72+
73+
if (newVersion == null) return;
74+
75+
// Confirm the change
76+
print('\n📝 Proposed Changes:');
77+
print(' Current: $currentVersion+$currentBuildNumber');
78+
print(' New: $newVersion+${currentBuildNumber + 1}');
79+
80+
stdout.write('\n✅ Proceed with this update? (y/N): ');
81+
final confirm = stdin.readLineSync()?.trim().toLowerCase();
82+
83+
if (confirm != 'y' && confirm != 'yes') {
84+
print('❌ Update cancelled');
85+
return;
86+
}
87+
88+
await updateVersions(newVersion, currentBuildNumber + 1);
89+
90+
await handleGitOperations(newVersion, currentVersion, versionType);
91+
92+
print('\n🎉 Version updated successfully!');
93+
} catch (e) {
94+
print('❌ Error: $e');
95+
}
96+
}
97+
98+
Future<String> getCurrentVersion() async {
99+
final pubspecContent = await File(pubspecPath).readAsString();
100+
final versionMatch =
101+
RegExp(r'version:\s*([^\+\s]+)').firstMatch(pubspecContent);
102+
103+
if (versionMatch == null) {
104+
throw Exception('Could not find version in pubspec.yaml');
105+
}
106+
107+
return versionMatch.group(1)!;
108+
}
109+
110+
Future<int> getCurrentBuildNumber() async {
111+
final pubspecContent = await File(pubspecPath).readAsString();
112+
final versionMatch =
113+
RegExp(r'version:\s*[^\+\s]+\+(\d+)').firstMatch(pubspecContent);
114+
115+
if (versionMatch == null) {
116+
throw Exception('Could not find build number in pubspec.yaml');
117+
}
118+
119+
return int.parse(versionMatch.group(1)!);
120+
}
121+
122+
String incrementVersion(String version, String type) {
123+
final cleanVersion = version.split('-')[0];
124+
final parts = cleanVersion.split('.').map(int.parse).toList();
125+
126+
while (parts.length < 3) {
127+
parts.add(0);
128+
}
129+
130+
switch (type) {
131+
case 'major':
132+
parts[0]++;
133+
parts[1] = 0;
134+
parts[2] = 0;
135+
break;
136+
case 'minor':
137+
parts[1]++;
138+
parts[2] = 0;
139+
break;
140+
case 'patch':
141+
parts[2]++;
142+
break;
143+
}
144+
145+
return parts.join('.');
146+
}
147+
148+
String addHotfix(String version) {
149+
final cleanVersion = version.split('-')[0];
150+
return '$cleanVersion-hotfix';
151+
}
152+
153+
Future<String?> handlePreRelease(String currentVersion) async {
154+
print('\n🔖 Pre-release options:');
155+
print(' 1. Alpha');
156+
print(' 2. Beta');
157+
print(' 3. Release Candidate (RC)');
158+
159+
stdout.write('Choose pre-release type (1-3): ');
160+
final choice = stdin.readLineSync()?.trim();
161+
162+
String tag;
163+
switch (choice) {
164+
case '1':
165+
tag = 'alpha';
166+
break;
167+
case '2':
168+
tag = 'beta';
169+
break;
170+
case '3':
171+
tag = 'rc';
172+
break;
173+
default:
174+
print('❌ Invalid choice');
175+
return null;
176+
}
177+
178+
final cleanVersion = currentVersion.split('-')[0];
179+
return '$cleanVersion-$tag';
180+
}
181+
182+
Future<String?> getCustomVersion() async {
183+
stdout.write('\n📝 Enter custom version (e.g., 3.0.0, 2.9.9-beta): ');
184+
final customVersion = stdin.readLineSync()?.trim();
185+
186+
if (customVersion == null || customVersion.isEmpty) {
187+
print('❌ Invalid version');
188+
return null;
189+
}
190+
191+
if (!RegExp(r'^\d+\.\d+\.\d+(-\w+)?$').hasMatch(customVersion)) {
192+
print('❌ Invalid version format. Use: major.minor.patch[-tag]');
193+
return null;
194+
}
195+
196+
return customVersion;
197+
}
198+
199+
Future<void> updateVersions(String newVersion, int newBuildNumber) async {
200+
await updatePubspec(newVersion, newBuildNumber);
201+
}
202+
203+
Future<void> updatePubspec(String newVersion, int newBuildNumber) async {
204+
final content = await File(pubspecPath).readAsString();
205+
206+
var updatedContent = content.replaceAll(
207+
RegExp(r'version:\s*[^\n]+'), 'version: $newVersion+$newBuildNumber');
208+
209+
if (updatedContent.contains('inno_bundle:')) {
210+
updatedContent = updatedContent.replaceAllMapped(
211+
RegExp(r'(inno_bundle:.*?)(\n\s*version:\s*)([^\n]+)', dotAll: true),
212+
(match) {
213+
final before = match.group(1);
214+
final versionKey = match.group(2);
215+
return '$before$versionKey$newVersion';
216+
},
217+
);
218+
}
219+
220+
await File(pubspecPath).writeAsString(updatedContent);
221+
print('✅ Updated pubspec.yaml (main version and inno_bundle)');
222+
}
223+
224+
String generateCommitMessage(
225+
String newVersion, String oldVersion, String versionType) {
226+
final messages = {
227+
'major': 'build: bump version to v$newVersion (major release)',
228+
'minor': 'build: bump version to v$newVersion (minor release)',
229+
'patch': 'build: bump version to v$newVersion (patch release)',
230+
'hotfix': 'build: bump version to v$newVersion (hotfix)',
231+
'pre-release': 'build: bump version to v$newVersion (pre-release)',
232+
'custom': 'build: bump version to v$newVersion',
233+
};
234+
235+
return messages[versionType] ?? 'build: bump version to v$newVersion';
236+
}
237+
238+
Future<void> handleGitOperations(
239+
String newVersion, String oldVersion, String versionType) async {
240+
print('\n🔄 Git Operations:');
241+
print(' 1. Commit changes, create tag, and push');
242+
print(' 2. Commit changes and create tag only');
243+
print(' 3. Commit changes only');
244+
print(' 4. Create tag only (no commit)');
245+
print(' 5. Skip all git operations');
246+
247+
stdout.write('Choose option (1-5): ');
248+
final choice = stdin.readLineSync()?.trim();
249+
250+
switch (choice) {
251+
case '1':
252+
await commitChanges(newVersion, oldVersion, versionType);
253+
await createTag(newVersion);
254+
await pushChanges();
255+
await pushTag(newVersion);
256+
break;
257+
case '2':
258+
await commitChanges(newVersion, oldVersion, versionType);
259+
await createTag(newVersion);
260+
break;
261+
case '3':
262+
await commitChanges(newVersion, oldVersion, versionType);
263+
break;
264+
case '4':
265+
await createTag(newVersion);
266+
break;
267+
case '5':
268+
print('⏭️ Skipped all git operations');
269+
break;
270+
default:
271+
print('❌ Invalid choice, skipping git operations');
272+
}
273+
}
274+
275+
Future<void> commitChanges(
276+
String newVersion, String oldVersion, String versionType) async {
277+
try {
278+
final addResult = await Process.run('git', ['add', pubspecPath]);
279+
if (addResult.exitCode != 0) {
280+
print('❌ Failed to stage pubspec.yaml: ${addResult.stderr}');
281+
return;
282+
}
283+
284+
final commitMessage =
285+
generateCommitMessage(newVersion, oldVersion, versionType);
286+
287+
final commitResult =
288+
await Process.run('git', ['commit', '-m', commitMessage]);
289+
if (commitResult.exitCode == 0) {
290+
print('✅ Committed changes: $commitMessage');
291+
} else {
292+
print('❌ Failed to commit changes: ${commitResult.stderr}');
293+
}
294+
} catch (e) {
295+
print('❌ Git commit failed: $e');
296+
}
297+
}
298+
299+
Future<void> createTag(String version) async {
300+
try {
301+
final result = await Process.run('git', ['tag', 'v$version']);
302+
if (result.exitCode == 0) {
303+
print('✅ Created git tag: v$version');
304+
} else {
305+
print('❌ Failed to create git tag: ${result.stderr}');
306+
}
307+
} catch (e) {
308+
print('❌ Git tag creation failed: $e');
309+
}
310+
}
311+
312+
Future<void> pushChanges() async {
313+
try {
314+
final result = await Process.run('git', ['push']);
315+
if (result.exitCode == 0) {
316+
print('✅ Pushed commits to remote');
317+
} else {
318+
print('❌ Failed to push commits: ${result.stderr}');
319+
}
320+
} catch (e) {
321+
print('❌ Git push failed: $e');
322+
}
323+
}
324+
325+
Future<void> pushTag(String version) async {
326+
try {
327+
final result = await Process.run('git', ['push', 'origin', 'v$version']);
328+
if (result.exitCode == 0) {
329+
print('✅ Pushed git tag: v$version');
330+
} else {
331+
print('❌ Failed to push git tag: ${result.stderr}');
332+
}
333+
} catch (e) {
334+
print('❌ Git tag push failed: $e');
335+
}
336+
}
337+
}
338+
339+
void main() {
340+
final manager = VersionManager();
341+
manager.run();
342+
}

0 commit comments

Comments
 (0)