go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/proto/config/project_config.proto (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  syntax = "proto3";
    16  
    17  package luci.analysis.config;
    18  
    19  import "google/protobuf/timestamp.proto";
    20  
    21  import "go.chromium.org/luci/analysis/proto/config/test_variant_analysis_config.proto";
    22  
    23  option go_package = "go.chromium.org/luci/analysis/proto/config;configpb";
    24  
    25  // ProjectConfig is the project-specific configuration data for LUCI Analysis.
    26  message ProjectConfig {
    27    // The project metadata (eg. display name).
    28    ProjectMetadata project_metadata = 6;
    29  
    30    // The last time this project configuration was updated.
    31    // LUCI Analysis sets and stores this value internally. Do not set
    32    // in your project's configuration file, it will be ignored.
    33    google.protobuf.Timestamp last_updated = 4;
    34  
    35    // Configuration for how to cluster test results.
    36    Clustering clustering = 5;
    37  
    38    // Configuration for automatic bug management.
    39    BugManagement bug_management = 9;
    40  
    41    // Configuration related to metrics in LUCI Analysis.
    42    Metrics metrics = 11;
    43  
    44    // Configuration for when tests are considered stable enough
    45    // to gate code changes. Only relevant for projects which integrate
    46    // with the TestVariants.QueryStability RPC to exonerate
    47    // unstable tests in presubmit.
    48    TestStabilityCriteria test_stability_criteria = 12;
    49  
    50    // Deprecated configuration follows. Setting these no longer
    51    // has any effect.
    52  
    53    // Per realm configurations.
    54    repeated RealmConfig realms = 3;
    55  
    56    // Deprecated. No longer has any effect. Retained for textproto
    57    // compatibility only. Use bug_management.default_bug_system instead.
    58    BugSystem bug_system = 7;
    59  
    60    // Deprecated. No longer has any effect. Retained for textproto
    61    // compatibility only. Use bug_management.monorail instead.
    62    MonorailProject monorail = 1;
    63  
    64    // Deprecated. No longer has any effect. Retained for textproto
    65    // compatibility only. Use bug_management.buganizer instead.
    66    BuganizerProject buganizer = 8;
    67  
    68    // Deprecated. No longer has any effect. Retained for textproto
    69    // compatibility only. Use bug_management.policies instead.
    70    ImpactThreshold bug_filing_threshold = 2;
    71  
    72    // Deprecated. No longer has any effect. Retained for textproto
    73    // compatibility only. Use bug_management.policies instead.
    74    repeated ImpactMetricThreshold bug_filing_thresholds = 10;
    75  
    76    // Next ID: 13
    77  }
    78  
    79  
    80  // ProjectMetadata provides data about the project that are mostly used in ui.
    81  message ProjectMetadata {
    82  
    83    // Indicates the preferred display name for the project in the UI.
    84    // Deprecated: not used anymore.
    85    string display_name = 1;
    86  }
    87  
    88  // Settings related to metrics used to measure cluster impact.
    89  message Metrics {
    90    message MetricOverride {
    91      // The id of the impact metric.
    92      //
    93      // Full list of available metrics here:
    94      // https://source.chromium.org/chromium/infra/infra/+/main:go/src/go.chromium.org/luci/analysis/internal/analysis/metrics/metrics.go
    95      string metric_id = 1;
    96  
    97      // Whether the metric should be selected by default.
    98      optional bool is_default = 2;
    99  
   100      // Controls the default sort order between metrics. By default,
   101      // a list will sort by the metric with the highest sort priority,
   102      // followed by the metric with second highest sort priority,
   103      // and so on.
   104      optional int32 sort_priority = 3;
   105    }
   106  
   107    // Overrides to the default metrics configuration for a project.
   108    repeated MetricOverride overrides = 1;
   109  }
   110  
   111  // Settings related to bug management.
   112  message BugManagement {
   113    // Disables creation of comments on bugs when LUCI Analysis successfully
   114    // handles duplicate bugs by merging/updating failure association rules.
   115    //
   116    // This setting does not prevent the creation of comments in response
   117    // to errors handling duplicate bugs.
   118    bool disable_duplicate_bug_comments = 1;
   119  
   120    // The set of policies which control the (re-)opening, closure and
   121    // prioritization of bugs under the control of LUCI Analysis.
   122    repeated BugManagementPolicy policies = 2;
   123  
   124    // The default bug system to route new bugs to, when the bug system and
   125    // component could not be automatically detected from a test metadata.
   126    BugSystem default_bug_system = 3;
   127  
   128    // Buganizer-specific bug filing configuration.
   129    BuganizerProject buganizer = 4;
   130  
   131    // Monorail-specific bug filing configuration.
   132    MonorailProject monorail = 5;
   133  }
   134  
   135  // A bug management policy in LUCI Analysis.
   136  //
   137  // Bug management policies control when and how bugs are automatically
   138  // opened, prioritised, and verified as fixed. Each policy has a user-visible
   139  // identity in the UI and can post custom instructions on the bug.
   140  //
   141  // LUCI Analysis avoids filing multiple bugs for the same failures by
   142  // allowing multiple policies to activate on the same failure association
   143  // rule. The bug associated with a rule will only be verified if all policies
   144  // have de-activated.
   145  message BugManagementPolicy {
   146    // A unique identifier for the bug management policy.
   147    //
   148    // Policies are stateful in that LUCI Analysis tracks which bugs have met the
   149    // activation condition on the policy (and not since met the deactivation
   150    // condition).
   151    //
   152    // Changing this value changes the identity of the policy and hence results in
   153    // the activation state for the policy being lost for all bugs.
   154    //
   155    // Valid syntax: ^[a-z]([a-z0-9-]{0,62}[a-z0-9])?$. (Syntax designed to comply
   156    // with google.aip.dev/122 for resource IDs.)
   157    string id = 1;
   158  
   159    // The owners of the policy, who can be contacted if there are issues/concerns
   160    // about the policy. Each item in the list should be an @google.com email
   161    // address. At least one owner (preferably a group) is required.
   162    repeated string owners = 2;
   163  
   164    // A short one-line description for the problem the policy identifies, which
   165    // will appear on the UI and in bugs comments. This is a sentence fragment
   166    // and not a sentence, so please do NOT include a full stop and or starting
   167    // capital letter.
   168    //
   169    // For example, "test variant(s) are being exonerated in presubmit".
   170    string human_readable_name = 3;
   171  
   172    // The priority of the problem this policy defines.
   173    //
   174    // If:
   175    // - the priority of the bug associated with a rule
   176    //   differs from this priority, and
   177    // - the policy is activate on the rule (see `metrics`), and
   178    // - LUCI Analysis is controlling the priority of the bug
   179    //   (the "Update bug priority" switch on the rule is enabled),
   180    // the priority of the bug will be updated to match this priority.
   181    //
   182    // Where are there multiple policies active on the same rule,
   183    // the highest priority (of all active policies) will be used.
   184    //
   185    // For monorail projects, the buganizer priority will be converted to the
   186    // equivalent monorail priority (P0 is converted to Pri-0, P1 to Pri-1,
   187    // P2 to Pri-2, etc.) until monorail is turned down.
   188    BuganizerPriority priority = 4;
   189  
   190    // The set of metrics which will control activation of the bug-filing policy.
   191    // If a policy activates on a suggested cluster, a new bug will be filed.
   192    // If a policy activates on an existing rule cluster, the bug will be
   193    // updated.
   194    //
   195    // The policy will activate if the activation threshold is met on *ANY*
   196    // metric, and will de-activate only if the deactivation threshold is met
   197    // on *ALL* metrics.
   198    //
   199    // Activation on suggested clusters will be based on the metric values after
   200    // excluding failures for which a bug has already been filed. This is to
   201    // avoid duplicate bug filing.
   202    repeated Metric metrics = 5;
   203  
   204    // A metric used to control activation of a bug-filing policy.
   205    message Metric {
   206      // The identifier of the metric.
   207      //
   208      // Full list of available metrics here:
   209      // https://source.chromium.org/chromium/infra/infra/+/main:go/src/go.chromium.org/luci/analysis/internal/analysis/metrics/metrics.go
   210      string metric_id = 1;
   211  
   212      // The level at which the policy activates. Activation occurs if the
   213      // cluster impact meets or exceeds this threshold.
   214      // MUST imply deactivation_threshold.
   215      MetricThreshold activation_threshold = 2;
   216  
   217      // The minimum metric level at which the policy remains active.
   218      // Deactivation occcurs if the cluster impact is below the de-activation
   219      // threshold. Deactivation_threshold should be set significantly lower
   220      // than activation_threshold to prevent policies repeatedly activating
   221      // and deactivating due to noise in the data, e.g. less tests executed
   222      // on weekends.
   223      MetricThreshold deactivation_threshold = 3;
   224    }
   225  
   226    // Expanatory text of the problem the policy identified, shown on the
   227    // user interface when the user requests more information. Required.
   228    Explanation explanation = 6;
   229  
   230    // Content displayed on the user interface, to explain the problem and
   231    // guide a developer to fix it.
   232    message Explanation {
   233      // A longer human-readable description of the problem this policy
   234      // has identified, in HTML.
   235      //
   236      // For example, "Test variant(s) in this cluster are being exonerated
   237      // (ignored) in presubmit because they are too flaky or failing. This
   238      // means they are no longer effective at preventing the breakage of
   239      // the functionality the test(s) cover.".
   240      //
   241      // MUST be sanitised by UI before rendering. Sanitisation is only
   242      // required to support simple uses of the following tags: ul, li, a.
   243      string problem_html = 1;
   244  
   245      // A description of how a human should go about trying to fix the
   246      // problem, in HTML.
   247      //
   248      // For example, "<ul>
   249      // <li>View recent failures</li>
   250      // <li><a href="http://goto.google.com/demote-from-cq">Demote</a> the test from CQ</li>
   251      // </ul>"
   252      //
   253      // MUST be sanitised by UI before rendering. Sanitisation is only
   254      // required to support simple uses of the following tags: ul, li, a.
   255      string action_html = 2;
   256    }
   257  
   258    // Settings which affect the contents of a bug for a policy has activated.
   259    BugTemplate bug_template = 7;
   260  
   261    // Settings which affect the contents of a bug for a policy has activated.
   262    message BugTemplate {
   263      // Text to be included in the bug comment advising of the activation of the
   264      // the policy. Leave blank to post no comment.
   265      //
   266      // The text here will be interpreted as a template by the golang
   267      // template/text library (https://pkg.go.dev/text/template). The following
   268      // fields are available:
   269      // - RuleURL (string): The URL of the rule page.
   270      // - BugID (BugID): The system-specific bug identifier. This type
   271      //   exposes the following methods with no arguments:
   272      //   - IsBuganizer returns (bool) indicating if the bug is a buganizer bug.
   273      //   - IsMonorail returns (bool) indicating if the bug is a monorail bug.
   274      //   - MonorailProject returns (string, error) indicating the monorail
   275      //     project, if the bug is a monorail bug, and errors otherwise.
   276      //   - MonorailBugID returns (string, error) indicating the monorail
   277      //     bug ID, if the bug is a monorail bug, and errors otherwise.
   278      //   - BuganizerBugID returns (string, error) indicating the buganizer
   279      //     bug ID, if the bug is a buganizer bug, and errors otherwise.
   280      //
   281      // Model usage of BugID in a template:
   282      // ```
   283      // {{if .BugID.IsBuganizer}}Buganizer bug: {{.BugID.BuganizerBugID}}{{end}}
   284      // {{if .BugID.IsMonorail}}Monorail bug: {{.BugID.MonorailProject}}/{{.BugID.MonorailBugID}}{{end}}
   285      // ```
   286      //
   287      // As for functions, only the standard global functions are available, see:
   288      // https://pkg.go.dev/text/template#hdr-Functions
   289      string comment_template = 1;
   290  
   291      // Bug content options that are specific to Google issue tracker (Buganizer).
   292      Buganizer buganizer = 2;
   293  
   294      // Bug content options that are specific to monorail.
   295      Monorail monorail = 3;
   296  
   297      // TODO(meiring): Add assignee, cc list.
   298  
   299      // Policy configuration that is specific to Google issue tracker (Buganizer).
   300      message Buganizer {
   301        // The numeric ID of the buganizer hotlist to add the issue to. Optional.
   302        // The bug is added to the hostlist when the policy transitions to
   303        // activated. The issue is not removed from the hotlist if the policy is
   304        // deactivated, to avoid excessive bug updates.
   305        repeated int64 hotlists = 1;
   306      }
   307  
   308      // Policy configuration that is specific to monorail issue tracker.
   309      message Monorail {
   310        // The labels to apply to the bug.
   311        repeated string labels = 1;
   312      }
   313    }
   314  }
   315  
   316  // Deprecated. No longer has any effect. Retained for textproto
   317  // compatibility only.
   318  message ImpactThreshold {
   319    MetricThreshold test_results_failed = 4;
   320    MetricThreshold test_runs_failed = 5;
   321    MetricThreshold presubmit_runs_failed = 6;
   322    MetricThreshold critical_failures_exonerated = 7;
   323    optional int64 unexpected_failures_1d = 1;
   324    optional int64 unexpected_failures_3d = 2;
   325    optional int64 unexpected_failures_7d = 3;
   326  }
   327  
   328  // ImpactMetricThreshold specifies a condition on a cluster's impact metric.
   329  message ImpactMetricThreshold {
   330    // The id of the impact metric.
   331    // e.g.
   332    // human-cls-failed-presubmit: The number of presubmit runs that failed.
   333    // critical-failures-exonerated: The number of test failures on critical
   334    //                               builders that were exonerated with an
   335    //                               exoneration reason other than NOT_CRITICAL.
   336    // test-runs-failed: The number of test runs that failed.
   337    //                   A test run (also known as a 'shard' (chromium) or
   338    //                   'task' (Chrome OS)) is considered failed if all tries of
   339    //                   test(s) in it unexpectedly failed. The failed test run is
   340    //                   attributed to the last failure of each of the test(s)
   341    //                   that failed on all tries.
   342    // failures: The number of test results that were unexpected failures.
   343    //
   344    // Full list of available metrics here:
   345    // https://source.chromium.org/chromium/infra/infra/+/main:go/src/go.chromium.org/luci/analysis/internal/analysis/metrics/metrics.go
   346    string metric_id = 1;
   347  
   348    // The thresholds against a metric.
   349    MetricThreshold threshold = 2;
   350  }
   351  
   352  // MetricThreshold specifies thresholds for a particular metric.
   353  // The threshold is considered satisfied if any of the individual metric
   354  // thresholds is met or exceeded (i.e. if multiple thresholds are set, they
   355  // are combined using an OR-semantic). If no threshold is set, the threshold
   356  // as a whole is unsatisfiable.
   357  message MetricThreshold {
   358    // The threshold for one day.
   359    optional int64 one_day = 1;
   360  
   361    // The threshold for three day.
   362    optional int64 three_day = 2;
   363  
   364    // The threshold for seven days.
   365    optional int64 seven_day = 3;
   366  }
   367  
   368  // MonorailProject describes the configuration to use when filing bugs
   369  // into a given monorail project.
   370  message MonorailProject {
   371    // The monorail project being described.
   372    // E.g. "chromium".
   373    string project = 1;
   374  
   375    // The field values to use when creating new bugs.
   376    // For example, on chromium issue tracker, there is a manadatory
   377    // issue type field (field 10), which must be set to "Bug".
   378    repeated MonorailFieldValue default_field_values = 2;
   379  
   380    // The ID of the issue's priority field. You can find this by visiting
   381    // https://monorail-prod.appspot.com/p/<project>/adminLabels, scrolling
   382    // down to Custom fields and finding the ID of the field you wish to set.
   383    //
   384    // This field must support the values: "Pri-0", "Pri-1", "Pri-2", "Pri-3".
   385    int64 priority_field_id = 3;
   386  
   387    // Deprecated. No longer has any effect. Retained for textproto
   388    // compatibility only. Use bug_management.policies instead.
   389    repeated MonorailPriority priorities = 4;
   390  
   391    // Deprecated. No longer has any effect. Retained for textproto
   392    // compatibility only.
   393    int64 priority_hysteresis_percent = 5;
   394  
   395    // The prefix that should appear when displaying bugs from the
   396    // given bug tracking system. E.g. "crbug.com" or "fxbug.dev".
   397    // If no prefix is specified, only the bug number will appear.
   398    // Otherwise, the supplifed prefix will appear, followed by a
   399    // forward slash ("/"), followed by the bug number.
   400    // Valid prefixes match `^[a-z0-9\-.]{0,64}$`.
   401    string display_prefix = 6;
   402  
   403    // The preferred hostname to use in links to monorail. For example,
   404    // "bugs.chromium.org" or "bugs.fuchsia.dev".
   405    string monorail_hostname = 7;
   406  
   407    // Whether the Restrict-View-Google tag should be omitted on new
   408    // auto-filed bugs. This makes those bugs publically visible.
   409    // If unset, defaults to filing with Restrict-View-Google.
   410    bool file_without_restrict_view_google = 8;
   411  }
   412  
   413  // MonorailFieldValue describes a monorail field/value pair.
   414  message MonorailFieldValue {
   415    // The ID of the field to set. You can find this by visiting
   416    // https://monorail-prod.appspot.com/p/<project>/adminLabels, scrolling
   417    // down to Custom fields and finding the ID of the field you wish to set.
   418    int64 field_id = 1;
   419  
   420    // The field value. Values are encoded according to the field type:
   421    // - Enumeration types: the string enumeration value (e.g. "Bug").
   422    // - Integer types: the integer, converted to a string (e.g. "1052").
   423    // - String types: the value, included verbatim.
   424    // - User types: the user's resource name (e.g. "users/2627516260").
   425    //   User IDs can be identified by looking at the people listing for a
   426    //   project:  https://monorail-prod.appspot.com/p/<project>/people/list.
   427    //   The User ID is included in the URL as u=<number> when clicking into
   428    //   the page for a particular user. For example, "user/3816576959" is
   429    //   https://monorail-prod.appspot.com/p/chromium/people/detail?u=3816576959.
   430    // - Date types: the number of seconds since epoch, as a string
   431    //   (e.g. "1609459200" for 1 January 2021).
   432    // - URL type: the URL value, as a string (e.g. "https://www.google.com/").
   433    //
   434    // The source of truth for mapping of field types to values is as
   435    // defined in the Monorail v3 API, found here:
   436    // https://source.chromium.org/chromium/infra/infra/+/main:appengine/monorail/api/v3/api_proto/issue_objects.proto?q=%22message%20FieldValue%22
   437    string value = 2;
   438  }
   439  
   440  
   441  // Deprecated. No longer has any effect. Retained for textproto
   442  // compatibility only.
   443  message MonorailPriority {
   444    string priority = 1;
   445    ImpactThreshold threshold = 2;
   446    repeated ImpactMetricThreshold thresholds = 3;
   447  }
   448  
   449  // Configurations per realm.
   450  message RealmConfig {
   451    // Name of the realm.
   452    //
   453    // Must match `^[a-z0-9_\.\-/]{1,400}$`.
   454    // Must not contain the project part. I.e. for "chromium:ci" realm the value
   455    // here must be "ci".
   456    string name = 1;
   457  
   458    // Test variant analysis configurations for the realm.
   459    TestVariantAnalysisConfig test_variant_analysis = 2;
   460  }
   461  
   462  // Configuration for how test results are clustered.
   463  message Clustering {
   464    // Rules used to cluster test results by test name.
   465    // The order of rules matters; the first matching rule will be used
   466    // to cluster a given test result.
   467    //
   468    // If no rule matches, the test results will be clustered on the
   469    // full test name. This corresponds approximately to the rule:
   470    // {
   471    //   name: "Full test name"
   472    //   pattern: "^(?P<testname>.*)$"
   473    //   like_template: "${testname}"
   474    // }
   475    repeated TestNameClusteringRule test_name_rules = 1;
   476  
   477    // Regular expressions used to mask out part of a failure reason
   478    // prior to clustering.
   479    //
   480    // The process of generating the clustering key is:
   481    // 1. All '%', '_' and '\' characters in the failure reason are
   482    //    escaped to generate a SQL LIKE expression that matches the
   483    //    failure reason literally.
   484    // 2. Regular expressions are run over the escaped failure reason
   485    //    one by one to identify parts of the failure reason to mask
   486    //    out (replace by a SQL LIKE wildcard match).
   487    // 3. The clustering key is used in the failure association rule
   488    //    of a newly field bug, or hashed to generate the clustering
   489    //    key.
   490    //
   491    // For regular expression run against the failure reason,
   492    // the part of the reason that matches the first (capturing)
   493    // subexpression is masked out in the reason cluster.
   494    // All non-overlapping matches are replaced.
   495    //
   496    // For example, given the masking expression:
   497    // "^\\[Fixture failure\\] (\\w+):"
   498    // The failure reason:
   499    // `[Fixture failure] myFixture: some_error`
   500    // will be escaped to (in step 1):
   501    // `[Fixture failure] myFixture: some\_error`
   502    // and will yield the following output after masking (step 2):
   503    // `[Fixture failure] %: some\_error`
   504    //
   505    // Masking expressions are applied in the order that they appear
   506    // in the list.
   507    repeated string reason_mask_patterns = 2;
   508  }
   509  
   510  // A rule used to cluster a test result by test name.
   511  message TestNameClusteringRule {
   512    // A human-readable name for the rule. This should be unique for each rule.
   513    // This may be used by LUCI Analysis to explain why it chose to cluster the
   514    // test name in this way.
   515    string name = 1;
   516  
   517    // The regular expression describing which test names should be clustered
   518    // by this rule.
   519    //
   520    // Example.
   521    //   Assume our project uploads google test (gtest) results with the test
   522    //   name prefix "gtest://".
   523    //   If want to cluster value-parameterized google tests
   524    //   together based on the test suite and test case name (ignoring
   525    //   the value parameter), we may use a pattern like:
   526    //     "^gtest://(\w+/)?(?P<testcase>\w+\.\w+)/\w+$"
   527    //
   528    //   This will allow us to cluster test names like:
   529    //     "gtest://InstantiationOne/ColorSpaceTest.testNullTransform/0"
   530    //     "gtest://InstantiationOne/ColorSpaceTest.testNullTransform/1"
   531    //     "gtest://InstantiationTwo/ColorSpaceTest.testNullTransform/0"
   532    //   together.
   533    //
   534    //   See https://github.com/google/googletest/blob/main/docs/advanced.md#how-to-write-value-parameterized-tests
   535    //   to understand value-parameterised google tests.
   536    //
   537    // Use ?P<name> to name capture groups, so their values can be used in
   538    // like_template below.
   539    string pattern = 2;
   540  
   541    // The template used to generate a LIKE expression on test names
   542    // that defines the test name cluster identified by this rule.
   543    //
   544    // This like expression has two purposes:
   545    // (1) If the test name cluster is large enough to justify the
   546    //     creation of a bug cluster, the like expression is used to
   547    //     generate a failure association rule of the following form:
   548    //        test LIKE "<evaluated like_template>"
   549    // (2) A hash of the expression is used as the clustering key for the
   550    //     test name-based suggested cluster. This generally has the desired
   551    //     clustering behaviour, i.e. the parts of the test name which
   552    //     are important enough to included in the LIKE expression for (1)
   553    //     are also those on which clustering should occur.
   554    //
   555    // As is usual for LIKE expressions, the template can contain
   556    // the following operators to do wildcard matching:
   557    // * '%' for wildcard match of an arbitrary number of characters, and
   558    // * '_' for single character wildcard match.
   559    //
   560    // To match literal '%' or '_', escape the operator with a '\',
   561    // i.e. use "\%" or "\_" to match literal '%' and '_' respectively.
   562    // To match literal '\', you should use "\\".
   563    //
   564    // The template can refer to parts of the test name matched by
   565    // the rule pattern using ${name}, where name refers to the capture
   566    // group (see pattern). To insert the literal '$', the sequence '$$'
   567    // should be used.
   568    //
   569    // Example.
   570    //   Assume our project uploads google test (gtest) results with the test
   571    //   name prefix "gtest://". Further assume we used the pattern:
   572    //     "^gtest://(\w+/)?(?P<testcase>\w+\.\w+)/\w+$"
   573    //
   574    //   We might use the following like_template:
   575    //     "gtest://%${testcase}%"
   576    //
   577    //   When instantiated for a value-parameterised test, e.g.
   578    //   "gtest://InstantiationOne/ColorSpaceTest.testNullTransform/0",
   579    //   the result would be a failure association rule like:
   580    //     test LIKE "gtest://%ColorSpaceTest.testNullTransform%"
   581    //
   582    //   Note the use of ${testcase} to refer to the testname capture group
   583    //   specified in the pattern example.
   584    //
   585    //   See https://github.com/google/googletest/blob/main/docs/advanced.md#how-to-write-value-parameterized-tests
   586    //   to understand value-parameterised google tests.
   587    //
   588    // It is known that not all clusters can be precisely matched by
   589    // a LIKE expression. Nonetheless, LUCI Analysis prefers LIKE expressions
   590    // as they are easier to comprehend and modify by users, and in
   591    // most cases, the added precision is not required.
   592    //
   593    // As such, your rule should try to ensure the generated LIKE statement
   594    // captures your clustering logic as best it can. Your LIKE expression
   595    // MUST match all test names matched by your regex pattern, and MAY
   596    // capture additional test names (though this is preferably minimised,
   597    // to reduce differences between the suggested clusters and eventual
   598    // bug clusters).
   599    //
   600    // LUCI Analysis will automatically escape any '%' '_' and '\' in parts of
   601    // the matched test name before substitution to ensure captured parts
   602    // of the test name are matched literally and not interpreted.
   603    string like_template = 3;
   604  }
   605  
   606  // An enum that represents the bug filing system that the project uses.
   607  enum BugSystem {
   608    // An unspecified bug system, Do not use, this will
   609    // break LUCI Analysis bug filing functionality.
   610    BUG_SYSTEM_UNSPECIFIED = 0;
   611    // Use Monorail to file bugs.
   612    MONORAIL = 1;
   613    // Use Buganizer to file bugs.
   614    BUGANIZER = 2;
   615  }
   616  
   617  // This enum represents the Buganizer priorities.
   618  // It is equivalent to the one in Buganizer API.
   619  enum BuganizerPriority {
   620    // Priority unspecified, Do not use this value.
   621    BUGANIZER_PRIORITY_UNSPECIFIED = 0;
   622    // P0, Highest priority.
   623    P0 = 1;
   624    P1 = 2;
   625    P2 = 3;
   626    P3 = 4;
   627    P4 = 5;
   628  }
   629  
   630  // Defines the required details for a Buganizer component.
   631  message BuganizerComponent {
   632    // The id of the component that we will use to file bugs in.
   633    int64 id = 1;
   634  }
   635  
   636  // The Buganizer configuration, this should only be
   637  // used when the bug tracking system ins Buganizer.
   638  message BuganizerProject {
   639    // The default Buganizer component.
   640    // This component will be used if we failed to find
   641    // a component for a cluster.
   642    BuganizerComponent default_component = 1;
   643  
   644    // Deprecated. No longer has any effect. Retained for textproto
   645    // compatibility only.
   646    int64 priority_hysteresis_percent = 2;
   647  
   648    // Deprecated. No longer has any effect. Retained for textproto
   649    // compatibility only.
   650    message PriorityMapping {
   651      BuganizerPriority priority = 1;
   652      ImpactThreshold threshold = 2;
   653      repeated ImpactMetricThreshold thresholds = 3;
   654    }
   655  
   656    // Deprecated. No longer has any effect. Retained for textproto
   657    // compatibility only. Use bug_management.policies instead.
   658    repeated PriorityMapping priority_mappings = 3;
   659  
   660    // Whether the LIMIT_VIEW_TRUSTED access level should be omitted
   661    // on new auto-filed bugs and LIMIT_NONE access level should be set.
   662    // This makes those bugs visible to all those who can see bugs
   663    // in a given component.
   664    bool file_without_limit_view_trusted = 4;
   665  }
   666  
   667  // Criteria used to determine test stability. This criteria is used
   668  // to inform test exoneration in presubmit via the
   669  // TestVariants.QueryStability RPC.
   670  //
   671  // Criteria is applied using a data source which contains
   672  // the last 14 days' of test result data for all test variants,
   673  // with certain filterings applied.
   674  //
   675  // See go/luci-exoneration-v2 as well each criteria below for more details.
   676  message TestStabilityCriteria {
   677    // The failure rate criteria to apply. Mandatory.
   678    FailureRateCriteria failure_rate = 1;
   679  
   680    // The failure rate criteria detects consistently failing
   681    // and highly flaky tests (e.g. 95%+ failing) by looking for
   682    // a high number of failures at the queried position of the
   683    // test's history.
   684    //
   685    // The criteria obtains from the last 14 days' of filtered test data
   686    // a set of (up to) 20 test runs centered on the queried commit
   687    // position (10 prior and 10 after) and applies criteria
   688    // to this in various ways.
   689    // The 20 test runs are sorted by commit position and then time.
   690    //
   691    // See go/luci-exoneration-v2 for more detail.
   692    message FailureRateCriteria {
   693        // The number of unexpected test runs that must be
   694        // found in a sliding window of size 10 containing the
   695        // queried position to begin exoneration.
   696        // 6 is a good starting value.
   697        //
   698        // The criteria is applied over sliding windows of size
   699        // 10 around the query position. Assuming the full 20 test
   700        // runs are obtained, this means 11 window positions are considered.
   701        // If any window satisifes the threshold, the criteria is met
   702        // and the test is considered unstable.
   703        //
   704        // In the event that 10 test runs cannot be found in the last
   705        // 14 days of test history, a window sized to the available
   706        // test runs is used but the criteria is not scaled.
   707        int32 failure_threshold = 1;
   708  
   709        // The number of consecutive unexpected test runs, which if
   710        // present at the leading or trailing part of the (up to) 20
   711        // test verdicts, will trigger exoneration.
   712        // 3 is a good starting value.
   713        //
   714        // The consecutive failures must also touch the query position.
   715        //
   716        // This is designed to create a fast path to exoneration for
   717        // 100% failing tests which produce a strong and consistent
   718        // failing signal, leveraging the statistical significance
   719        // of consecutive failures. If this threshold is met,
   720        // the failure_threshold above does NOT need to be met.
   721        //
   722        // E.g. the following scenario WILL trigger this criteria for
   723        // a threshold of four or less.
   724        //
   725        // History: >F F F F< P P P P P P P
   726        //            ^
   727        //            Query position
   728        //
   729        // The following scenario WILL NOT trigger this criteria:
   730        //
   731        // History:>P F F F F< P P P P P P P
   732        //              ^
   733        //              Query position
   734        //
   735        // (N.B. Direction of history is irrelevant as criteria is
   736        // applied symmetrically. Either the left or right could
   737        // represent 'later' by commit position.)
   738        int32 consecutive_failure_threshold = 2;
   739    }
   740  
   741    // The flake rate criteria to apply. Mandatory.
   742    FlakeRateCriteria flake_rate = 2;
   743  
   744    // The flake rate criteria detects flaky tests by looking for
   745    // examples where a test has obtained expected and unexpected
   746    // test runs for the same sources under test.
   747    //
   748    // If there are more flaky source verdicts found than a threshold,
   749    // the test is considered flaky.
   750    //
   751    // The analysis window is all source verdicts for 7 days' worth
   752    // of commit positions either side of the queried position.
   753    // The conversion between time and commit position is discussed
   754    // in go/luci-exoneration-v2.
   755    //
   756    // In the event that an unsatisfactory number of source positions
   757    // are found using this method, the window is enlarged to possibly
   758    // include any verdict in the last 14 days. This is to improve
   759    // detection performance on tests with a low volume of results.
   760    message FlakeRateCriteria {
   761      // The minimum number of source verdicts desired
   762      // for the analysis window.
   763      //
   764      // As standard, all source verdicts for sources
   765      // +/- 7 days from the queried position are used.
   766      //
   767      // However, if the number of verdicts is not equal
   768      // to or greater than min_window, all source verdicts
   769      // from the last 14 days will be used. This is designed
   770      // to prioritise adequate flake detection performance
   771      // for test variants with low result volumes, at the
   772      // cost of data recency.
   773      //
   774      // If the number of source verdicts in the last 14 days
   775      // is less than min_window, then whatever source verdicts
   776      // are available are still used.
   777      //
   778      // 100 is a good starting value.
   779      int32 min_window = 1;
   780  
   781      // The minimum number of flaky source verdicts required
   782      // to trigger the criteria. 2 is a good starting value.
   783      int32 flake_threshold = 2;
   784  
   785      // The minimum flake rate required to trigger the criteria,
   786      // as a proportion of all source verdicts. This must be a
   787      // value between 0.0 and 1.0.
   788      // 0.01 (1%) is a good starting value.
   789      //
   790      // Both flake_threshold AND the flake_rate_threshold must be met
   791      // for a test to be considered unstable.
   792      //
   793      // Note that not even the most flaky (50% flaky) test would
   794      // be expected to produce more than a 25% flake rate if
   795      // failures are retried once. This is because its expected
   796      // outcomes are:
   797      // - Pass on first try = 50%
   798      // - Fail on first try, pass on second try = 25% (flaky)
   799      // - Fail on both tries = 25%
   800      double flake_rate_threshold = 3;
   801    }
   802  }