Skip to content

[ci]Adds mechanism for packages to opt in to batched release#10237

Merged
auto-submit[bot] merged 6 commits intoflutter:mainfrom
chunhtai:issues/176435
Oct 22, 2025
Merged

[ci]Adds mechanism for packages to opt in to batched release#10237
auto-submit[bot] merged 6 commits intoflutter:mainfrom
chunhtai:issues/176435

Conversation

@chunhtai
Copy link
Contributor

@chunhtai chunhtai commented Oct 15, 2025

This is pure ci setup and should not change packages' behaviors in anyway, feel free to ignore if you are pinned as a result due to being the package owners

This PR introduced an optional ci_config.yaml in package root meant to collect package level settings flutter/flutter#172244. As of now, it only contains the batch release opt in.

Also added repocheck for this yaml file's format check.

fixes flutter/flutter#176435

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism for packages to opt-in to batched releases by adding ci_config.yaml files and a new CI check, ci-config-check, to validate them. My review focuses on improving the robustness of the new validation script and pointing out a TODO that should be addressed before merging.

Comment on lines +56 to +75
final YamlMap config = loadYaml(ciConfig.readAsStringSync()) as YamlMap;

final YamlMap? release = config['release'] as YamlMap?;
if (release == null) {
printError('${indentation}Must have `release` property in '
'${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
errors.add('Missing `release` property');
} else {
final Object? batch = release['batch'];
if (batch == null) {
printError('${indentation}Must have `batch` property in `release` in '
'${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
errors.add('Missing `batch` property in `release`');
} else if (batch is! bool) {
printError(
'${indentation}The `batch` property in `release` must be boolean in '
'${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
errors.add('Wrong value for `batch`');
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This validation logic can be made more robust. The current implementation uses as casts which can throw a TypeError if the YAML structure is not as expected (e.g., if release is not a map). Also, a YamlException from loadYaml would be caught as a generic exception higher up. It's better to handle these cases gracefully with type checks and a specific try-catch for YamlException to provide clearer error messages.

    final YamlMap config;
    try {
      final dynamic yaml = loadYaml(ciConfig.readAsStringSync());
      if (yaml is! YamlMap) {
        printError('${indentation}The ci_config.yaml file must be a map.');
        errors.add('Root of config is not a map.');
        return errors;
      }
      config = yaml;
    } on YamlException catch (e) {
      printError(
          '${indentation}Invalid YAML in ${getRelativePosixPath(ciConfig, from: mainPackage.directory)}:');
      printError(e.toString());
      errors.add('Invalid YAML');
      return errors;
    }

    final Object? releaseNode = config['release'];
    if (releaseNode == null) {
      printError('${indentation}Must have `release` property in '
          '${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
      errors.add('Missing `release` property');
    } else if (releaseNode is! YamlMap) {
      printError('${indentation}The `release` property must be a map in '
          '${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
      errors.add('`release` property is not a map');
    } else {
      final YamlMap release = releaseNode;
      final Object? batch = release['batch'];
      if (batch == null) {
        printError('${indentation}Must have `batch` property in `release` in '
            '${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
        errors.add('Missing `batch` property in `release`');
      } else if (batch is! bool) {
        printError(
            '${indentation}The `batch` property in `release` must be boolean in '
            '${getRelativePosixPath(ciConfig, from: mainPackage.directory)}');
        errors.add('Wrong value for `batch`');
      }
    }

Comment on lines +13 to +14
const String _instructionUrl = //TODO(chunhtai): update this link
'https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a TODO here to update a link. This should be resolved before merging, or a tracking issue should be created to ensure it's not forgotten.

@chunhtai
Copy link
Contributor Author

reason for overrides: ci only

@chunhtai
Copy link
Contributor Author

@@ -0,0 +1,2 @@
release:
batch: false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for requiring every package to explicitly configure everything? I was envisioning this being more like a Dart test config file, where a package only needs a file if it needs non-default behavior.

Requiring every package to explicitly declare everything would make this a maintenance nightmare, because every time we add a new config option we would need to touch every single package.

import 'common/repository_package.dart';

/// A command to enforce ci_config conventions across the repository.
class CiConfigCheckCommand extends PackageLoopingCommand {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validation can go into RepoPackageInfoCheckCommand as a new method, rather than requiring a whole new command.


final Object? releaseNode = config['release'];
if (releaseNode == null) {
printError('${indentation}Must have `release` property in '
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should require every file to have this key, for the same reason that I don't think we should require every package to have the file. We should have reasonable defaults, and only make people opt in to unusual behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I did this for discoverability and make it more clear what the behavior is instead giving a default when not provided.

Without this I would have to document the default behavior.

but I am ok changing it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this I would have to document the default behavior.

We already document the default behavior. All having a default will require in addition is adding a very short note to that documentation (as part of adding documentation of the other mode) saying it's the default behavior.

Copy link
Collaborator

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App override: no changelog needed Override the check requiring CHANGELOG updates for most changes override: no versioning needed Override the check requiring version bumps for most changes p: go_router_builder p: go_router

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[batch-release] figure out a mechanism for package to opt in

4 participants