@@ -7,14 +7,14 @@ import 'package:path/path.dart' as p;
77import 'package:pubspec_parse/pubspec_parse.dart' ;
88import 'package:yaml/yaml.dart' ;
99
10+ import 'ci_config.dart' ;
1011import 'core.dart' ;
12+ import 'pending_changelog_entry.dart' ;
1113
1214export 'package:pubspec_parse/pubspec_parse.dart' show Pubspec;
15+ export 'ci_config.dart' ;
1316export 'core.dart' show FlutterPlatform;
14-
15- // The template file name used to draft a pending changelog file.
16- // This file will not be picked up by the batch release process.
17- const String _kTemplateFileName = 'template.yaml' ;
17+ export 'pending_changelog_entry.dart' ;
1818
1919/// A package in the repository.
2020//
@@ -125,14 +125,14 @@ class RepositoryPackage {
125125 /// Caches for future use.
126126 Pubspec parsePubspec () => _parsedPubspec;
127127
128- late final CiConfig ? _parsedCiConfig = ciConfigFile.existsSync ()
129- ? CiConfig . _parse (ciConfigFile.readAsStringSync ())
128+ late final CIConfig ? _parsedCIConfig = ciConfigFile.existsSync ()
129+ ? CIConfig . parse (ciConfigFile.readAsStringSync ())
130130 : null ;
131131
132132 /// Returns the parsed [ciConfigFile] , or null if it does not exist.
133133 ///
134134 /// Throws if the file exists but is not a valid ci_config.yaml.
135- CiConfig ? parseCiConfig () => _parsedCiConfig ;
135+ CIConfig ? parseCIConfig () => _parsedCIConfig ;
136136
137137 /// Returns true if the package depends on Flutter.
138138 bool requiresFlutter () {
@@ -262,7 +262,7 @@ class RepositoryPackage {
262262 for (final File file in allFiles) {
263263 final String basename = p.basename (file.path);
264264 if (basename.endsWith ('.yaml' )) {
265- if (basename != _kTemplateFileName ) {
265+ if (! PendingChangelogEntry . isTemplate (file) ) {
266266 pendingChangelogFiles.add (file);
267267 }
268268 } else {
@@ -273,8 +273,7 @@ class RepositoryPackage {
273273
274274 for (final File file in pendingChangelogFiles) {
275275 try {
276- entries
277- .add (PendingChangelogEntry ._parse (file.readAsStringSync (), file));
276+ entries.add (PendingChangelogEntry .parse (file.readAsStringSync (), file));
278277 } on FormatException catch (e) {
279278 throw FormatException (
280279 'Malformed pending changelog file: ${file .path }\n $e ' );
@@ -283,135 +282,3 @@ class RepositoryPackage {
283282 return entries;
284283 }
285284}
286-
287- /// A class representing the parsed content of a `ci_config.yaml` file.
288- class CiConfig {
289- /// Creates a [CiConfig] from a parsed YAML map.
290- CiConfig ._(this .isBatchRelease);
291-
292- /// Parses a [CiConfig] from a YAML string.
293- ///
294- /// Throws if the YAML is not a valid ci_config.yaml.
295- factory CiConfig ._parse (String yaml) {
296- final Object ? loaded = loadYaml (yaml);
297- if (loaded is ! YamlMap ) {
298- throw const FormatException ('Root of ci_config.yaml must be a map.' );
299- }
300-
301- _checkCiConfigEntries (loaded, syntax: _validCiConfigSyntax);
302-
303- bool isBatchRelease = false ;
304- final Object ? release = loaded['release' ];
305- if (release is Map ) {
306- isBatchRelease = release['batch' ] == true ;
307- }
308-
309- return CiConfig ._(isBatchRelease);
310- }
311-
312- static const Map <String , Object ?> _validCiConfigSyntax = < String , Object ? > {
313- 'release' : < String , Object ? > {
314- 'batch' : < bool > {true , false }
315- },
316- };
317-
318- /// Returns true if the package is configured for batch release.
319- final bool isBatchRelease;
320-
321- static void _checkCiConfigEntries (YamlMap config,
322- {required Map <String , Object ?> syntax, String configPrefix = '' }) {
323- for (final MapEntry <Object ?, Object ?> entry in config.entries) {
324- if (! syntax.containsKey (entry.key)) {
325- throw FormatException (
326- 'Unknown key `${entry .key }` in config${_formatConfigPrefix (configPrefix )}, the possible keys are ${syntax .keys .toList ()}' );
327- } else {
328- final Object syntaxValue = syntax[entry.key]! ;
329- final String newConfigPrefix = configPrefix.isEmpty
330- ? entry.key! as String
331- : '$configPrefix .${entry .key }' ;
332- if (syntaxValue is Set ) {
333- if (! syntaxValue.contains (entry.value)) {
334- throw FormatException (
335- 'Invalid value `${entry .value }` for key${_formatConfigPrefix (newConfigPrefix )}, the possible values are ${syntaxValue .toList ()}' );
336- }
337- } else if (entry.value is ! YamlMap ) {
338- throw FormatException (
339- 'Invalid value `${entry .value }` for key${_formatConfigPrefix (newConfigPrefix )}, the value must be a map' );
340- } else {
341- _checkCiConfigEntries (entry.value! as YamlMap ,
342- syntax: syntaxValue as Map <String , Object ?>,
343- configPrefix: newConfigPrefix);
344- }
345- }
346- }
347- }
348-
349- static String _formatConfigPrefix (String configPrefix) =>
350- configPrefix.isEmpty ? '' : ' `$configPrefix `' ;
351- }
352-
353- /// The type of version change described by a changelog entry.
354- ///
355- /// The order of the enum values is important as it is used to determine which version
356- /// take priority when multiple version changes are specified. The top most value
357- /// (the samller the index) has the highest priority.
358- enum VersionChange {
359- /// A major version change (e.g., 1.2.3 -> 2.0.0).
360- major,
361-
362- /// A minor version change (e.g., 1.2.3 -> 1.3.0).
363- minor,
364-
365- /// A patch version change (e.g., 1.2.3 -> 1.2.4).
366- patch,
367-
368- /// No version change.
369- skip,
370- }
371-
372- /// Represents a single entry in the pending changelog.
373- class PendingChangelogEntry {
374- /// Creates a new pending changelog entry.
375- PendingChangelogEntry (
376- {required this .changelog, required this .version, required this .file});
377-
378- /// Creates a PendingChangelogEntry from a YAML string.
379- ///
380- /// Throws if the YAML is not a valid pending changelog entry.
381- factory PendingChangelogEntry ._parse (String yamlContent, File file) {
382- final dynamic yaml = loadYaml (yamlContent);
383- if (yaml is ! YamlMap ) {
384- throw FormatException (
385- 'Expected a YAML map, but found ${yaml .runtimeType }.' );
386- }
387-
388- final dynamic changelogYaml = yaml['changelog' ];
389- if (changelogYaml is ! String ) {
390- throw FormatException (
391- 'Expected "changelog" to be a string, but found ${changelogYaml .runtimeType }.' );
392- }
393- final String changelog = changelogYaml.trim ();
394-
395- final String ? versionString = yaml['version' ] as String ? ;
396- if (versionString == null ) {
397- throw const FormatException ('Missing "version" key.' );
398- }
399- final VersionChange version = VersionChange .values.firstWhere (
400- (VersionChange e) => e.name == versionString,
401- orElse: () =>
402- throw FormatException ('Invalid version type: $versionString ' ),
403- );
404-
405- return PendingChangelogEntry (
406- changelog: changelog, version: version, file: file);
407- }
408-
409- /// The changelog messages for this entry.
410- final String changelog;
411-
412- /// The type of version change for this entry.
413- final VersionChange version;
414-
415- /// The file that this entry was parsed from.
416- final File file;
417- }
0 commit comments