| // Copyright 2021 The LUCI Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| syntax = "proto3"; |
| |
| package cv.internal.tryjob; |
| |
| option go_package = "go.chromium.org/luci/cv/internal/tryjob;tryjob"; |
| |
| import "google/protobuf/timestamp.proto"; |
| |
| import "go.chromium.org/luci/buildbucket/proto/builder_common.proto"; |
| import "go.chromium.org/luci/buildbucket/proto/common.proto"; |
| |
| import "go.chromium.org/luci/cv/api/config/v2/cq.proto"; |
| import "go.chromium.org/luci/cv/api/recipe/v1/cq.proto"; |
| |
| // Definition defines what a Tryjob should do. |
| // |
| // It must be sufficient to trigger a new tryjob. |
| message Definition { |
| oneof backend { |
| // For buildbucket, it's just a builder. |
| Buildbucket buildbucket = 1; |
| } |
| |
| message Buildbucket { |
| string host = 1; |
| buildbucket.v2.BuilderID builder = 2; |
| } |
| |
| // If set, existing tryjob matching this definition is deemed equivalent |
| // to the primary Definition. |
| // |
| // Note that recursive `equivalent_to` is not supported. Also, this doesn't |
| // affect triggering a new tryjob. |
| Definition equivalent_to = 2; |
| |
| // If true, trigger a new tryjob using this definition regardless of whether |
| // reusable tryjobs exist. |
| bool disable_reuse = 3; |
| |
| // If true, CV should let this tryjob run even if it becomes stale, |
| // e.g. by a new non-trivial patchset on one of this tryjob's CLs. |
| // |
| // If the Tryjob is not triggered by CV, then this is value is ignored and |
| // in effect it's assumed true. I.e. we don't cancel tryjobs not triggered |
| // by CV. |
| bool skip_stale_check = 4; |
| |
| // If true, this tryjob is deemed critical for the Run to succeed, i.e. |
| // the Run will fail unless one of the attempts of this tryjob is successful. |
| bool critical = 5; |
| |
| // If true, this tryjob will be marked as experimental. |
| // |
| // However, experimental tryjob could be critical iff it is requested |
| // explicitly (i.e. via git footer). |
| bool experimental = 7; |
| |
| // If set to restricted, CV should only post generic messages such as |
| // "Build failed: https://ci.chromium.org/b/1234" |
| // and no summary markdown about tryjobs with this definition. |
| cv.config.CommentLevel result_visibility = 6; |
| } |
| |
| // Requirement is what has to happen to verify a specific Run. |
| // |
| // It is computed based on the Project Config and specifics of the Run. |
| message Requirement { |
| // Definitions is the definitions of all Tryjobs that should be triggered |
| // to verify a specific Run. |
| repeated Definition definitions = 1; |
| // RetryConfig specifies retries allowed in case of Tryjob failure. |
| // |
| // No retry allowed if nil. |
| cv.config.Verifiers.Tryjob.RetryConfig retry_config = 2; |
| // Version increments by 1 every time this requirement changes. |
| // |
| // Starts with 1. |
| int32 version = 3; |
| // The timestamp when requirement is last computed. |
| // |
| // Every requirement computation will update this field even if the result |
| // requirement is the same as the existing one. |
| google.protobuf.Timestamp last_computed_at = 4; |
| } |
| |
| // Status is a high level status of a Tryjob from CV implementation PoV. |
| enum Status { |
| // STATUS_UNSPECIFIED is never used. |
| STATUS_UNSPECIFIED = 0; |
| |
| // PENDING means Tryjob is being triggered by CV. |
| // |
| // *may* not yet have an external ID. |
| // *must* have no Result. |
| PENDING = 1; |
| |
| // TRIGGERED means Tryjob was triggered. |
| // |
| // *must* have an External ID. |
| // *may* have been triggered not by CV, but by another user, service, etc. |
| // *may* have a Result, which *may* still change. |
| TRIGGERED = 2; |
| |
| // ENDED means the Tryjob completed. Final status. |
| // |
| // *must* have an External ID. |
| // *must* have a Result, whose Status is not UNKNOWN. |
| ENDED = 3; |
| // CANCELLED means Tryjob was cancelled by CV. Final status. |
| // |
| // *must* have an External ID. |
| // *must* have no Result. |
| CANCELLED = 4; |
| // UNTRIGGERED means Tryjob was never triggered. Final state. |
| // |
| // *must* have no External ID. |
| // *must* have no Result. |
| // |
| // This status is an implementation detail of CV, used for Tryjobs which |
| // weren't actually triggered. |
| // |
| // TODO(crbug/1227363): add a field to the Tryjob model to record reason for |
| // this status, notably to record permission denied errors. |
| UNTRIGGERED = 5; |
| } |
| |
| // Result of a Tryjob. |
| // |
| // It's interpreted by the Run Manager. |
| message Result { |
| // Next tag: 6. |
| |
| // Status of the Result. |
| // |
| // This is the verdict of verification of Run's CLs by this Tryjob. |
| Status status = 1; |
| enum Status { |
| // RESULT_STATUS_UNSPECIFIED is never used. |
| RESULT_STATUS_UNSPECIFIED = 0; |
| // UNKNOWN means Tryjob didn't reach a conclusion. |
| // |
| // *must* be used only if Tryjob.Status is TRIGGERED and the Tryjob |
| // hasn't made a decision yet. |
| UNKNOWN = 1; |
| // SUCCEEDED means that Run's CLs are considered OK by this Tryjob. |
| SUCCEEDED = 2; |
| // FAILED_PERMANENTLY means that Run's CLs are most likely not good. |
| FAILED_PERMANENTLY = 3; |
| // FAILED_TRANSIENTLY means that Run's CLs are most likely not to blame |
| // for the failure. |
| // TODO(crbug/1227363): consider removing transiency aspect if possible. |
| FAILED_TRANSIENTLY = 4; |
| // TIMEOUT means the Tryjob ran over some deadline and did not make a |
| // decision about this Run's CLs. |
| TIMEOUT = 5; |
| } |
| |
| // Time when the Tryjob was created in the backend. |
| // |
| // This is used by CV to determine if the Tryjob is fresh enough to be used |
| // to verify a Run. |
| google.protobuf.Timestamp create_time = 2; |
| // Time when the tryjob was last updated in the backend. |
| // |
| // This is used by CV to determine if it needs to refresh Tryjob's Result by |
| // querying its backend. |
| google.protobuf.Timestamp update_time = 3; |
| |
| // Output is a rich result of a Tryjob. |
| // This includes details related to retry and reuse. |
| // |
| // It's typically set by LUCI recipes. |
| cq.recipe.Output output = 4; |
| |
| // Backend houses backend-specific output. |
| oneof backend { |
| Buildbucket buildbucket = 5; |
| } |
| |
| message Buildbucket { |
| int64 id = 1; |
| buildbucket.v2.BuilderID builder = 4; |
| buildbucket.v2.Status status = 2; |
| // SummaryMarkdown is a field containing a human readable summary of the |
| // build's result. |
| string summary_markdown = 3; |
| } |
| } |
| |
| // ExecutionState is the state of executing Tryjobs requirement. |
| message ExecutionState { |
| // Execution tracks the execution state of each individual Tryjob requirement. |
| message Execution { |
| // Attempt represents each attempt to complete an execution. |
| // |
| // Failed attempt will trigger a retry attempt if quota allows. |
| message Attempt { |
| // TryjobId is the id of this attempt of the Tryjob. |
| int64 tryjob_id = 1; |
| // ExternalID is the external ID of this attempt of the Tryjob |
| string external_id = 2; |
| // Status is the status of this attempt of the Tryjob. |
| cv.internal.tryjob.Status status = 3; |
| // Result of this attempt of the Tryjob. |
| cv.internal.tryjob.Result result = 4; |
| // Reused indicates the current attempt of the Tryjob wasn't triggered |
| // by CV for this Run specifically. |
| // |
| // In other words, either: |
| // * tryjob was triggered by CV for a previous Run |
| // * tryjob was triggered by non-CV (e.g. `git cl try`) |
| bool reused = 5; |
| |
| // TODO(yiwzhang): add model for children tryjobs. It could reuse |
| // `Attempt` messages, it may also have a trimmed version of `Attempt` |
| // message because some of the fields don't make sense to children |
| // Tryjobs. Also, if crbug.com/1031205 is shipped before we implement |
| // children support in LUCI CV, we may not even need a new field |
| // (maybe a new status will suffice: like WAITING_FOR_CHILDREN). |
| } |
| // Attempts records all attempts (including retries) to verify the Run with |
| // this Tryjob Execution. |
| repeated Attempt attempts = 2; |
| // UsedQuota is the quota consumed for retrying the execution of this |
| // Tryjob. |
| int32 used_quota = 3; |
| } |
| // Status describes the summarized status of the overall tryjob execution. |
| enum Status { |
| // Unspecified is never used. |
| STATUS_UNSPECIFIED = 0; |
| // At least one critical tryjob is not yet finished so its result is |
| // unknown. |
| RUNNING = 1; |
| // At least one critical tryjob in the state failed and cannot be retried. |
| FAILED = 2; |
| // All the critical tryjobs in the execution state succeeded. |
| SUCCEEDED = 3; |
| } |
| // Executions track the execution state of all required Tryjobs. |
| // |
| // It is one to one mapped to `requirement.definitions` |
| repeated Execution executions = 1; |
| // Requirement is the requirement that is currently being worked on. |
| Requirement requirement = 2; |
| // Status will be set to SUCCEEDED if all tryjobs succeed, |
| // FAILED if at least one tryjob fails and cannot be retried, |
| // or RUNNING otherwise. |
| Status status = 3; |
| // FailureReason provides a user-readable explanation of the |
| // failure. |
| string failure_reason = 4; |
| } |
| |
| // TryjobUpdatedEvent describes which Tryjob entity is updated. |
| message TryjobUpdatedEvent { |
| int64 tryjob_id = 1; |
| } |
| |
| // TryjobUpdatedEvents is a batch of TryjobUpdatedEvent. |
| message TryjobUpdatedEvents { |
| repeated TryjobUpdatedEvent events = 1; |
| } |