[app_dart] Get branches only from datastore (#2081)

diff --git a/app_dart/lib/src/foundation/utils.dart b/app_dart/lib/src/foundation/utils.dart
index bd75a85..36a1d70 100644
--- a/app_dart/lib/src/foundation/utils.dart
+++ b/app_dart/lib/src/foundation/utils.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
-import 'dart:typed_data';
 
 import 'package:cocoon_service/cocoon_service.dart';
 import 'package:github/github.dart';
@@ -104,30 +103,6 @@
   }
 }
 
-/// Gets supported branch list of `flutter/flutter` via GitHub http request.
-Future<Uint8List> getBranches(
-  HttpClientProvider httpClientProvider, {
-  RetryOptions retryOptions = const RetryOptions(maxAttempts: 3),
-}) async {
-  String content;
-  try {
-    content = await githubFileContent(
-      RepositorySlug('flutter', 'cocoon'),
-      'app_dart/dev/branches.txt',
-      httpClientProvider: httpClientProvider,
-      ref: Config.defaultBranch(Config.cocoonSlug),
-      retryOptions: retryOptions,
-    );
-  } on HttpException {
-    log.warning('githubFileContent failed to get branches');
-    content = 'master';
-  }
-
-  final List<String> branches = content.split('\n').map((String branch) => branch.trim()).toList();
-  branches.removeWhere((String branch) => branch.isEmpty);
-  return Uint8List.fromList(branches.join(',').codeUnits);
-}
-
 Future<RepositorySlug?> repoNameForBuilder(List<LuciBuilder> builders, String builderName) async {
   final LuciBuilder builderConfig = builders.firstWhere(
     (LuciBuilder builder) => builder.name == builderName,
diff --git a/app_dart/lib/src/model/appengine/branch.dart b/app_dart/lib/src/model/appengine/branch.dart
index d84b20c..04d2786 100644
--- a/app_dart/lib/src/model/appengine/branch.dart
+++ b/app_dart/lib/src/model/appengine/branch.dart
@@ -26,7 +26,7 @@
 
   String get repository => key.id!.substring(0, key.id!.lastIndexOf('/'));
 
-  String get branch => key.id!.substring(key.id!.lastIndexOf('/') + 1);
+  String get name => key.id!.substring(key.id!.lastIndexOf('/') + 1);
 
   @override
   String toString() {
@@ -34,7 +34,7 @@
       ..write('$runtimeType(')
       ..write('id: $id')
       ..write(', key: ${parentKey == null ? null : key.id}')
-      ..write(', branch: $branch')
+      ..write(', branch: $name')
       ..write(', channel: $channel')
       ..write(', repository: $repository')
       ..write(', lastActivity: $lastActivity')
@@ -46,7 +46,7 @@
     return <String, dynamic>{
       'id': id,
       'branch': <String, dynamic>{
-        'branch': branch,
+        'branch': name,
         'repository': repository,
       },
     };
diff --git a/app_dart/lib/src/request_handlers/reset_prod_task.dart b/app_dart/lib/src/request_handlers/reset_prod_task.dart
index dd6d524..6a7b9cd 100644
--- a/app_dart/lib/src/request_handlers/reset_prod_task.dart
+++ b/app_dart/lib/src/request_handlers/reset_prod_task.dart
@@ -157,12 +157,6 @@
   }) async {
     gitBranch = gitBranch.trim();
     sha = sha.trim();
-    final List<String> flutterBranches = await config.flutterBranches;
-    if (!flutterBranches.contains(gitBranch)) {
-      throw BadRequestException('Failed to find flutter/flutter branch: $gitBranch\n'
-          'If this is a valid branch, '
-          'see https://github.com/flutter/cocoon/tree/master/app_dart#branching-support-for-flutter-repo');
-    }
     final String id = '${slug.fullName}/$gitBranch/$sha';
     final Key<String> commitKey = datastore.db.emptyKey.append<String>(Commit, id: id);
     log.fine('Constructed commit key=$id');
diff --git a/app_dart/lib/src/request_handlers/scheduler/batch_backfiller.dart b/app_dart/lib/src/request_handlers/scheduler/batch_backfiller.dart
index eeef15b..ac128e3 100644
--- a/app_dart/lib/src/request_handlers/scheduler/batch_backfiller.dart
+++ b/app_dart/lib/src/request_handlers/scheduler/batch_backfiller.dart
@@ -49,7 +49,6 @@
 
   Future<void> backfillRepository(RepositorySlug slug) async {
     final DatastoreService datastore = datastoreProvider(config.db);
-    // TODO(chillers): There's a bug in how this is getting the tasks for the test. It's duplicating all of them.
     final List<FullTask> tasks = await (datastore.queryRecentTasks(slug: slug)).toList();
 
     // Construct Task columns to scan for backfilling
diff --git a/app_dart/lib/src/request_handlers/update_task_status.dart b/app_dart/lib/src/request_handlers/update_task_status.dart
index 0a8ca3e..e4e6ed4 100644
--- a/app_dart/lib/src/request_handlers/update_task_status.dart
+++ b/app_dart/lib/src/request_handlers/update_task_status.dart
@@ -100,12 +100,7 @@
   Future<Key<String>> _constructCommitKey(DatastoreService datastore) async {
     final String gitBranch = (requestData![gitBranchParam] as String).trim();
     final String gitSha = (requestData![gitShaParam] as String).trim();
-    final List<String> flutterBranches = await config.flutterBranches;
-    if (!flutterBranches.contains(gitBranch)) {
-      throw BadRequestException('Failed to find flutter/flutter branch: $gitBranch\n'
-          'If this is a valid branch, '
-          'see https://github.com/flutter/cocoon/tree/master/app_dart#branching-support-for-flutter-repo');
-    }
+
     final String id = 'flutter/flutter/$gitBranch/$gitSha';
     final Key<String> commitKey = datastore.db.emptyKey.append<String>(Commit, id: id);
     log.fine('Constructed commit key=$id');
diff --git a/app_dart/lib/src/request_handlers/vacuum_github_commits.dart b/app_dart/lib/src/request_handlers/vacuum_github_commits.dart
index d1d93db..6bfb109 100644
--- a/app_dart/lib/src/request_handlers/vacuum_github_commits.dart
+++ b/app_dart/lib/src/request_handlers/vacuum_github_commits.dart
@@ -5,10 +5,11 @@
 import 'dart:async';
 
 import 'package:gcloud/db.dart';
-import 'package:github/github.dart';
+import 'package:github/github.dart' as gh;
 import 'package:meta/meta.dart';
 import 'package:truncate/truncate.dart';
 
+import '../model/appengine/branch.dart';
 import '../model/appengine/commit.dart';
 import '../request_handling/api_request_handler.dart';
 import '../request_handling/body.dart';
@@ -36,16 +37,17 @@
   Future<Body> get() async {
     final DatastoreService datastore = datastoreProvider(config.db);
 
-    for (RepositorySlug slug in config.supportedRepos) {
+    for (gh.RepositorySlug slug in config.supportedRepos) {
       await _vacuumRepository(slug, datastore: datastore);
     }
 
     return Body.empty;
   }
 
-  Future<void> _vacuumRepository(RepositorySlug slug, {DatastoreService? datastore}) async {
+  Future<void> _vacuumRepository(gh.RepositorySlug slug, {DatastoreService? datastore}) async {
     final GithubService githubService = await config.createGithubService(slug);
-    for (String branch in await config.getSupportedBranches(slug)) {
+    final List<Branch> branches = (await config.getBranches(slug)).toList();
+    for (Branch branch in branches) {
       final List<Commit> commits =
           await _vacuumBranch(slug, branch, datastore: datastore, githubService: githubService);
       await scheduler.addCommits(commits);
@@ -53,42 +55,42 @@
   }
 
   Future<List<Commit>> _vacuumBranch(
-    RepositorySlug slug,
-    String branch, {
+    gh.RepositorySlug slug,
+    Branch branch, {
     DatastoreService? datastore,
     required GithubService githubService,
   }) async {
-    List<RepositoryCommit> commits = <RepositoryCommit>[];
+    List<gh.RepositoryCommit> commits = <gh.RepositoryCommit>[];
     // Sliding window of times to add commits from.
     final DateTime queryAfter = DateTime.now().subtract(const Duration(days: 1));
     final DateTime queryBefore = DateTime.now().subtract(const Duration(minutes: 3));
     try {
       log.fine('Listing commit for slug: $slug branch: $branch and msSinceEpoch: ${queryAfter.millisecondsSinceEpoch}');
-      commits = await githubService.listCommits(slug, branch, queryAfter.millisecondsSinceEpoch);
+      commits = await githubService.listCommits(slug, branch.name, queryAfter.millisecondsSinceEpoch);
       log.fine('Retrieved ${commits.length} commits from GitHub');
       // Do not try to add recent commits as they may already be processed
       // by cocoon, which can cause race conditions.
       commits = commits
-          .where((RepositoryCommit commit) =>
+          .where((gh.RepositoryCommit commit) =>
               commit.commit!.committer!.date!.millisecondsSinceEpoch < queryBefore.millisecondsSinceEpoch)
           .toList();
-    } on GitHubError catch (error) {
+    } on gh.GitHubError catch (error) {
       log.severe('$error');
     }
 
     // For release branches, only look at the latest commit.
-    if (branch != Config.defaultBranch(slug) && commits.isNotEmpty) {
-      commits = <RepositoryCommit>[commits.last];
+    if (branch.name != Config.defaultBranch(slug) && commits.isNotEmpty) {
+      commits = <gh.RepositoryCommit>[commits.last];
     }
 
-    return _toDatastoreCommit(slug, commits, datastore, branch);
+    return _toDatastoreCommit(slug, commits, datastore, branch.name);
   }
 
   /// Convert [RepositoryCommit] to Cocoon's [Commit] format.
   Future<List<Commit>> _toDatastoreCommit(
-      RepositorySlug slug, List<RepositoryCommit> commits, DatastoreService? datastore, String branch) async {
+      gh.RepositorySlug slug, List<gh.RepositoryCommit> commits, DatastoreService? datastore, String branch) async {
     final List<Commit> recentCommits = <Commit>[];
-    for (RepositoryCommit commit in commits) {
+    for (gh.RepositoryCommit commit in commits) {
       final String id = '${slug.fullName}/$branch/${commit.sha}';
       final Key<String> key = datastore!.db.emptyKey.append<String>(Commit, id: id);
       recentCommits.add(Commit(
diff --git a/app_dart/lib/src/service/config.dart b/app_dart/lib/src/service/config.dart
index f05efa8..d01b328 100644
--- a/app_dart/lib/src/service/config.dart
+++ b/app_dart/lib/src/service/config.dart
@@ -6,10 +6,11 @@
 import 'dart:typed_data';
 
 import 'package:appengine/appengine.dart';
+import 'package:cocoon_service/src/service/datastore.dart';
 import 'package:corsac_jwt/corsac_jwt.dart';
 import 'package:gcloud/db.dart';
 import 'package:gcloud/service_scope.dart' as ss;
-import 'package:github/github.dart';
+import 'package:github/github.dart' as gh;
 import 'package:googleapis/bigquery/v2.dart';
 import 'package:graphql/client.dart';
 import 'package:http/http.dart' as http;
@@ -17,7 +18,7 @@
 import 'package:retry/retry.dart';
 
 import '../../cocoon_service.dart';
-import '../foundation/providers.dart';
+import '../model/appengine/branch.dart';
 import '../model/appengine/cocoon_config.dart';
 import '../model/appengine/key_helper.dart';
 import 'access_client_provider.dart';
@@ -46,7 +47,7 @@
   /// This adds support for the `waiting for tree to go green label` to the repo.
   ///
   /// Relies on the GitHub Checks API being enabled for this repo.
-  Set<RepositorySlug> get supportedRepos => <RepositorySlug>{
+  Set<gh.RepositorySlug> get supportedRepos => <gh.RepositorySlug>{
         cocoonSlug,
         engineSlug,
         flutterSlug,
@@ -58,14 +59,14 @@
   static Set<String> cirrusSupportedRepos = <String>{'plugins', 'packages', 'flutter'};
 
   /// GitHub repositories that use CI status to determine if pull requests can be submitted.
-  static Set<RepositorySlug> reposWithTreeStatus = <RepositorySlug>{
+  static Set<gh.RepositorySlug> reposWithTreeStatus = <gh.RepositorySlug>{
     engineSlug,
     flutterSlug,
   };
 
   /// The tip of tree branch for [slug].
-  static String defaultBranch(RepositorySlug slug) {
-    final Map<RepositorySlug, String> defaultBranches = <RepositorySlug, String>{
+  static String defaultBranch(gh.RepositorySlug slug) {
+    final Map<gh.RepositorySlug, String> defaultBranches = <gh.RepositorySlug, String>{
       cocoonSlug: 'main',
       flutterSlug: 'master',
       engineSlug: 'main',
@@ -88,15 +89,11 @@
 
   Logging get loggingService => ss.lookup(#appengine.logging) as Logging;
 
-  Future<List<String>> _getFlutterBranches() async {
-    final Uint8List? cacheValue = await _cache.getOrCreate(
-      configCacheName,
-      'flutterBranches',
-      createFn: () => getBranches(Providers.freshHttpClient),
-      ttl: configCacheTtl,
-    );
+  Future<Iterable<Branch>> getBranches(gh.RepositorySlug slug) async {
+    final DatastoreService datastore = DatastoreService(db, defaultMaxEntityGroups);
+    final List<Branch> branches = await (datastore.queryBranches().toList());
 
-    return String.fromCharCodes(cacheValue!).split(',');
+    return branches.where((Branch branch) => branch.slug == slug);
   }
 
   Future<List<String>> _getReleaseAccounts() async {
@@ -149,23 +146,6 @@
   /// Max retries when scheduling builds.
   static const RetryOptions schedulerRetry = RetryOptions(maxAttempts: 3);
 
-  /// Retrieve the supported branches for a repository.
-  Future<List<String>> getSupportedBranches(RepositorySlug slug) async {
-    // TODO(xilaizhang): Switch this to query datastore once branch entities are being written. https://github.com/flutter/flutter/issues/100491
-    final List<String> branches = await flutterBranches;
-    if (slug == Config.flutterSlug) {
-      branches.remove('main');
-      return branches;
-    } else if (slug == Config.engineSlug) {
-      branches.remove('master');
-      return branches;
-    }
-
-    return <String>['main'];
-  }
-
-  Future<List<String>> get flutterBranches => _getFlutterBranches();
-
   /// List of GitHub accounts related to releases.
   Future<List<String>> get releaseAccounts => _getReleaseAccounts();
 
@@ -259,7 +239,7 @@
   String flutterGoldFollowUpAlert(String url) => 'Golden file changes are available for triage from new commit, '
       'Click [here to view]($url).\n\n';
 
-  String flutterGoldAlertConstant(RepositorySlug slug) {
+  String flutterGoldAlertConstant(gh.RepositorySlug slug) {
     if (slug == Config.flutterSlug) {
       return '\n\nFor more guidance, visit '
           '[Writing a golden file test for `package:flutter`](https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter).\n\n'
@@ -269,7 +249,7 @@
     return '';
   }
 
-  String flutterGoldCommentID(PullRequest pr) =>
+  String flutterGoldCommentID(gh.PullRequest pr) =>
       '_Changes reported for pull request #${pr.number} at sha ${pr.head!.sha}_\n\n';
 
   /// Post submit service account email used by LUCI swarming tasks.
@@ -304,14 +284,14 @@
   String get flutterBuildDescription => 'Tree is currently broken. Please do not merge this '
       'PR unless it contains a fix for the tree.';
 
-  static RepositorySlug get cocoonSlug => RepositorySlug('flutter', 'cocoon');
-  static RepositorySlug get engineSlug => RepositorySlug('flutter', 'engine');
-  static RepositorySlug get flutterSlug => RepositorySlug('flutter', 'flutter');
-  static RepositorySlug get packagesSlug => RepositorySlug('flutter', 'packages');
-  static RepositorySlug get pluginsSlug => RepositorySlug('flutter', 'plugins');
+  static gh.RepositorySlug get cocoonSlug => gh.RepositorySlug('flutter', 'cocoon');
+  static gh.RepositorySlug get engineSlug => gh.RepositorySlug('flutter', 'engine');
+  static gh.RepositorySlug get flutterSlug => gh.RepositorySlug('flutter', 'flutter');
+  static gh.RepositorySlug get packagesSlug => gh.RepositorySlug('flutter', 'packages');
+  static gh.RepositorySlug get pluginsSlug => gh.RepositorySlug('flutter', 'plugins');
 
   /// Flutter recipes is hosted on Gerrit instead of GitHub.
-  static RepositorySlug get recipesSlug => RepositorySlug('flutter', 'recipes');
+  static gh.RepositorySlug get recipesSlug => gh.RepositorySlug('flutter', 'recipes');
 
   String get waitingForTreeToGoGreenLabelName => 'waiting for tree to go green';
 
@@ -339,7 +319,7 @@
     return signedToken.toString();
   }
 
-  Future<String> generateGithubToken(RepositorySlug slug) async {
+  Future<String> generateGithubToken(gh.RepositorySlug slug) async {
     // GitHub's secondary rate limits are run into very frequently when making auth tokens.
     final Uint8List? cacheValue = await _cache.getOrCreate(
       configCacheName,
@@ -352,7 +332,7 @@
     return String.fromCharCodes(cacheValue!);
   }
 
-  Future<Uint8List> _generateGithubToken(RepositorySlug slug) async {
+  Future<Uint8List> _generateGithubToken(gh.RepositorySlug slug) async {
     final Map<String, dynamic> appInstallations = await githubAppInstallations;
     final String? appInstallation = appInstallations[slug.fullName]['installation_id'] as String?;
     final String jsonWebToken = await generateJsonWebToken();
@@ -371,14 +351,14 @@
     return Uint8List.fromList(token.codeUnits);
   }
 
-  Future<GitHub> createGitHubClient({PullRequest? pullRequest, RepositorySlug? slug}) async {
+  Future<gh.GitHub> createGitHubClient({gh.PullRequest? pullRequest, gh.RepositorySlug? slug}) async {
     slug ??= pullRequest!.base!.repo!.slug();
     final String githubToken = await generateGithubToken(slug);
     return createGitHubClientWithToken(githubToken);
   }
 
-  GitHub createGitHubClientWithToken(String token) {
-    return GitHub(auth: Authentication.withToken(token));
+  gh.GitHub createGitHubClientWithToken(String token) {
+    return gh.GitHub(auth: gh.Authentication.withToken(token));
   }
 
   Future<GraphQLClient> createGitHubGraphQLClient() async {
@@ -427,17 +407,17 @@
     return createGithubService(flutterSlug);
   }
 
-  Future<GithubService> createGithubService(RepositorySlug slug) async {
-    final GitHub github = await createGitHubClient(slug: slug);
+  Future<GithubService> createGithubService(gh.RepositorySlug slug) async {
+    final gh.GitHub github = await createGitHubClient(slug: slug);
     return GithubService(github);
   }
 
   GithubService createGithubServiceWithToken(String token) {
-    final GitHub github = createGitHubClientWithToken(token);
+    final gh.GitHub github = createGitHubClientWithToken(token);
     return GithubService(github);
   }
 
-  bool githubPresubmitSupportedRepo(RepositorySlug slug) {
+  bool githubPresubmitSupportedRepo(gh.RepositorySlug slug) {
     return supportedRepos.contains(slug);
   }
 }
diff --git a/app_dart/test/foundation/utils_test.dart b/app_dart/test/foundation/utils_test.dart
index fccdd8d..9082b32 100644
--- a/app_dart/test/foundation/utils_test.dart
+++ b/app_dart/test/foundation/utils_test.dart
@@ -4,7 +4,6 @@
 
 import 'dart:convert';
 import 'dart:io';
-import 'dart:typed_data';
 
 import 'package:cocoon_service/src/foundation/utils.dart';
 import 'package:cocoon_service/src/model/ci_yaml/target.dart';
@@ -172,30 +171,6 @@
       });
     });
 
-    group('GetBranches', () {
-      late MockClient branchHttpClient;
-
-      test('returns branches', () async {
-        branchHttpClient = MockClient((_) async => http.Response(branchRegExp, HttpStatus.ok));
-        final Uint8List branches = await getBranches(
-          () => branchHttpClient,
-          retryOptions: noRetry,
-        );
-        expect(String.fromCharCodes(branches), 'master,flutter-1.1-candidate.1');
-      });
-
-      test('returns master when http request fails', () async {
-        branchHttpClient = MockClient((_) async {
-          return http.Response('', HttpStatus.serviceUnavailable);
-        });
-        final Uint8List builders = await getBranches(
-          () => branchHttpClient,
-          retryOptions: noRetry,
-        );
-        expect(String.fromCharCodes(builders), 'master');
-      });
-    });
-
     group('GitHubBackoffCalculator', () {
       test('twoSecondLinearBackoff', () {
         expect(twoSecondLinearBackoff(0), const Duration(seconds: 2));
diff --git a/app_dart/test/request_handlers/reset_prod_task_test.dart b/app_dart/test/request_handlers/reset_prod_task_test.dart
index 1e37597..12737ec 100644
--- a/app_dart/test/request_handlers/reset_prod_task_test.dart
+++ b/app_dart/test/request_handlers/reset_prod_task_test.dart
@@ -37,7 +37,7 @@
       config = FakeConfig(
         dbValue: datastoreDB,
         keyHelperValue: keyHelper,
-        flutterBranchesValue: <String>[
+        supportedBranchesValue: <String>[
           Config.defaultBranch(Config.flutterSlug),
         ],
       );
diff --git a/app_dart/test/request_handlers/update_task_status_test.dart b/app_dart/test/request_handlers/update_task_status_test.dart
index 57d9791..9325d1f 100644
--- a/app_dart/test/request_handlers/update_task_status_test.dart
+++ b/app_dart/test/request_handlers/update_task_status_test.dart
@@ -5,7 +5,6 @@
 import 'package:cocoon_service/src/model/appengine/commit.dart';
 import 'package:cocoon_service/src/model/appengine/task.dart';
 import 'package:cocoon_service/src/request_handlers/update_task_status.dart';
-import 'package:cocoon_service/src/request_handling/exceptions.dart';
 import 'package:cocoon_service/src/service/config.dart';
 import 'package:cocoon_service/src/service/datastore.dart';
 import 'package:gcloud/db.dart';
@@ -31,7 +30,6 @@
       final FakeDatastoreDB datastoreDB = FakeDatastoreDB();
       config = FakeConfig(
         dbValue: datastoreDB,
-        flutterBranchesValue: <String>['master'],
         tabledataResource: tabledataResourceApi,
         maxTaskRetriesValue: 2,
       );
@@ -172,15 +170,5 @@
       expect(cocoonTask.status, Task.statusNew);
       expect(cocoonTask.attempts, 0);
     });
-
-    test('task name request fails with unknown branches', () async {
-      tester.requestData = <String, dynamic>{
-        UpdateTaskStatus.gitBranchParam: 'release-abc',
-        UpdateTaskStatus.gitShaParam: commitSha,
-        UpdateTaskStatus.newStatusParam: 'Failed',
-        UpdateTaskStatus.builderNameParam: 'linux_integration_ui_ios',
-      };
-      expect(tester.post(handler), throwsA(isA<BadRequestException>()));
-    });
   });
 }
diff --git a/app_dart/test/request_handlers/vacuum_github_commits_test.dart b/app_dart/test/request_handlers/vacuum_github_commits_test.dart
index 58ec920..fdbdb81 100644
--- a/app_dart/test/request_handlers/vacuum_github_commits_test.dart
+++ b/app_dart/test/request_handlers/vacuum_github_commits_test.dart
@@ -108,7 +108,7 @@
 
     test('succeeds when GitHub returns no commits', () async {
       githubCommits = <String>[];
-      config.flutterBranchesValue = <String>['master'];
+      config.supportedBranchesValue = <String>['master'];
       final Body body = await tester.get<Body>(handler);
       expect(yieldedCommitCount, 0);
       expect(db.values, isEmpty);
@@ -153,7 +153,6 @@
 
     test('inserts all relevant fields of the commit', () async {
       githubCommits = <String>['1'];
-      config.flutterBranchesValue = <String>['master'];
       expect(db.values.values.whereType<Commit>().length, 0);
       await tester.get<Body>(handler);
       const int supportedBranchesCount = 2;
@@ -173,7 +172,6 @@
 
     test('skips commits for which transaction commit fails', () async {
       githubCommits = <String>['2', '3', '4'];
-      config.flutterBranchesValue = <String>['main'];
 
       /// This test is simulating an existing branch, which must already
       /// have at least one commit in the datastore.
diff --git a/app_dart/test/service/branch_service_test.dart b/app_dart/test/service/branch_service_test.dart
index 8a0ca89..27c9d95 100644
--- a/app_dart/test/service/branch_service_test.dart
+++ b/app_dart/test/service/branch_service_test.dart
@@ -63,7 +63,7 @@
       expect(db.values.values.whereType<Branch>().length, 1);
       final Branch branch = db.values.values.whereType<Branch>().single;
       expect(branch.repository, 'flutter/flutter');
-      expect(branch.branch, 'flutter-2.12-candidate.4');
+      expect(branch.name, 'flutter-2.12-candidate.4');
     });
 
     test('should not add duplicate entity if branch already exists in db', () async {
@@ -82,7 +82,7 @@
       expect(db.values.values.whereType<Branch>().length, 1);
       final Branch branch = db.values.values.whereType<Branch>().single;
       expect(branch.repository, 'flutter/flutter');
-      expect(branch.branch, 'flutter-2.12-candidate.4');
+      expect(branch.name, 'flutter-2.12-candidate.4');
     });
 
     test('should add branch if it is different from previously existing branches', () async {
@@ -100,7 +100,7 @@
       await branchService.handleCreateRequest(createEvent);
 
       expect(db.values.values.whereType<Branch>().length, 2);
-      expect(db.values.values.whereType<Branch>().map<String>((Branch b) => b.branch),
+      expect(db.values.values.whereType<Branch>().map<String>((Branch b) => b.name),
           containsAll(<String>['flutter-2.12-candidate.4', 'flutter-2.12-candidate.5']));
     });
   });
diff --git a/app_dart/test/service/config_test.dart b/app_dart/test/service/config_test.dart
index ffbedd2..c653139 100644
--- a/app_dart/test/service/config_test.dart
+++ b/app_dart/test/service/config_test.dart
@@ -56,14 +56,5 @@
         isNot(contains('package:flutter')),
       );
     });
-
-    test('flutter branches', () async {
-      final List<String> branches = <String>['master', 'main', 'flutter-2.13-candidate.0'];
-      final Uint8List branchesBytes = Uint8List.fromList(branches.join(',').codeUnits);
-      await cacheService.set(Config.configCacheName, 'flutterBranches', branchesBytes);
-      expect(await config.getSupportedBranches(Config.flutterSlug), <String>['master', 'flutter-2.13-candidate.0']);
-      expect(await config.getSupportedBranches(Config.engineSlug), <String>['main', 'flutter-2.13-candidate.0']);
-      expect(await config.getSupportedBranches(Config.cocoonSlug), <String>['main']);
-    });
   });
 }
diff --git a/app_dart/test/service/scheduler_test.dart b/app_dart/test/service/scheduler_test.dart
index 2e53d21..69c6d57 100644
--- a/app_dart/test/service/scheduler_test.dart
+++ b/app_dart/test/service/scheduler_test.dart
@@ -165,7 +165,7 @@
       });
 
       test('inserts all relevant fields of the commit', () async {
-        config.flutterBranchesValue = <String>['master'];
+        config.supportedBranchesValue = <String>['master'];
         expect(db.values.values.whereType<Commit>().length, 0);
         await scheduler.addCommits(createCommitList(<String>['1']));
         expect(db.values.values.whereType<Commit>().length, 1);
@@ -180,13 +180,13 @@
       });
 
       test('skips scheduling for unsupported repos', () async {
-        config.flutterBranchesValue = <String>['master'];
+        config.supportedBranchesValue = <String>['master'];
         await scheduler.addCommits(createCommitList(<String>['1'], repo: 'not-supported'));
         expect(db.values.values.whereType<Commit>().length, 0);
       });
 
       test('skips commits for which transaction commit fails', () async {
-        config.flutterBranchesValue = <String>['master'];
+        config.supportedBranchesValue = <String>['master'];
 
         // Existing commits should not be duplicated.
         final Commit commit = shaToCommit('1');
@@ -208,7 +208,7 @@
       });
 
       test('skips commits for which task transaction fails', () async {
-        config.flutterBranchesValue = <String>['master'];
+        config.supportedBranchesValue = <String>['master'];
 
         // Existing commits should not be duplicated.
         final Commit commit = shaToCommit('1');
diff --git a/app_dart/test/src/datastore/fake_config.dart b/app_dart/test/src/datastore/fake_config.dart
index 114e934..295f769 100644
--- a/app_dart/test/src/datastore/fake_config.dart
+++ b/app_dart/test/src/datastore/fake_config.dart
@@ -5,13 +5,14 @@
 import 'dart:async';
 
 import 'package:appengine/appengine.dart';
+import 'package:cocoon_service/src/model/appengine/branch.dart';
 import 'package:cocoon_service/src/model/appengine/key_helper.dart';
 import 'package:cocoon_service/src/model/appengine/service_account_info.dart';
 import 'package:cocoon_service/src/service/bigquery.dart';
 import 'package:cocoon_service/src/service/config.dart';
 import 'package:cocoon_service/src/service/github_service.dart';
 import 'package:cocoon_service/src/service/luci.dart';
-import 'package:github/github.dart';
+import 'package:github/github.dart' as gh;
 import 'package:googleapis/bigquery/v2.dart';
 import 'package:graphql/client.dart';
 
@@ -43,7 +44,6 @@
     this.rollerAccountsValue,
     this.flutterBuildValue,
     this.flutterBuildDescriptionValue,
-    this.flutterBranchesValue,
     this.maxRecordsValue,
     this.flutterGoldPendingValue,
     this.flutterGoldSuccessValue,
@@ -60,7 +60,7 @@
     FakeDatastoreDB? dbValue,
   }) : dbValue = dbValue ?? FakeDatastoreDB();
 
-  GitHub? githubClient;
+  gh.GitHub? githubClient;
   GraphQLClient? githubGraphQLClient;
   GraphQLClient? cirrusGraphQLClient;
   TabledataResource? tabledataResource;
@@ -85,7 +85,6 @@
   Logging? loggingServiceValue;
   String? waitingForTreeToGoGreenLabelNameValue;
   Set<String>? rollerAccountsValue;
-  List<String>? flutterBranchesValue;
   int? maxRecordsValue;
   String? flutterGoldPendingValue;
   String? flutterGoldSuccessValue;
@@ -98,13 +97,13 @@
   List<String>? supportedBranchesValue;
   List<LuciBuilder>? luciBuildersValue;
   String? overrideTreeStatusLabelValue;
-  Set<RepositorySlug>? supportedReposValue;
+  Set<gh.RepositorySlug>? supportedReposValue;
 
   @override
-  Future<GitHub> createGitHubClient({PullRequest? pullRequest, RepositorySlug? slug}) async => githubClient!;
+  Future<gh.GitHub> createGitHubClient({gh.PullRequest? pullRequest, gh.RepositorySlug? slug}) async => githubClient!;
 
   @override
-  GitHub createGitHubClientWithToken(String token) => githubClient!;
+  gh.GitHub createGitHubClientWithToken(String token) => githubClient!;
 
   @override
   Future<GraphQLClient> createGitHubGraphQLClient() async => githubGraphQLClient!;
@@ -119,7 +118,7 @@
   Future<BigqueryService> createBigQueryService() async => bigqueryService!;
 
   @override
-  Future<GithubService> createGithubService(RepositorySlug slug) async => githubService!;
+  Future<GithubService> createGithubService(gh.RepositorySlug slug) async => githubService!;
 
   @override
   GithubService createGithubServiceWithToken(String token) => githubService!;
@@ -165,18 +164,15 @@
   String flutterGoldFollowUpAlert(String url) => flutterGoldFollowUpAlertValue!;
 
   @override
-  String flutterGoldAlertConstant(RepositorySlug slug) => flutterGoldAlertConstantValue!;
+  String flutterGoldAlertConstant(gh.RepositorySlug slug) => flutterGoldAlertConstantValue!;
 
   @override
-  String flutterGoldCommentID(PullRequest pr) => 'PR ${pr.number}, at ${pr.head!.sha}';
+  String flutterGoldCommentID(gh.PullRequest pr) => 'PR ${pr.number}, at ${pr.head!.sha}';
 
   @override
   int get commitNumber => 30;
 
   @override
-  Future<List<String>> get flutterBranches async => flutterBranchesValue!;
-
-  @override
   KeyHelper get keyHelper => keyHelperValue!;
 
   @override
@@ -222,18 +218,18 @@
   Set<String> get rollerAccounts => rollerAccountsValue!;
 
   @override
-  bool githubPresubmitSupportedRepo(RepositorySlug slug) {
-    return <RepositorySlug>[
-      RepositorySlug('flutter', 'flutter'),
-      RepositorySlug('flutter', 'engine'),
-      RepositorySlug('flutter', 'cocoon'),
-      RepositorySlug('flutter', 'packages'),
-      RepositorySlug('flutter', 'plugins'),
+  bool githubPresubmitSupportedRepo(gh.RepositorySlug slug) {
+    return <gh.RepositorySlug>[
+      Config.flutterSlug,
+      Config.engineSlug,
+      Config.cocoonSlug,
+      Config.packagesSlug,
+      Config.pluginsSlug,
     ].contains(slug);
   }
 
   @override
-  Future<String> generateGithubToken(RepositorySlug slug) {
+  Future<String> generateGithubToken(gh.RepositorySlug slug) {
     throw UnimplementedError();
   }
 
@@ -255,9 +251,6 @@
   Future<String> get githubPublicKey => throw UnimplementedError();
 
   @override
-  Future<List<String>> getSupportedBranches(RepositorySlug slug) async => supportedBranchesValue!;
-
-  @override
   Future<GithubService> createDefaultGitHubService() async => githubService!;
 
   @override
@@ -270,5 +263,18 @@
   Future<List<String>> get releaseAccounts async => <String>['dart-flutter-releaser'];
 
   @override
-  Set<RepositorySlug> get supportedRepos => supportedReposValue ?? <RepositorySlug>{Config.flutterSlug};
+  Set<gh.RepositorySlug> get supportedRepos => supportedReposValue ?? <gh.RepositorySlug>{Config.flutterSlug};
+
+  @override
+  Future<Iterable<Branch>> getBranches(gh.RepositorySlug slug) async {
+    if (supportedBranchesValue == null) {
+      throw Exception('Test must set suportedBranchesValue to be able to use Config.getBranches');
+    }
+    return supportedBranchesValue!.map((String branch) => Branch(
+          key: db.emptyKey.append<String>(
+            Branch,
+            id: '${slug.fullName}/$branch',
+          ),
+        ));
+  }
 }