blob: 8106ac193d278a1042756e289b1558f2659694f6 [file] [edit]
// 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.
}