[dart] Add support for the new experimental channel

* -experimental builders are treated as if "is_experimental" is true.
* Unify channel detection logic.

Bug: https://crbug.com/1207358
Change-Id: I8a11e3b3d1f9913a060e7b8757dc727d7ad79103
Reviewed-on: https://dart-review.googlesource.com/c/recipes/+/201420
Reviewed-by: Karl Klose <karlklose@google.com>
Commit-Queue: Alexander Thomas <athom@google.com>
diff --git a/README.recipes.md b/README.recipes.md
index 0e6be6f..e318219 100644
--- a/README.recipes.md
+++ b/README.recipes.md
@@ -74,7 +74,7 @@
 
 Checks out the dart code and prepares it for building.
 
-&mdash; **def [collect\_all](/recipe_modules/dart/api.py#327)(self, steps):**
+&mdash; **def [collect\_all](/recipe_modules/dart/api.py#330)(self, steps):**
 
 Collects the results of a sharded test run.
 
@@ -82,17 +82,17 @@
 
 Returns the path to the checked-in SDK dart executable.
 
-&mdash; **def [delete\_debug\_log](/recipe_modules/dart/api.py#688)(self):**
+&mdash; **def [delete\_debug\_log](/recipe_modules/dart/api.py#691)(self):**
 
 Deletes the debug log file
 
-&mdash; **def [download\_browser](/recipe_modules/dart/api.py#998)(self, runtime, version):**
+&mdash; **def [download\_browser](/recipe_modules/dart/api.py#1001)(self, runtime, version):**
 
 &mdash; **def [get\_secret](/recipe_modules/dart/api.py#93)(self, name):**
 
 Decrypts the specified secret and returns the location of the result
 
-&mdash; **def [has\_infra\_failure](/recipe_modules/dart/api.py#1292)(self, failure):**
+&mdash; **def [has\_infra\_failure](/recipe_modules/dart/api.py#1290)(self, failure):**
 
 Returns whether failure is an aggregated failure that directly or
 indirectly contains an InfraFailure.
@@ -101,7 +101,7 @@
 
 Kills leftover tasks from previous runs or steps.
 
-&mdash; **def [read\_debug\_log](/recipe_modules/dart/api.py#676)(self):**
+&mdash; **def [read\_debug\_log](/recipe_modules/dart/api.py#679)(self):**
 
 Reads the debug log file
 
@@ -110,7 +110,7 @@
 Runs test.py in the given isolate, sharded over several swarming tasks.
 Returns the created tasks, which can be collected with collect_all().
 
-&mdash; **def [test](/recipe_modules/dart/api.py#694)(self, test_data):**
+&mdash; **def [test](/recipe_modules/dart/api.py#697)(self, test_data):**
 
 Reads the test-matrix.json file in the checkout and runs each step listed
 in the file.
diff --git a/recipe_modules/dart/api.py b/recipe_modules/dart/api.py
index a23772c..fbdcadf 100644
--- a/recipe_modules/dart/api.py
+++ b/recipe_modules/dart/api.py
@@ -278,19 +278,22 @@
       tasks.append(task_request)
     return self.m.swarming.trigger('trigger shards for %s' % name, tasks)
 
+  @property
+  def _is_experimental(self):
+    return self.m.runtime.is_experimental or self._channel() == 'experimental'
 
   def _channel(self):
     channel = self.m.buildbucket.builder_name.split('-')[-1]
-    if channel in ['beta', 'dev', 'stable', 'try']:
+    if channel in ['beta', 'dev', 'experimental', 'stable', 'try']:
       return channel
     return 'master'
 
 
   def _release_builder(self):
     """Boolean that reports whether the builder is on the
-       beta, dev or stable channels. Some steps are only
+       beta, dev, experimental or stable channels. Some steps are only
        run on the master and try builders."""
-    return self._channel() in ['beta', 'dev', 'stable']
+    return self._channel() in ['beta', 'dev', 'experimental', 'stable']
 
 
   def _try_builder(self):
@@ -485,14 +488,14 @@
       path = 'configuration/%s/%s' % (self._channel(), configuration)
     else:
       path = 'builders/%s' % builder
-    if (self.m.runtime.is_experimental):
+    if (self._is_experimental):
       path = 'experimental/%s' % path
     self._upload_result(path, build_number, 'revision', build_revision)
     self._upload_result(path, build_number, 'logs.json', logs_str)
     self._upload_result(path, build_number, 'results.json', results_str)
     self._upload_result(path, build_number, 'flaky.json', flaky_json_str)
     if (not self._release_builder() and not configuration and
-        not self.m.runtime.is_experimental):
+        not self._is_experimental):
       self._upload_result('builders/current_flakiness', 'single_directory',
                           'flaky_current_%s.json' % builder, flaky_json_str)
     # Update "latest" file, if this is not a bisection build (bisection builds
@@ -515,7 +518,7 @@
     self.m.gsutil.upload(*args, name='upload %s' % filename)
 
   def _update_blamelist(self, results_by_configuration):
-    if not self._supports_result_database() or self.m.runtime.is_experimental:
+    if not self._supports_result_database() or self._is_experimental:
       return
     access_token = self.m.service_account.default().get_access_token(
         ['https://www.googleapis.com/auth/cloud-platform'])
@@ -543,7 +546,7 @@
       # Cloud functions can only handle commits on certain branches and
       # CL references (for try jobs).
       return
-    if self.m.runtime.is_experimental:
+    if self._is_experimental:
       return
     access_token = self.m.service_account.default().get_access_token(
       ['https://www.googleapis.com/auth/cloud-platform'])
@@ -704,7 +707,7 @@
           step_test_data=lambda: self.m.json.test_api.output(test_data))
       test_matrix = read_json.json.output
       builder = str(self.m.buildbucket.builder_name)
-      if builder.endswith(('-be', '-beta', '-dev', '-stable', '-try')):
+      if builder.endswith(('-beta', '-dev', 'experimental', '-stable', '-try')):
         builder = builder[0:builder.rfind('-')]
       isolate_hashes = {}
       global_config = test_matrix['global']
@@ -1028,7 +1031,7 @@
       # Upload at most 1000 lines at once
       for match in re.finditer(r'(?:.*\n){1,1000}', results_str):
         chunk = match.group(0)
-        if not self.m.runtime.is_experimental:
+        if not self._is_experimental:
           self.m.step(
               'upload results chunk to big query',
               cmd,
@@ -1267,14 +1270,9 @@
 
       self.environment_variables = step_json.get('environment', {})
 
-      channels = {
-          "refs/heads/ci-test-data": "infra",
-          "refs/heads/master": "be",
-          "refs/heads/beta": "beta",
-          "refs/heads/dev": "dev",
-          "refs/heads/stable": "stable",
-      }
-      channel = channels.get(self.m.buildbucket.gitiles_commit.ref, 'try')
+      channel = m.dart._channel()
+      if channel == 'master':
+        channel = 'be'
       self.environment_variables['BUILDBOT_BUILDERNAME'] = (
           builder_name + "-%s" % channel)
 
diff --git a/recipe_modules/dart/examples/example.expected/basic-mac.json b/recipe_modules/dart/examples/example.expected/basic-mac.json
index cfab157..93d9d75 100644
--- a/recipe_modules/dart/examples/example.expected/basic-mac.json
+++ b/recipe_modules/dart/examples/example.expected/basic-mac.json
@@ -581,7 +581,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -612,7 +612,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -652,7 +652,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -965,7 +965,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -990,7 +990,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -1016,7 +1016,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -1045,7 +1045,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -1084,7 +1084,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -1110,7 +1110,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -1139,7 +1139,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-be"
+      "BUILDBOT_BUILDERNAME": "dart2js-strong-mac-x64-chrome-dev"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
diff --git a/recipe_modules/dart/examples/example.expected/branch-builder-does-not-publish-results.json b/recipe_modules/dart/examples/example.expected/branch-builder-does-not-publish-results.json
index 3b59321..5ef08c8 100644
--- a/recipe_modules/dart/examples/example.expected/branch-builder-does-not-publish-results.json
+++ b/recipe_modules/dart/examples/example.expected/branch-builder-does-not-publish-results.json
@@ -518,7 +518,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-try"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -544,7 +544,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-try"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -574,7 +574,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-try"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -761,7 +761,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-try"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -790,7 +790,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-try"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -822,7 +822,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-try"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
diff --git a/recipe_modules/dart/examples/example.expected/ci-test-data-branch-builder-does-publish-results.json b/recipe_modules/dart/examples/example.expected/ci-test-data-branch-builder-does-publish-results.json
index dbedc1c..74bae01 100644
--- a/recipe_modules/dart/examples/example.expected/ci-test-data-branch-builder-does-publish-results.json
+++ b/recipe_modules/dart/examples/example.expected/ci-test-data-branch-builder-does-publish-results.json
@@ -518,7 +518,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-infra"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -544,7 +544,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-infra"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -574,7 +574,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-infra"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -761,7 +761,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-infra"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -790,7 +790,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-infra"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
@@ -822,7 +822,7 @@
     ],
     "cwd": "[CACHE]/builder/sdk",
     "env": {
-      "BUILDBOT_BUILDERNAME": "co19-infra"
+      "BUILDBOT_BUILDERNAME": "co19-be"
     },
     "env_suffixes": {
       "DEPOT_TOOLS_UPDATE": [
diff --git a/recipe_modules/dart/examples/example.py b/recipe_modules/dart/examples/example.py
index c094f1e..5b41e7f 100644
--- a/recipe_modules/dart/examples/example.py
+++ b/recipe_modules/dart/examples/example.py
@@ -538,28 +538,41 @@
       api.post_process(StatusSuccess),
   )
 
-  yield api.test(
-      'experimental-builds-are-side-effect-free',
-      api.properties(bot_id='trusty-dart-123'),
-      api.buildbucket.ci_build(
-          revision='3456abce78ef',
-          build_number=1357,
-          builder='analyzer-linux-release',
-          git_repo='https://dart.googlesource.com/sdk',
-          project='dart'),
-      _canned_step(api, 'test1', 2, False),
-      _canned_step(api, 'test2'),
-      _canned_step(api, 'test3', 2),
-      api.runtime(is_experimental=True),
-      _upload_isolate_step_data(api, 'test'),
-      _upload_isolate_step_data(api, 'trigger'),
-      api.step_data('buildbucket.put', stdout=api.json.output(TRIGGER_RESULT)),
-      api.step_data('add fields to result records',
-                    api.raw_io.output_text(RESULT_DATA)),
-      api.post_process(DoesNotRunRE, r'.*publish results.*'),
-      api.post_process(StatusSuccess),
-      api.post_process(DropExpectation),
-  )
+  def expect_no_side_effects(name,
+                             builder='analyzer-linux-release',
+                             is_experimental=True):
+    return api.test(
+        name,
+        api.properties(bot_id='trusty-dart-123'),
+        api.buildbucket.ci_build(
+            revision='3456abce78ef',
+            build_number=1357,
+            builder=builder,
+            git_repo='https://dart.googlesource.com/sdk',
+            project='dart'),
+        _canned_step(api, 'test1', 2, False),
+        _canned_step(api, 'test2'),
+        _canned_step(api, 'test3', 2),
+        api.runtime(is_experimental=is_experimental),
+        _upload_isolate_step_data(api, 'test'),
+        _upload_isolate_step_data(api, 'trigger'),
+        api.step_data(
+            'buildbucket.put', stdout=api.json.output(TRIGGER_RESULT)),
+        api.step_data('add fields to result records',
+                      api.raw_io.output_text(RESULT_DATA)),
+        api.post_process(DoesNotRunRE, r'.*publish results.*'),
+        api.post_process(StatusSuccess),
+        api.post_process(DropExpectation),
+    )
+
+  yield expect_no_side_effects('experimental-builds-are-side-effect-free')
+  yield expect_no_side_effects(
+      'experimental-channel-builds-are-side-effect-free',
+      builder='analyzer-linux-release-experimental',
+      is_experimental=False)
+  yield expect_no_side_effects(
+      'experimental-experimental-channel-builds-are-side-effect-free',
+      builder='analyzer-linux-release-experimental')
 
   yield api.test(
       'build-failure-in-matrix',