| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| syntax = "proto3"; |
| |
| package turboci.graph.orchestrator.v1; |
| |
| import "google/api/field_behavior.proto"; |
| import "turboci/graph/ids/v1/identifier.proto"; |
| import "turboci/graph/orchestrator/v1/actor.proto"; |
| import "turboci/graph/orchestrator/v1/check_kind.proto"; |
| import "turboci/graph/orchestrator/v1/check_state.proto"; |
| import "turboci/graph/orchestrator/v1/dependencies.proto"; |
| import "turboci/graph/orchestrator/v1/edit.proto"; |
| import "turboci/graph/orchestrator/v1/field_options.proto"; |
| import "turboci/graph/orchestrator/v1/revision.proto"; |
| import "turboci/graph/orchestrator/v1/stage_attempt_state.proto"; |
| import "turboci/graph/orchestrator/v1/value_ref.proto"; |
| |
| option go_package = "go.chromium.org/turboci/proto/go/graph/orchestrator/v1;orchestratorpb"; |
| option java_multiple_files = true; |
| |
| // A Check is a node in a TurboCI graph which ties together: |
| // * A named objective of the Workflow (sometimes thought of as a question). |
| // For example: |
| // * Does source X build for platform Y? |
| // * Do these tests built for Y pass when run on Z? |
| // * Are the aggregate test results good enough to allow this CL to land? |
| // * Options which describe *how* to answer that question. For example: |
| // * Which compile targets should be built? |
| // * Which test cases should be skipped? Or how many times should retry if |
| // they fail? |
| // * What test targets should we consider when evaluating the CL? |
| // * The answers to that question (i.e. the results of the Check) |
| // * Pointers to build artifacts, test results, small bits of workflow |
| // specific output which don't fit nicely elsewhere, etc. |
| // |
| // Checks are not, themselves, executable, but Stages are the executable nodes |
| // which operate to plan and resolve Checks. |
| // |
| // Next ID: 13 |
| message Check { |
| // The Check's identifier. |
| // |
| // `identifier.id` is provided by the Stage which creates this Check. |
| optional ids.v1.Check identifier = 1 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // Optional, non-unique, display name of this Check. |
| // |
| // Should only be set if it provides meaningful context for what this Check |
| // is for, above and beyond the Check's identifier.id and kind. |
| optional string display_name = 12 [(turboci).check.editable = CHECK_STATE_PLANNING]; |
| |
| // Actor which created the Check. |
| optional Actor created_by = 2 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // The coarse-grained kind of this Check. |
| // |
| // Used in UI and Data registration to restrict what data types are usable in |
| // `options` and `results.data`. |
| // |
| // Used as part of a Checks query for a coarse-grained filter. |
| optional CheckKind kind = 3 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // The security realm for this Check. |
| // |
| // If unset on creation, then this will be populated with the realm of the |
| // Stage which creates this Check. |
| optional string realm = 4 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // The version of this Check. |
| // |
| // Updated any time fields in this Check change. |
| optional Revision version = 5; |
| |
| // The current state of the Check. |
| optional CheckState state = 6; |
| |
| // StateHistoryEntry records the database revision (commit timestamp) when |
| // each time this Check's state changes. |
| message StateHistoryEntry { |
| // The changed state. |
| optional CheckState state = 1 [(google.api.field_behavior) = IMMUTABLE]; |
| // The revision when the state change happens. |
| optional Revision version = 2 [(google.api.field_behavior) = IMMUTABLE]; |
| } |
| |
| // Append-only list of StateHistoryEntry to record the database revision |
| // (commit timestamp) when each time this Check's state changes. |
| repeated StateHistoryEntry state_history = 7; |
| |
| // Dependencies on other objects in the graph. |
| // |
| // Checks may only depend on other Checks. |
| // |
| // While the check is in the PLANNING state, its dependencies can be mutated |
| // freely via WriteNodes calls. |
| // |
| // Once the Check is moved into PLANNED state by a WriteNodes call, |
| // dependencies are "locked" and the Orchestrator starts tracking their |
| // resolution. Once they are resolved, the Orchestrator will switch the check |
| // into the WAITING state. |
| optional Dependencies dependencies = 8 [(turboci).id.allowed = IDENTIFIER_KIND_CHECK]; |
| |
| // Options form the bulk of 'how to answer this Check'. |
| // |
| // It is expected that small details (like assignments to specific |
| // hardware/devices) will not be present here and will be decided by the |
| // Stages which actually produce results for this Check. The balance of what |
| // is in the Check options vs. what is in the Stage args is up to the workflow |
| // authors. It should be expected that Check options will be consumed by |
| // entities external to the Workflow (such as individual developers), and so |
| // it's recommended that the option data here be formulated in a way to be |
| // useful both in-workflow (to Stages) and to users outside the workflow. If |
| // small execution details ARE stored here, it's recommended that they be |
| // stored in a secondary data type to make it clear to external users that |
| // these details are not intended to be intrinsic for reproduction/replication |
| // of the Check results. |
| // |
| // Orchestrator will ensure that the option types here are registered to be |
| // valid for this Check's kind. |
| // |
| // This field is kept sorted, and unique, by `type_url`. |
| repeated ValueRef options = 9 [(turboci).check.editable = CHECK_STATE_PLANNING]; |
| |
| // A Result is a container of result data for a Check. |
| // |
| // Results belong to exactly one Actor (usually a StageAttempt), and any given |
| // Actor may only have one Result per Check. |
| // |
| // A Check may have multiple Results, and each Result may have multiple pieces |
| // of result data. This could occur when multiple Stages all contribute |
| // results to the same Check (e.g. sharding, multiple executions, etc.). |
| message Result { |
| // Identifier for this Result. |
| optional ids.v1.CheckResult identifier = 1 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // The entity which created this Result. |
| // |
| // This is the only entity which can modify this Result. |
| optional Actor owner = 2 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // The database revision (commit timestamp) at which this Result was |
| // created. |
| optional Revision created_at = 3 [(google.api.field_behavior) = IMMUTABLE]; |
| |
| // Data form the bulk of the result. |
| // |
| // NOTE: Most data should be stored in ResultDB via turboci.ResultStorage. |
| // |
| // This field is kept sorted, and unique, by `type_url`. |
| // |
| // Orchestrator will ensure that the option types here are registered to be |
| // valid for this Check's kind. |
| repeated ValueRef data = 4; |
| |
| // The database revision (commit timestamp) at which this Result is |
| // finalized. |
| // |
| // This is set when: |
| // * A StageAttempt `owner` ends (becomes COMPLETE or INCOMPLETE). |
| // * The `owner` explicitly indicates that their results are final. |
| // * The Check advances to the FINAL state. |
| optional Revision finalized_at = 5; |
| |
| // If the Result was finalized automatically by the conclusion of the owner |
| // Stage Attempt, this indicates the final state of that Stage Attempt (i.e. |
| // COMPLETE or INCOMPLETE). |
| // |
| // If this is unset, it means that the Result was either finalized |
| // explicitly by the owner, or by the Check advancing to the final state. |
| optional StageAttemptState attempt_state = 6; |
| } |
| // The list of Results this Check has. |
| // |
| // Any time a StageAttempt adds new result *data* for this Check for the first |
| // time, a new Result will be added to this list. |
| // |
| // So, if you had 3 Stages, each with one Stage Attempt, which add result |
| // data for this Check, you would see 3 Result messages. Similarly, if you |
| // had one Stage with 3 Attempts, all 3 of which add result data for this |
| // check, you would see 3 Result messages. |
| repeated Result results = 10 [ |
| (turboci).check.editable = CHECK_STATE_PLANNED, |
| (turboci).check.editable = CHECK_STATE_WAITING |
| ]; |
| |
| // Edits for this Check. |
| // |
| // Sorted ascending by `version`. |
| repeated Edit edits = 11; |
| |
| // TBD: Add another field for 'Resolved-To' edges to Checks for the case where |
| // this Check is 'underspecified' and the Workflow resolves/evolves it to |
| // one or more concrete Checks. |
| } |