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