| // Copyright 2013 The Flutter Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'package:yaml/yaml.dart'; | |
| const String _releaseModeKey = 'release'; | |
| const String _isBatchModeKey = 'batch'; | |
| const String _exemptFromExcerptsKey = 'exempt_from_excerpts'; | |
| const String _analyzeSkillsKey = 'analyze_skills'; | |
| const String _allowCustomAnalysisOptionsKey = 'allow_custom_analysis_options'; | |
| /// A class representing the parsed content of a `ci_config.yaml` file. | |
| class CIConfig { | |
| /// Creates a [CIConfig] from a parsed YAML map. | |
| CIConfig._({ | |
| required this.isBatchRelease, | |
| required this.requiresExcerpts, | |
| required this.analyzeSkills, | |
| required this.allowCustomAnalysisOptions, | |
| }); | |
| /// Parses a [CIConfig] from a YAML string. | |
| /// | |
| /// Throws if the YAML is not a valid ci_config.yaml. | |
| factory CIConfig.parse(String yaml) { | |
| final Object? loaded = loadYaml(yaml); | |
| if (loaded is! YamlMap) { | |
| throw const FormatException('Root of ci_config.yaml must be a map.'); | |
| } | |
| _checkCIConfigEntries(loaded, syntax: _validCIConfigSyntax); | |
| var isBatchRelease = false; | |
| final Object? release = loaded[_releaseModeKey]; | |
| if (release is Map) { | |
| isBatchRelease = release[_isBatchModeKey] == true; | |
| } | |
| // Any package that hasn't been explicitly exempted is assumed to require | |
| // excerpts. | |
| final requiresExcerpts = loaded[_exemptFromExcerptsKey] != true; | |
| final analyzeSkills = loaded[_analyzeSkillsKey] == true; | |
| final allowCustomAnalysisOptions = loaded[_allowCustomAnalysisOptionsKey] == true; | |
| return CIConfig._( | |
| isBatchRelease: isBatchRelease, | |
| requiresExcerpts: requiresExcerpts, | |
| analyzeSkills: analyzeSkills, | |
| allowCustomAnalysisOptions: allowCustomAnalysisOptions, | |
| ); | |
| } | |
| static const Map<String, Object?> _validCIConfigSyntax = <String, Object?>{ | |
| _releaseModeKey: <String, Object?>{ | |
| _isBatchModeKey: <bool>{true, false}, | |
| }, | |
| _exemptFromExcerptsKey: <bool>{true, false}, | |
| _analyzeSkillsKey: <bool>{true, false}, | |
| _allowCustomAnalysisOptionsKey: <bool>{true, false}, | |
| }; | |
| /// Returns true if the package is configured for batch release. | |
| final bool isBatchRelease; | |
| /// Returns true if the package is configured to require excerpts. | |
| final bool requiresExcerpts; | |
| /// Returns true if the package has its agent skills analyzed. | |
| final bool analyzeSkills; | |
| /// Returns true if the package is allowed to have its own analysis options. | |
| final bool allowCustomAnalysisOptions; | |
| static void _checkCIConfigEntries( | |
| YamlMap config, { | |
| required Map<String, Object?> syntax, | |
| String configPrefix = '', | |
| }) { | |
| for (final MapEntry<Object?, Object?> entry in config.entries) { | |
| if (!syntax.containsKey(entry.key)) { | |
| throw FormatException( | |
| 'Unknown key `${entry.key}` in config${_formatConfigPrefix(configPrefix)}, the possible keys are ${syntax.keys.toList()}', | |
| ); | |
| } else { | |
| final Object syntaxValue = syntax[entry.key]!; | |
| final newConfigPrefix = configPrefix.isEmpty | |
| ? entry.key! as String | |
| : '$configPrefix.${entry.key}'; | |
| if (syntaxValue is Set) { | |
| if (!syntaxValue.contains(entry.value)) { | |
| throw FormatException( | |
| 'Invalid value `${entry.value}` for key${_formatConfigPrefix(newConfigPrefix)}, the possible values are ${syntaxValue.toList()}', | |
| ); | |
| } | |
| } else if (entry.value is! YamlMap) { | |
| throw FormatException( | |
| 'Invalid value `${entry.value}` for key${_formatConfigPrefix(newConfigPrefix)}, the value must be a map', | |
| ); | |
| } else { | |
| _checkCIConfigEntries( | |
| entry.value! as YamlMap, | |
| syntax: syntaxValue as Map<String, Object?>, | |
| configPrefix: newConfigPrefix, | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| static String _formatConfigPrefix(String configPrefix) => | |
| configPrefix.isEmpty ? '' : ' `$configPrefix`'; | |
| } |