// Copyright 2020-2025 Buf Technologies, Inc.
//
// 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 buf.alpha.registry.v1alpha1;

import "buf/alpha/registry/v1alpha1/role.proto";
import "buf/alpha/registry/v1alpha1/user.proto";
import "buf/alpha/registry/v1alpha1/verification_status.proto";
import "google/protobuf/timestamp.proto";

enum Visibility {
  VISIBILITY_UNSPECIFIED = 0;
  VISIBILITY_PUBLIC = 1;
  VISIBILITY_PRIVATE = 2;
}

message Repository {
  // primary key, unique, immutable
  string id = 1;
  // immutable
  google.protobuf.Timestamp create_time = 2;
  // mutable
  google.protobuf.Timestamp update_time = 3;
  // unique, mutable
  string name = 4;
  oneof owner {
    // foreign key, mutable
    string user_id = 5;
    // foreign key, mutable
    string organization_id = 6;
  }
  Visibility visibility = 7;
  // deprecated means this repository is deprecated.
  bool deprecated = 8;
  // deprecation_message is the message shown if the repository is deprecated.
  string deprecation_message = 9;
  // owner_name is the name of the owner of the repository,
  // either a username or organization name.
  string owner_name = 10;
  // description is the user configurable description of the repository.
  string description = 11;
  // url is the user configurable URL in the description of the repository,
  // always included the scheme and will not have a #fragment suffix.
  string url = 12;
  // default_branch in a BSR repository. It is used when syncing a git repository, to make sure both
  // default branches (BSR and Git) are in sync. By default, every BSR repository is created with a
  // "main" default branch.
  string default_branch = 13;
}

message RepositoryCounts {
  reserved 2;
  reserved "tracks_count";

  uint32 tags_count = 1;
  uint32 drafts_count = 3;
}

message RepositoryContributor {
  User user = 1;
  // The ID of the for which the role belongs to.
  string repository_id = 2;
  // The role that the user has been explicitly assigned against the repository.
  RepositoryRole explicit_role = 3;
  // Optionally defines the role that the user has implicitly against the repository through the owning organization.
  // If the repository does not belong to an organization or the user is not part of the owning organization, this is unset.
  RepositoryRole implicit_role = 4;
}

message RepositoryMetadata {
  // The ID of the repository.
  string id = 1;
  // The name of the repository.
  string name = 2;
  // The owner name of the repository.
  string owner_name = 3;
  // The verification status of the owner of the repository.
  VerificationStatus owner_verification_status = 4;
  // The commit time of the latest main commit in the repository.
  google.protobuf.Timestamp latest_commit_time = 5;
  // The SPDX license ID of the latest main commit in the repository.
  string latest_spdx_license_id = 6;
}

// RepositoryService is the Repository service.
service RepositoryService {
  // GetRepository gets a repository by ID.
  rpc GetRepository(GetRepositoryRequest) returns (GetRepositoryResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // GetRepositoryByFullName gets a repository by full name.
  rpc GetRepositoryByFullName(GetRepositoryByFullNameRequest) returns (GetRepositoryByFullNameResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // ListRepositories lists all repositories.
  rpc ListRepositories(ListRepositoriesRequest) returns (ListRepositoriesResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // ListUserRepositories lists all repositories belonging to a user.
  rpc ListUserRepositories(ListUserRepositoriesRequest) returns (ListUserRepositoriesResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // ListRepositoriesUserCanAccess lists all repositories a user can access.
  rpc ListRepositoriesUserCanAccess(ListRepositoriesUserCanAccessRequest) returns (ListRepositoriesUserCanAccessResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // ListOrganizationRepositories lists all repositories for an organization.
  rpc ListOrganizationRepositories(ListOrganizationRepositoriesRequest) returns (ListOrganizationRepositoriesResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // CreateRepositoryByFullName creates a new repository by full name.
  rpc CreateRepositoryByFullName(CreateRepositoryByFullNameRequest) returns (CreateRepositoryByFullNameResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // DeleteRepository deletes a repository.
  rpc DeleteRepository(DeleteRepositoryRequest) returns (DeleteRepositoryResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // DeleteRepositoryByFullName deletes a repository by full name.
  rpc DeleteRepositoryByFullName(DeleteRepositoryByFullNameRequest) returns (DeleteRepositoryByFullNameResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // DeprecateRepositoryByName deprecates the repository.
  rpc DeprecateRepositoryByName(DeprecateRepositoryByNameRequest) returns (DeprecateRepositoryByNameResponse);
  // UndeprecateRepositoryByName makes the repository not deprecated and removes any deprecation_message.
  rpc UndeprecateRepositoryByName(UndeprecateRepositoryByNameRequest) returns (UndeprecateRepositoryByNameResponse);
  // GetRepositoriesByFullName gets repositories by full name. Response order is unspecified.
  // Errors if any of the repositories don't exist or the caller does not have access to any of the repositories.
  rpc GetRepositoriesByFullName(GetRepositoriesByFullNameRequest) returns (GetRepositoriesByFullNameResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // SetRepositoryContributor sets the role of a user in the repository.
  rpc SetRepositoryContributor(SetRepositoryContributorRequest) returns (SetRepositoryContributorResponse);
  // ListRepositoryContributors returns the list of contributors that has an explicit role against the repository.
  // This does not include users who have implicit roles against the repository, unless they have also been
  // assigned a role explicitly.
  rpc ListRepositoryContributors(ListRepositoryContributorsRequest) returns (ListRepositoryContributorsResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // GetRepositorySettings gets the settings of a repository.
  rpc GetRepositorySettings(GetRepositorySettingsRequest) returns (GetRepositorySettingsResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // UpdateRepositorySettingsByName updates the settings of a repository.
  rpc UpdateRepositorySettingsByName(UpdateRepositorySettingsByNameRequest) returns (UpdateRepositorySettingsByNameResponse);
  // GetRepositoriesMetadata gets the metadata of the repositories in the request, the length of repositories in the
  // request should match the length of the metadata in the response, and the order of repositories in the response
  // should match the order of the metadata in the request.
  rpc GetRepositoriesMetadata(GetRepositoriesMetadataRequest) returns (GetRepositoriesMetadataResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // GetRepositoryDependencyDOTString gets the dependency graph DOT string for the repository.
  rpc GetRepositoryDependencyDOTString(GetRepositoryDependencyDOTStringRequest) returns (GetRepositoryDependencyDOTStringResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // AddRepositoryGroup adds an IdP Group to the repository.
  //
  // Only repositories owned by an organization can have groups.
  rpc AddRepositoryGroup(AddRepositoryGroupRequest) returns (AddRepositoryGroupResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // UpdateRepositoryGroup updates an IdP Group for the repository.
  rpc UpdateRepositoryGroup(UpdateRepositoryGroupRequest) returns (UpdateRepositoryGroupResponse) {
    option idempotency_level = IDEMPOTENT;
  }
  // RemoveRepositoryGroup removes an IdP Group from the repository.
  rpc RemoveRepositoryGroup(RemoveRepositoryGroupRequest) returns (RemoveRepositoryGroupResponse) {
    option idempotency_level = IDEMPOTENT;
  }
}

message GetRepositoriesByFullNameRequest {
  // minimum length is 1
  // maximum length is 250
  repeated string full_names = 1;
}

message GetRepositoriesByFullNameResponse {
  repeated Repository repositories = 1;
}

message GetRepositoryRequest {
  string id = 1;
}

message GetRepositoryResponse {
  Repository repository = 1;
  RepositoryCounts counts = 2;
}

message GetRepositoryByFullNameRequest {
  string full_name = 1;
}

message GetRepositoryByFullNameResponse {
  Repository repository = 1;
  RepositoryCounts counts = 2;
}

message ListRepositoriesRequest {
  uint32 page_size = 1;
  // The first page is returned if this is empty.
  string page_token = 2;
  bool reverse = 3;
}

message ListRepositoriesResponse {
  repeated Repository repositories = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message ListUserRepositoriesRequest {
  // The ID of the user whose repositories should be listed.
  string user_id = 1;
  uint32 page_size = 2;
  // The first page is returned if this is empty.
  string page_token = 3;
  bool reverse = 4;
}

message ListUserRepositoriesResponse {
  repeated Repository repositories = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message ListRepositoriesUserCanAccessRequest {
  uint32 page_size = 1;
  // The first page is returned if this is empty.
  string page_token = 2;
  bool reverse = 3;
}

message ListRepositoriesUserCanAccessResponse {
  repeated Repository repositories = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message ListOrganizationRepositoriesRequest {
  // The ID of the organization whose repositories should be listed.
  string organization_id = 1;
  uint32 page_size = 2;
  // The first page is returned if this is empty.
  string page_token = 3;
  bool reverse = 4;
}

message ListOrganizationRepositoriesResponse {
  repeated Repository repositories = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message CreateRepositoryByFullNameRequest {
  // Must be unique across repositories.
  string full_name = 1;
  Visibility visibility = 2;
}

message CreateRepositoryByFullNameResponse {
  Repository repository = 1;
}

message DeleteRepositoryRequest {
  string id = 1;
}

message DeleteRepositoryResponse {}

message DeleteRepositoryByFullNameRequest {
  string full_name = 1;
}

message DeleteRepositoryByFullNameResponse {}

message DeprecateRepositoryByNameRequest {
  string owner_name = 1;
  string repository_name = 2;
  // A message shown along with the deprecation warning for this repository.
  // It must be a utf8 encoded string containing 256 or fewer characters.
  string deprecation_message = 3;
}

message DeprecateRepositoryByNameResponse {
  Repository repository = 1;
}

message UndeprecateRepositoryByNameRequest {
  string owner_name = 1;
  string repository_name = 2;
}

message UndeprecateRepositoryByNameResponse {
  Repository repository = 1;
}

message SetRepositoryContributorRequest {
  // The ID of the repository for which the user's role will be set.
  string repository_id = 1;
  // The ID of the user whose role will be set.
  string user_id = 2;
  // The role to assign to the user.
  // Setting UNSPECIFIED means removing the user's role.
  RepositoryRole repository_role = 3;
}

message SetRepositoryContributorResponse {}

message ListRepositoryContributorsRequest {
  string repository_id = 1;
  uint32 page_size = 2;
  // The first page is returned if this is empty.
  string page_token = 3;
  bool reverse = 4;
}

message ListRepositoryContributorsResponse {
  repeated RepositoryContributor users = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message GetRepositorySettingsRequest {
  // The ID of the repository for which to get the settings.
  string repository_id = 1;
}

message GetRepositorySettingsResponse {
  // The number of outside contributors in the repository,
  // excluding owning-organization's members that have an explicit role.
  uint32 contributors_count = 1;
}

message UpdateRepositorySettingsByNameRequest {
  string owner_name = 1;
  string repository_name = 2;
  // optional, update to visibility will only be made if this is specified.
  Visibility visibility = 3;
  // optional, update to description will only be made when this is present
  optional string description = 4;
  // optional, update to url will only be made when this is present
  optional string url = 5;
  // optional, update to default_branch will only be made when this is present
  optional string default_branch = 6;
}

message UpdateRepositorySettingsByNameResponse {}

message GetRepositoriesMetadataRequest {
  // The list of repository IDs to request the metadata.
  repeated string ids = 1;
}

message GetRepositoriesMetadataResponse {
  repeated RepositoryMetadata metadata = 1;
}

message GetRepositoryDependencyDOTStringRequest {
  // The owner of the BSR repository.
  string owner = 1;
  // The name of the BSR repository.
  string repository = 2;
  // Optional reference (if unspecified, will use the repository's default_branch).
  string reference = 3;
}

message GetRepositoryDependencyDOTStringResponse {
  // The string DOT representation of the dependency graph for the repository.
  //
  // DOT language reference: https://graphviz.org/doc/info/lang.html
  string dot_string = 1;
}

message AddRepositoryGroupRequest {
  // The ID of the repository for which to add the group.
  string repository_id = 1;
  // The name of the group to add.
  string group_name = 2;
  // The role to associate with any user who is added to the repository via this group.
  //
  // Any user who maps to this repository via this group will be granted this role. If no role is
  // set, the user will be granted the containing-organization's base repository role.
  RepositoryRole role_override = 3;
}

message AddRepositoryGroupResponse {}

message UpdateRepositoryGroupRequest {
  // The ID of the repository to which this group belongs.
  string repository_id = 1;
  // The name of the group to update.
  string group_name = 2;
  // The role to associate with this repository group.
  //
  // Setting this to 'UNSPECIFIED' will remove the override. Leaving this unset will not update this
  // property.
  optional RepositoryRole role_override = 3;
}

message UpdateRepositoryGroupResponse {}

message RemoveRepositoryGroupRequest {
  // The ID of the repository for which to remove the group.
  string repository_id = 1;
  // The name of the group to remove.
  string group_name = 2;
}

message RemoveRepositoryGroupResponse {}
