Skip to content

Commit fb0209c

Browse files
committed
everything before non batch check
1 parent a3c7ab2 commit fb0209c

16 files changed

+817
-504
lines changed

packages/go_router/pending_changelogs/template.yaml

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/go_router/pending_changelogs/test_only_1.yaml

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/go_router/pending_changelogs/test_only_2.yaml

Lines changed: 0 additions & 5 deletions
This file was deleted.

script/tool/lib/src/branch_for_batch_release_command.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ class BranchForBatchReleaseCommand extends PackageCommand {
117117
List<PendingChangelogEntry> pendingChangelogEntries,
118118
Version oldVersion,
119119
) {
120-
final List<String> changelogs = <String>[];
120+
final changelogs = <String>[];
121121
int versionIndex = VersionChange.skip.index;
122-
for (final PendingChangelogEntry entry in pendingChangelogEntries) {
122+
for (final entry in pendingChangelogEntries) {
123123
changelogs.add(entry.changelog);
124124
versionIndex = math.min(versionIndex, entry.version.index);
125125
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2013 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:yaml/yaml.dart';
6+
7+
/// A class representing the parsed content of a `ci_config.yaml` file.
8+
class CIConfig {
9+
/// Creates a [CIConfig] from a parsed YAML map.
10+
CIConfig._(this.isBatchRelease);
11+
12+
/// Parses a [CIConfig] from a YAML string.
13+
///
14+
/// Throws if the YAML is not a valid ci_config.yaml.
15+
factory CIConfig.parse(String yaml) {
16+
final Object? loaded = loadYaml(yaml);
17+
if (loaded is! YamlMap) {
18+
throw const FormatException('Root of ci_config.yaml must be a map.');
19+
}
20+
21+
_checkCIConfigEntries(loaded, syntax: _validCIConfigSyntax);
22+
23+
var isBatchRelease = false;
24+
final Object? release = loaded['release'];
25+
if (release is Map) {
26+
isBatchRelease = release['batch'] == true;
27+
}
28+
29+
return CIConfig._(isBatchRelease);
30+
}
31+
32+
static const Map<String, Object?> _validCIConfigSyntax = <String, Object?>{
33+
'release': <String, Object?>{
34+
'batch': <bool>{true, false},
35+
},
36+
};
37+
38+
/// Returns true if the package is configured for batch release.
39+
final bool isBatchRelease;
40+
41+
static void _checkCIConfigEntries(
42+
YamlMap config, {
43+
required Map<String, Object?> syntax,
44+
String configPrefix = '',
45+
}) {
46+
for (final MapEntry<Object?, Object?> entry in config.entries) {
47+
if (!syntax.containsKey(entry.key)) {
48+
throw FormatException(
49+
'Unknown key `${entry.key}` in config${_formatConfigPrefix(configPrefix)}, the possible keys are ${syntax.keys.toList()}',
50+
);
51+
} else {
52+
final Object syntaxValue = syntax[entry.key]!;
53+
final newConfigPrefix = configPrefix.isEmpty
54+
? entry.key! as String
55+
: '$configPrefix.${entry.key}';
56+
if (syntaxValue is Set) {
57+
if (!syntaxValue.contains(entry.value)) {
58+
throw FormatException(
59+
'Invalid value `${entry.value}` for key${_formatConfigPrefix(newConfigPrefix)}, the possible values are ${syntaxValue.toList()}',
60+
);
61+
}
62+
} else if (entry.value is! YamlMap) {
63+
throw FormatException(
64+
'Invalid value `${entry.value}` for key${_formatConfigPrefix(newConfigPrefix)}, the value must be a map',
65+
);
66+
} else {
67+
_checkCIConfigEntries(
68+
entry.value! as YamlMap,
69+
syntax: syntaxValue as Map<String, Object?>,
70+
configPrefix: newConfigPrefix,
71+
);
72+
}
73+
}
74+
}
75+
}
76+
77+
static String _formatConfigPrefix(String configPrefix) =>
78+
configPrefix.isEmpty ? '' : ' `$configPrefix`';
79+
}

script/tool/lib/src/common/package_state_utils.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Future<PackageChangeState> checkPackageChangeState(
8080
continue;
8181
}
8282

83-
if (package.parseCiConfig()?.isBatchRelease ?? false) {
83+
if (package.parseCIConfig()?.isBatchRelease ?? false) {
8484
if (components.first == 'pending_changelogs') {
8585
hasChangelogChange = true;
8686
continue;
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2013 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:file/file.dart';
6+
import 'package:path/path.dart' as p;
7+
import 'package:yaml/yaml.dart';
8+
9+
/// The system for managing pending changelog entries.
10+
///
11+
/// When package opts into batch release (through ci_config.yaml), it uses a "pending
12+
/// changelog" system. When a PR makes a change that requires a changelog entry,
13+
/// the entry is written to a new YAML file in the `pending_changelogs` directory
14+
/// of the package, rather than editing `CHANGELOG.md` directly.
15+
///
16+
/// ## Directory Structure
17+
/// For batch release packages, it has a `pending_changelogs` directory containing:
18+
/// - A `template.yaml` file (which is ignored by the release tooling).
19+
/// - One or more YAML files for pending changes (e.g., `fix_issue_123.yaml`).
20+
///
21+
/// ## File Format
22+
/// The YAML file must contain the following keys:
23+
/// - `changelog`: The text of the changelog entry.
24+
/// - `version`: The type of version bump (`major`, `minor`, `patch`, or `skip`).
25+
///
26+
/// Example:
27+
/// ```yaml
28+
/// changelog: Fixes a bug in the foo widget.
29+
/// version: patch
30+
/// ```
31+
///
32+
/// During a release (specifically the `update-changelogs` command), all
33+
/// pending entries are aggregated, the package version is updated based on the
34+
/// highest priority change, and `CHANGELOG.md` is updated.
35+
36+
/// The type of version change described by a changelog entry.
37+
///
38+
/// The order of the enum values is important as it is used to determine which version
39+
/// take priority when multiple version changes are specified. The top most value
40+
/// (the samller the index) has the highest priority.
41+
enum VersionChange {
42+
/// A major version change (e.g., 1.2.3 -> 2.0.0).
43+
major,
44+
45+
/// A minor version change (e.g., 1.2.3 -> 1.3.0).
46+
minor,
47+
48+
/// A patch version change (e.g., 1.2.3 -> 1.2.4).
49+
patch,
50+
51+
/// No version change.
52+
skip,
53+
}
54+
55+
/// Represents a single entry in the pending changelog.
56+
class PendingChangelogEntry {
57+
/// Creates a new pending changelog entry.
58+
PendingChangelogEntry({
59+
required this.changelog,
60+
required this.version,
61+
required this.file,
62+
});
63+
64+
/// Creates a PendingChangelogEntry from a YAML string.
65+
///
66+
/// Throws if the YAML is not a valid pending changelog entry.
67+
factory PendingChangelogEntry.parse(String yamlContent, File file) {
68+
final dynamic yaml = loadYaml(yamlContent);
69+
if (yaml is! YamlMap) {
70+
throw FormatException(
71+
'Expected a YAML map, but found ${yaml.runtimeType}.',
72+
);
73+
}
74+
75+
final dynamic changelogYaml = yaml['changelog'];
76+
if (changelogYaml is! String) {
77+
throw FormatException(
78+
'Expected "changelog" to be a string, but found ${changelogYaml.runtimeType}.',
79+
);
80+
}
81+
final String changelog = changelogYaml.trim();
82+
83+
final versionString = yaml['version'] as String?;
84+
if (versionString == null) {
85+
throw const FormatException('Missing "version" key.');
86+
}
87+
final VersionChange version = VersionChange.values.firstWhere(
88+
(VersionChange e) => e.name == versionString,
89+
orElse: () =>
90+
throw FormatException('Invalid version type: $versionString'),
91+
);
92+
93+
return PendingChangelogEntry(
94+
changelog: changelog,
95+
version: version,
96+
file: file,
97+
);
98+
}
99+
100+
/// The template file name used to draft a pending changelog file.
101+
/// This file will not be picked up by the batch release process.
102+
static const String _batchReleaseChangelogTemplateFileName = 'template.yaml';
103+
104+
/// Returns true if the file is a template file.
105+
static bool isTemplate(File file) {
106+
return p.basename(file.path) == _batchReleaseChangelogTemplateFileName;
107+
}
108+
109+
/// The changelog messages for this entry.
110+
final String changelog;
111+
112+
/// The type of version change for this entry.
113+
final VersionChange version;
114+
115+
/// The file that this entry was parsed from.
116+
final File file;
117+
}

0 commit comments

Comments
 (0)