// Copyright 2020 Google LLC
//
// 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 google.devtools.build.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/devtools/build/v1/build_events.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";

option cc_enable_arenas = true;
option go_package = "google.golang.org/genproto/googleapis/devtools/build/v1;build";
option java_multiple_files = true;
option java_outer_classname = "BackendProto";
option java_package = "com.google.devtools.build.v1";
option php_namespace = "Google\\Cloud\\Build\\V1";

// A service for publishing BuildEvents. BuildEvents are generated by Build
// Systems to record actions taken during a Build. Events occur in streams,
// are identified by a StreamId, and ordered by sequence number in a stream.
//
// A Build may contain several streams of BuildEvents, depending on the systems
// that are involved in the Build. Some BuildEvents are used to declare the
// beginning and end of major portions of a Build; these are called
// LifecycleEvents, and are used (for example) to indicate the beginning or end
// of a Build, and the beginning or end of an Invocation attempt (there can be
// more than 1 Invocation in a Build if, for example, a failure occurs somewhere
// and it needs to be retried).
//
// Other, build-tool events represent actions taken by the Build tool, such as
// target objects produced via compilation, tests run, et cetera. There could be
// more than one build tool stream for an invocation attempt of a build.
service PublishBuildEvent {
  option (google.api.default_host) = "buildeventservice.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Publish a build event stating the new state of a build (typically from the
  // build queue). The BuildEnqueued event must be publishd before all other
  // events for the same build ID.
  //
  // The backend will persist the event and deliver it to registered frontend
  // jobs immediately without batching.
  //
  // The commit status of the request is reported by the RPC's util_status()
  // function. The error code is the canoncial error code defined in
  // //util/task/codes.proto.
  rpc PublishLifecycleEvent(PublishLifecycleEventRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v1/projects/{project_id=*}/lifecycleEvents:publish"
      body: "*"
      additional_bindings { post: "/v1/lifecycleEvents:publish" body: "*" }
    };
  }

  // Publish build tool events belonging to the same stream to a backend job
  // using bidirectional streaming.
  rpc PublishBuildToolEventStream(stream PublishBuildToolEventStreamRequest)
      returns (stream PublishBuildToolEventStreamResponse) {
    option (google.api.http) = {
      post: "/v1/projects/{project_id=*}/events:publish"
      body: "*"
      additional_bindings { post: "/v1/events:publish" body: "*" }
    };
    option (google.api.method_signature) =
        "ordered_build_event,notification_keywords,project_id";
  }
}

// Publishes 'lifecycle events' that update the high-level state of a build:
// - BuildEnqueued: When a build is scheduled.
// - InvocationAttemptStarted: When work for a build starts; there can be
//     multiple invocations for a build (e.g. retries).
// - InvocationAttemptCompleted: When work for a build finishes.
// - BuildFinished: When a build is finished.
message PublishLifecycleEventRequest {
  // The service level of the build request. Backends only uses this value when
  // the BuildEnqueued event is published to determine what level of service
  // this build should receive.
  enum ServiceLevel {
    // Non-interactive builds can tolerate longer event latencies. This is the
    // default ServiceLevel if callers do not specify one.
    NONINTERACTIVE = 0;

    // The events of an interactive build should be delivered with low latency.
    INTERACTIVE = 1;
  }

  // The interactivity of this build.
  ServiceLevel service_level = 1;

  // Required. The lifecycle build event. If this is a build tool event, the RPC
  // will fail with INVALID_REQUEST.
  OrderedBuildEvent build_event = 2 [(google.api.field_behavior) = REQUIRED];

  // If the next event for this build or invocation (depending on the event
  // type) hasn't been published after this duration from when {build_event}
  // is written to BES, consider this stream expired. If this field is not set,
  // BES backend will use its own default value.
  google.protobuf.Duration stream_timeout = 3;

  // Additional information about a build request. These are define by the event
  // publishers, and the Build Event Service does not validate or interpret
  // them. They are used while notifying internal systems of new builds and
  // invocations if the OrderedBuildEvent.event type is
  // BuildEnqueued/InvocationAttemptStarted.
  repeated string notification_keywords = 4;

  // Required. The project this build is associated with.
  // This should match the project used for the initial call to
  // PublishLifecycleEvent (containing a BuildEnqueued message).
  string project_id = 6 [(google.api.field_behavior) = REQUIRED];

  // Whether to require a previously received matching parent lifecycle event
  // for the current request's event before continuing processing.
  // - InvocationAttemptStarted and BuildFinished events require a BuildEnqueued
  //   parent event.
  // - InvocationAttemptFinished events require an InvocationAttemptStarted
  //   parent event.
  bool check_preceding_lifecycle_events_present = 7;
}

// States which event has been committed. Any failure to commit will cause
// RPC errors, hence not recorded by this proto.
message PublishBuildToolEventStreamResponse {
  // The stream that contains this event.
  StreamId stream_id = 1;

  // The sequence number of this event that has been committed.
  int64 sequence_number = 2;
}

// Build event with contextual information about the stream it belongs to and
// its position in that stream.
message OrderedBuildEvent {
  // Which build event stream this event belongs to.
  StreamId stream_id = 1;

  // The position of this event in the stream. The sequence numbers for a build
  // event stream should be a sequence of consecutive natural numbers starting
  // from one. (1, 2, 3, ...)
  int64 sequence_number = 2;

  // The actual event.
  BuildEvent event = 3;
}

// Streaming request message for PublishBuildToolEventStream.
message PublishBuildToolEventStreamRequest {
  // Required. The build event with position info.
  // New publishing clients should use this field rather than the 3 above.
  OrderedBuildEvent ordered_build_event = 4
      [(google.api.field_behavior) = REQUIRED];

  // The keywords to be attached to the notification which notifies the start
  // of a new build event stream. BES only reads this field when sequence_number
  // or ordered_build_event.sequence_number is 1 in this message. If this field
  // is empty, BES will not publish notification messages for this stream.
  repeated string notification_keywords = 5;

  // Required. The project this build is associated with.
  // This should match the project used for the initial call to
  // PublishLifecycleEvent (containing a BuildEnqueued message).
  string project_id = 6 [(google.api.field_behavior) = REQUIRED];

  // Whether to require a previously received matching InvocationAttemptStarted
  // event before continuing event processing for the event in the current
  // request. BES only performs this check for events with sequence_number 1
  // i.e. the first event in the stream.
  bool check_preceding_lifecycle_events_present = 7;
}
