diff --git a/.github/templates/.vscode/settings.json b/.github/templates/.vscode/settings.json index f9953fe..13899f9 100644 --- a/.github/templates/.vscode/settings.json +++ b/.github/templates/.vscode/settings.json @@ -1,5 +1,5 @@ { - "dart.flutterSdkPath": ".fvm/flutter_sdk", + "dart.flutterSdkPath": ".fvm/versions/{{flutterVersion}}", "search.exclude": { "**/.fvm": true }, diff --git a/.github/workflows/template-cleanup.yaml b/.github/workflows/template-cleanup.yaml index 0ca4621..d4e9c7b 100644 --- a/.github/workflows/template-cleanup.yaml +++ b/.github/workflows/template-cleanup.yaml @@ -30,60 +30,21 @@ jobs: # - name: Create issues from challenges # uses: ./.github/actions/create-issues-from-challenges - - name: Cleanup + # https://github.com/dart-lang/setup-dart + - name: Set up dart + uses: dart-lang/setup-dart@v1 + with: + sdk: "3.3.0" # See: tools/cleanup_template/pubspec.yaml + + - name: Install dependencies + run: dart pub get shell: bash - run: | - # Make tmp dir and move work dir to tmp - mkdir "tmp" && cd tmp || exit - - # Install fvm - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - brew tap leoafarias/fvm - brew install fvm - - # Install & Setup Flutter - flutterLatestVersion=$(fvm releases | grep -o -E "v?[0-9]+\.[0-9]+\.[0-9]+\s+stable" | sed -e "s/[ ]*stable//g") - fvm install "$flutterLatestVersion" - fvm use "$flutterLatestVersion" --force - - # Create Flutter Project - fvm flutter create \ - -t app \ - --empty \ - -i swift \ - -a kotlin \ - --platforms ios,android \ - --org jp.co.yumemi \ - --project-name flutter_training \ - . - - # Add lints to dev_dependencies - fvm flutter pub add dev:yumemi_lints - fvm flutter pub remove flutter_lints - - # Override the analysis_options.yaml - cat < analysis_options.yaml - # https://pub.dev/packages/yumemi_lints - include: package:yumemi_lints/flutter/$flutterLatestVersion/recommended.yaml - EOF - - # Move work dir to project root - cd .. - - # Copy templates - cp -R .github/templates/. tmp - - # Delete anything except tmp dir - rm -rf \ - .github \ - docs \ - packages \ - .gitignore \ - LICENSE \ - README.md - - # Move new training project to project root - mv -f tmp/* tmp/.[^\.]* ./ && rm -rf tmp + working-directory: tools/cleanup_template + + - name: Run cleanup_template + run: dart run bin/cleanup_template.dart + shell: bash + working-directory: tools/cleanup_template - name: Commit files run: | @@ -97,4 +58,4 @@ jobs: uses: ad-m/github-push-action@v0.8.0 with: branch: main - github_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/tools/cleanup_template/.gitattributes b/tools/cleanup_template/.gitattributes new file mode 100644 index 0000000..243a769 --- /dev/null +++ b/tools/cleanup_template/.gitattributes @@ -0,0 +1,2 @@ +*.freezed.dart linguist-generated=true +*.g.dart linguist-generated=true diff --git a/tools/cleanup_template/.gitignore b/tools/cleanup_template/.gitignore new file mode 100644 index 0000000..e6f9e54 --- /dev/null +++ b/tools/cleanup_template/.gitignore @@ -0,0 +1,6 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# custom_lint +*.log diff --git a/tools/cleanup_template/CHANGELOG.md b/tools/cleanup_template/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/tools/cleanup_template/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/tools/cleanup_template/README.md b/tools/cleanup_template/README.md new file mode 100644 index 0000000..f38efef --- /dev/null +++ b/tools/cleanup_template/README.md @@ -0,0 +1,41 @@ +# CLI to Cleanup flutter-training-template + +This CLI is run when a new repository is created from flutter-training-template. + +This CLI provides an environment for receiving Flutter training. + +## Get Started + +### 1. Install Dart SDK + +Before using this tool, make sure you have the Dart SDK installed. You can follow the instructions in the official documentation to install the Dart SDK and set up the dart command: + +[Install Dart SDK] + +> **Note** +> Ensure that your Dart SDK version is 3.3.0. + +### 2. Install Dependencies + +After installing the Dart SDK, you need to install the project dependencies using the following command: + +```shell +dart pub get +``` + +## Usage + +> **Note** +> This package is intended for use exclusively within the GitHub Actions workflow of [yumemi-inc/flutter-training-template] and is not published on [Pub.dev]. + +To run cleanup_template, execute the following command: + +```shell +dart run bin/cleanup_template.dart +``` + + + +[Install Dart SDK]: https://dart.dev/get-dart +[yumemi-inc/flutter-training-template]: https://github.com/yumemi-inc/flutter-training-template +[Pub.dev]: https://pub.dev/ diff --git a/tools/cleanup_template/analysis_options.yaml b/tools/cleanup_template/analysis_options.yaml new file mode 100644 index 0000000..1012654 --- /dev/null +++ b/tools/cleanup_template/analysis_options.yaml @@ -0,0 +1,8 @@ +include: package:yumemi_lints/dart/3.3.0/recommended.yaml + +analyzer: + plugins: + - custom_lint + errors: + # https://pub.dev/packages/freezed + invalid_annotation_target: ignore diff --git a/tools/cleanup_template/bin/cleanup_template.dart b/tools/cleanup_template/bin/cleanup_template.dart new file mode 100644 index 0000000..35b62e0 --- /dev/null +++ b/tools/cleanup_template/bin/cleanup_template.dart @@ -0,0 +1,12 @@ +import 'dart:io'; + +import 'package:cleanup_template/cleanup_template.dart' as cleanup_template; + +void main() async { + final status = await cleanup_template.run(); + + return Future.wait([ + stdout.close(), + stderr.close(), + ]).then((_) => exit(status.code)); +} diff --git a/tools/cleanup_template/build.yaml b/tools/cleanup_template/build.yaml new file mode 100644 index 0000000..7a9030c --- /dev/null +++ b/tools/cleanup_template/build.yaml @@ -0,0 +1,20 @@ +targets: + $default: + builders: + # https://github.com/dart-lang/source_gen#ignore_for_file + source_gen:combining_builder: + options: + ignore_for_file: + - type=lint + - duplicate_ignore + json_serializable: + generate_for: + include: + - lib/src/models/*.dart + options: + # json のデシリアライズ時に発生する Exception を CheckedFromJsonException にまとめる + checked: true + freezed: + generate_for: + include: + - lib/src/models/*.dart diff --git a/tools/cleanup_template/lib/cleanup_template.dart b/tools/cleanup_template/lib/cleanup_template.dart new file mode 100644 index 0000000..9edd5a1 --- /dev/null +++ b/tools/cleanup_template/lib/cleanup_template.dart @@ -0,0 +1,37 @@ +import 'package:cleanup_template/src/models/exit_status.dart'; +import 'package:cleanup_template/src/services/cleanup_service.dart'; +import 'package:cleanup_template/src/services/flutter_sdk_service.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:riverpod/riverpod.dart'; + +Future run() async { + final container = ProviderContainer(); + + try { + final exitStatus = await cleanupTemplate(container); + return exitStatus; + } finally { + container.dispose(); + } +} + +Future cleanupTemplate(ProviderContainer container) async { + final flutterSdkService = container.read(flutterSdkServiceProvider); + final cleanupService = container.read(cleanupServiceProvider); + + try { + final flutterVersion = await flutterSdkService.getLatestFlutterSdkVersion(); + final exitStatus = cleanupService.call(flutterVersion); + + return exitStatus; + } on CheckedFromJsonException catch (e) { + print(e.message); + return ExitStatus.errors; + } on FormatException catch (e) { + print(e.message); + return ExitStatus.errors; + } on Exception catch (e) { + print(e); + return ExitStatus.errors; + } +} diff --git a/tools/cleanup_template/lib/src/clients/app_client.dart b/tools/cleanup_template/lib/src/clients/app_client.dart new file mode 100644 index 0000000..7d362e5 --- /dev/null +++ b/tools/cleanup_template/lib/src/clients/app_client.dart @@ -0,0 +1,25 @@ +import 'package:http/http.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'app_client.g.dart'; + +@Riverpod(keepAlive: true, dependencies: []) +AppClient appClient(AppClientRef ref) { + final appClient = AppClient(Client()); + ref.onDispose(appClient.close); + return appClient; +} + +class AppClient extends BaseClient { + AppClient(this._inner); + + final Client _inner; + + @override + Future send(BaseRequest request) async { + return _inner.send(request).timeout(const Duration(seconds: 3)); + } + + @override + void close() => _inner.close(); +} diff --git a/tools/cleanup_template/lib/src/clients/app_client.g.dart b/tools/cleanup_template/lib/src/clients/app_client.g.dart new file mode 100644 index 0000000..40f4a6c --- /dev/null +++ b/tools/cleanup_template/lib/src/clients/app_client.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: type=lint, duplicate_ignore + +part of 'app_client.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$appClientHash() => r'ef8530eab0482762644d5fccab69a4eccdd0bfd4'; + +/// See also [appClient]. +@ProviderFor(appClient) +final appClientProvider = Provider.internal( + appClient, + name: r'appClientProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$appClientHash, + dependencies: const [], + allTransitiveDependencies: const {}, +); + +typedef AppClientRef = ProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/tools/cleanup_template/lib/src/file_system.dart b/tools/cleanup_template/lib/src/file_system.dart new file mode 100644 index 0000000..b2ef6c0 --- /dev/null +++ b/tools/cleanup_template/lib/src/file_system.dart @@ -0,0 +1,8 @@ +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'file_system.g.dart'; + +@Riverpod(dependencies: []) +FileSystem fileSystem(FileSystemRef ref) => LocalFileSystem(); diff --git a/tools/cleanup_template/lib/src/file_system.g.dart b/tools/cleanup_template/lib/src/file_system.g.dart new file mode 100644 index 0000000..bd8dd9c --- /dev/null +++ b/tools/cleanup_template/lib/src/file_system.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: type=lint, duplicate_ignore + +part of 'file_system.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$fileSystemHash() => r'599c2fc26ae187d5c12fee2f5e48522e59609c32'; + +/// See also [fileSystem]. +@ProviderFor(fileSystem) +final fileSystemProvider = AutoDisposeProvider.internal( + fileSystem, + name: r'fileSystemProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$fileSystemHash, + dependencies: const [], + allTransitiveDependencies: const {}, +); + +typedef FileSystemRef = AutoDisposeProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/tools/cleanup_template/lib/src/models/exit_status.dart b/tools/cleanup_template/lib/src/models/exit_status.dart new file mode 100644 index 0000000..59fd091 --- /dev/null +++ b/tools/cleanup_template/lib/src/models/exit_status.dart @@ -0,0 +1,17 @@ +/// https://dart.dev/tutorials/server/cmdline#setting-exit-codes +enum ExitStatus { + success(0), + warnings(1), + errors(2), + ; + + const ExitStatus(this.code); + + factory ExitStatus.fromCode(int code) => switch (code) { + 0 => ExitStatus.success, + 1 => ExitStatus.warnings, + _ => ExitStatus.errors, + }; + + final int code; +} diff --git a/tools/cleanup_template/lib/src/models/flutter_sdk_release.dart b/tools/cleanup_template/lib/src/models/flutter_sdk_release.dart new file mode 100644 index 0000000..14fb0ce --- /dev/null +++ b/tools/cleanup_template/lib/src/models/flutter_sdk_release.dart @@ -0,0 +1,32 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:pub_semver/pub_semver.dart'; + +part 'flutter_sdk_release.freezed.dart'; +part 'flutter_sdk_release.g.dart'; + +@freezed +class FlutterSdkRelease with _$FlutterSdkRelease { + factory FlutterSdkRelease({ + required FlutterChannel channel, + @_VersionJsonConverter() required Version version, + }) = _FlutterSdkRelease; + + factory FlutterSdkRelease.fromJson(Map json) => + _$FlutterSdkReleaseFromJson(json); +} + +enum FlutterChannel { + dev, + beta, + stable, +} + +class _VersionJsonConverter implements JsonConverter { + const _VersionJsonConverter(); + + @override + Version fromJson(String value) => Version.parse(value); + + @override + String toJson(Version version) => version.toString(); +} diff --git a/tools/cleanup_template/lib/src/models/flutter_sdk_release.freezed.dart b/tools/cleanup_template/lib/src/models/flutter_sdk_release.freezed.dart new file mode 100644 index 0000000..72b7b9f --- /dev/null +++ b/tools/cleanup_template/lib/src/models/flutter_sdk_release.freezed.dart @@ -0,0 +1,175 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'flutter_sdk_release.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +FlutterSdkRelease _$FlutterSdkReleaseFromJson(Map json) { + return _FlutterSdkRelease.fromJson(json); +} + +/// @nodoc +mixin _$FlutterSdkRelease { + FlutterChannel get channel => throw _privateConstructorUsedError; + @_VersionJsonConverter() + Version get version => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $FlutterSdkReleaseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FlutterSdkReleaseCopyWith<$Res> { + factory $FlutterSdkReleaseCopyWith( + FlutterSdkRelease value, $Res Function(FlutterSdkRelease) then) = + _$FlutterSdkReleaseCopyWithImpl<$Res, FlutterSdkRelease>; + @useResult + $Res call({FlutterChannel channel, @_VersionJsonConverter() Version version}); +} + +/// @nodoc +class _$FlutterSdkReleaseCopyWithImpl<$Res, $Val extends FlutterSdkRelease> + implements $FlutterSdkReleaseCopyWith<$Res> { + _$FlutterSdkReleaseCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? channel = null, + Object? version = null, + }) { + return _then(_value.copyWith( + channel: null == channel + ? _value.channel + : channel // ignore: cast_nullable_to_non_nullable + as FlutterChannel, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as Version, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$FlutterSdkReleaseImplCopyWith<$Res> + implements $FlutterSdkReleaseCopyWith<$Res> { + factory _$$FlutterSdkReleaseImplCopyWith(_$FlutterSdkReleaseImpl value, + $Res Function(_$FlutterSdkReleaseImpl) then) = + __$$FlutterSdkReleaseImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({FlutterChannel channel, @_VersionJsonConverter() Version version}); +} + +/// @nodoc +class __$$FlutterSdkReleaseImplCopyWithImpl<$Res> + extends _$FlutterSdkReleaseCopyWithImpl<$Res, _$FlutterSdkReleaseImpl> + implements _$$FlutterSdkReleaseImplCopyWith<$Res> { + __$$FlutterSdkReleaseImplCopyWithImpl(_$FlutterSdkReleaseImpl _value, + $Res Function(_$FlutterSdkReleaseImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? channel = null, + Object? version = null, + }) { + return _then(_$FlutterSdkReleaseImpl( + channel: null == channel + ? _value.channel + : channel // ignore: cast_nullable_to_non_nullable + as FlutterChannel, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as Version, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$FlutterSdkReleaseImpl implements _FlutterSdkRelease { + _$FlutterSdkReleaseImpl( + {required this.channel, @_VersionJsonConverter() required this.version}); + + factory _$FlutterSdkReleaseImpl.fromJson(Map json) => + _$$FlutterSdkReleaseImplFromJson(json); + + @override + final FlutterChannel channel; + @override + @_VersionJsonConverter() + final Version version; + + @override + String toString() { + return 'FlutterSdkRelease(channel: $channel, version: $version)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FlutterSdkReleaseImpl && + (identical(other.channel, channel) || other.channel == channel) && + (identical(other.version, version) || other.version == version)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, channel, version); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FlutterSdkReleaseImplCopyWith<_$FlutterSdkReleaseImpl> get copyWith => + __$$FlutterSdkReleaseImplCopyWithImpl<_$FlutterSdkReleaseImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$FlutterSdkReleaseImplToJson( + this, + ); + } +} + +abstract class _FlutterSdkRelease implements FlutterSdkRelease { + factory _FlutterSdkRelease( + {required final FlutterChannel channel, + @_VersionJsonConverter() required final Version version}) = + _$FlutterSdkReleaseImpl; + + factory _FlutterSdkRelease.fromJson(Map json) = + _$FlutterSdkReleaseImpl.fromJson; + + @override + FlutterChannel get channel; + @override + @_VersionJsonConverter() + Version get version; + @override + @JsonKey(ignore: true) + _$$FlutterSdkReleaseImplCopyWith<_$FlutterSdkReleaseImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/tools/cleanup_template/lib/src/models/flutter_sdk_release.g.dart b/tools/cleanup_template/lib/src/models/flutter_sdk_release.g.dart new file mode 100644 index 0000000..3f2fecd --- /dev/null +++ b/tools/cleanup_template/lib/src/models/flutter_sdk_release.g.dart @@ -0,0 +1,38 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: type=lint, duplicate_ignore + +part of 'flutter_sdk_release.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$FlutterSdkReleaseImpl _$$FlutterSdkReleaseImplFromJson( + Map json) => + $checkedCreate( + r'_$FlutterSdkReleaseImpl', + json, + ($checkedConvert) { + final val = _$FlutterSdkReleaseImpl( + channel: $checkedConvert( + 'channel', (v) => $enumDecode(_$FlutterChannelEnumMap, v)), + version: $checkedConvert('version', + (v) => const _VersionJsonConverter().fromJson(v as String)), + ); + return val; + }, + ); + +Map _$$FlutterSdkReleaseImplToJson( + _$FlutterSdkReleaseImpl instance) => + { + 'channel': _$FlutterChannelEnumMap[instance.channel]!, + 'version': const _VersionJsonConverter().toJson(instance.version), + }; + +const _$FlutterChannelEnumMap = { + FlutterChannel.dev: 'dev', + FlutterChannel.beta: 'beta', + FlutterChannel.stable: 'stable', +}; diff --git a/tools/cleanup_template/lib/src/services/cleanup_service.dart b/tools/cleanup_template/lib/src/services/cleanup_service.dart new file mode 100644 index 0000000..ef7d02a --- /dev/null +++ b/tools/cleanup_template/lib/src/services/cleanup_service.dart @@ -0,0 +1,199 @@ +import 'dart:io'; + +import 'package:cleanup_template/src/file_system.dart'; +import 'package:cleanup_template/src/models/exit_status.dart'; +import 'package:cleanup_template/src/utils/process_run_exception.dart'; +import 'package:file/file.dart'; +import 'package:path/path.dart' as path; +import 'package:pub_semver/pub_semver.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'cleanup_service.g.dart'; + +@Riverpod(dependencies: [fileSystem]) +CleanupService cleanupService(CleanupServiceRef ref) { + final fileSystem = ref.watch(fileSystemProvider); + + return CleanupService( + fileSystem: fileSystem, + ); +} + +class CleanupService { + CleanupService({ + required FileSystem fileSystem, + }) : _fileSystem = fileSystem; + + final FileSystem _fileSystem; + + ExitStatus call(Version flutterVersion) { + // setup fvm + Process.runSync( + 'dart', + ['pub', 'global', 'activate', 'fvm'], + ).throwExceptionIfFailed(); + + // flutter-training-practice-template/ + final rootDir = _fileSystem.directory( + path.normalize( + path.join(_fileSystem.currentDirectory.path, '../../'), + ), + ); + + final tempDir = _fileSystem.systemTempDirectory; + + try { + // install latest flutter sdk and setup + Process.runSync( + 'fvm', + ['install', flutterVersion.toString(), '-s'], + ).throwExceptionIfFailed(); + + // create .fvm/ + Process.runSync( + 'fvm', + ['use', flutterVersion.toString(), '-f'], + workingDirectory: tempDir.path, + ).throwExceptionIfFailed(); + + // remove .gitignore + final gitignoreFile = + _fileSystem.file(path.join(tempDir.path, '.gitignore')); + gitignoreFile.deleteSync(); + + // create flutter project + Process.runSync( + 'fvm', + [ + 'flutter', + 'create', + '-t', + 'app', + '--empty', + '-i', + 'swift', + '-a', + 'kotlin', + '--platforms', + 'ios,android', + '--org', + 'jp.co.yumemi', + '--project-name', + 'flutter_training', + '.', + ], + workingDirectory: tempDir.path, + ).throwExceptionIfFailed(); + + // add .fvm/ to gitignore + gitignoreFile.writeAsStringSync( + ''' + +# FVM Version Cache +.fvm/ +''', + mode: FileMode.append, + ); + + // add yumemi_lints + Process.runSync( + 'fvm', + [ + 'flutter', + 'pub', + 'add', + '--dev', + 'yumemi_lints', + ], + workingDirectory: tempDir.path, + ).throwExceptionIfFailed(); + + // delete flutter_lints + Process.runSync( + 'fvm', + [ + 'flutter', + 'pub', + 'remove', + 'flutter_lints', + ], + workingDirectory: tempDir.path, + ).throwExceptionIfFailed(); + + // override analysis_options.yaml + final analysisOptionsPath = path.join( + tempDir.path, + 'analysis_options.yaml', + ); + _fileSystem.file(analysisOptionsPath).writeAsStringSync(''' +# https://pub.dev/packages/yumemi_lints +include: package:yumemi_lints/flutter/$flutterVersion/recommended.yaml +'''); + + // setting dart.flutterSdkPath + final githubTemplatesPath = path.join(rootDir.path, '.github/templates'); + final settingsJson = _fileSystem.file( + path.join(githubTemplatesPath, '.vscode/settings.json'), + ); + final replacedContent = settingsJson.readAsStringSync().replaceFirst( + RegExp('{{flutterVersion}}'), + flutterVersion.toString(), + ); + settingsJson.writeAsStringSync(replacedContent); + + // copy templates contents to tempDir + Process.runSync( + 'cp', + ['-R', '$githubTemplatesPath/.', tempDir.path], + ).throwExceptionIfFailed(); + + // delete anything except tempDir and toolsDir + Process.runSync( + 'rm', + [ + '-rf', + ...[ + '.gitignore', + '.github/', + 'docs/', + 'packages/', + 'LICENSE', + 'README.md', + ].map((e) => path.join(rootDir.path, e)), + ], + ).throwExceptionIfFailed(); + + // copy tempDir contents to rootDir + Process.runSync( + 'cp', + ['-R', '${tempDir.path}/.', rootDir.path], + ).throwExceptionIfFailed(); + + // delete tools directory + final toolsDir = _fileSystem.directory( + path.join( + rootDir.path, + 'tools', + ), + ); + toolsDir.deleteSync(recursive: true); + + return ExitStatus.success; + } on ProcessRunException catch (e) { + print(e.message); + return e.exitStatus; + } on FileSystemException catch (e) { + print(e.message); + return ExitStatus.errors; + } + } +} + +extension _ProcessResultExt on ProcessResult { + void throwExceptionIfFailed() { + final exitStatus = ExitStatus.fromCode(exitCode); + if (exitStatus != ExitStatus.success) { + throw ProcessRunException(exitStatus, stdout.toString()); + } + } +} diff --git a/tools/cleanup_template/lib/src/services/cleanup_service.g.dart b/tools/cleanup_template/lib/src/services/cleanup_service.g.dart new file mode 100644 index 0000000..954a67b --- /dev/null +++ b/tools/cleanup_template/lib/src/services/cleanup_service.g.dart @@ -0,0 +1,30 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: type=lint, duplicate_ignore + +part of 'cleanup_service.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$cleanupServiceHash() => r'071521002621dcfd0d94392783785c7d4b5ab56e'; + +/// See also [cleanupService]. +@ProviderFor(cleanupService) +final cleanupServiceProvider = AutoDisposeProvider.internal( + cleanupService, + name: r'cleanupServiceProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$cleanupServiceHash, + dependencies: [fileSystemProvider], + allTransitiveDependencies: { + fileSystemProvider, + ...?fileSystemProvider.allTransitiveDependencies + }, +); + +typedef CleanupServiceRef = AutoDisposeProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/tools/cleanup_template/lib/src/services/flutter_sdk_service.dart b/tools/cleanup_template/lib/src/services/flutter_sdk_service.dart new file mode 100644 index 0000000..2d6b017 --- /dev/null +++ b/tools/cleanup_template/lib/src/services/flutter_sdk_service.dart @@ -0,0 +1,62 @@ +import 'dart:convert'; + +import 'package:cleanup_template/src/clients/app_client.dart'; +import 'package:cleanup_template/src/models/flutter_sdk_release.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'flutter_sdk_service.g.dart'; + +@Riverpod(dependencies: [appClient]) +FlutterSdkService flutterSdkService(FlutterSdkServiceRef ref) { + final appClient = ref.watch(appClientProvider); + return FlutterSdkService( + appClient: appClient, + ); +} + +class FlutterSdkService { + const FlutterSdkService({ + required AppClient appClient, + }) : _appClient = appClient; + + final AppClient _appClient; + + @visibleForTesting + Future getLatestFlutterSdkRelease() async { + final url = Uri.https( + 'storage.googleapis.com', + '/flutter_infra_release/releases/releases_linux.json', + ); + + final responseBody = await _appClient.read(url); + + final json = jsonDecode(responseBody); + if (json is! Map) { + throw FormatException( + 'The type of `json` should be `Map`.', + ); + } + final releases = json['releases']; + if (releases is! List) { + throw FormatException( + 'The type of `releases` should be `List`.', + ); + } + + return releases.map((release) { + if (release is! Map) { + throw FormatException( + 'The type of `release` should be `Map`.', + ); + } + return FlutterSdkRelease.fromJson(release); + }).firstWhere((release) => release.channel == FlutterChannel.stable); + } + + Future getLatestFlutterSdkVersion() async { + final latestFlutterSdkRelease = await getLatestFlutterSdkRelease(); + return latestFlutterSdkRelease.version; + } +} diff --git a/tools/cleanup_template/lib/src/services/flutter_sdk_service.g.dart b/tools/cleanup_template/lib/src/services/flutter_sdk_service.g.dart new file mode 100644 index 0000000..ee1a180 --- /dev/null +++ b/tools/cleanup_template/lib/src/services/flutter_sdk_service.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: type=lint, duplicate_ignore + +part of 'flutter_sdk_service.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$flutterSdkServiceHash() => r'c61c0af1623cd0a26fd30cfe776a142bc95f5919'; + +/// See also [flutterSdkService]. +@ProviderFor(flutterSdkService) +final flutterSdkServiceProvider = + AutoDisposeProvider.internal( + flutterSdkService, + name: r'flutterSdkServiceProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$flutterSdkServiceHash, + dependencies: [appClientProvider], + allTransitiveDependencies: { + appClientProvider, + ...?appClientProvider.allTransitiveDependencies + }, +); + +typedef FlutterSdkServiceRef = AutoDisposeProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/tools/cleanup_template/lib/src/utils/process_run_exception.dart b/tools/cleanup_template/lib/src/utils/process_run_exception.dart new file mode 100644 index 0000000..d745ae0 --- /dev/null +++ b/tools/cleanup_template/lib/src/utils/process_run_exception.dart @@ -0,0 +1,7 @@ +import 'package:cleanup_template/src/models/exit_status.dart'; + +class ProcessRunException implements Exception { + const ProcessRunException(this.exitStatus, this.message); + final ExitStatus exitStatus; + final String message; +} diff --git a/tools/cleanup_template/pubspec.lock b/tools/cleanup_template/pubspec.lock new file mode 100644 index 0000000..5ae76e8 --- /dev/null +++ b/tools/cleanup_template/pubspec.lock @@ -0,0 +1,693 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + url: "https://pub.dev" + source: hosted + version: "0.11.3" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + url: "https://pub.dev" + source: hosted + version: "2.4.8" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + url: "https://pub.dev" + source: hosted + version: "7.3.0" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + url: "https://pub.dev" + source: hosted + version: "8.9.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + custom_lint: + dependency: "direct dev" + description: + name: custom_lint + sha256: "445242371d91d2e24bd7b82e3583a2c05610094ba2d0575262484ad889c8f981" + url: "https://pub.dev" + source: hosted + version: "0.6.2" + custom_lint_builder: + dependency: transitive + description: + name: custom_lint_builder + sha256: "4c0aed2a3491096e91cf1281923ba1b6814993f16dde0fd60f697925225bbbd6" + url: "https://pub.dev" + source: hosted + version: "0.6.2" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: ce5d6215f4e143f7780ce53f73dfa6fc503f39d2d30bef76c48be9ac1a09d9a6 + url: "https://pub.dev" + source: hosted + version: "0.6.2" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + file: + dependency: "direct main" + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "57247f692f35f068cae297549a46a9a097100685c6780fe67177503eea5ed4e5" + url: "https://pub.dev" + source: hosted + version: "2.4.7" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + hotreloader: + dependency: transitive + description: + name: hotreloader + sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e + url: "https://pub.dev" + source: hosted + version: "4.2.0" + http: + dependency: "direct main" + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + url: "https://pub.dev" + source: hosted + version: "6.7.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: "direct main" + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + riverpod: + dependency: "direct main" + description: + name: riverpod + sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d + url: "https://pub.dev" + source: hosted + version: "2.5.1" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: "8b71f03fc47ae27d13769496a1746332df4cec43918aeba9aff1e232783a780f" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + riverpod_annotation: + dependency: "direct main" + description: + name: riverpod_annotation + sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c + url: "https://pub.dev" + source: hosted + version: "2.3.5" + riverpod_generator: + dependency: "direct dev" + description: + name: riverpod_generator + sha256: d451608bf17a372025fc36058863737636625dfdb7e3cbf6142e0dfeb366ab22 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + riverpod_lint: + dependency: "direct dev" + description: + name: riverpod_lint + sha256: "3c67c14ccd16f0c9d53e35ef70d06cd9d072e2fb14557326886bbde903b230a5" + url: "https://pub.dev" + source: hosted + version: "2.3.10" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + url: "https://pub.dev" + source: hosted + version: "1.25.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + url: "https://pub.dev" + source: hosted + version: "4.3.3" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: e7d5ecd604e499358c5fe35ee828c0298a320d54455e791e9dcf73486bc8d9f0 + url: "https://pub.dev" + source: hosted + version: "14.1.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + yumemi_lints: + dependency: "direct main" + description: + name: yumemi_lints + sha256: "51aefbdf37ec2096f0440f91627735c10a1eaacc7cd3e34f372e1e91a8e146f4" + url: "https://pub.dev" + source: hosted + version: "1.7.0" +sdks: + dart: ">=3.3.0 <4.0.0" diff --git a/tools/cleanup_template/pubspec.yaml b/tools/cleanup_template/pubspec.yaml new file mode 100644 index 0000000..35785dd --- /dev/null +++ b/tools/cleanup_template/pubspec.yaml @@ -0,0 +1,26 @@ +name: cleanup_template +description: A sample command-line application. +version: 1.0.0 + +environment: + sdk: ^3.3.0 + +dependencies: + file: ^7.0.0 + freezed_annotation: ^2.4.1 + http: ^1.2.1 + json_annotation: ^4.8.1 + path: ^1.9.0 + pub_semver: ^2.1.4 + riverpod: ^2.5.1 + riverpod_annotation: ^2.3.5 + yumemi_lints: ^1.7.0 + +dev_dependencies: + build_runner: ^2.4.8 + custom_lint: ^0.6.2 + freezed: ^2.4.7 + json_serializable: ^6.7.1 + riverpod_generator: ^2.4.0 + riverpod_lint: ^2.3.10 + test: ^1.25.2 diff --git a/tools/cleanup_template/test/cleanup_template_test.dart b/tools/cleanup_template/test/cleanup_template_test.dart new file mode 100644 index 0000000..2bad7b8 --- /dev/null +++ b/tools/cleanup_template/test/cleanup_template_test.dart @@ -0,0 +1,30 @@ +import 'package:cleanup_template/cleanup_template.dart'; +import 'package:cleanup_template/src/file_system.dart'; +import 'package:cleanup_template/src/models/exit_status.dart'; +import 'package:cleanup_template/src/services/cleanup_service.dart'; +import 'package:cleanup_template/src/services/flutter_sdk_service.dart'; +import 'package:file/memory.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:test/test.dart'; + +import 'fakes/services/fake_cleanup_service.dart'; +import 'fakes/services/fake_flutter_sdk_service.dart'; + +void main() { + test('cleanupTemplate', () async { + final fileSystem = MemoryFileSystem(); + + final container = ProviderContainer( + overrides: [ + fileSystemProvider.overrideWithValue(fileSystem), + flutterSdkServiceProvider.overrideWithValue(FakeFlutterSdkService()), + cleanupServiceProvider.overrideWithValue(FakeCleanupService()), + ], + ); + addTearDown(container.dispose); + + final status = await cleanupTemplate(container); + + expect(status, ExitStatus.success); + }); +} diff --git a/tools/cleanup_template/test/fakes/services/fake_cleanup_service.dart b/tools/cleanup_template/test/fakes/services/fake_cleanup_service.dart new file mode 100644 index 0000000..fcf5aac --- /dev/null +++ b/tools/cleanup_template/test/fakes/services/fake_cleanup_service.dart @@ -0,0 +1,10 @@ +import 'package:cleanup_template/src/models/exit_status.dart'; +import 'package:cleanup_template/src/services/cleanup_service.dart'; +import 'package:pub_semver/src/version.dart'; + +class FakeCleanupService implements CleanupService { + @override + ExitStatus call(Version flutterVersion) { + return ExitStatus.success; + } +} diff --git a/tools/cleanup_template/test/fakes/services/fake_flutter_sdk_service.dart b/tools/cleanup_template/test/fakes/services/fake_flutter_sdk_service.dart new file mode 100644 index 0000000..0531217 --- /dev/null +++ b/tools/cleanup_template/test/fakes/services/fake_flutter_sdk_service.dart @@ -0,0 +1,18 @@ +import 'package:cleanup_template/src/models/flutter_sdk_release.dart'; +import 'package:cleanup_template/src/services/flutter_sdk_service.dart'; +import 'package:pub_semver/pub_semver.dart'; + +class FakeFlutterSdkService implements FlutterSdkService { + @override + Future getLatestFlutterSdkRelease() async { + return FlutterSdkRelease( + channel: FlutterChannel.stable, + version: Version(3, 19, 0), + ); + } + + @override + Future getLatestFlutterSdkVersion() async { + return Version(3, 19, 0); + } +}