go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/common/services/milo_internal.ts (about)

     1  // Copyright 2020 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import stableStringify from 'fast-json-stable-stringify';
    16  
    17  import { Build, BuilderID, BuilderItem } from '@/common/services/buildbucket';
    18  import { cached, CacheOption } from '@/generic_libs/tools/cached_fn';
    19  import { PrpcClientExt } from '@/generic_libs/tools/prpc_client_ext';
    20  
    21  import { GitilesCommit } from './common';
    22  
    23  /**
    24   * Manually coded type definition and classes for milo internal service.
    25   * TODO(weiweilin): To be replaced by code generated version once we have one.
    26   * source: https://chromium.googlesource.com/infra/luci/luci-go/+/HEAD/milo/api/service/v1/rpc.proto
    27   */
    28  
    29  export interface QueryBlamelistRequest {
    30    readonly gitilesCommit: GitilesCommit;
    31    readonly builder: BuilderID;
    32    readonly pageSize?: number;
    33    readonly pageToken?: string;
    34  }
    35  
    36  export interface CommitUser {
    37    readonly name: string;
    38    readonly email: string;
    39    readonly time: string;
    40  }
    41  
    42  export const enum CommitTreeDiffChangeType {
    43    Add = 'ADD',
    44    Copy = 'COPY',
    45    Delete = 'DELETE',
    46    Modify = 'MODIFY',
    47    Rename = 'RENAME',
    48  }
    49  
    50  export interface CommitTreeDiff {
    51    readonly type: CommitTreeDiffChangeType;
    52    readonly oldId: string;
    53    readonly oldMode: number;
    54    readonly oldPath: string;
    55    readonly newId: string;
    56    readonly newMode: number;
    57    readonly newPath: string;
    58  }
    59  
    60  export interface GitCommit {
    61    readonly id: string;
    62    readonly tree: string;
    63    readonly parents?: string[];
    64    readonly author: CommitUser;
    65    readonly committer: CommitUser;
    66    readonly message: string;
    67    readonly treeDiff: CommitTreeDiff[];
    68  }
    69  
    70  export interface QueryBlamelistResponse {
    71    readonly commits?: GitCommit[];
    72    readonly nextPageToken?: string;
    73    readonly precedingCommit?: GitCommit;
    74  }
    75  
    76  export interface GetProjectCfgRequest {
    77    readonly project: string;
    78  }
    79  
    80  export interface Project {
    81    readonly logoUrl?: string;
    82    readonly bugUrlTemplate?: string;
    83    readonly metadataConfig?: MetadataConfig;
    84  }
    85  
    86  export interface MetadataConfig {
    87    readonly testMetadataProperties?: readonly DisplayRule[];
    88  }
    89  export interface DisplayRule {
    90    readonly schema: string;
    91    readonly displayItems: readonly DisplayItem[];
    92  }
    93  
    94  export interface DisplayItem {
    95    readonly displayName: string;
    96    readonly path: string;
    97  }
    98  
    99  export interface BugTemplate {
   100    readonly summary?: string;
   101    readonly description?: string;
   102    readonly monorailProject?: string;
   103    readonly components?: readonly string[];
   104  }
   105  
   106  export interface QueryRecentBuildsRequest {
   107    readonly builder: BuilderID;
   108    readonly pageSize?: number;
   109    readonly pageToken?: string;
   110  }
   111  
   112  export interface QueryRecentBuildsResponse {
   113    readonly builds?: readonly Build[];
   114    readonly nextPageToken?: string;
   115  }
   116  
   117  export interface ListBuildersRequest {
   118    readonly project?: string;
   119    readonly group?: string;
   120    readonly pageSize?: number;
   121    readonly pageToken?: string;
   122  }
   123  
   124  export interface ListBuildersResponse {
   125    readonly builders?: readonly BuilderItem[];
   126    readonly nextPageToken?: string;
   127  }
   128  
   129  export interface ProjectItem {
   130    readonly id: string;
   131  }
   132  
   133  export interface ListProjectsRequest {
   134    readonly pageSize?: number;
   135    readonly pageToken?: string;
   136  }
   137  
   138  export interface ListProjectsResponse {
   139    readonly projects?: readonly ProjectListItem[];
   140    readonly nextPageToken?: string;
   141  }
   142  
   143  export interface ProjectListItem {
   144    readonly id: string;
   145    readonly logoUrl?: string;
   146  }
   147  
   148  export interface QueryBuilderStatsRequest {
   149    readonly builder: BuilderID;
   150  }
   151  
   152  export interface BuilderStats {
   153    readonly builder: BuilderID;
   154    readonly pendingBuildsCount?: number;
   155    readonly runningBuildsCount?: number;
   156  }
   157  
   158  export interface BatchCheckPermissionsRequest {
   159    readonly realm: string;
   160    readonly permissions: readonly string[];
   161  }
   162  
   163  export interface BatchCheckPermissionsResponse {
   164    readonly results: { readonly [key: string]: boolean };
   165  }
   166  
   167  export interface ConsolePredicate {
   168    readonly project?: string;
   169    readonly builder?: BuilderID;
   170  }
   171  
   172  export interface QueryConsolesRequest {
   173    readonly predicate: ConsolePredicate;
   174    readonly pageSize?: number;
   175    readonly pageToken?: string;
   176  }
   177  
   178  export interface Builder {
   179    readonly id: BuilderID;
   180    readonly category?: string;
   181    readonly shortName?: string;
   182  }
   183  
   184  export interface Console {
   185    readonly id: string;
   186    readonly name: string;
   187    readonly realm: string;
   188    readonly repoUrl: string;
   189    readonly builders?: readonly Builder[];
   190  }
   191  
   192  export interface QueryConsolesResponse {
   193    readonly consoles?: readonly Console[];
   194    readonly nextPageToken?: string;
   195  }
   196  
   197  export interface QueryConsoleSnapshotsRequest {
   198    readonly predicate: ConsolePredicate;
   199    readonly pageSize?: number;
   200    readonly pageToken?: string;
   201  }
   202  
   203  export interface BuilderSnapshot {
   204    readonly builder: BuilderID;
   205    readonly build?: Build;
   206  }
   207  
   208  export interface ConsoleSnapshot {
   209    readonly console: Console;
   210    readonly builderSnapshots?: readonly BuilderSnapshot[];
   211  }
   212  
   213  export interface QueryConsoleSnapshotsResponse {
   214    readonly snapshots?: readonly ConsoleSnapshot[];
   215    readonly nextPageToken?: string;
   216  }
   217  
   218  export class MiloInternal {
   219    static readonly SERVICE = 'luci.milo.v1.MiloInternal';
   220    private readonly cachedCallFn: (
   221      opt: CacheOption,
   222      method: string,
   223      message: object,
   224    ) => Promise<unknown>;
   225  
   226    constructor(client: PrpcClientExt) {
   227      this.cachedCallFn = cached(
   228        (method: string, message: object) =>
   229          client.call(MiloInternal.SERVICE, method, message),
   230        {
   231          key: (method, message) => `${method}-${stableStringify(message)}`,
   232        },
   233      );
   234    }
   235  
   236    async queryBlamelist(req: QueryBlamelistRequest, cacheOpt: CacheOption = {}) {
   237      return (await this.cachedCallFn(
   238        cacheOpt,
   239        'QueryBlamelist',
   240        req,
   241      )) as QueryBlamelistResponse;
   242    }
   243  
   244    async getProjectCfg(req: GetProjectCfgRequest, cacheOpt: CacheOption = {}) {
   245      return (await this.cachedCallFn(cacheOpt, 'GetProjectCfg', req)) as Project;
   246    }
   247  
   248    async queryRecentBuilds(
   249      req: QueryRecentBuildsRequest,
   250      cacheOpt: CacheOption = {},
   251    ) {
   252      return (await this.cachedCallFn(
   253        cacheOpt,
   254        'QueryRecentBuilds',
   255        req,
   256      )) as QueryRecentBuildsResponse;
   257    }
   258  
   259    async listBuilders(req: ListBuildersRequest, cacheOpt: CacheOption = {}) {
   260      return (await this.cachedCallFn(
   261        cacheOpt,
   262        'ListBuilders',
   263        req,
   264      )) as ListBuildersResponse;
   265    }
   266  
   267    async listProjects(req: ListProjectsRequest, cacheOpt: CacheOption = {}) {
   268      return (await this.cachedCallFn(
   269        cacheOpt,
   270        'ListProjects',
   271        req,
   272      )) as ListProjectsResponse;
   273    }
   274  
   275    async queryBuilderStats(
   276      req: QueryBuilderStatsRequest,
   277      cacheOpt: CacheOption = {},
   278    ) {
   279      return (await this.cachedCallFn(
   280        cacheOpt,
   281        'QueryBuilderStats',
   282        req,
   283      )) as BuilderStats;
   284    }
   285  
   286    async batchCheckPermissions(
   287      req: BatchCheckPermissionsRequest,
   288      cacheOpt: CacheOption = {},
   289    ) {
   290      return (await this.cachedCallFn(
   291        cacheOpt,
   292        'BatchCheckPermissions',
   293        req,
   294      )) as BatchCheckPermissionsResponse;
   295    }
   296  
   297    async queryConsoles(req: QueryConsolesRequest, cacheOpt: CacheOption = {}) {
   298      return (await this.cachedCallFn(
   299        cacheOpt,
   300        'QueryConsoles',
   301        req,
   302      )) as QueryConsolesResponse;
   303    }
   304  
   305    async queryConsoleSnapshots(
   306      req: QueryConsoleSnapshotsRequest,
   307      cacheOpt: CacheOption = {},
   308    ) {
   309      return (await this.cachedCallFn(
   310        cacheOpt,
   311        'QueryConsoleSnapshots',
   312        req,
   313      )) as QueryConsoleSnapshotsResponse;
   314    }
   315  }