From a545387b87636de52a939c3454a5597b6ab1961b Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Mar 2026 12:57:51 -0500 Subject: [PATCH 1/3] Implement code freeze mechanism at autosubmit --- .../lib/configuration/code_freeze.yaml | 7 ++ .../code_freeze_configuration.dart | 65 +++++++++++ auto_submit/lib/service/config.dart | 17 +++ auto_submit/lib/validations/code_freeze.dart | 64 +++++++++++ .../lib/validations/validation_filter.dart | 4 + .../code_freeze_configuration_test.dart | 56 +++++++++ auto_submit/test/src/service/fake_config.dart | 6 + .../test/validations/code_freeze_test.dart | 107 ++++++++++++++++++ 8 files changed, 326 insertions(+) create mode 100644 auto_submit/lib/configuration/code_freeze.yaml create mode 100644 auto_submit/lib/configuration/code_freeze_configuration.dart create mode 100644 auto_submit/lib/validations/code_freeze.dart create mode 100644 auto_submit/test/configuration/code_freeze_configuration_test.dart create mode 100644 auto_submit/test/validations/code_freeze_test.dart diff --git a/auto_submit/lib/configuration/code_freeze.yaml b/auto_submit/lib/configuration/code_freeze.yaml new file mode 100644 index 0000000000..04420afac7 --- /dev/null +++ b/auto_submit/lib/configuration/code_freeze.yaml @@ -0,0 +1,7 @@ +flutter/flutter: + frozen_labels: + - "f: material design" + - "f: cupertino" + frozen_paths: + - "packages/flutter/lib/src/material/" + - "packages/flutter/lib/src/cupertino/" diff --git a/auto_submit/lib/configuration/code_freeze_configuration.dart b/auto_submit/lib/configuration/code_freeze_configuration.dart new file mode 100644 index 0000000000..61fdf48d0b --- /dev/null +++ b/auto_submit/lib/configuration/code_freeze_configuration.dart @@ -0,0 +1,65 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:github/github.dart'; +import 'package:yaml/yaml.dart'; + +/// Configuration for repository-specific code freezes. +class CodeFreezeConfiguration { + CodeFreezeConfiguration(this.repoFreezeCriteria); + + /// A mapping of repository slugs to their freeze criteria. + final Map repoFreezeCriteria; + + /// Parses the configuration from a YAML string. + factory CodeFreezeConfiguration.fromYaml(String yaml) { + final dynamic yamlDoc = loadYaml(yaml); + final repoFreezeCriteria = {}; + + if (yamlDoc is YamlMap) { + for (final entry in yamlDoc.entries) { + final repoName = entry.key as String; + final repoConfig = entry.value as YamlMap?; + if (repoConfig != null) { + final frozenLabels = {}; + final yamlLabels = repoConfig['frozen_labels'] as YamlList?; + if (yamlLabels != null) { + frozenLabels.addAll(yamlLabels.map((label) => label as String)); + } + + final frozenPaths = {}; + final yamlPaths = repoConfig['frozen_paths'] as YamlList?; + if (yamlPaths != null) { + frozenPaths.addAll(yamlPaths.map((path) => path as String)); + } + + repoFreezeCriteria[repoName] = FreezeCriteria( + frozenLabels: frozenLabels, + frozenPaths: frozenPaths, + ); + } + } + } + + return CodeFreezeConfiguration(repoFreezeCriteria); + } + + /// Returns the freeze criteria for the given [slug]. + FreezeCriteria getFreezeCriteria(RepositorySlug slug) { + return repoFreezeCriteria[slug.fullName] ?? const FreezeCriteria(); + } +} + +/// Criteria used to determine if a PR is affected by a code freeze. +class FreezeCriteria { + const FreezeCriteria({ + this.frozenLabels = const {}, + this.frozenPaths = const {}, + }); + + final Set frozenLabels; + final Set frozenPaths; + + bool get isEmpty => frozenLabels.isEmpty && frozenPaths.isEmpty; +} diff --git a/auto_submit/lib/service/config.dart b/auto_submit/lib/service/config.dart index 5eae762543..15a113065e 100644 --- a/auto_submit/lib/service/config.dart +++ b/auto_submit/lib/service/config.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:convert'; +import 'dart:io'; import 'dart:typed_data'; import 'package:cocoon_server/bigquery.dart'; @@ -16,6 +17,7 @@ import 'package:neat_cache/cache_provider.dart'; import 'package:neat_cache/neat_cache.dart'; import 'package:retry/retry.dart'; +import '../configuration/code_freeze_configuration.dart'; import '../configuration/repository_configuration.dart'; import '../configuration/repository_configuration_manager.dart'; import '../foundation/providers.dart'; @@ -49,9 +51,24 @@ class Config { this, cache, ); + final codeFreezeFile = File( + Platform.script + .resolve('../lib/configuration/code_freeze.yaml') + .toFilePath(), + ); + if (codeFreezeFile.existsSync()) { + codeFreezeConfiguration = CodeFreezeConfiguration.fromYaml( + codeFreezeFile.readAsStringSync(), + ); + } else { + codeFreezeConfiguration = CodeFreezeConfiguration( + const {}, + ); + } } late RepositoryConfigurationManager repositoryConfigurationManager; + late CodeFreezeConfiguration codeFreezeConfiguration; /// Project/GCP constants static const String flutter = 'flutter'; diff --git a/auto_submit/lib/validations/code_freeze.dart b/auto_submit/lib/validations/code_freeze.dart new file mode 100644 index 0000000000..dfe6d8af4a --- /dev/null +++ b/auto_submit/lib/validations/code_freeze.dart @@ -0,0 +1,64 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:github/github.dart' as github; + +import '../model/auto_submit_query_result.dart'; +import 'validation.dart'; + +/// Validates that a pull request is not affected by an active code freeze. +class CodeFreeze extends Validation { + CodeFreeze({required super.config}); + + @override + Future validate( + QueryResult result, + github.PullRequest pr, + ) async { + final slug = pr.base!.repo!.slug(); + final criteria = config.codeFreezeConfiguration.getFreezeCriteria(slug); + + if (criteria.isEmpty) { + return ValidationResult(true, Action.IGNORE_FAILURE, ''); + } + + // Check labels first as it is cheaper. + final prLabels = + pr.labels?.map((label) => label.name).toSet() ?? {}; + final matchedLabels = criteria.frozenLabels.intersection(prLabels); + if (matchedLabels.isNotEmpty) { + final message = + 'This pull request is blocked due to an active code freeze for the following labels: ${matchedLabels.join(", ")}.'; + return ValidationResult(false, Action.REMOVE_LABEL, message); + } + + // Check paths if frozen paths are defined. + if (criteria.frozenPaths.isNotEmpty) { + final githubService = await config.createGithubService(slug); + final files = await githubService.getPullRequestFiles(slug, pr); + final matchedPaths = {}; + + for (final file in files) { + final filename = file.filename; + if (filename == null) continue; + for (final frozenPath in criteria.frozenPaths) { + if (filename.startsWith(frozenPath)) { + matchedPaths.add(frozenPath); + } + } + } + + if (matchedPaths.isNotEmpty) { + final message = + 'This pull request is blocked due to an active code freeze for the following paths: ${matchedPaths.join(", ")}.'; + return ValidationResult(false, Action.REMOVE_LABEL, message); + } + } + + return ValidationResult(true, Action.IGNORE_FAILURE, ''); + } + + @override + String get name => 'CodeFreeze'; +} diff --git a/auto_submit/lib/validations/validation_filter.dart b/auto_submit/lib/validations/validation_filter.dart index 5f523f9ab4..363ce07441 100644 --- a/auto_submit/lib/validations/validation_filter.dart +++ b/auto_submit/lib/validations/validation_filter.dart @@ -8,6 +8,7 @@ import '../service/process_method.dart'; import 'approval.dart'; import 'base_commit_date_allowed.dart'; import 'ci_successful.dart'; +import 'code_freeze.dart'; import 'empty_checks.dart'; import 'mergeable.dart'; import 'required_check_runs.dart'; @@ -50,6 +51,7 @@ class PullRequestValidationFilter implements ValidationFilter { validationsToRun.add(BaseCommitDateAllowed(config: config)); validationsToRun.add(Approval(config: config)); + validationsToRun.add(CodeFreeze(config: config)); // If we are running ci then we need to check the checkRuns and make sure // there are check runs created. if (repositoryConfiguration.runCi) { @@ -72,6 +74,7 @@ class EmergencyValidationFilter implements ValidationFilter { @override Set getValidations() => { Approval(config: config), + CodeFreeze(config: config), Mergeable(config: config), }; } @@ -87,6 +90,7 @@ class RevertRequestValidationFilter implements ValidationFilter { @override Set getValidations() => { Approval(config: config), + CodeFreeze(config: config), RequiredCheckRuns(config: config), Mergeable(config: config), }; diff --git a/auto_submit/test/configuration/code_freeze_configuration_test.dart b/auto_submit/test/configuration/code_freeze_configuration_test.dart new file mode 100644 index 0000000000..2d66c42c68 --- /dev/null +++ b/auto_submit/test/configuration/code_freeze_configuration_test.dart @@ -0,0 +1,56 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:auto_submit/configuration/code_freeze_configuration.dart'; +import 'package:github/github.dart'; +import 'package:test/test.dart'; + +void main() { + group('CodeFreezeConfiguration', () { + test('parses YAML correctly', () { + const yaml = ''' +flutter/flutter: + frozen_labels: + - "f: material design" + - "f: cupertino" + frozen_paths: + - "packages/flutter/lib/src/material/" + - "packages/flutter/lib/src/cupertino/" +flutter/packages: + frozen_labels: + - "blocked" +'''; + final config = CodeFreezeConfiguration.fromYaml(yaml); + + final flutterCriteria = config.getFreezeCriteria( + RepositorySlug('flutter', 'flutter'), + ); + expect( + flutterCriteria.frozenLabels, + containsAll(['f: material design', 'f: cupertino']), + ); + expect( + flutterCriteria.frozenPaths, + containsAll([ + 'packages/flutter/lib/src/material/', + 'packages/flutter/lib/src/cupertino/', + ]), + ); + + final packagesCriteria = config.getFreezeCriteria( + RepositorySlug('flutter', 'packages'), + ); + expect(packagesCriteria.frozenLabels, contains('blocked')); + expect(packagesCriteria.frozenPaths, isEmpty); + }); + + test('returns empty criteria for unknown slug', () { + final config = CodeFreezeConfiguration.fromYaml('{}'); + final criteria = config.getFreezeCriteria( + RepositorySlug('unknown', 'unknown'), + ); + expect(criteria.isEmpty, isTrue); + }); + }); +} diff --git a/auto_submit/test/src/service/fake_config.dart b/auto_submit/test/src/service/fake_config.dart index a2546869d7..9c5bb89cce 100644 --- a/auto_submit/test/src/service/fake_config.dart +++ b/auto_submit/test/src/service/fake_config.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import 'package:auto_submit/configuration/code_freeze_configuration.dart'; import 'package:auto_submit/configuration/repository_configuration.dart'; import 'package:auto_submit/service/config.dart'; import 'package:auto_submit/service/github_service.dart'; @@ -48,6 +49,11 @@ class FakeConfig extends Config { @override String get pubsubRevertRequestSubscription => 'auto-submit-revert-queue-sub'; + @override + CodeFreezeConfiguration get codeFreezeConfiguration => + codeFreezeConfigurationValue ?? CodeFreezeConfiguration({}); + CodeFreezeConfiguration? codeFreezeConfigurationValue; + @override int get kPubsubPullNumber => kPubsubPullNumberValue ?? 1; diff --git a/auto_submit/test/validations/code_freeze_test.dart b/auto_submit/test/validations/code_freeze_test.dart new file mode 100644 index 0000000000..95bed014ae --- /dev/null +++ b/auto_submit/test/validations/code_freeze_test.dart @@ -0,0 +1,107 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; + +import 'package:auto_submit/configuration/code_freeze_configuration.dart'; +import 'package:auto_submit/model/auto_submit_query_result.dart'; +import 'package:auto_submit/validations/code_freeze.dart'; +import 'package:auto_submit/validations/validation.dart'; +import 'package:test/test.dart'; + +import '../requests/github_webhook_test_data.dart'; +import '../src/service/fake_config.dart'; +import '../src/service/fake_github_service.dart'; + +void main() { + late CodeFreeze codeFreeze; + late FakeConfig config; + late FakeGithubService githubService; + late QueryResult queryResult; + + setUp(() { + githubService = FakeGithubService(); + config = FakeConfig(githubService: githubService); + queryResult = QueryResult(); + codeFreeze = CodeFreeze(config: config); + }); + + group('CodeFreeze', () { + test('returns success when no freeze is active', () async { + final pr = generatePullRequest(); + + config.codeFreezeConfigurationValue = CodeFreezeConfiguration({}); + + final result = await codeFreeze.validate(queryResult, pr); + expect(result.result, isTrue); + expect(result.action, Action.IGNORE_FAILURE); + }); + + test('blocks PR with frozen label', () async { + final pr = generatePullRequest(labelName: 'f: material design'); + + final criteria = FreezeCriteria(frozenLabels: {'f: material design'}); + config.codeFreezeConfigurationValue = CodeFreezeConfiguration({ + 'flutter/flutter': criteria, + }); + + final result = await codeFreeze.validate(queryResult, pr); + expect(result.result, isFalse); + expect(result.action, Action.REMOVE_LABEL); + expect( + result.message, + contains( + 'blocked due to an active code freeze for the following labels: f: material design', + ), + ); + }); + + test('blocks PR with frozen path', () async { + final pr = generatePullRequest(prNumber: 123); + + final criteria = FreezeCriteria( + frozenPaths: {'packages/flutter/lib/src/material/'}, + ); + config.codeFreezeConfigurationValue = CodeFreezeConfiguration({ + 'flutter/flutter': criteria, + }); + + githubService.pullrequestFilesData = jsonEncode([ + {'filename': 'packages/flutter/lib/src/material/flat_button.dart'}, + ]); + + final result = await codeFreeze.validate(queryResult, pr); + expect(result.result, isFalse); + expect(result.action, Action.REMOVE_LABEL); + expect( + result.message, + contains( + 'blocked due to an active code freeze for the following paths: packages/flutter/lib/src/material/', + ), + ); + }); + + test('allows PR with no frozen label or path', () async { + final pr = generatePullRequest( + prNumber: 123, + labelName: 'f: some other label', + ); + + final criteria = FreezeCriteria( + frozenLabels: {'f: material design'}, + frozenPaths: {'packages/flutter/lib/src/material/'}, + ); + config.codeFreezeConfigurationValue = CodeFreezeConfiguration({ + 'flutter/flutter': criteria, + }); + + githubService.pullrequestFilesData = jsonEncode([ + {'filename': 'packages/flutter/lib/src/widgets/framework.dart'}, + ]); + + final result = await codeFreeze.validate(queryResult, pr); + expect(result.result, isTrue); + }); + }); +} From 2bfe5e6f827cf5428dbe2d31a04cd7ef03841412 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Mar 2026 13:21:34 -0500 Subject: [PATCH 2/3] Analyzer --- auto_submit/test/validations/code_freeze_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/auto_submit/test/validations/code_freeze_test.dart b/auto_submit/test/validations/code_freeze_test.dart index 95bed014ae..354743d113 100644 --- a/auto_submit/test/validations/code_freeze_test.dart +++ b/auto_submit/test/validations/code_freeze_test.dart @@ -41,7 +41,7 @@ void main() { test('blocks PR with frozen label', () async { final pr = generatePullRequest(labelName: 'f: material design'); - final criteria = FreezeCriteria(frozenLabels: {'f: material design'}); + const criteria = FreezeCriteria(frozenLabels: {'f: material design'}); config.codeFreezeConfigurationValue = CodeFreezeConfiguration({ 'flutter/flutter': criteria, }); @@ -60,7 +60,7 @@ void main() { test('blocks PR with frozen path', () async { final pr = generatePullRequest(prNumber: 123); - final criteria = FreezeCriteria( + const criteria = FreezeCriteria( frozenPaths: {'packages/flutter/lib/src/material/'}, ); config.codeFreezeConfigurationValue = CodeFreezeConfiguration({ @@ -88,7 +88,7 @@ void main() { labelName: 'f: some other label', ); - final criteria = FreezeCriteria( + const criteria = FreezeCriteria( frozenLabels: {'f: material design'}, frozenPaths: {'packages/flutter/lib/src/material/'}, ); From 954b2d0165264ad2e0f940cad27cda76f7aee8c3 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Mar 2026 18:26:16 -0500 Subject: [PATCH 3/3] Review feedback --- auto_submit/hook/build.dart | 30 +++++++ .../code_freeze_configuration.dart | 87 ++++++++++++------- .../code_freeze_configuration.g.dart | 45 ++++++++++ auto_submit/lib/service/config.dart | 16 +--- auto_submit/lib/src/generated_config.dart | 12 +++ auto_submit/pubspec.yaml | 1 + 6 files changed, 147 insertions(+), 44 deletions(-) create mode 100644 auto_submit/hook/build.dart create mode 100644 auto_submit/lib/configuration/code_freeze_configuration.g.dart create mode 100644 auto_submit/lib/src/generated_config.dart diff --git a/auto_submit/hook/build.dart b/auto_submit/hook/build.dart new file mode 100644 index 0000000000..7b6a625797 --- /dev/null +++ b/auto_submit/hook/build.dart @@ -0,0 +1,30 @@ +// Copyright 2026 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:native_assets_cli/native_assets_cli.dart'; + +void main(List args) async { + await build(args, (config, output) async { + // 1. Read the source file (the code freeze config) + final configFile = File('lib/configuration/code_freeze.yaml'); + final content = await configFile.readAsString(); + + // 2. Define the path for the generated code + final outputFile = File('lib/src/generated_config.dart'); + + // 3. Write the file as a raw string constant + await outputFile.writeAsString(""" +// GENERATED CODE - DO NOT MODIFY BY HAND +// Generated by hook/build.dart + +const String codeFreezeConfigContent = + r'''$content'''; +"""); + + // 4. Tell Dart that this hook depends on the config file + output.addDependency(configFile.uri); + }); +} diff --git a/auto_submit/lib/configuration/code_freeze_configuration.dart b/auto_submit/lib/configuration/code_freeze_configuration.dart index 61fdf48d0b..0c9014ca34 100644 --- a/auto_submit/lib/configuration/code_freeze_configuration.dart +++ b/auto_submit/lib/configuration/code_freeze_configuration.dart @@ -3,47 +3,36 @@ // found in the LICENSE file. import 'package:github/github.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:meta/meta.dart'; import 'package:yaml/yaml.dart'; +part 'code_freeze_configuration.g.dart'; + /// Configuration for repository-specific code freezes. -class CodeFreezeConfiguration { - CodeFreezeConfiguration(this.repoFreezeCriteria); +@JsonSerializable(explicitToJson: true) +@immutable +final class CodeFreezeConfiguration { + const CodeFreezeConfiguration([this.repoFreezeCriteria = const {}]); /// A mapping of repository slugs to their freeze criteria. + @JsonKey(name: 'repoFreezeCriteria') final Map repoFreezeCriteria; /// Parses the configuration from a YAML string. factory CodeFreezeConfiguration.fromYaml(String yaml) { - final dynamic yamlDoc = loadYaml(yaml); - final repoFreezeCriteria = {}; - - if (yamlDoc is YamlMap) { - for (final entry in yamlDoc.entries) { - final repoName = entry.key as String; - final repoConfig = entry.value as YamlMap?; - if (repoConfig != null) { - final frozenLabels = {}; - final yamlLabels = repoConfig['frozen_labels'] as YamlList?; - if (yamlLabels != null) { - frozenLabels.addAll(yamlLabels.map((label) => label as String)); - } - - final frozenPaths = {}; - final yamlPaths = repoConfig['frozen_paths'] as YamlList?; - if (yamlPaths != null) { - frozenPaths.addAll(yamlPaths.map((path) => path as String)); - } + final yamlDoc = loadYaml(yaml) as YamlMap; + final map = { + 'repoFreezeCriteria': yamlDoc.asMap, + }; + return CodeFreezeConfiguration.fromJson(map); + } - repoFreezeCriteria[repoName] = FreezeCriteria( - frozenLabels: frozenLabels, - frozenPaths: frozenPaths, - ); - } - } - } + /// Creates [CodeFreezeConfiguration] from a [json] object. + factory CodeFreezeConfiguration.fromJson(Map json) => _$CodeFreezeConfigurationFromJson(json); - return CodeFreezeConfiguration(repoFreezeCriteria); - } + /// Converts [CodeFreezeConfiguration] to a [json] object. + Map toJson() => _$CodeFreezeConfigurationToJson(this); /// Returns the freeze criteria for the given [slug]. FreezeCriteria getFreezeCriteria(RepositorySlug slug) { @@ -52,7 +41,9 @@ class CodeFreezeConfiguration { } /// Criteria used to determine if a PR is affected by a code freeze. -class FreezeCriteria { +@JsonSerializable() +@immutable +final class FreezeCriteria { const FreezeCriteria({ this.frozenLabels = const {}, this.frozenPaths = const {}, @@ -61,5 +52,39 @@ class FreezeCriteria { final Set frozenLabels; final Set frozenPaths; + /// Creates [FreezeCriteria] from a [json] object. + factory FreezeCriteria.fromJson(Map json) => _$FreezeCriteriaFromJson(json); + + /// Converts [FreezeCriteria] to a [json] object. + Map toJson() => _$FreezeCriteriaToJson(this); + bool get isEmpty => frozenLabels.isEmpty && frozenPaths.isEmpty; } + +extension _YamlMapToMap on YamlMap { + Map get asMap => { + for (final MapEntry(:key, :value) in entries) + if (value is YamlMap) + '$key': value.asMap + else if (value is YamlList) + '$key': value.asList + else if (value is YamlScalar) + '$key': value.value + else + '$key': value, + }; +} + +extension _YamlListToList on YamlList { + List get asList => [ + for (final node in nodes) + if (node is YamlMap) + node.asMap + else if (node is YamlList) + node.asList + else if (node is YamlScalar) + node.value + else + node, + ]; +} diff --git a/auto_submit/lib/configuration/code_freeze_configuration.g.dart b/auto_submit/lib/configuration/code_freeze_configuration.g.dart new file mode 100644 index 0000000000..414ea8f377 --- /dev/null +++ b/auto_submit/lib/configuration/code_freeze_configuration.g.dart @@ -0,0 +1,45 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'code_freeze_configuration.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CodeFreezeConfiguration _$CodeFreezeConfigurationFromJson( + Map json, +) => CodeFreezeConfiguration( + (json['repoFreezeCriteria'] as Map?)?.map( + (k, e) => + MapEntry(k, FreezeCriteria.fromJson(e as Map)), + ) ?? + const {}, +); + +Map _$CodeFreezeConfigurationToJson( + CodeFreezeConfiguration instance, +) => { + 'repoFreezeCriteria': instance.repoFreezeCriteria.map( + (k, e) => MapEntry(k, e.toJson()), + ), +}; + +FreezeCriteria _$FreezeCriteriaFromJson(Map json) => + FreezeCriteria( + frozenLabels: + (json['frozen_labels'] as List?) + ?.map((e) => e as String) + .toSet() ?? + const {}, + frozenPaths: + (json['frozen_paths'] as List?) + ?.map((e) => e as String) + .toSet() ?? + const {}, + ); + +Map _$FreezeCriteriaToJson(FreezeCriteria instance) => + { + 'frozen_labels': instance.frozenLabels.toList(), + 'frozen_paths': instance.frozenPaths.toList(), + }; diff --git a/auto_submit/lib/service/config.dart b/auto_submit/lib/service/config.dart index 15a113065e..411449d5e3 100644 --- a/auto_submit/lib/service/config.dart +++ b/auto_submit/lib/service/config.dart @@ -21,6 +21,7 @@ import '../configuration/code_freeze_configuration.dart'; import '../configuration/repository_configuration.dart'; import '../configuration/repository_configuration_manager.dart'; import '../foundation/providers.dart'; +import '../src/generated_config.dart'; import 'github_service.dart'; class CocoonGitHubRequestException implements Exception { @@ -51,20 +52,9 @@ class Config { this, cache, ); - final codeFreezeFile = File( - Platform.script - .resolve('../lib/configuration/code_freeze.yaml') - .toFilePath(), + codeFreezeConfiguration = CodeFreezeConfiguration.fromYaml( + codeFreezeConfigContent, ); - if (codeFreezeFile.existsSync()) { - codeFreezeConfiguration = CodeFreezeConfiguration.fromYaml( - codeFreezeFile.readAsStringSync(), - ); - } else { - codeFreezeConfiguration = CodeFreezeConfiguration( - const {}, - ); - } } late RepositoryConfigurationManager repositoryConfigurationManager; diff --git a/auto_submit/lib/src/generated_config.dart b/auto_submit/lib/src/generated_config.dart new file mode 100644 index 0000000000..4f88512cc4 --- /dev/null +++ b/auto_submit/lib/src/generated_config.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// Generated by hook/build.dart + +const String codeFreezeConfigContent = + r'''flutter/flutter: + frozen_labels: + - "f: material design" + - "f: cupertino" + frozen_paths: + - "packages/flutter/lib/src/material/" + - "packages/flutter/lib/src/cupertino/" +'''; diff --git a/auto_submit/pubspec.yaml b/auto_submit/pubspec.yaml index af6f6dd2d2..a60aaab1d1 100644 --- a/auto_submit/pubspec.yaml +++ b/auto_submit/pubspec.yaml @@ -45,6 +45,7 @@ dev_dependencies: dart_flutter_team_lints: 3.5.2 json_serializable: ^6.9.4 mockito: ^5.4.6 + native_assets_cli: ^0.18.0 test: ^1.26.3 builders: