feat: automate version.g.dart generation via build_runner

Replace manual generate_version.dart script with a custom build_runner
builder that automatically generates lib/version.g.dart from pubspec.yaml
during the build process. This eliminates manual steps and ensures version
info stays in sync.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-30 17:27:10 +01:00
co-authored by Claude Opus 4.5
parent 3af4fd16f8
commit 4b0c6b292a
6 changed files with 67 additions and 52 deletions
+8 -1
View File
@@ -129,7 +129,9 @@ flutter run # Default device
### Code Generation ### Code Generation
After modifying any `@freezed`, `@JsonSerializable`, or `@riverpod` annotated code: Run build_runner after modifying:
- `@freezed`, `@JsonSerializable`, or `@riverpod` annotated code
- `pubspec.yaml` version (auto-generates `lib/version.g.dart`)
```bash ```bash
dart run build_runner build --delete-conflicting-outputs dart run build_runner build --delete-conflicting-outputs
@@ -138,6 +140,11 @@ dart run build_runner build --delete-conflicting-outputs
dart run build_runner watch --delete-conflicting-outputs dart run build_runner watch --delete-conflicting-outputs
``` ```
**Generated files**:
- `*.freezed.dart` - Freezed immutable classes
- `*.g.dart` - JSON serialization, Riverpod providers
- `lib/version.g.dart` - App version from pubspec.yaml
## Deployment ## Deployment
### Web (Docker) ### Web (Docker)
+8
View File
@@ -0,0 +1,8 @@
builders:
version_builder:
import: "tool/version_builder.dart"
builder_factories: ["versionBuilder"]
build_extensions: { r"$package$": ["lib/version.g.dart"] }
auto_apply: root_package
build_to: source
runs_before: ["freezed", "riverpod_generator", "json_serializable"]
+1 -1
View File
@@ -1,5 +1,5 @@
// GENERATED FILE - DO NOT EDIT // GENERATED FILE - DO NOT EDIT
// Generated by: dart run tool/generate_version.dart // Generated by build_runner from pubspec.yaml
/// Application version information from pubspec.yaml /// Application version information from pubspec.yaml
class AppVersion { class AppVersion {
+1
View File
@@ -76,6 +76,7 @@ dev_dependencies:
mocktail: ^1.0.4 mocktail: ^1.0.4
# Build tools # Build tools
build: ^2.4.0
yaml: ^3.1.0 yaml: ^3.1.0
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
-50
View File
@@ -1,50 +0,0 @@
#!/usr/bin/env dart
/// Generates lib/version.g.dart from pubspec.yaml
///
/// Run before building: `dart run tool/generate_version.dart`
import 'dart:io';
import 'package:yaml/yaml.dart';
void main() {
final pubspecFile = File('pubspec.yaml');
if (!pubspecFile.existsSync()) {
stderr.writeln('Error: pubspec.yaml not found');
exit(1);
}
final pubspec = loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
final name = pubspec['name'] as String;
final description = pubspec['description'] as String;
final versionString = pubspec['version'] as String;
// Parse version: "0.1.0+1" -> version="0.1.0", buildNumber=1
final versionParts = versionString.split('+');
final version = versionParts[0];
final buildNumber = versionParts.length > 1 ? int.parse(versionParts[1]) : 0;
final output = '''
// GENERATED FILE - DO NOT EDIT
// Generated by: dart run tool/generate_version.dart
/// Application version information from pubspec.yaml
class AppVersion {
AppVersion._();
static const String name = '$name';
static const String description = '$description';
static const String version = '$version';
static const int buildNumber = $buildNumber;
static const String fullVersion = '$version+$buildNumber';
}
''';
final outputFile = File('lib/version.g.dart');
outputFile.writeAsStringSync(output);
print('Generated lib/version.g.dart');
print(' name: $name');
print(' version: $version+$buildNumber');
}
+49
View File
@@ -0,0 +1,49 @@
import 'dart:async';
import 'package:build/build.dart';
import 'package:yaml/yaml.dart';
/// Builder that generates version.g.dart from pubspec.yaml.
Builder versionBuilder(BuilderOptions options) => VersionBuilder();
class VersionBuilder implements Builder {
@override
final buildExtensions = const {
r'$package$': ['lib/version.g.dart'],
};
@override
Future<void> build(BuildStep buildStep) async {
final pubspecId = AssetId(buildStep.inputId.package, 'pubspec.yaml');
final pubspecContent = await buildStep.readAsString(pubspecId);
final pubspec = loadYaml(pubspecContent) as YamlMap;
final name = pubspec['name'] as String;
final description = pubspec['description'] as String? ?? '';
final versionString = pubspec['version'] as String;
// Parse version: "0.2.0+2" -> version="0.2.0", buildNumber=2
final versionParts = versionString.split('+');
final version = versionParts[0];
final buildNumber = versionParts.length > 1 ? int.parse(versionParts[1]) : 0;
final output = '''
// GENERATED FILE - DO NOT EDIT
// Generated by build_runner from pubspec.yaml
/// Application version information from pubspec.yaml
class AppVersion {
AppVersion._();
static const String name = '$name';
static const String description = '$description';
static const String version = '$version';
static const int buildNumber = $buildNumber;
static const String fullVersion = '$version+$buildNumber';
}
''';
final outputId = AssetId(buildStep.inputId.package, 'lib/version.g.dart');
await buildStep.writeAsString(outputId, output);
}
}