go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/proto/v1/clusters.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.v1; 18 19 option go_package = "go.chromium.org/luci/analysis/proto/v1;analysispb"; 20 21 import "google/protobuf/timestamp.proto"; 22 import "go.chromium.org/luci/analysis/proto/v1/common.proto"; 23 import "go.chromium.org/luci/analysis/proto/v1/sources.proto"; 24 import "go.chromium.org/luci/analysis/proto/v1/failure_reason.proto"; 25 26 // Provides methods to cluster test results, and obtain the impact of those 27 // clusters. 28 // 29 // A cluster is a group of test failures with a common characteristic. 30 // For example, test results may form a cluster with other failures that share 31 // a common test name, or failure reason. Test results may also be in a cluster 32 // defined by a user-modifiable failure association rule (which associates 33 // failures with a bug). In this case, the failures have the property defined 34 // by the failure association rule in common. 35 // 36 // A test result may be in many clusters, and each cluster may contain many 37 // test results. 38 // 39 // Each cluster has an identity, consisting of three components: 40 // - The LUCI Project name, e.g. "chromium" or "fuchsia". 41 // - The Clustering Algorithm that identified the cluster. As at writing 42 // (April 2022), the algorithms are 'testname-v3' for version 3 of the 43 // test-name clustering algorithm, 'reason-v3' for version 3 of the failure 44 // reason clustering algorithm, and 'rules-v2' for the rules-based clustering 45 // algorithm. 46 // (Although internally versioned, the rules algorithm version is hidden 47 // for clients, so that {luci_project}/rules/{rule_id} always represents 48 // the cluster defined by the given rule_id.) 49 // We make no guarantees about the structure of algorithm names, they should 50 // be treated as opaque strings by clients. 51 // - An algorithm-defined cluster identifier. This is algorithm-dependent and 52 // although (as at April 2022) a lowercase hexadecimal string, should be 53 // treated as an opaque value by clients. 54 // For the 'rules' algorithm, the cluster identifier will always correspond 55 // to the Rule ID of the rule that defines the cluster. 56 service Clusters { 57 // Identifies the cluster(s) for one or more test failure(s). 58 // 59 // This RPC returns the clusters of each test result, using 60 // current suggested cluster algorithms, configured failure 61 // association rules, and ingested project configuration with 62 // a bounded staleness of up to one minute. (Returned clusters 63 // may be based on project configuration and configured failure 64 // association rules that is up to one minute out-of-date). 65 // 66 // As at April 2022, the implementation does not use stale 67 // rules, but you are instructed NOT to rely on this property to 68 // allow reversion to the faster implementation that is tolerant 69 // to higher QPS in future. If your use case require strong reads 70 // (e.g. you want to call cluster immediately after updating a rule), 71 // please contact LUCI Analysis owners. We may be able to provide a 72 // request flag to select this processing behaviour. 73 // 74 // This RPC is a pure query API and does not lead to the ingestion of the 75 // test failures by LUCI Analysis (e.g. for cluster impact calculations). 76 rpc Cluster(ClusterRequest) returns (ClusterResponse) {}; 77 78 // Reads information about the given cluster. 79 // 80 // Please consult LUCI Analysis owners before adding additional calls to 81 // this RPC, as the implementation currently calls back to BigQuery and as 82 // such, is not cost-optimised if many queries are to be made. 83 // 84 // As of writing (April 13, 2022) this query reads ~1 GB per call for 85 // the largest LUCI Project, which translates to a cost of 0.5 US cents 86 // per query at published pricing (US$5/TB analyzed for BigQuery). 87 // 88 // Changes to this RPC should comply with https://google.aip.dev/131. 89 rpc Get(GetClusterRequest) returns (luci.analysis.v1.Cluster) {}; 90 91 // Reads current progress re-clustering the given project. Re-clustering 92 // means updating the clusters each failure is in to reflect the latest 93 // failure association rules, suggested clustering algorithms and 94 // clustering configuration. 95 rpc GetReclusteringProgress(GetReclusteringProgressRequest) 96 returns (ReclusteringProgress) {}; 97 98 // Queries summary information about top clusters. 99 // 100 // The set of test failures used as input to the clustering can be 101 // specified using the failure_filter field on the request. 102 // The returned clusters include only the impact derived from the 103 // filtered failures. 104 // 105 // This allows investigation of the highest impact clusters for some 106 // subset of the failure data in a project. For example, a filter string 107 // of "failure_reason:ssh" would find all of the clusters where any test 108 // results mention "ssh" in their failure reason, and show how big the 109 // impact from these ssh failures is in each cluster. This is useful when 110 // investigating specific problems, or ownership areas of the tests. 111 // 112 // Please consult LUCI Analysis owners before adding additional calls 113 // to this RPC, as the implementation currently calls back to BigQuery and as 114 // such, is not cost-optimised if many queries are to be made. 115 // 116 // As of writing (April 13, 2022) this query reads up to 10 GB per call for 117 // 7 days of data for the largest LUCI Project, which translates to a cost 118 // of up to 5 US cents per query at published pricing 119 // (US$5/TB analyzed for BigQuery). 120 rpc QueryClusterSummaries(QueryClusterSummariesRequest) 121 returns (QueryClusterSummariesResponse) {}; 122 123 // Queries examples of failures in the given cluster. 124 // 125 // Please consult LUCI Analysis owners before adding additional calls to 126 // this RPC, as the implementation currently calls back to BigQuery and as 127 // such, is not cost-optimised if many queries are to be made. 128 rpc QueryClusterFailures(QueryClusterFailuresRequest) 129 returns (QueryClusterFailuresResponse) {}; 130 131 // Queries test variants in the cluster which have recently had an 132 // exoneration recorded against them. Only exonerations on failures 133 // which are part of the cluster are considered. 134 // 135 // Consider solving this use case in future by a standard AIP-132 List 136 // method with filter and order_by support. 137 // 138 // This RPC is useful for projects using the legacy QueryFailureRate 139 // API for exoneration. 140 rpc QueryExoneratedTestVariants(QueryClusterExoneratedTestVariantsRequest) 141 returns (QueryClusterExoneratedTestVariantsResponse) {}; 142 143 // Queries test variant branches in the cluster which have recently had 144 // an exoneration recorded against them. Only exonerations on failures 145 // which are part of the cluster are considered. 146 // 147 // Use for projects performing branch-scoped exoneration using 148 // QueryStability. 149 rpc QueryExoneratedTestVariantBranches(QueryClusterExoneratedTestVariantBranchesRequest) 150 returns (QueryClusterExoneratedTestVariantBranchesResponse) {}; 151 152 // Queries the history of metrics for clustered failures satisying given criteria. 153 // For example the number of test runs failed on each day for the last 7 days. 154 // 155 // Please consult LUCI Analysis owners before adding additional calls to 156 // this RPC, as the implementation currently calls back to BigQuery and as 157 // such, is not cost-optimised if many queries are to be made. 158 rpc QueryHistory(QueryClusterHistoryRequest) 159 returns (QueryClusterHistoryResponse) {}; 160 } 161 162 message ClusterRequest { 163 // TestResult captures information about a test result, sufficient to 164 // cluster it. The fields requested here may be expanded over time. 165 // For example, variant information may be requested in future. 166 message TestResult { 167 // Opaque tag supplied by the caller, to be returned in the 168 // response. Provided to assist correlating responses with requests. 169 // Does not need to be unique. Optional. 170 string request_tag = 1; 171 172 // Identifier of the test (as reported to ResultDB). 173 // For chromium projects, this starts with ninja://. 174 string test_id = 2; 175 176 // The failure reason of the test (if any). 177 luci.analysis.v1.FailureReason failure_reason = 3; 178 } 179 // The LUCI Project for which the test result should be clustered. 180 string project = 1; 181 182 // The test results to cluster. At most 1000 test results may be 183 // clustered in one request. 184 repeated TestResult test_results = 2; 185 } 186 187 message ClusterResponse { 188 // The cluster(s) a test result is contained in. 189 message ClusteredTestResult { 190 // An individual cluster a test result is contained in. 191 message ClusterEntry { 192 // The unique identifier of the cluster. 193 // If the algorithm is "rules", the cluster ID is also a rule ID. 194 luci.analysis.v1.ClusterId cluster_id = 1; 195 196 // The bug associated with the cluster, if any. This is only 197 // populated for clusters defined by a failure association rule, 198 // which associates specified failures to a bug. 199 luci.analysis.v1.AssociatedBug bug = 2; 200 } 201 // Opaque tag supplied by the caller in the request. Provided to assist 202 // the caller correlate responses with requests. 203 string request_tag = 1; 204 205 // The clusters the test result is contained within. 206 repeated ClusterEntry clusters = 2; 207 } 208 209 // The clusters each test result is in. 210 // Contains one result for each test result specified in the request. 211 // Results are provided in the same order as the request, so 212 // the i-th ClusteredTestResult corresponds to the i-th 213 // TestResult in the request. 214 repeated ClusteredTestResult clustered_test_results = 1; 215 216 // The versions of clustering algorithms, rules and project configuration 217 // used to service this request. For debugging purposes only. 218 ClusteringVersion clustering_version = 2; 219 } 220 221 // The versions of algorithms, rules and configuration used by LUCI Analysis 222 // to cluster test results. For a given test result and ClusteringVersion, 223 // the set of returned clusters should always be the same. 224 message ClusteringVersion { 225 // The version of clustering algorithms used. 226 int32 algorithms_version = 1; 227 228 // The version of failure association rules used. This is the Spanner 229 // commit timestamp of the last rule modification incorporated in the 230 // set of rules used to cluster the results. 231 google.protobuf.Timestamp rules_version = 2; 232 233 // The version of project configuration used. This is the timestamp 234 // the project configuration was ingested by LUCI Analysis. 235 google.protobuf.Timestamp config_version = 3; 236 } 237 238 message GetClusterRequest { 239 // The resource name of the cluster to retrieve. 240 // Format: projects/{project}/clusters/{cluster_algorithm}/{cluster_id}. 241 // Designed to conform to aip.dev/131. 242 string name = 1; 243 } 244 245 message Cluster { 246 // The resource name of the cluster. 247 // Format: projects/{project}/clusters/{cluster_algorithm}/{cluster_id}. 248 string name = 1; 249 250 // Whether there is a recent example in the cluster. 251 bool has_example = 2; 252 253 // A human-readable name for the cluster. 254 // Only populated for suggested clusters where has_example = true. 255 // Not populated for rule-based clusters. 256 string title = 3; 257 258 message Counts { 259 // The value of the metric (summed over all failures). 260 int64 nominal = 1; 261 } 262 263 message TimewiseCounts { 264 // The impact value for the last day. 265 Counts one_day = 2; 266 // The impact value for the last three days. 267 Counts three_day = 3; 268 // The impact value for the last week. 269 Counts seven_day = 4; 270 } 271 272 // The values of metrics associated with the cluster. The map key is the ID 273 // of the metric (e.g. "human-cls-failed-presubmit"). 274 // 275 // The following metrics are currently defined: 276 // - "human-cls-failed-presubmit": 277 // The number of distinct developer changelists that failed at least one 278 // presubmit (CQ) run because of failure(s) in this cluster. Excludes 279 // changelists authored by automation. 280 // - "critical-failures-exonerated": 281 // The number of failures on test variants which were configured to be 282 // presubmit-blocking, which were exonerated (i.e. did not actually block 283 // presubmit) because infrastructure determined the test variant to be 284 // failing or too flaky at tip-of-tree. If this number is non-zero, it 285 // means a test variant which was configured to be presubmit-blocking is 286 // not stable enough to do so, and should be fixed or made non-blocking. 287 // - "failures": 288 // The total number of test results in this cluster. LUCI Analysis only 289 // clusters test results which are unexpected and have a status of crash, 290 // abort or fail, so by definition the only test results counted here 291 // will be an unexpected fail/crash/abort. 292 map<string, TimewiseCounts> metrics = 10; 293 294 // The failure association rule equivalent to the cluster. Populated only 295 // for suggested clusters where has_example = true. 296 // Not populated for rule-based clusters. If you need the failure 297 // association rule for a rule-based cluster, use 298 // luci.analysis.v1.Rules/Get to retrieve the rule with ID matching the 299 // cluster ID. 300 // Used to facilitate creating a new rule based on a suggested cluster. 301 string equivalent_failure_association_rule = 7; 302 303 // Next ID: 11. 304 } 305 306 // Designed to conform with aip.dev/131. 307 message GetReclusteringProgressRequest { 308 // The name of the reclustering progress resource to retrieve. 309 // Format: projects/{project}/reclusteringProgress. 310 string name = 1; 311 } 312 313 // ReclusteringProgress captures the progress re-clustering a 314 // given LUCI project's test results using specific rules 315 // versions or algorithms versions. 316 message ReclusteringProgress { 317 // The name of the reclustering progress resource. 318 // Format: projects/{project}/reclusteringProgress. 319 string name = 1; 320 321 // ProgressPerMille is the progress of the current re-clustering run, 322 // measured in thousandths (per mille). As such, this value ranges 323 // from 0 (0% complete) to 1000 (100% complete). 324 int32 progress_per_mille = 2; 325 326 // The goal of the last completed re-clustering run. 327 ClusteringVersion last = 5; 328 329 // The goal of the current re-clustering run. (For which 330 // ProgressPerMille is specified.) This may be the same as the 331 // last completed re-clustering run the available algorithm versions, 332 // rules and configuration is unchanged. 333 ClusteringVersion next = 6; 334 } 335 336 enum ClusterSummaryView { 337 // The default / unset value. 338 // The API will default to the BASIC view. 339 CLUSTER_SUMMARY_VIEW_UNSPECIFIED = 0; 340 341 // Include most fields in the cluster summary, EXCLUDING 342 // daily breakdowns of the cluster's impact metrics. 343 BASIC = 1; 344 345 // Include everything in the cluster summary. 346 FULL = 2; 347 } 348 349 message QueryClusterSummariesRequest { 350 // The LUCI Project. 351 string project = 1; 352 353 // An AIP-160 style filter to select test failures in the project 354 // to cluster and calculate metrics for. 355 // 356 // Filtering supports a subset of [AIP-160 filtering](https://google.aip.dev/160). 357 // 358 // All values are case-sensitive. 359 // 360 // A bare value is searched for in the columns test_id and 361 // failure_reason. E.g. ninja or "test failed". 362 // 363 // You can use AND, OR and NOT (case sensitive) logical operators, along 364 // with grouping. '-' is equivalent to NOT. Multiple bare values are 365 // considered to be AND separated. E.g. These are equivalent: 366 // hello world 367 // and: 368 // hello AND world 369 // 370 // More examples: 371 // a OR b 372 // a AND NOT(b or -c) 373 // 374 // You can filter particular columns with '=', '!=' and ':' (has) operators. 375 // The right hand side of the operator must be a simple value. E.g: 376 // test_id:telemetry 377 // -failure_reason:Timeout 378 // ingested_invocation_id="build-8822963500388678513" 379 // 380 // Supported columns to search on: 381 // - test_id 382 // - failure_reason 383 // - realm 384 // - ingested_invocation_id 385 // - cluster_algorithm 386 // - cluster_id 387 // - variant_hash 388 // - test_run_id 389 // - tags 390 // 391 // Note that cost is greatly reduced (more than 90%) if exact matches for the 392 // cluster_algorithm and cluster_id field are both provided in the filter string. 393 string failure_filter = 2; 394 395 // A comma-separated list of fields to order the response by. 396 // 397 // The default sorting order is ascending; to specify descending order 398 // for a field append a " desc" suffix. The dot syntax can be used 399 // to navigate fields and map keys, and the backtick character (``) used 400 // to escape field names that do not match `[a-zA-Z_][a-zA-Z0-9_]`. 401 // 402 // The only sortable columns that are supported currently are metric 403 // fields. 404 // 405 // For example, to sort by human CLs failed presubmit descending, use: 406 // "metrics.`human-cls-failed-presubmit`.value desc". 407 // To sort by human CLs failed presubmit followed by failures, use: 408 // "metrics.`human-cls-failed-presubmit`.value desc, metrics.`failures`.value desc" 409 // 410 // For more details, see aip.dev/132 for ordering syntax, and 411 // aip.dev/161#map-fields for navigating map fields. 412 string order_by = 3; 413 414 // The resource name(s) of the metrics to include in the cluster summaries. 415 // Format: projects/{project}/metrics/{metric_id}. 416 // See the metrics field on the luci.analysis.v1.Cluster message for details 417 // about valid metric identifiers. 418 repeated string metrics = 4; 419 420 // The time range over which to get the cluster summaries. 421 // Note: the response will include only data for the portion of the 422 // time range that is within the data retention period of 90 days. 423 TimeRange time_range = 5; 424 425 // The level of detail that the returned cluster summaries should have. See 426 // luci.analysis.v1.ClusterSummaryView. 427 ClusterSummaryView view = 6; 428 } 429 430 message QueryClusterSummariesResponse { 431 // The clusters and impact metrics from the filtered failures. 432 repeated ClusterSummary cluster_summaries = 1; 433 } 434 435 message ClusterSummary { 436 // The cluster ID of this cluster. 437 luci.analysis.v1.ClusterId cluster_id = 1; 438 439 // Title is a one-line description of the cluster. 440 string title = 2; 441 442 // The bug associated with the cluster. This will only be present for 443 // rules algorithm clusters. 444 luci.analysis.v1.AssociatedBug bug = 3; 445 446 message MetricValue { 447 // The residual value of the cluster metric. 448 // For bug clusters, the residual metric value is the metric value 449 // calculated using all of the failures in the cluster. 450 // For suggested clusters, the residual metric value is calculated 451 // using the failures in the cluster which are not also part of a 452 // bug cluster. In this way, measures attributed to bug clusters 453 // are not counted again against suggested clusters. 454 int64 value = 1; 455 456 // The value of the cluster metric over time, grouped by 24-hour periods 457 // in the queried time range, in reverse chronological order 458 // i.e. the first entry is the metric value for the 24-hour period 459 // immediately preceding the time range's latest time. 460 repeated int64 daily_breakdown = 2; 461 } 462 463 // The values of cluster metrics. The key of the map is the identifier 464 // of the metric (e.g. "human-cls-failed-presubmit"). 465 // See the metrics field on the luci.analysis.v1.Cluster message for details 466 // about valid metric identifiers. 467 map<string, MetricValue> metrics = 7; 468 469 // Next ID: 8. 470 } 471 472 message QueryClusterFailuresRequest { 473 // The resource name of the cluster failures to retrieve. 474 // Format: projects/{project}/clusters/{cluster_algorithm}/{cluster_id}/failures. 475 string parent = 1; 476 477 // Optional. The resource name of the metric for which failures should 478 // be displayed. 479 // Format: projects/{project}/metrics/{metric_id}. 480 // 481 // If no metrics is specified here, then no filtering is performed 482 // and all failures are eligible to be returned. Over time, we may wish 483 // to migrate this to an AIP-160 filter clause, e.g. "in_metric(`metric-id`)" 484 // where in_metric is a function. 485 string metric_filter = 2; 486 } 487 488 message QueryClusterFailuresResponse { 489 // Example failures in the cluster. 490 // Limited to the most recent 2000 examples. 491 repeated DistinctClusterFailure failures = 1; 492 } 493 494 // DistinctClusterFailure represents a number of failures which have identical 495 // properties. This provides slightly compressed transfer of examples. 496 message DistinctClusterFailure { 497 // Representation of an exoneration. An exoneration means the subject of 498 // the test (e.g. a CL) is absolved from blame for the unexpected results 499 // of the test variant. 500 message Exoneration { 501 // The machine-readable reason for the exoneration. 502 luci.analysis.v1.ExonerationReason reason = 1; 503 } 504 505 // Representation of a presubmit run (e.g. LUCI CV Run). 506 message PresubmitRun { 507 // Identity of the presubmit run that contains this test result. 508 // This should be unique per "CQ+1"/"CQ+2" attempt on gerrit. 509 // 510 // One presumbit run MAY have many ingested invocation IDs (e.g. for its 511 // various tryjobs), but every ingested invocation ID only ever has one 512 // presubmit run ID (if any). 513 // 514 // All test results for the same presubmit run will have one 515 // partition_time. 516 // 517 // If the test result was not collected as part of a presubmit run, 518 // this is unset. 519 luci.analysis.v1.PresubmitRunId presubmit_run_id = 1; 520 521 // The owner of the presubmit run (if any). 522 // This is the owner of the CL on which CQ+1/CQ+2 was clicked 523 // (even in case of presubmit run with multiple CLs). 524 // There is scope for this field to become an email address if privacy 525 // approval is obtained, until then it is "automation" (for automation 526 // service accounts) and "user" otherwise. 527 string owner = 2; 528 529 // The mode of the presubmit run. E.g. DRY_RUN, FULL_RUN, QUICK_DRY_RUN. 530 luci.analysis.v1.PresubmitRunMode mode = 3; 531 532 // The status of the presubmit run. E.g. succeeded, failed or cancelled. 533 luci.analysis.v1.PresubmitRunStatus status = 4; 534 } 535 536 // The identity of the test. 537 string test_id = 1; 538 539 // Description of one specific way of running the test, 540 // e.g. a specific bucket, builder and a test suite. 541 luci.analysis.v1.Variant variant = 2; 542 543 // Timestamp representing the start of the data retention period for the 544 // test results in this group. 545 // The partition time is usually the presubmit run start time (if any) or 546 // build start time. 547 google.protobuf.Timestamp partition_time = 3; 548 549 // Details if the presubmit run associated with these results (if any). 550 PresubmitRun presubmit_run = 4; 551 552 // Whether the build was critical to a presubmit run succeeding. 553 // If the build was not part of a presubmit run, this field should 554 // be ignored. 555 bool is_build_critical = 5; 556 557 // The exonerations applied to the test variant verdict. 558 repeated Exoneration exonerations = 6; 559 560 // The status of the build that contained this test result. Can be used 561 // to filter incomplete results (e.g. where build was cancelled or had 562 // an infra failure). Can also be used to filter builds with incomplete 563 // exonerations (e.g. build succeeded but some tests not exonerated). 564 // This is the build corresponding to ingested_invocation_id. 565 luci.analysis.v1.BuildStatus build_status = 7; 566 567 // The invocation from which this test result was ingested. This is 568 // the top-level invocation that was ingested, an "invocation" being 569 // a container of test results as identified by the source test result 570 // system. 571 // 572 // For ResultDB, LUCI Analysis ingests invocations corresponding to 573 // buildbucket builds. 574 string ingested_invocation_id = 8; 575 576 // Is the ingested invocation blocked by this test variant? This is 577 // only true if all (non-skipped) test results for this test variant 578 // (in the ingested invocation) are unexpected failures. 579 // 580 // Exoneration does not factor into this value; check exonerations 581 // to see if the impact of this ingested invocation being blocked was 582 // mitigated by exoneration. 583 bool is_ingested_invocation_blocked = 9; 584 585 // The unsubmitted changelists that were tested (if any). 586 // Up to 10 changelists are captured. 587 repeated luci.analysis.v1.Changelist changelists = 10; 588 589 // The number of test results which have these properties. 590 int32 count = 11; 591 } 592 593 message QueryClusterExoneratedTestVariantsRequest { 594 // The resource name of the cluster exonerated test variants to retrieve. 595 // Format: projects/{project}/clusters/{cluster_algorithm}/{cluster_id}/exoneratedTestVariants. 596 string parent = 1; 597 } 598 599 message QueryClusterExoneratedTestVariantsResponse { 600 // A list of test variants in the cluster which have exonerated critical 601 // failures. Ordered by recency of the exoneration (most recent exonerations 602 // first) and limited to at most 100 test variants. 603 repeated ClusterExoneratedTestVariant test_variants = 1; 604 } 605 606 // ClusterExoneratedTestVariant represents a test variant in a cluster 607 // which has been exonerated. A cluster test variant is the subset 608 // of a test variant that intersects with the failures of a cluster. 609 message ClusterExoneratedTestVariant { 610 // A unique identifier of the test in a LUCI project. 611 string test_id = 1; 612 613 // Description of one specific way of running the test, 614 // e.g. a specific bucket, builder and a test suite. 615 luci.analysis.v1.Variant variant = 2; 616 617 // The number of critical (presubmit-blocking) failures in the 618 // cluster which have been exonerated on this test variant 619 // in the last week. 620 int32 critical_failures_exonerated = 3; 621 622 // The partition time of the most recent exoneration of a 623 // critical failure. 624 google.protobuf.Timestamp last_exoneration = 4; 625 } 626 627 message QueryClusterExoneratedTestVariantBranchesRequest { 628 // The resource name of the cluster exonerated test variant branches to retrieve. 629 // Format: projects/{project}/clusters/{cluster_algorithm}/{cluster_id}/exoneratedTestVariantBranches. 630 string parent = 1; 631 } 632 633 message QueryClusterExoneratedTestVariantBranchesResponse { 634 // A list of test variants branches in the cluster which have exonerated 635 // critical failures. Ordered by recency of the exoneration (most recent 636 // exonerations first) and limited to at most 100 test variant branches. 637 // 638 // Pagination following AIP-158 may be implemented in future if 639 // more than 100 items is needed. 640 repeated ClusterExoneratedTestVariantBranch test_variant_branches = 1; 641 } 642 643 // ClusterExoneratedTestVariantBranch represents a (test, variant, source ref) 644 // in a cluster which has been exonerated. A cluster test variant branch is 645 // the subset of a test variant branch that intersects with the failures of a 646 // cluster. 647 message ClusterExoneratedTestVariantBranch { 648 // The LUCI project. 649 string project = 1; 650 651 // A unique identifier of the test in a LUCI project. 652 string test_id = 2; 653 654 // Description of one specific way of running the test, 655 // e.g. a specific bucket, builder and a test suite. 656 luci.analysis.v1.Variant variant = 3; 657 658 // The branch in source control that was tested, if known. 659 // For example, the `refs/heads/main` branch in the `chromium/src` repo 660 // hosted by `chromium.googlesource.com`. 661 luci.analysis.v1.SourceRef source_ref = 4; 662 663 // The number of critical (presubmit-blocking) failures in the 664 // cluster which have been exonerated on this test variant 665 // in the last week. 666 int32 critical_failures_exonerated = 5; 667 668 // The partition time of the most recent exoneration of a 669 // critical failure. 670 google.protobuf.Timestamp last_exoneration = 6; 671 } 672 673 message QueryClusterHistoryRequest { 674 // The LUCI Project. 675 string project = 1; 676 677 // An AIP-160 style filter to select test failures in the project 678 // to calculate metrics for. 679 // 680 // See the description of the QueryClusterSummariesRequest.failure_filter 681 // above for the format of this field. 682 // 683 // Note that cost is greatly reduced (more than 90%) if exact matches for the 684 // cluster_algorithm and cluster_id field are both provided in the filter string. 685 string failure_filter = 2; 686 687 // The number of days of history to return. Maximum of 90 as only 90 days of 688 // history is kept by LUCI Analysis. Note that the cost of the query scales 689 // linearly with the number of days. 690 int32 days = 3; 691 692 // The resource name(s) of the metrics to include in the cluster histories. 693 // Format: projects/{project}/metrics/{metric_id}. 694 // See the metrics field on the luci.analysis.v1.Cluster message for details 695 // about valid metric identifiers. 696 repeated string metrics = 4; 697 } 698 699 message QueryClusterHistoryResponse { 700 // The metrics for each day. There will be the same number of days as 701 // requested in the request. The entries will be returned in sorted date 702 // order, earliest day first. 703 repeated ClusterHistoryDay days = 1; 704 } 705 706 // Represents metrics about a cluster on a specific day. 707 message ClusterHistoryDay { 708 // A map from requested metric name to the value of that metric on this day. 709 // The key of the map is the metric ID. 710 map<string, int32> metrics = 1; 711 712 // The date that these metrics are for. 713 // This is a UTC date in ISO 8601 format, e.g. 2022-11-29 714 string date = 2; 715 }