// ignore_for_file: avoid_print import 'dart:io'; String version = ''; String code = ''; Future main() async { version = await askWhichVersion(); code = await askWhichCode(); final procedures = [ switchToDevBranch, updateVersionCodes, updateLinuxReleases, addReleaseNotes, pushChanges, updateMainBranch, createReleaseTag, rebuildGeneratedFiles, // iOS buildIOSArchive, distributeIOSArchive, // macOS buildMacOSArchive, distributMacOSSArchive, // Windows distributeWindowsBuild, // Linux calculateLinuxShasum, distributeLinuxArchive, switchToDevBranch, ]; for (final procedure in procedures) { await procedure(); } print('Done.'); } Future askWhichVersion() async { final file = File('pubspec.yaml'); final lines = (await file.readAsLines()).toList(); final versionAndCode = lines.singleWhere((l) => l.startsWith('version: ')).split(': ')[1]; final version = versionAndCode.split('+')[0]; print('What is the new version? The current version is "$version".'); String? reply; while (reply == null) { reply = stdin.readLineSync(); } return reply; } Future askWhichCode() async { final file = File('pubspec.yaml'); final lines = (await file.readAsLines()).toList(); final versionAndCode = lines.singleWhere((l) => l.startsWith('version: ')).split(': ')[1]; final code = versionAndCode.split('+')[1]; print('What is the new version? The current code is "$code".'); String? reply; while (reply == null) { reply = stdin.readLineSync(); } return reply; } Future switchToDevBranch() async { print('Press ENTER to switch to the `dev` branch and get the latest updates'); await waitForEnter(); await Process.run('git', ['checkout', 'dev']); await Process.run('git', ['pull']); } Future updateVersionCodes() async { final file = File('pubspec.yaml'); final lines = (await file.readAsLines()).toList(); final versionIndex = lines.indexWhere((l) => l.startsWith('version: ')); lines ..removeAt(versionIndex) ..insert(versionIndex, 'version: $version+$code'); final msixIndex = lines.indexWhere((l) => l.startsWith(' msix_version: ')); lines ..removeAt(msixIndex) ..insert(msixIndex, ' msix_version: $version.0'); await file.writeAsString('${lines.join('\n')}\n'); print((await Process.run('git', ['--no-pager', 'diff', 'pubspec.yaml'])) .stdout); print('Press ENTER if the version updates in `pubspec.yaml` are correct:'); await waitForEnter(); } Future updateLinuxReleases() async { final today = DateTime.now(); final dateSlug = '${today.year.toString()}-' '${today.month.toString().padLeft(2, '0')}-' '${today.day.toString().padLeft(2, '0')}'; final file = File('linux/flathub/app.getspace.Space.metainfo.xml'); final lines = (await file.readAsLines()).toList(); final releasesIndex = lines.indexWhere((l) => l.startsWith(' ')); lines.insert( releasesIndex + 1, ' ', ); await file.writeAsString('${lines.join('\n')}\n'); print((await Process.run('git', [ '--no-pager', 'diff', 'linux/flathub/app.getspace.Space.metainfo.xml' ])) .stdout); print( 'Press ENTER if the version update in `linux/flathub/app.getspace.Space.metainfo.xml` is correct:'); await waitForEnter(); } Future addReleaseNotes() async { print('Add the release notes in:'); print(' lib/utils/release_notes.dart'); print(' android/whats_new/whatsnew-en-US'); await waitForEnter(); } Future pushChanges() async { print('Press ENTER to commit and push the files:'); await waitForEnter(); await Process.run('git', [ 'add', 'pubspec.yaml', 'lib/utils/release_notes.dart', 'linux/flathub/app.getspace.Space.metainfo.xml', 'android/whats_new/whatsnew-en-US' ]); await Process.run('git', ['commit', '-m', 'Bump to $version']); await Process.run('git', ['push']); } Future updateMainBranch() async { print('Press ENTER to switch to the `main` branch ' 'and get the latest dev updates'); await waitForEnter(); await Process.run('git', ['checkout', 'main']); await Process.run('git', ['pull', 'origin', 'dev']); await Process.run('git', ['push']); } Future createReleaseTag() async { print('Press ENTER to create a release tag'); await waitForEnter(); await Process.run('git', ['tag', version]); await Process.run('git', ['push', 'origin', version]); } Future rebuildGeneratedFiles() async { print('Press ENTER to update latest packages and ' 'rebuild the generated files'); await waitForEnter(); await Process.run('flutter', ['pub', 'get']); await Process.run('./scripts/update_generated_files.sh', []); await Process.run('./scripts/update_language_files.sh', []); } Future buildIOSArchive() async { print('Press ENTER to build the iOS build archive'); await waitForEnter(); // This refreshes the release mode configuration in Xcode (updates version // and number, maybe more) await Process.run( 'flutter', ['build', 'ipa', '--release', '--flavor', 'prod']); // Source: [Build and release an iOS app](https://flutter.dev/docs/deployment/ios#create-a-build-archive) } Future distributeIOSArchive() async { print('Distribute the iOS archive:'); print(' Open `build/ios/archive/Runner.xcarchive` in Xcode'); print(' Click "Distribute App".'); print( ' In 30 minutes you will receive an email that the release is available ' 'in the test flight.', ); await waitForEnter(); } Future buildMacOSArchive() async { print('Press ENTER to build the macOS archive'); await waitForEnter(); await Process.run( 'flutter', ['build', 'macos', '--dart-define', 'app.flavor=prod']); } Future distributMacOSSArchive() async { print('Distribute the MacOS archive:'); print(' Open `macos/Runner.xcworkspace` with Xcode'); print(' Select `Product` -> `Archive`'); print(' Click "Distribute App".'); print( ' In 30 minutes you will receive an email that the release is available ' 'in the test flight.', ); await waitForEnter(); } Future distributeWindowsBuild() async { print('Distribute the Windows app:'); print( ' Go to https://github.com/friebetill/tubecards/releases/tag/$version', ); print(' Download space_$version.msix'); print(' Go to `https://partner.microsoft.com/` and publish the file.'); await waitForEnter(); } Future calculateLinuxShasum() async { print('Press ENTER to calculate the shasum of the Linux archive'); await waitForEnter(); await Process.run('j', ['flathub']); print('Wait until the checksum of the Linux release has been calculated'); final releaseUrl = 'https://space-linux.s3.eu-west-1.amazonaws.com/releases/space_$version.tar.xz'; await Process.run('curl', ['-O', releaseUrl]); final result = await Process.run('shasum', ['-a', '256', 'space_$version.tar.xz']); final shasum = (result.stdout as String).split(' ')[0]; await Process.run('rm', ['space_$version.tar.xz']); final file = File('app.getspace.Space.json'); final lines = (await file.readAsLines()).toList(); final urlIndex = lines.indexWhere((l) => l.startsWith(' "url": ')); lines ..removeAt(urlIndex) ..insert(urlIndex, ' "url": "$releaseUrl",'); final sha256Index = lines.indexWhere((l) => l.startsWith(' "sha256":')); lines ..removeAt(sha256Index) ..insert(sha256Index, ' "sha256": "$shasum",'); await file.writeAsString('${lines.join('\n')}\n'); print((await Process.run( 'git', ['--no-pager', 'diff', 'app.getspace.Space.json'])) .stdout); print('Press ENTER if the version updates in ' '`app.getspace.Space.json` are correct:'); await waitForEnter(); } Future distributeLinuxArchive() async { print('Press ENTER to distribute the Linux archive'); await waitForEnter(); await Process.run('git', ['add', 'app.getspace.Space.json']); await Process.run('git', ['commit', '-m', '"Release $version"']); await Process.run('git', ['push']); } Future waitForEnter() async { while (stdin.readLineSync(retainNewlines: true) != '\n') {} }