go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/testdata/full_example_no_legacy_acls.star (about)

     1  lucicfg.enable_experiment("crbug.com/1347252")
     2  lucicfg.enable_experiment("crbug.com/1496969")
     3  
     4  lucicfg.config(config_dir = ".output")
     5  lucicfg.config(tracked_files = ["*.cfg"])
     6  lucicfg.config(fail_on_warnings = True)
     7  
     8  luci.project(
     9      name = "infra",
    10      buildbucket = "cr-buildbucket.appspot.com",
    11      logdog = "luci-logdog.appspot.com",
    12      milo = "luci-milo.appspot.com",
    13      notify = "luci-notify.appspot.com",
    14      scheduler = "luci-scheduler.appspot.com",
    15      swarming = "chromium-swarm.appspot.com",
    16      tricium = "tricium-prod.appspot.com",
    17      acls = [
    18          acl.entry(
    19              roles = [
    20                  acl.PROJECT_CONFIGS_READER,
    21                  acl.LOGDOG_READER,
    22                  acl.BUILDBUCKET_READER,
    23                  acl.SCHEDULER_READER,
    24              ],
    25              groups = ["all"],
    26          ),
    27          acl.entry(
    28              roles = [
    29                  acl.BUILDBUCKET_OWNER,
    30                  acl.SCHEDULER_OWNER,
    31                  acl.CQ_COMMITTER,
    32              ],
    33              groups = ["admins"],
    34          ),
    35      ],
    36  )
    37  
    38  luci.logdog(
    39      gs_bucket = "chromium-luci-logdog",
    40      cloud_logging_project = "chromium-build-logs",
    41  )
    42  
    43  luci.milo(
    44      logo = "https://storage.googleapis.com/chrome-infra-public/logo/chrome-infra-logo-200x200.png",
    45      favicon = "https://storage.googleapis.com/chrome-infra-public/logo/favicon.ico",
    46      bug_url_template = "https://bugs.chromium.org/p/tutu%%2C%%20all%%20aboard/issues/entry?summary=Bug%%20summary&description=Everything%%20is%%20broken&components=Stuff%%3EHard",
    47  )
    48  
    49  # Recipes.
    50  
    51  luci.recipe(
    52      name = "main/recipe",
    53      cipd_package = "recipe/bundles/main",
    54      use_python3 = True,
    55      wrapper = ["path/to/wrapper"],
    56  )
    57  
    58  # Executables.
    59  
    60  luci.executable(
    61      name = "main/executable",
    62      cipd_package = "executable/bundles/main",
    63      cmd = ["cmd"],
    64  )
    65  
    66  # CI bucket.
    67  
    68  luci.bucket(
    69      name = "ci",
    70  
    71      # Allow developers to force-launch CI builds through Scheduler, but not
    72      # directly through Buildbucket. The direct access to Buildbucket allows to
    73      # override almost all aspects of the builds (e.g. what recipe is used),
    74      # and Buildbucket totally ignores any concurrency limitations set in the
    75      # LUCI Scheduler configs. This makes direct Buildbucket access to CI buckets
    76      # dangerous. They usually have very small pool of machines, and these
    77      # machines are assumed to be running only "approved" code (being post-submit
    78      # builders).
    79      acls = [
    80          acl.entry(
    81              acl.SCHEDULER_TRIGGERER,
    82              groups = ["devs"],
    83              projects = ["some-project"],
    84          ),
    85      ],
    86  )
    87  
    88  luci.gitiles_poller(
    89      name = "main-poller",
    90      bucket = "ci",
    91      repo = "https://noop.com",
    92      refs = [
    93          "refs/heads/main",
    94          "refs/tags/blah",
    95          r"refs/branch-heads/\d+\.\d+",
    96      ],
    97      path_regexps = [".*"],
    98      path_regexps_exclude = ["excluded"],
    99      schedule = "with 10s interval",
   100  )
   101  
   102  luci.builder(
   103      name = "linux ci builder",
   104      bucket = "ci",
   105      description_html = "this is a linux ci builder",
   106      executable = "main/recipe",
   107      triggered_by = ["main-poller"],
   108      triggers = [
   109          "ci/generically named builder",
   110          "ci/generically named executable builder",
   111      ],
   112      properties = {
   113          "prop2": ["val2", 123],
   114          "prop1": "val1",
   115      },
   116      allowed_property_overrides = ["prop1"],
   117      service_account = "builder@example.com",
   118      caches = [
   119          swarming.cache("path1"),
   120          swarming.cache("path2", name = "name2"),
   121          swarming.cache("path3", name = "name3", wait_for_warm_cache = 10 * time.minute),
   122      ],
   123      execution_timeout = 3 * time.hour,
   124      grace_period = 2 * time.minute,
   125      dimensions = {
   126          "os": "Linux",
   127          "builder": "linux ci builder",  # no auto_builder_dimension
   128          "prefer_if_available": [
   129              swarming.dimension("first-choice", expiration = 5 * time.minute),
   130              swarming.dimension("fallback"),
   131          ],
   132      },
   133      priority = 80,
   134      swarming_tags = ["tag1:val1", "tag2:val2"],
   135      expiration_timeout = time.hour,
   136      build_numbers = True,
   137      triggering_policy = scheduler.greedy_batching(
   138          max_concurrent_invocations = 5,
   139          max_batch_size = 10,
   140      ),
   141      # This will be replaced with a proper experiment entry.
   142      task_template_canary_percentage = 17,
   143      resultdb_settings = resultdb.settings(
   144          enable = True,
   145          bq_exports = [
   146              resultdb.export_test_results(
   147                  bq_table = "luci-resultdb.my-awesome-project.all_test_results",
   148                  predicate = resultdb.test_result_predicate(
   149                      test_id_regexp = "ninja:.*",
   150                      unexpected_only = True,
   151                      variant_contains = True,
   152                      variant = {"test_suite": "super_interesting_suite"},
   153                  ),
   154              ),
   155              resultdb.export_text_artifacts(
   156                  bq_table = "luci-resultdb.my-awesome-project.all_text_artifacts",
   157                  predicate = resultdb.artifact_predicate(
   158                      test_result_predicate = resultdb.test_result_predicate(
   159                          test_id_regexp = "ninja:.*",
   160                          unexpected_only = True,
   161                          variant_contains = True,
   162                          variant = {"test_suite": "super_interesting_suite"},
   163                      ),
   164                      included_invocations = False,
   165                      test_results = True,
   166                      content_type_regexp = "text.*",
   167                  ),
   168              ),
   169          ],
   170          history_options = resultdb.history_options(
   171              by_timestamp = True,
   172          ),
   173      ),
   174      test_presentation = resultdb.test_presentation(
   175          column_keys = ["v.gpu"],
   176          grouping_keys = ["status", "v.test_suite"],
   177      ),
   178      contact_team_email = "a@b.com",
   179  )
   180  
   181  luci.builder(
   182      name = "generically named builder",
   183      bucket = "ci",
   184      executable = "main/recipe",
   185      triggered_by = ["main-poller"],
   186  )
   187  
   188  luci.builder(
   189      name = "generically named executable builder",
   190      bucket = "ci",
   191      executable = "main/executable",
   192      properties = {
   193          "prop2": ["val2", 123],
   194          "prop1": "val1",
   195      },
   196      allowed_property_overrides = ["*"],
   197      triggered_by = ["main-poller"],
   198  )
   199  
   200  luci.builder(
   201      name = "cron builder",
   202      bucket = "ci",
   203      executable = "main/recipe",
   204      schedule = "0 6 * * *",
   205      repo = "https://cron.repo.example.com",
   206  )
   207  
   208  luci.builder(
   209      name = "builder with custom swarming host",
   210      bucket = "ci",
   211      executable = "main/recipe",
   212      swarming_host = "another-swarming.appspot.com",
   213  )
   214  
   215  luci.builder(
   216      name = "builder with the default test presentation config",
   217      bucket = "ci",
   218      executable = "main/recipe",
   219      test_presentation = resultdb.test_presentation(
   220          column_keys = [],
   221          grouping_keys = ["status"],
   222      ),
   223  )
   224  
   225  # Try bucket.
   226  
   227  luci.bucket(
   228      name = "try",
   229  
   230      # Allow developers to launch try jobs directly with whatever parameters
   231      # they want. Try bucket is basically a free build farm for all developers.
   232      acls = [
   233          acl.entry(acl.BUILDBUCKET_TRIGGERER, groups = "devs"),
   234      ],
   235  )
   236  
   237  luci.builder(
   238      name = "linux try builder",
   239      bucket = "try",
   240      executable = "main/recipe",
   241  )
   242  
   243  luci.builder(
   244      name = "linux try builder 2",
   245      bucket = "try",
   246      executable = "main/recipe",
   247  )
   248  
   249  luci.builder(
   250      name = "generically named builder",
   251      bucket = "try",
   252      executable = "main/recipe",
   253  )
   254  
   255  luci.builder(
   256      name = "builder with executable",
   257      bucket = "try",
   258      executable = "main/executable",
   259  )
   260  
   261  luci.builder(
   262      name = "builder with experiment map",
   263      bucket = "try",
   264      executable = "main/executable",
   265      experiments = {
   266          "luci.enable_new_beta_feature": 32,
   267      },
   268  )
   269  
   270  luci.builder(
   271      name = "spell-checker",
   272      bucket = "try",
   273      executable = "main/recipe",
   274  )
   275  
   276  # Inline definitions.
   277  
   278  def inline_poller():
   279      return luci.gitiles_poller(
   280          name = "inline poller",
   281          bucket = "inline",
   282          repo = "https://noop.com",
   283          refs = [
   284              "refs/heads/main",
   285              "refs/tags/blah",
   286              r"refs/branch-heads/\d+\.\d+",
   287          ],
   288          schedule = "with 10s interval",
   289      )
   290  
   291  luci.builder(
   292      name = "triggerer builder",
   293      bucket = luci.bucket(name = "inline"),
   294      executable = luci.recipe(
   295          name = "inline/recipe",
   296          cipd_package = "recipe/bundles/inline",
   297          use_bbagent = True,
   298      ),
   299      service_account = "builder@example.com",
   300      triggers = [
   301          luci.builder(
   302              name = "triggered builder",
   303              bucket = "inline",
   304              executable = "inline/recipe",
   305          ),
   306      ],
   307      triggered_by = [inline_poller()],
   308  )
   309  
   310  luci.builder(
   311      name = "another builder",
   312      bucket = "inline",
   313      executable = luci.recipe(
   314          name = "inline/recipe",
   315          cipd_package = "recipe/bundles/inline",
   316          use_bbagent = True,
   317      ),
   318      service_account = "builder@example.com",
   319      triggered_by = [inline_poller()],
   320  )
   321  
   322  luci.builder(
   323      name = "another executable builder",
   324      bucket = "inline",
   325      executable = luci.executable(
   326          name = "inline/executable",
   327          cipd_package = "executable/bundles/inline",
   328      ),
   329      service_account = "builder@example.com",
   330      triggered_by = [inline_poller()],
   331  )
   332  
   333  luci.builder(
   334      name = "executable builder wrapper",
   335      bucket = "inline",
   336      executable = luci.executable(
   337          name = "wrapped executable",
   338          cipd_package = "executable/bundles/inline",
   339          wrapper = ["/path/to/wrapper"],
   340      ),
   341      service_account = "builder@example.com",
   342  )
   343  
   344  # List views.
   345  
   346  luci.list_view(
   347      name = "List view",
   348      entries = [
   349          "cron builder",
   350          "ci/generically named builder",
   351          luci.list_view_entry(
   352              builder = "linux ci builder",
   353          ),
   354      ],
   355  )
   356  
   357  luci.list_view_entry(
   358      list_view = "List view",
   359      builder = "inline/triggered builder",
   360  )
   361  
   362  # Console views.
   363  
   364  luci.console_view(
   365      name = "Console view",
   366      title = "CI Builders",
   367      header = {
   368          "links": [
   369              {"name": "a", "links": [{"text": "a"}]},
   370              {"name": "b", "links": [{"text": "b"}]},
   371          ],
   372      },
   373      repo = "https://noop.com",
   374      refs = ["refs/tags/blah", r"refs/branch-heads/\d+\.\d+"],
   375      exclude_ref = "refs/heads/main",
   376      include_experimental_builds = True,
   377      entries = [
   378          luci.console_view_entry(
   379              builder = "linux ci builder",
   380              category = "a|b",
   381              short_name = "lnx",
   382          ),
   383          # An alias for luci.console_view_entry(**{...}).
   384          {"builder": "cron builder", "category": "cron"},
   385      ],
   386      default_commit_limit = 3,
   387      default_expand = True,
   388  )
   389  
   390  luci.console_view_entry(
   391      console_view = "Console view",
   392      builder = "inline/triggered builder",
   393  )
   394  
   395  luci.external_console_view(
   396      name = "external-console",
   397      title = "External console",
   398      source = "chromium:main",
   399  )
   400  
   401  # Notifier.
   402  
   403  luci.notifier(
   404      name = "main notifier",
   405      on_new_status = ["FAILURE"],
   406      notify_emails = ["someone@example,com"],
   407      notify_blamelist = True,
   408      template = "notifier_template",
   409      notified_by = [
   410          "linux ci builder",
   411          "cron builder",
   412      ],
   413  )
   414  
   415  luci.notifier_template(
   416      name = "notifier_template",
   417      body = "Hello\n\nHi\n",
   418  )
   419  
   420  luci.notifier_template(
   421      name = "another_template",
   422      body = "Boo!\n",
   423  )
   424  
   425  luci.builder(
   426      name = "watched builder",
   427      bucket = "ci",
   428      executable = "main/recipe",
   429      repo = "https://custom.example.com/repo",
   430      notifies = ["main notifier"],
   431  )
   432  
   433  # CQ.
   434  
   435  luci.cq(
   436      submit_max_burst = 10,
   437      submit_burst_delay = 10 * time.minute,
   438      draining_start_time = "2017-12-23T15:47:58Z",
   439      status_host = "chromium-cq-status.appspot.com",
   440  )
   441  
   442  luci.cq_group(
   443      name = "main-cq",
   444      watch = [
   445          cq.refset("https://example.googlesource.com/repo"),
   446          cq.refset(
   447              "https://example.googlesource.com/another/repo",
   448              refs_exclude = ["refs/heads/infra/config"],
   449          ),
   450      ],
   451      acls = [
   452          acl.entry(acl.CQ_COMMITTER, groups = ["committers"]),
   453          acl.entry(acl.CQ_DRY_RUNNER, groups = ["dry-runners"]),
   454      ],
   455      allow_submit_with_open_deps = True,
   456      allow_owner_if_submittable = cq.ACTION_COMMIT,
   457      tree_status_host = "tree-status.example.com",
   458      verifiers = [
   459          luci.cq_tryjob_verifier(
   460              builder = "linux try builder",
   461              cancel_stale = False,
   462              result_visibility = cq.COMMENT_LEVEL_RESTRICTED,
   463              location_filters = [
   464                  cq.location_filter(
   465                      gerrit_host_regexp = "example.com",
   466                      gerrit_project_regexp = "repo",
   467                      path_regexp = "all/one.txt",
   468                      exclude = True,
   469                  ),
   470              ],
   471              mode_allowlist = [cq.MODE_DRY_RUN, cq.MODE_FULL_RUN],
   472          ),
   473          # An experimental verifier with location filter.
   474          luci.cq_tryjob_verifier(
   475              builder = "linux try builder 2",
   476              location_filters = [
   477                  cq.location_filter(
   478                      gerrit_host_regexp = "example.com",
   479                      gerrit_project_regexp = "repo",
   480                      path_regexp = "all/one.txt",
   481                      exclude = True,
   482                  ),
   483              ],
   484              experiment_percentage = 50,
   485          ),
   486          # An alias for luci.cq_tryjob_verifier(**{...}).
   487          {"builder": "try/generically named builder", "disable_reuse": True},
   488          # An alias for luci.cq_tryjob_verifier(<builder>).
   489          "another-project:try/yyy",
   490          luci.cq_tryjob_verifier(
   491              builder = "another-project:try/zzz",
   492              includable_only = True,
   493              owner_whitelist = ["another-project-committers"],
   494          ),
   495          luci.cq_tryjob_verifier(
   496              builder = "spell-checker",
   497              owner_whitelist = ["project-contributor"],
   498              mode_allowlist = [cq.MODE_ANALYZER_RUN],
   499          ),
   500      ],
   501      additional_modes = cq.run_mode(
   502          name = "TEST_RUN",
   503          cq_label_value = 1,
   504          triggering_label = "TEST_RUN_LABEL",
   505          triggering_value = 1,
   506      ),
   507      user_limits = [
   508          cq.user_limit(
   509              name = "comitters",
   510              groups = ["comitters"],
   511              run = cq.run_limits(max_active = 3),
   512          ),
   513      ],
   514      user_limit_default = cq.user_limit(
   515          name = "user_limit_default",
   516          run = cq.run_limits(max_active = 1),
   517      ),
   518  )
   519  
   520  luci.cq_tryjob_verifier(
   521      builder = "triggerer builder",
   522      cq_group = "main-cq",
   523      experiment_percentage = 50.0,
   524  )
   525  
   526  luci.cq_tryjob_verifier(
   527      builder = luci.builder(
   528          name = "main cq builder",
   529          bucket = "try",
   530          executable = "main/recipe",
   531      ),
   532      equivalent_builder = luci.builder(
   533          name = "equivalent cq builder",
   534          bucket = "try",
   535          executable = "main/recipe",
   536      ),
   537      equivalent_builder_percentage = 60,
   538      equivalent_builder_whitelist = "owners",
   539      cq_group = "main-cq",
   540  )
   541  
   542  luci.cq_tryjob_verifier(
   543      builder = "another-project:analyzer/format checker",
   544      cq_group = "main-cq",
   545      location_filters = [
   546          cq.location_filter(path_regexp = ".+\\.py"),
   547          cq.location_filter(path_regexp = ".+\\.go"),
   548      ],
   549      owner_whitelist = ["project-contributor"],
   550      mode_allowlist = [cq.MODE_ANALYZER_RUN, cq.MODE_FULL_RUN],
   551  )
   552  
   553  # Emitting arbitrary configs,
   554  
   555  lucicfg.emit(
   556      dest = "dir/custom.cfg",
   557      data = "hello!\n",
   558  )
   559  
   560  # Expect configs:
   561  #
   562  # === commit-queue.cfg
   563  # draining_start_time: "2017-12-23T15:47:58Z"
   564  # cq_status_host: "chromium-cq-status.appspot.com"
   565  # submit_options {
   566  #   max_burst: 10
   567  #   burst_delay {
   568  #     seconds: 600
   569  #   }
   570  # }
   571  # config_groups {
   572  #   name: "main-cq"
   573  #   gerrit {
   574  #     url: "https://example-review.googlesource.com"
   575  #     projects {
   576  #       name: "repo"
   577  #       ref_regexp: "refs/heads/main"
   578  #     }
   579  #     projects {
   580  #       name: "another/repo"
   581  #       ref_regexp: "refs/heads/main"
   582  #       ref_regexp_exclude: "refs/heads/infra/config"
   583  #     }
   584  #   }
   585  #   verifiers {
   586  #     gerrit_cq_ability {
   587  #       committer_list: "admins"
   588  #       committer_list: "committers"
   589  #       dry_run_access_list: "dry-runners"
   590  #       allow_submit_with_open_deps: true
   591  #       allow_owner_if_submittable: COMMIT
   592  #     }
   593  #     tree_status {
   594  #       url: "https://tree-status.example.com"
   595  #     }
   596  #     tryjob {
   597  #       builders {
   598  #         name: "another-project/analyzer/format checker"
   599  #         location_filters {
   600  #           gerrit_host_regexp: ".*"
   601  #           gerrit_project_regexp: ".*"
   602  #           path_regexp: ".+\\.py"
   603  #         }
   604  #         location_filters {
   605  #           gerrit_host_regexp: ".*"
   606  #           gerrit_project_regexp: ".*"
   607  #           path_regexp: ".+\\.go"
   608  #         }
   609  #         owner_whitelist_group: "project-contributor"
   610  #         mode_allowlist: "ANALYZER_RUN"
   611  #         mode_allowlist: "FULL_RUN"
   612  #       }
   613  #       builders {
   614  #         name: "another-project/try/yyy"
   615  #       }
   616  #       builders {
   617  #         name: "another-project/try/zzz"
   618  #         includable_only: true
   619  #         owner_whitelist_group: "another-project-committers"
   620  #       }
   621  #       builders {
   622  #         name: "infra/inline/triggerer builder"
   623  #         experiment_percentage: 50
   624  #       }
   625  #       builders {
   626  #         name: "infra/try/generically named builder"
   627  #         disable_reuse: true
   628  #       }
   629  #       builders {
   630  #         name: "infra/try/linux try builder"
   631  #         result_visibility: COMMENT_LEVEL_RESTRICTED
   632  #         cancel_stale: NO
   633  #         location_filters {
   634  #           gerrit_host_regexp: "example.com"
   635  #           gerrit_project_regexp: "repo"
   636  #           path_regexp: "all/one.txt"
   637  #           exclude: true
   638  #         }
   639  #         mode_allowlist: "DRY_RUN"
   640  #         mode_allowlist: "FULL_RUN"
   641  #       }
   642  #       builders {
   643  #         name: "infra/try/linux try builder 2"
   644  #         experiment_percentage: 50
   645  #         location_filters {
   646  #           gerrit_host_regexp: "example.com"
   647  #           gerrit_project_regexp: "repo"
   648  #           path_regexp: "all/one.txt"
   649  #           exclude: true
   650  #         }
   651  #       }
   652  #       builders {
   653  #         name: "infra/try/main cq builder"
   654  #         equivalent_to {
   655  #           name: "infra/try/equivalent cq builder"
   656  #           percentage: 60
   657  #           owner_whitelist_group: "owners"
   658  #         }
   659  #       }
   660  #       builders {
   661  #         name: "infra/try/spell-checker"
   662  #         owner_whitelist_group: "project-contributor"
   663  #         mode_allowlist: "ANALYZER_RUN"
   664  #       }
   665  #       retry_config {
   666  #         single_quota: 1
   667  #         global_quota: 2
   668  #         failure_weight: 100
   669  #         transient_failure_weight: 1
   670  #         timeout_weight: 100
   671  #       }
   672  #     }
   673  #   }
   674  #   additional_modes {
   675  #     name: "TEST_RUN"
   676  #     cq_label_value: 1
   677  #     triggering_label: "TEST_RUN_LABEL"
   678  #     triggering_value: 1
   679  #   }
   680  #   user_limits {
   681  #     name: "comitters"
   682  #     principals: "group:comitters"
   683  #     run {
   684  #       max_active {
   685  #         value: 3
   686  #       }
   687  #     }
   688  #   }
   689  #   user_limit_default {
   690  #     name: "user_limit_default"
   691  #     run {
   692  #       max_active {
   693  #         value: 1
   694  #       }
   695  #     }
   696  #   }
   697  # }
   698  # ===
   699  #
   700  # === cr-buildbucket.cfg
   701  # buckets {
   702  #   name: "ci"
   703  #   swarming {
   704  #     builders {
   705  #       name: "builder with custom swarming host"
   706  #       swarming_host: "another-swarming.appspot.com"
   707  #       exe {
   708  #         cipd_package: "recipe/bundles/main"
   709  #         cipd_version: "refs/heads/main"
   710  #         cmd: "luciexe"
   711  #         wrapper: "path/to/wrapper"
   712  #       }
   713  #       properties:
   714  #         '{'
   715  #         '  "recipe": "main/recipe"'
   716  #         '}'
   717  #       experiments {
   718  #         key: "luci.recipes.use_python3"
   719  #         value: 100
   720  #       }
   721  #     }
   722  #     builders {
   723  #       name: "builder with the default test presentation config"
   724  #       swarming_host: "chromium-swarm.appspot.com"
   725  #       exe {
   726  #         cipd_package: "recipe/bundles/main"
   727  #         cipd_version: "refs/heads/main"
   728  #         cmd: "luciexe"
   729  #         wrapper: "path/to/wrapper"
   730  #       }
   731  #       properties:
   732  #         '{'
   733  #         '  "recipe": "main/recipe"'
   734  #         '}'
   735  #       experiments {
   736  #         key: "luci.recipes.use_python3"
   737  #         value: 100
   738  #       }
   739  #     }
   740  #     builders {
   741  #       name: "cron builder"
   742  #       swarming_host: "chromium-swarm.appspot.com"
   743  #       exe {
   744  #         cipd_package: "recipe/bundles/main"
   745  #         cipd_version: "refs/heads/main"
   746  #         cmd: "luciexe"
   747  #         wrapper: "path/to/wrapper"
   748  #       }
   749  #       properties:
   750  #         '{'
   751  #         '  "recipe": "main/recipe"'
   752  #         '}'
   753  #       experiments {
   754  #         key: "luci.recipes.use_python3"
   755  #         value: 100
   756  #       }
   757  #     }
   758  #     builders {
   759  #       name: "generically named builder"
   760  #       swarming_host: "chromium-swarm.appspot.com"
   761  #       exe {
   762  #         cipd_package: "recipe/bundles/main"
   763  #         cipd_version: "refs/heads/main"
   764  #         cmd: "luciexe"
   765  #         wrapper: "path/to/wrapper"
   766  #       }
   767  #       properties:
   768  #         '{'
   769  #         '  "recipe": "main/recipe"'
   770  #         '}'
   771  #       experiments {
   772  #         key: "luci.recipes.use_python3"
   773  #         value: 100
   774  #       }
   775  #     }
   776  #     builders {
   777  #       name: "generically named executable builder"
   778  #       swarming_host: "chromium-swarm.appspot.com"
   779  #       exe {
   780  #         cipd_package: "executable/bundles/main"
   781  #         cipd_version: "refs/heads/main"
   782  #         cmd: "cmd"
   783  #       }
   784  #       properties:
   785  #         '{'
   786  #         '  "prop1": "val1",'
   787  #         '  "prop2": ['
   788  #         '    "val2",'
   789  #         '    123'
   790  #         '  ]'
   791  #         '}'
   792  #       allowed_property_overrides: "*"
   793  #     }
   794  #     builders {
   795  #       name: "linux ci builder"
   796  #       swarming_host: "chromium-swarm.appspot.com"
   797  #       swarming_tags: "tag1:val1"
   798  #       swarming_tags: "tag2:val2"
   799  #       dimensions: "builder:linux ci builder"
   800  #       dimensions: "os:Linux"
   801  #       dimensions: "300:prefer_if_available:first-choice"
   802  #       dimensions: "prefer_if_available:fallback"
   803  #       exe {
   804  #         cipd_package: "recipe/bundles/main"
   805  #         cipd_version: "refs/heads/main"
   806  #         cmd: "luciexe"
   807  #         wrapper: "path/to/wrapper"
   808  #       }
   809  #       properties:
   810  #         '{'
   811  #         '  "$recipe_engine/resultdb/test_presentation": {'
   812  #         '    "column_keys": ['
   813  #         '      "v.gpu"'
   814  #         '    ],'
   815  #         '    "grouping_keys": ['
   816  #         '      "status",'
   817  #         '      "v.test_suite"'
   818  #         '    ]'
   819  #         '  },'
   820  #         '  "prop1": "val1",'
   821  #         '  "prop2": ['
   822  #         '    "val2",'
   823  #         '    123'
   824  #         '  ],'
   825  #         '  "recipe": "main/recipe"'
   826  #         '}'
   827  #       allowed_property_overrides: "prop1"
   828  #       priority: 80
   829  #       execution_timeout_secs: 10800
   830  #       expiration_secs: 3600
   831  #       grace_period {
   832  #         seconds: 120
   833  #       }
   834  #       caches {
   835  #         name: "name2"
   836  #         path: "path2"
   837  #       }
   838  #       caches {
   839  #         name: "name3"
   840  #         path: "path3"
   841  #         wait_for_warm_cache_secs: 600
   842  #       }
   843  #       caches {
   844  #         name: "path1"
   845  #         path: "path1"
   846  #       }
   847  #       build_numbers: YES
   848  #       service_account: "builder@example.com"
   849  #       experiments {
   850  #         key: "luci.buildbucket.canary_software"
   851  #         value: 17
   852  #       }
   853  #       experiments {
   854  #         key: "luci.recipes.use_python3"
   855  #         value: 100
   856  #       }
   857  #       resultdb {
   858  #         enable: true
   859  #         bq_exports {
   860  #           project: "luci-resultdb"
   861  #           dataset: "my-awesome-project"
   862  #           table: "all_test_results"
   863  #           test_results {
   864  #             predicate {
   865  #               test_id_regexp: "ninja:.*"
   866  #               variant {
   867  #                 contains {
   868  #                   def {
   869  #                     key: "test_suite"
   870  #                     value: "super_interesting_suite"
   871  #                   }
   872  #                 }
   873  #               }
   874  #               expectancy: VARIANTS_WITH_UNEXPECTED_RESULTS
   875  #             }
   876  #           }
   877  #         }
   878  #         bq_exports {
   879  #           project: "luci-resultdb"
   880  #           dataset: "my-awesome-project"
   881  #           table: "all_text_artifacts"
   882  #           text_artifacts {
   883  #             predicate {
   884  #               follow_edges {
   885  #                 test_results: true
   886  #               }
   887  #               test_result_predicate {
   888  #                 test_id_regexp: "ninja:.*"
   889  #                 variant {
   890  #                   contains {
   891  #                     def {
   892  #                       key: "test_suite"
   893  #                       value: "super_interesting_suite"
   894  #                     }
   895  #                   }
   896  #                 }
   897  #                 expectancy: VARIANTS_WITH_UNEXPECTED_RESULTS
   898  #               }
   899  #               content_type_regexp: "text.*"
   900  #             }
   901  #           }
   902  #         }
   903  #         history_options {
   904  #           use_invocation_timestamp: true
   905  #         }
   906  #       }
   907  #       description_html: "this is a linux ci builder"
   908  #       contact_team_email: "a@b.com"
   909  #     }
   910  #     builders {
   911  #       name: "watched builder"
   912  #       swarming_host: "chromium-swarm.appspot.com"
   913  #       exe {
   914  #         cipd_package: "recipe/bundles/main"
   915  #         cipd_version: "refs/heads/main"
   916  #         cmd: "luciexe"
   917  #         wrapper: "path/to/wrapper"
   918  #       }
   919  #       properties:
   920  #         '{'
   921  #         '  "recipe": "main/recipe"'
   922  #         '}'
   923  #       experiments {
   924  #         key: "luci.recipes.use_python3"
   925  #         value: 100
   926  #       }
   927  #     }
   928  #   }
   929  # }
   930  # buckets {
   931  #   name: "inline"
   932  #   swarming {
   933  #     builders {
   934  #       name: "another builder"
   935  #       swarming_host: "chromium-swarm.appspot.com"
   936  #       exe {
   937  #         cipd_package: "recipe/bundles/inline"
   938  #         cipd_version: "refs/heads/main"
   939  #         cmd: "luciexe"
   940  #       }
   941  #       properties:
   942  #         '{'
   943  #         '  "recipe": "inline/recipe"'
   944  #         '}'
   945  #       service_account: "builder@example.com"
   946  #     }
   947  #     builders {
   948  #       name: "another executable builder"
   949  #       swarming_host: "chromium-swarm.appspot.com"
   950  #       exe {
   951  #         cipd_package: "executable/bundles/inline"
   952  #         cipd_version: "refs/heads/main"
   953  #       }
   954  #       properties: '{}'
   955  #       service_account: "builder@example.com"
   956  #     }
   957  #     builders {
   958  #       name: "executable builder wrapper"
   959  #       swarming_host: "chromium-swarm.appspot.com"
   960  #       exe {
   961  #         cipd_package: "executable/bundles/inline"
   962  #         cipd_version: "refs/heads/main"
   963  #         wrapper: "/path/to/wrapper"
   964  #       }
   965  #       properties: '{}'
   966  #       service_account: "builder@example.com"
   967  #     }
   968  #     builders {
   969  #       name: "triggered builder"
   970  #       swarming_host: "chromium-swarm.appspot.com"
   971  #       exe {
   972  #         cipd_package: "recipe/bundles/inline"
   973  #         cipd_version: "refs/heads/main"
   974  #         cmd: "luciexe"
   975  #       }
   976  #       properties:
   977  #         '{'
   978  #         '  "recipe": "inline/recipe"'
   979  #         '}'
   980  #     }
   981  #     builders {
   982  #       name: "triggerer builder"
   983  #       swarming_host: "chromium-swarm.appspot.com"
   984  #       exe {
   985  #         cipd_package: "recipe/bundles/inline"
   986  #         cipd_version: "refs/heads/main"
   987  #         cmd: "luciexe"
   988  #       }
   989  #       properties:
   990  #         '{'
   991  #         '  "recipe": "inline/recipe"'
   992  #         '}'
   993  #       service_account: "builder@example.com"
   994  #     }
   995  #   }
   996  # }
   997  # buckets {
   998  #   name: "try"
   999  #   swarming {
  1000  #     builders {
  1001  #       name: "builder with executable"
  1002  #       swarming_host: "chromium-swarm.appspot.com"
  1003  #       exe {
  1004  #         cipd_package: "executable/bundles/main"
  1005  #         cipd_version: "refs/heads/main"
  1006  #         cmd: "cmd"
  1007  #       }
  1008  #       properties: '{}'
  1009  #     }
  1010  #     builders {
  1011  #       name: "builder with experiment map"
  1012  #       swarming_host: "chromium-swarm.appspot.com"
  1013  #       exe {
  1014  #         cipd_package: "executable/bundles/main"
  1015  #         cipd_version: "refs/heads/main"
  1016  #         cmd: "cmd"
  1017  #       }
  1018  #       properties: '{}'
  1019  #       experiments {
  1020  #         key: "luci.enable_new_beta_feature"
  1021  #         value: 32
  1022  #       }
  1023  #     }
  1024  #     builders {
  1025  #       name: "equivalent cq builder"
  1026  #       swarming_host: "chromium-swarm.appspot.com"
  1027  #       exe {
  1028  #         cipd_package: "recipe/bundles/main"
  1029  #         cipd_version: "refs/heads/main"
  1030  #         cmd: "luciexe"
  1031  #         wrapper: "path/to/wrapper"
  1032  #       }
  1033  #       properties:
  1034  #         '{'
  1035  #         '  "recipe": "main/recipe"'
  1036  #         '}'
  1037  #       experiments {
  1038  #         key: "luci.recipes.use_python3"
  1039  #         value: 100
  1040  #       }
  1041  #     }
  1042  #     builders {
  1043  #       name: "generically named builder"
  1044  #       swarming_host: "chromium-swarm.appspot.com"
  1045  #       exe {
  1046  #         cipd_package: "recipe/bundles/main"
  1047  #         cipd_version: "refs/heads/main"
  1048  #         cmd: "luciexe"
  1049  #         wrapper: "path/to/wrapper"
  1050  #       }
  1051  #       properties:
  1052  #         '{'
  1053  #         '  "recipe": "main/recipe"'
  1054  #         '}'
  1055  #       experiments {
  1056  #         key: "luci.recipes.use_python3"
  1057  #         value: 100
  1058  #       }
  1059  #     }
  1060  #     builders {
  1061  #       name: "linux try builder"
  1062  #       swarming_host: "chromium-swarm.appspot.com"
  1063  #       exe {
  1064  #         cipd_package: "recipe/bundles/main"
  1065  #         cipd_version: "refs/heads/main"
  1066  #         cmd: "luciexe"
  1067  #         wrapper: "path/to/wrapper"
  1068  #       }
  1069  #       properties:
  1070  #         '{'
  1071  #         '  "recipe": "main/recipe"'
  1072  #         '}'
  1073  #       experiments {
  1074  #         key: "luci.recipes.use_python3"
  1075  #         value: 100
  1076  #       }
  1077  #     }
  1078  #     builders {
  1079  #       name: "linux try builder 2"
  1080  #       swarming_host: "chromium-swarm.appspot.com"
  1081  #       exe {
  1082  #         cipd_package: "recipe/bundles/main"
  1083  #         cipd_version: "refs/heads/main"
  1084  #         cmd: "luciexe"
  1085  #         wrapper: "path/to/wrapper"
  1086  #       }
  1087  #       properties:
  1088  #         '{'
  1089  #         '  "recipe": "main/recipe"'
  1090  #         '}'
  1091  #       experiments {
  1092  #         key: "luci.recipes.use_python3"
  1093  #         value: 100
  1094  #       }
  1095  #     }
  1096  #     builders {
  1097  #       name: "main cq builder"
  1098  #       swarming_host: "chromium-swarm.appspot.com"
  1099  #       exe {
  1100  #         cipd_package: "recipe/bundles/main"
  1101  #         cipd_version: "refs/heads/main"
  1102  #         cmd: "luciexe"
  1103  #         wrapper: "path/to/wrapper"
  1104  #       }
  1105  #       properties:
  1106  #         '{'
  1107  #         '  "recipe": "main/recipe"'
  1108  #         '}'
  1109  #       experiments {
  1110  #         key: "luci.recipes.use_python3"
  1111  #         value: 100
  1112  #       }
  1113  #     }
  1114  #     builders {
  1115  #       name: "spell-checker"
  1116  #       swarming_host: "chromium-swarm.appspot.com"
  1117  #       exe {
  1118  #         cipd_package: "recipe/bundles/main"
  1119  #         cipd_version: "refs/heads/main"
  1120  #         cmd: "luciexe"
  1121  #         wrapper: "path/to/wrapper"
  1122  #       }
  1123  #       properties:
  1124  #         '{'
  1125  #         '  "recipe": "main/recipe"'
  1126  #         '}'
  1127  #       experiments {
  1128  #         key: "luci.recipes.use_python3"
  1129  #         value: 100
  1130  #       }
  1131  #     }
  1132  #   }
  1133  # }
  1134  # ===
  1135  #
  1136  # === dir/custom.cfg
  1137  # hello!
  1138  # ===
  1139  #
  1140  # === luci-logdog.cfg
  1141  # reader_auth_groups: "all"
  1142  # archive_gs_bucket: "chromium-luci-logdog"
  1143  # cloud_logging_config {
  1144  #   destination: "chromium-build-logs"
  1145  # }
  1146  # ===
  1147  #
  1148  # === luci-milo.cfg
  1149  # consoles {
  1150  #   id: "List view"
  1151  #   name: "List view"
  1152  #   builders {
  1153  #     name: "buildbucket/luci.infra.ci/cron builder"
  1154  #   }
  1155  #   builders {
  1156  #     name: "buildbucket/luci.infra.ci/generically named builder"
  1157  #   }
  1158  #   builders {
  1159  #     name: "buildbucket/luci.infra.ci/linux ci builder"
  1160  #   }
  1161  #   builders {
  1162  #     name: "buildbucket/luci.infra.inline/triggered builder"
  1163  #   }
  1164  #   favicon_url: "https://storage.googleapis.com/chrome-infra-public/logo/favicon.ico"
  1165  #   builder_view_only: true
  1166  # }
  1167  # consoles {
  1168  #   id: "Console view"
  1169  #   name: "CI Builders"
  1170  #   repo_url: "https://noop.com"
  1171  #   refs: "regexp:refs/tags/blah"
  1172  #   refs: "regexp:refs/branch-heads/\\d+\\.\\d+"
  1173  #   exclude_ref: "refs/heads/main"
  1174  #   manifest_name: "REVISION"
  1175  #   builders {
  1176  #     name: "buildbucket/luci.infra.ci/linux ci builder"
  1177  #     category: "a|b"
  1178  #     short_name: "lnx"
  1179  #   }
  1180  #   builders {
  1181  #     name: "buildbucket/luci.infra.ci/cron builder"
  1182  #     category: "cron"
  1183  #   }
  1184  #   builders {
  1185  #     name: "buildbucket/luci.infra.inline/triggered builder"
  1186  #   }
  1187  #   favicon_url: "https://storage.googleapis.com/chrome-infra-public/logo/favicon.ico"
  1188  #   header {
  1189  #     links {
  1190  #       name: "a"
  1191  #       links {
  1192  #         text: "a"
  1193  #       }
  1194  #     }
  1195  #     links {
  1196  #       name: "b"
  1197  #       links {
  1198  #         text: "b"
  1199  #       }
  1200  #     }
  1201  #   }
  1202  #   include_experimental_builds: true
  1203  #   default_commit_limit: 3
  1204  #   default_expand: true
  1205  # }
  1206  # consoles {
  1207  #   id: "external-console"
  1208  #   name: "External console"
  1209  #   external_project: "chromium"
  1210  #   external_id: "main"
  1211  # }
  1212  # logo_url: "https://storage.googleapis.com/chrome-infra-public/logo/chrome-infra-logo-200x200.png"
  1213  # bug_url_template: "https://bugs.chromium.org/p/tutu%2C%20all%20aboard/issues/entry?summary=Bug%20summary&description=Everything%20is%20broken&components=Stuff%3EHard"
  1214  # ===
  1215  #
  1216  # === luci-notify.cfg
  1217  # notifiers {
  1218  #   notifications {
  1219  #     on_new_status: FAILURE
  1220  #     email {
  1221  #       recipients: "someone@example,com"
  1222  #     }
  1223  #     template: "notifier_template"
  1224  #     notify_blamelist {}
  1225  #   }
  1226  #   builders {
  1227  #     bucket: "ci"
  1228  #     name: "cron builder"
  1229  #     repository: "https://cron.repo.example.com"
  1230  #   }
  1231  # }
  1232  # notifiers {
  1233  #   notifications {
  1234  #     on_new_status: FAILURE
  1235  #     email {
  1236  #       recipients: "someone@example,com"
  1237  #     }
  1238  #     template: "notifier_template"
  1239  #     notify_blamelist {}
  1240  #   }
  1241  #   builders {
  1242  #     bucket: "ci"
  1243  #     name: "linux ci builder"
  1244  #     repository: "https://noop.com"
  1245  #   }
  1246  # }
  1247  # notifiers {
  1248  #   notifications {
  1249  #     on_new_status: FAILURE
  1250  #     email {
  1251  #       recipients: "someone@example,com"
  1252  #     }
  1253  #     template: "notifier_template"
  1254  #     notify_blamelist {}
  1255  #   }
  1256  #   builders {
  1257  #     bucket: "ci"
  1258  #     name: "watched builder"
  1259  #     repository: "https://custom.example.com/repo"
  1260  #   }
  1261  # }
  1262  # ===
  1263  #
  1264  # === luci-notify/email-templates/another_template.template
  1265  # Boo!
  1266  # ===
  1267  #
  1268  # === luci-notify/email-templates/notifier_template.template
  1269  # Hello
  1270  #
  1271  # Hi
  1272  # ===
  1273  #
  1274  # === luci-scheduler.cfg
  1275  # job {
  1276  #   id: "another builder"
  1277  #   realm: "inline"
  1278  #   buildbucket {
  1279  #     server: "cr-buildbucket.appspot.com"
  1280  #     bucket: "inline"
  1281  #     builder: "another builder"
  1282  #   }
  1283  # }
  1284  # job {
  1285  #   id: "another executable builder"
  1286  #   realm: "inline"
  1287  #   buildbucket {
  1288  #     server: "cr-buildbucket.appspot.com"
  1289  #     bucket: "inline"
  1290  #     builder: "another executable builder"
  1291  #   }
  1292  # }
  1293  # job {
  1294  #   id: "cron builder"
  1295  #   realm: "ci"
  1296  #   schedule: "0 6 * * *"
  1297  #   buildbucket {
  1298  #     server: "cr-buildbucket.appspot.com"
  1299  #     bucket: "ci"
  1300  #     builder: "cron builder"
  1301  #   }
  1302  # }
  1303  # job {
  1304  #   id: "generically named builder"
  1305  #   realm: "ci"
  1306  #   buildbucket {
  1307  #     server: "cr-buildbucket.appspot.com"
  1308  #     bucket: "ci"
  1309  #     builder: "generically named builder"
  1310  #   }
  1311  # }
  1312  # job {
  1313  #   id: "generically named executable builder"
  1314  #   realm: "ci"
  1315  #   buildbucket {
  1316  #     server: "cr-buildbucket.appspot.com"
  1317  #     bucket: "ci"
  1318  #     builder: "generically named executable builder"
  1319  #   }
  1320  # }
  1321  # job {
  1322  #   id: "linux ci builder"
  1323  #   realm: "ci"
  1324  #   triggering_policy {
  1325  #     kind: GREEDY_BATCHING
  1326  #     max_concurrent_invocations: 5
  1327  #     max_batch_size: 10
  1328  #   }
  1329  #   buildbucket {
  1330  #     server: "cr-buildbucket.appspot.com"
  1331  #     bucket: "ci"
  1332  #     builder: "linux ci builder"
  1333  #   }
  1334  # }
  1335  # job {
  1336  #   id: "triggered builder"
  1337  #   realm: "inline"
  1338  #   buildbucket {
  1339  #     server: "cr-buildbucket.appspot.com"
  1340  #     bucket: "inline"
  1341  #     builder: "triggered builder"
  1342  #   }
  1343  # }
  1344  # job {
  1345  #   id: "triggerer builder"
  1346  #   realm: "inline"
  1347  #   buildbucket {
  1348  #     server: "cr-buildbucket.appspot.com"
  1349  #     bucket: "inline"
  1350  #     builder: "triggerer builder"
  1351  #   }
  1352  # }
  1353  # trigger {
  1354  #   id: "inline poller"
  1355  #   realm: "inline"
  1356  #   schedule: "with 10s interval"
  1357  #   triggers: "another builder"
  1358  #   triggers: "another executable builder"
  1359  #   triggers: "triggerer builder"
  1360  #   gitiles {
  1361  #     repo: "https://noop.com"
  1362  #     refs: "regexp:refs/heads/main"
  1363  #     refs: "regexp:refs/tags/blah"
  1364  #     refs: "regexp:refs/branch-heads/\\d+\\.\\d+"
  1365  #   }
  1366  # }
  1367  # trigger {
  1368  #   id: "main-poller"
  1369  #   realm: "ci"
  1370  #   schedule: "with 10s interval"
  1371  #   triggers: "generically named builder"
  1372  #   triggers: "generically named executable builder"
  1373  #   triggers: "linux ci builder"
  1374  #   gitiles {
  1375  #     repo: "https://noop.com"
  1376  #     refs: "regexp:refs/heads/main"
  1377  #     refs: "regexp:refs/tags/blah"
  1378  #     refs: "regexp:refs/branch-heads/\\d+\\.\\d+"
  1379  #     path_regexps: ".*"
  1380  #     path_regexps_exclude: "excluded"
  1381  #   }
  1382  # }
  1383  # ===
  1384  #
  1385  # === project.cfg
  1386  # name: "infra"
  1387  # access: "group:all"
  1388  # ===
  1389  #
  1390  # === realms.cfg
  1391  # realms {
  1392  #   name: "@root"
  1393  #   bindings {
  1394  #     role: "role/buildbucket.owner"
  1395  #     principals: "group:admins"
  1396  #   }
  1397  #   bindings {
  1398  #     role: "role/buildbucket.reader"
  1399  #     principals: "group:all"
  1400  #   }
  1401  #   bindings {
  1402  #     role: "role/configs.reader"
  1403  #     principals: "group:all"
  1404  #   }
  1405  #   bindings {
  1406  #     role: "role/cq.committer"
  1407  #     principals: "group:admins"
  1408  #   }
  1409  #   bindings {
  1410  #     role: "role/logdog.reader"
  1411  #     principals: "group:all"
  1412  #   }
  1413  #   bindings {
  1414  #     role: "role/scheduler.owner"
  1415  #     principals: "group:admins"
  1416  #   }
  1417  #   bindings {
  1418  #     role: "role/scheduler.reader"
  1419  #     principals: "group:all"
  1420  #   }
  1421  # }
  1422  # realms {
  1423  #   name: "ci"
  1424  #   bindings {
  1425  #     role: "role/buildbucket.builderServiceAccount"
  1426  #     principals: "user:builder@example.com"
  1427  #   }
  1428  #   bindings {
  1429  #     role: "role/scheduler.triggerer"
  1430  #     principals: "group:devs"
  1431  #     principals: "project:some-project"
  1432  #   }
  1433  #   bindings {
  1434  #     role: "role/scheduler.triggerer"
  1435  #     principals: "user:builder@example.com"
  1436  #     conditions {
  1437  #       restrict {
  1438  #         attribute: "scheduler.job.name"
  1439  #         values: "generically named builder"
  1440  #         values: "generically named executable builder"
  1441  #       }
  1442  #     }
  1443  #   }
  1444  # }
  1445  # realms {
  1446  #   name: "inline"
  1447  #   bindings {
  1448  #     role: "role/buildbucket.builderServiceAccount"
  1449  #     principals: "user:builder@example.com"
  1450  #   }
  1451  #   bindings {
  1452  #     role: "role/scheduler.triggerer"
  1453  #     principals: "user:builder@example.com"
  1454  #     conditions {
  1455  #       restrict {
  1456  #         attribute: "scheduler.job.name"
  1457  #         values: "triggered builder"
  1458  #       }
  1459  #     }
  1460  #   }
  1461  # }
  1462  # realms {
  1463  #   name: "try"
  1464  #   bindings {
  1465  #     role: "role/buildbucket.triggerer"
  1466  #     principals: "group:devs"
  1467  #   }
  1468  # }
  1469  # ===
  1470  #
  1471  # === tricium-prod.cfg
  1472  # functions {
  1473  #   type: ANALYZER
  1474  #   name: "AnotherProjectAnalyzerFormatChecker"
  1475  #   needs: GIT_FILE_DETAILS
  1476  #   provides: RESULTS
  1477  #   path_filters: "*.go"
  1478  #   path_filters: "*.py"
  1479  #   impls {
  1480  #     provides_for_platform: LINUX
  1481  #     runtime_platform: LINUX
  1482  #     recipe {
  1483  #       project: "another-project"
  1484  #       bucket: "analyzer"
  1485  #       builder: "format checker"
  1486  #     }
  1487  #   }
  1488  # }
  1489  # functions {
  1490  #   type: ANALYZER
  1491  #   name: "InfraTrySpellChecker"
  1492  #   needs: GIT_FILE_DETAILS
  1493  #   provides: RESULTS
  1494  #   impls {
  1495  #     provides_for_platform: LINUX
  1496  #     runtime_platform: LINUX
  1497  #     recipe {
  1498  #       project: "infra"
  1499  #       bucket: "try"
  1500  #       builder: "spell-checker"
  1501  #     }
  1502  #   }
  1503  # }
  1504  # selections {
  1505  #   function: "AnotherProjectAnalyzerFormatChecker"
  1506  #   platform: LINUX
  1507  # }
  1508  # selections {
  1509  #   function: "InfraTrySpellChecker"
  1510  #   platform: LINUX
  1511  # }
  1512  # repos {
  1513  #   gerrit_project {
  1514  #     host: "example-review.googlesource.com"
  1515  #     project: "another/repo"
  1516  #     git_url: "https://example.googlesource.com/another/repo"
  1517  #   }
  1518  #   whitelisted_group: "project-contributor"
  1519  # }
  1520  # repos {
  1521  #   gerrit_project {
  1522  #     host: "example-review.googlesource.com"
  1523  #     project: "repo"
  1524  #     git_url: "https://example.googlesource.com/repo"
  1525  #   }
  1526  #   whitelisted_group: "project-contributor"
  1527  # }
  1528  # service_account: "tricium-prod@appspot.gserviceaccount.com"
  1529  # ===