From 4b0c6b292a7a024ebcd8f9233b96037e04781101 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 30 Dec 2025 17:27:10 +0100 Subject: [PATCH] feat: automate version.g.dart generation via build_runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- README.md | 9 ++++++- build.yaml | 8 ++++++ lib/version.g.dart | 2 +- pubspec.yaml | 1 + tool/generate_version.dart | 50 -------------------------------------- tool/version_builder.dart | 49 +++++++++++++++++++++++++++++++++++++ 6 files changed, 67 insertions(+), 52 deletions(-) create mode 100644 build.yaml delete mode 100644 tool/generate_version.dart create mode 100644 tool/version_builder.dart diff --git a/README.md b/README.md index b92c1e9..0128e31 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,9 @@ flutter run # Default device ### 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 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 ``` +**Generated files**: +- `*.freezed.dart` - Freezed immutable classes +- `*.g.dart` - JSON serialization, Riverpod providers +- `lib/version.g.dart` - App version from pubspec.yaml + ## Deployment ### Web (Docker) diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000..4a5216a --- /dev/null +++ b/build.yaml @@ -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"] diff --git a/lib/version.g.dart b/lib/version.g.dart index 5fbc6ce..8bd25d4 100644 --- a/lib/version.g.dart +++ b/lib/version.g.dart @@ -1,5 +1,5 @@ // 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 class AppVersion { diff --git a/pubspec.yaml b/pubspec.yaml index c1590a1..600b077 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,6 +76,7 @@ dev_dependencies: mocktail: ^1.0.4 # Build tools + build: ^2.4.0 yaml: ^3.1.0 # For information on the generic Dart part of this file, see the diff --git a/tool/generate_version.dart b/tool/generate_version.dart deleted file mode 100644 index c0d6130..0000000 --- a/tool/generate_version.dart +++ /dev/null @@ -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'); -} diff --git a/tool/version_builder.dart b/tool/version_builder.dart new file mode 100644 index 0000000..f42ab1f --- /dev/null +++ b/tool/version_builder.dart @@ -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 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); + } +}