('');
27 | const qs = QueryString.parse(location.search);
28 | const fileName = qs.fileName as string;
29 | const prefix = qs.prefix as string;
30 | const fullFileLocation = `${prefix}/${fileName}`;
31 |
32 | useEffect(() => {
33 | const formatResponse = (data: string) => {
34 | const splitFileName = fileName.split('.');
35 | if (splitFileName[splitFileName.length - 1] === 'json') {
36 | return `${JSON.stringify(
37 | JSON.parse(data),
38 | null,
39 | 2
40 | )}`;
41 | } else {
42 | return data;
43 | }
44 | };
45 |
46 | const downloadFileCallback: DownloadFileCallback = (err, response) => {
47 | if (err) {
48 | console.error(err);
49 | } else {
50 | setFileData(formatResponse(response.getFileData()));
51 | }
52 | };
53 |
54 | downloadFile(
55 | fullFileLocation,
56 | authContext.tokenId,
57 | downloadFileCallback
58 | );
59 | }, [isLoggedIn, fullFileLocation, fileName, authContext.tokenId]);
60 |
61 | return ;
62 | };
63 |
64 | export default FilePage;
65 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/components/FlakyTestTable/styles.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import Paper from '@material-ui/core/Paper';
3 | const TestNameCellWidth = 400;
4 | export const GridContainer = styled.div<{ width: number }>`
5 | display: flex;
6 | width: ${({ width }) => width}px;
7 | `;
8 |
9 | export const GridBodyContainer = styled.div`
10 | width: 100%;
11 | `;
12 |
13 | export const HeaderContainer = styled.div`
14 | width: ${TestNameCellWidth}px;
15 | `;
16 |
17 | export const NoTestCell = styled.div`
18 | background-color: grey;
19 | border: 1px solid black;
20 | `;
21 |
22 | export const PassingTestCell = styled.div`
23 | background-color: #4eb369;
24 | border: 1px solid black;
25 | cursor: pointer;
26 | `;
27 |
28 | export const FailingTestCell = styled.div`
29 | background-color: #d73f35;
30 | border: 1px solid black;
31 | display: flex;
32 | align-items: center;
33 | justify-content: center;
34 | text-align: center;
35 | font-size: 14px;
36 | cursor: pointer;
37 | `;
38 |
39 | export const TestNameCell = styled.div`
40 | width: ${TestNameCellWidth - 10}px !important;
41 | display: flex;
42 | align-items: center;
43 | padding-left: 10px;
44 | border-bottom: 1px solid black;
45 | border-right: 1px solid black;
46 | text-overflow: ellipsis;
47 | overflow: hidden;
48 | white-space: nowrap;
49 | `;
50 |
51 | export const TestNameDividerCell = styled.div`
52 | width: ${TestNameCellWidth - 10}px !important;
53 | display: flex;
54 | align-items: center;
55 | padding-left: 10px;
56 | border-right: 1px solid black;
57 | background-color: #e0e1dd;
58 | font-weight: bold;
59 | text-overflow: ellipsis;
60 | overflow: hidden;
61 | white-space: nowrap;
62 | `;
63 |
64 | export const DividerCell = styled.div`
65 | background-color: #e0e1dd;
66 | `;
67 |
68 | export const TitleHeaderCell = styled.div`
69 | display: flex;
70 | align-items: center;
71 | border-right: 1px solid black;
72 | `;
73 |
74 | export const HeaderCell = styled.div`
75 | display: flex;
76 | align-items: center;
77 | justify-content: center;
78 | text-align: center;
79 | `;
80 |
81 | export const Container = styled(Paper)`
82 | width: 91.5%;
83 | height: calc(98vh - 120px);
84 | margin-left: auto;
85 | margin-right: auto;
86 | margin-top: 20px;
87 | outline: none;
88 | `;
89 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/api/file_processing_error_pb.d.ts:
--------------------------------------------------------------------------------
1 | import * as jspb from "google-protobuf"
2 |
3 | export class FileProcessingErrors extends jspb.Message {
4 | getFileUid(): string;
5 | setFileUid(value: string): FileProcessingErrors;
6 |
7 | getFileProcessingErrorsList(): Array;
8 | setFileProcessingErrorsList(value: Array): FileProcessingErrors;
9 | clearFileProcessingErrorsList(): FileProcessingErrors;
10 | addFileProcessingErrors(value?: FileProcessingError, index?: number): FileProcessingError;
11 |
12 | serializeBinary(): Uint8Array;
13 | toObject(includeInstance?: boolean): FileProcessingErrors.AsObject;
14 | static toObject(includeInstance: boolean, msg: FileProcessingErrors): FileProcessingErrors.AsObject;
15 | static serializeBinaryToWriter(message: FileProcessingErrors, writer: jspb.BinaryWriter): void;
16 | static deserializeBinary(bytes: Uint8Array): FileProcessingErrors;
17 | static deserializeBinaryFromReader(message: FileProcessingErrors, reader: jspb.BinaryReader): FileProcessingErrors;
18 | }
19 |
20 | export namespace FileProcessingErrors {
21 | export type AsObject = {
22 | fileUid: string,
23 | fileProcessingErrorsList: Array,
24 | }
25 | }
26 |
27 | export class FileProcessingError extends jspb.Message {
28 | getType(): FileProcessingErrorType;
29 | setType(value: FileProcessingErrorType): FileProcessingError;
30 |
31 | getMessage(): string;
32 | setMessage(value: string): FileProcessingError;
33 |
34 | serializeBinary(): Uint8Array;
35 | toObject(includeInstance?: boolean): FileProcessingError.AsObject;
36 | static toObject(includeInstance: boolean, msg: FileProcessingError): FileProcessingError.AsObject;
37 | static serializeBinaryToWriter(message: FileProcessingError, writer: jspb.BinaryWriter): void;
38 | static deserializeBinary(bytes: Uint8Array): FileProcessingError;
39 | static deserializeBinaryFromReader(message: FileProcessingError, reader: jspb.BinaryReader): FileProcessingError;
40 | }
41 |
42 | export namespace FileProcessingError {
43 | export type AsObject = {
44 | type: FileProcessingErrorType,
45 | message: string,
46 | }
47 | }
48 |
49 | export enum FileProcessingErrorType {
50 | FILE_PROCESSING_ERROR_TYPE_UNSPECIFIED = 0,
51 | GENERIC_READ_ERROR = 1,
52 | GENERIC_PARSE_ERROR = 2,
53 | FILE_TOO_LARGE = 3,
54 | OUTPUT_TOO_LARGE = 4,
55 | ACCESS_DENIED = 5,
56 | DEADLINE_EXCEEDED = 6,
57 | NOT_FOUND = 7,
58 | FILE_EMPTY = 8,
59 | }
60 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/components/GoogleButton/index.tsx:
--------------------------------------------------------------------------------
1 | // BackButton Component
2 | /**
3 | * Component that handles user login / logout via google sign-in
4 | * @packageDocumentation
5 | */
6 | import React, { useState, useContext } from 'react';
7 | import { GoogleLogout, GoogleLogin } from 'react-google-login';
8 | import styled from 'styled-components';
9 | import config from '../../config/ConfigLoader';
10 | import { AuthContext } from '../../contexts/AuthContext';
11 |
12 | const CustomGoogleLogin = styled(GoogleLogin)`
13 | width: 100px;
14 | height: 56px;
15 | margin-top: auto;
16 | margin-bottom: auto;
17 | margin-right: 5px;
18 | `;
19 |
20 | const CustomGoogleLogout = styled(GoogleLogout)`
21 | width: 100px;
22 | height: 56px;
23 | margin-top: auto;
24 | margin-bottom: auto;
25 | margin-right: 5px;
26 | `;
27 |
28 | /** GoogleButton State */
29 | interface State {
30 | /** True if user is logged in*/
31 | isLoggedIn: boolean;
32 | }
33 |
34 | /*
35 | Button that handles google login and logout
36 | */
37 | export const GoogleButton: React.FC = () => {
38 | const authContext = useContext(AuthContext);
39 | const [isLoggedIn, setIsLoggedIn] = useState(false);
40 |
41 | const logIn = (response) => {
42 | authContext.setTokenId(response.tokenObj.id_token);
43 | setIsLoggedIn(true);
44 | };
45 |
46 | const logOut = () => {
47 | authContext.setTokenId('');
48 | setIsLoggedIn(false);
49 | };
50 |
51 | const handleError = () => {};
52 |
53 | return (
54 | <>
55 | {!isLoggedIn && (
56 |
65 | )}
66 | {isLoggedIn && (
67 |
75 | )}
76 | >
77 | );
78 | };
79 |
80 | export default GoogleButton;
81 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/auth/auth_interceptor.py:
--------------------------------------------------------------------------------
1 | """
2 | gRPC Interceptor that verifies that users are signed in with google
3 | and have the appropriate permissions to make requests to resultstore instance
4 | """
5 | import grpc
6 | from google.oauth2 import id_token
7 | from google.auth.transport import requests
8 |
9 |
10 | def _unary_unary_rpc_terminator(code, details):
11 | def terminate(ignored_request, context):
12 | context.abort(code, details)
13 |
14 | return grpc.unary_unary_rpc_method_handler(terminate)
15 |
16 |
17 | class AuthInterceptor(grpc.ServerInterceptor):
18 | """
19 | Interceptor to verify that client calls are authenticated
20 | """
21 | def __init__(self, code, details, creds):
22 | self._creds = creds
23 | self._terminator = _unary_unary_rpc_terminator(code, details)
24 |
25 | def intercept_service(self, continuation, handler_call_details):
26 | """
27 | Intercepts incoming RPCs before handing them over to a handler.
28 |
29 | Args:
30 | continuation: A function that takes a HandlerCallDetails and
31 | proceeds to invoke the next interceptor in the chain, if any,
32 | or the RPC handler lookup logic, with the call details passed
33 | as an argument, and returns an RpcMethodHandler instance if
34 | the RPC is considered serviced, or None otherwise.
35 | handler_call_details: A HandlerCallDetails describing the RPC.
36 |
37 | Returns:
38 | An RpcMethodHandler with which the RPC may be serviced if the
39 | interceptor chooses to service this RPC, or None otherwise.
40 | """
41 | metadata = dict(handler_call_details.invocation_metadata)
42 | if 'id_token' not in metadata:
43 | return self._terminator
44 | token = metadata['id_token']
45 |
46 | try:
47 | idinfo = id_token.verify_oauth2_token(token, requests.Request(),
48 | self._creds.get_client_id())
49 | if idinfo['iss'] not in [
50 | 'accounts.google.com', 'https://accounts.google.com'
51 | ]:
52 | raise ValueError('Wrong issuer.')
53 | user_email = idinfo['email']
54 | except ValueError:
55 | return self._terminator
56 |
57 | verified = self._creds.verify_user(user_email)
58 | if verified:
59 | return continuation(handler_call_details)
60 | return self._terminator
61 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/components/InvocationTable/utils.ts:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 | import invocation_pb from '../../api/invocation_pb';
3 | import common_pb from '../../api/common_pb';
4 | import { Data } from './types';
5 | import { getDate } from '../../utils';
6 |
7 | /*
8 | Parses invocation returned from search into invocation table consumable data
9 |
10 | Args:
11 | Invocation: An invocation to be parsed
12 |
13 | Returns:
14 | Table consumable object
15 | */
16 | export const parseInvocationTableData = (
17 | invocation: invocation_pb.Invocation
18 | ): Data => {
19 | const statusAttributes = invocation.getStatusAttributes();
20 | const invocationAttributes = invocation.getInvocationAttributes();
21 | const workspaceInfo = invocation.getWorkspaceInfo();
22 | const timing = invocation.getTiming();
23 |
24 | const status = getStatus(statusAttributes);
25 | const name = invocation.getName();
26 | const labels = getLabels(invocationAttributes);
27 | const date = getDate(timing);
28 | const duration = getDuration(timing);
29 | const user = getUser(invocationAttributes, workspaceInfo);
30 |
31 | return { status, name, labels, date, duration, user };
32 | };
33 |
34 | /*
35 | Helper functions to format invocation table data
36 | */
37 |
38 | const getUser = (
39 | invocationAttributes: invocation_pb.InvocationAttributes | undefined,
40 | workspaceInfo: invocation_pb.WorkspaceInfo | undefined
41 | ) => {
42 | const hostname = (workspaceInfo && workspaceInfo.getHostname()) || '';
43 | const usersList = (invocationAttributes &&
44 | invocationAttributes.getUsersList()) || ['None'];
45 | const userPrefix = (usersList.length > 0 && usersList[0]) || 'None';
46 | return `${userPrefix}@${hostname}`;
47 | };
48 |
49 | const getStatus = (
50 | statusAttributes: common_pb.StatusAttributes | undefined
51 | ) => {
52 | return (statusAttributes && statusAttributes.getDescription()) || 'UNKNOWN';
53 | };
54 |
55 | const getLabels = (
56 | invocationAttributes: invocation_pb.InvocationAttributes
57 | ) => {
58 | const labelsList =
59 | (invocationAttributes && invocationAttributes.getLabelsList()) || [];
60 | return labelsList.join(',');
61 | };
62 |
63 | const getDuration = (timing: common_pb.Timing | undefined) => {
64 | const timingDuration = timing.getDuration();
65 | const durationSeconds =
66 | (timingDuration && timingDuration.getSeconds()) || 0;
67 | return moment
68 | .utc(moment.duration(durationSeconds, 's').asMilliseconds())
69 | .format('mm:ss');
70 | };
71 |
--------------------------------------------------------------------------------
/resultstoreui/bigstore_client.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pathlib
3 | from google import auth
4 | from google.cloud import storage
5 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import (file_pb2)
6 |
7 |
8 | class BigStoreClient(object):
9 | """ Client for BigStore"""
10 | def __init__(self, credentials, project_name, storage_dir, bucket_name):
11 | """
12 | Initialize BigStore Client
13 |
14 | Args:
15 | credentials (Credentials): credentials and scope for the client
16 | project_name (str): Porject name to connect to
17 | storage_dir (str): Specify directory to store uploaded files
18 | bucket_name (str): Bucket name to upload files to
19 |
20 | Return:
21 | List of files that were uploaded
22 | """
23 | self.credentials = credentials
24 | self.storage_dir = storage_dir
25 | self.bucket_name = bucket_name
26 | self.project_name = project_name
27 |
28 | def upload_files_to_bigstore(self, files):
29 | """
30 | Upload files to bigstore (aka google cloud storage).
31 |
32 | Args:
33 | files (Sequence[str]): list of file path names
34 | storage_dir (str): cloud storage dir where files should be saved
35 | bucket_name (str): cloud storage bucket name
36 |
37 | Returns:
38 | uploaded_files: A list of file_pb2.File() objects
39 |
40 | Raises:
41 | FileNotFoundError: if a file is missing.
42 | """
43 | prefix = self.storage_dir
44 | credentials = auth.default(scopes=self.credentials.get_scopes())
45 |
46 | # Create the client using the credentials and specifying a project ID.
47 | storage_client = storage.Client(credentials=credentials[0],
48 | project=self.project_name)
49 | bucket = storage_client.get_bucket(self.bucket_name)
50 | uploaded_files = []
51 |
52 | for pathname in files:
53 | path = pathlib.Path(pathname)
54 | if not path.exists() or not path.is_file():
55 | raise FileNotFoundError(pathname)
56 | filename = pathname.split('/')[-1]
57 | blob = bucket.blob(os.path.join(prefix, filename))
58 | blob.upload_from_filename(pathname)
59 | file_object = file_pb2.File(
60 | uid=filename,
61 | uri='googlefile:/bigstore/{}/{}'.format(
62 | self.bucket_name, prefix + filename))
63 | uploaded_files.append(file_object)
64 | return uploaded_files
65 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoresearchapi/duration_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: duration.proto
4 |
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import message as _message
7 | from google.protobuf import reflection as _reflection
8 | from google.protobuf import symbol_database as _symbol_database
9 | # @@protoc_insertion_point(imports)
10 |
11 | _sym_db = _symbol_database.Default()
12 |
13 |
14 |
15 |
16 | DESCRIPTOR = _descriptor.FileDescriptor(
17 | name='duration.proto',
18 | package='resultstoresearch.v1',
19 | syntax='proto3',
20 | serialized_options=None,
21 | create_key=_descriptor._internal_create_key,
22 | serialized_pb=b'\n\x0e\x64uration.proto\x12\x14resultstoresearch.v1\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x62\x06proto3'
23 | )
24 |
25 |
26 |
27 |
28 | _DURATION = _descriptor.Descriptor(
29 | name='Duration',
30 | full_name='resultstoresearch.v1.Duration',
31 | filename=None,
32 | file=DESCRIPTOR,
33 | containing_type=None,
34 | create_key=_descriptor._internal_create_key,
35 | fields=[
36 | _descriptor.FieldDescriptor(
37 | name='seconds', full_name='resultstoresearch.v1.Duration.seconds', index=0,
38 | number=1, type=3, cpp_type=2, label=1,
39 | has_default_value=False, default_value=0,
40 | message_type=None, enum_type=None, containing_type=None,
41 | is_extension=False, extension_scope=None,
42 | serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
43 | _descriptor.FieldDescriptor(
44 | name='nanos', full_name='resultstoresearch.v1.Duration.nanos', index=1,
45 | number=2, type=5, cpp_type=1, label=1,
46 | has_default_value=False, default_value=0,
47 | message_type=None, enum_type=None, containing_type=None,
48 | is_extension=False, extension_scope=None,
49 | serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
50 | ],
51 | extensions=[
52 | ],
53 | nested_types=[],
54 | enum_types=[
55 | ],
56 | serialized_options=None,
57 | is_extendable=False,
58 | syntax='proto3',
59 | extension_ranges=[],
60 | oneofs=[
61 | ],
62 | serialized_start=40,
63 | serialized_end=82,
64 | )
65 |
66 | DESCRIPTOR.message_types_by_name['Duration'] = _DURATION
67 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
68 |
69 | Duration = _reflection.GeneratedProtocolMessageType('Duration', (_message.Message,), {
70 | 'DESCRIPTOR' : _DURATION,
71 | '__module__' : 'duration_pb2'
72 | # @@protoc_insertion_point(class_scope:resultstoresearch.v1.Duration)
73 | })
74 | _sym_db.RegisterMessage(Duration)
75 |
76 |
77 | # @@protoc_insertion_point(module_scope)
78 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoresearchapi/timestamp_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: timestamp.proto
4 |
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import message as _message
7 | from google.protobuf import reflection as _reflection
8 | from google.protobuf import symbol_database as _symbol_database
9 | # @@protoc_insertion_point(imports)
10 |
11 | _sym_db = _symbol_database.Default()
12 |
13 |
14 |
15 |
16 | DESCRIPTOR = _descriptor.FileDescriptor(
17 | name='timestamp.proto',
18 | package='resultstoresearch.v1',
19 | syntax='proto3',
20 | serialized_options=None,
21 | create_key=_descriptor._internal_create_key,
22 | serialized_pb=b'\n\x0ftimestamp.proto\x12\x14resultstoresearch.v1\"+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x62\x06proto3'
23 | )
24 |
25 |
26 |
27 |
28 | _TIMESTAMP = _descriptor.Descriptor(
29 | name='Timestamp',
30 | full_name='resultstoresearch.v1.Timestamp',
31 | filename=None,
32 | file=DESCRIPTOR,
33 | containing_type=None,
34 | create_key=_descriptor._internal_create_key,
35 | fields=[
36 | _descriptor.FieldDescriptor(
37 | name='seconds', full_name='resultstoresearch.v1.Timestamp.seconds', index=0,
38 | number=1, type=3, cpp_type=2, label=1,
39 | has_default_value=False, default_value=0,
40 | message_type=None, enum_type=None, containing_type=None,
41 | is_extension=False, extension_scope=None,
42 | serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
43 | _descriptor.FieldDescriptor(
44 | name='nanos', full_name='resultstoresearch.v1.Timestamp.nanos', index=1,
45 | number=2, type=5, cpp_type=1, label=1,
46 | has_default_value=False, default_value=0,
47 | message_type=None, enum_type=None, containing_type=None,
48 | is_extension=False, extension_scope=None,
49 | serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
50 | ],
51 | extensions=[
52 | ],
53 | nested_types=[],
54 | enum_types=[
55 | ],
56 | serialized_options=None,
57 | is_extendable=False,
58 | syntax='proto3',
59 | extension_ranges=[],
60 | oneofs=[
61 | ],
62 | serialized_start=41,
63 | serialized_end=84,
64 | )
65 |
66 | DESCRIPTOR.message_types_by_name['Timestamp'] = _TIMESTAMP
67 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
68 |
69 | Timestamp = _reflection.GeneratedProtocolMessageType('Timestamp', (_message.Message,), {
70 | 'DESCRIPTOR' : _TIMESTAMP,
71 | '__module__' : 'timestamp_pb2'
72 | # @@protoc_insertion_point(class_scope:resultstoresearch.v1.Timestamp)
73 | })
74 | _sym_db.RegisterMessage(Timestamp)
75 |
76 |
77 | # @@protoc_insertion_point(module_scope)
78 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/components/SearchWrapper/ToolSelect/index.tsx:
--------------------------------------------------------------------------------
1 | // ToolSelect Component
2 | /**
3 | * Dropdown to filter invocation search on tooltype
4 | * @packageDocumentation
5 | */
6 | import React, { useEffect } from 'react';
7 | import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
8 | import FormControl from '@material-ui/core/FormControl';
9 | import InputLabel from '@material-ui/core/InputLabel';
10 | import Select from '@material-ui/core/Select';
11 | import MenuItem from '@material-ui/core/MenuItem';
12 | import { getInitialState } from '../../../api/client/client';
13 |
14 | /** ToolSelect Props */
15 | export interface ToolSelectProps {
16 | /** List of tools available for selection in dropdown */
17 | toolsList: Array;
18 | /** Set the list of tools available for selection in the dropdown */
19 | setToolsList: (toolsList: Array) => void;
20 | /** Currently selected tool */
21 | selectedTool: string;
22 | /** Callback fired when a tool is selected from the dropdown */
23 | setSelectedTool: (selectedTool: string) => void;
24 | }
25 |
26 | const useStyles = makeStyles((theme: Theme) =>
27 | createStyles({
28 | formControl: {
29 | margin: theme.spacing(1),
30 | minWidth: 120,
31 | },
32 | })
33 | );
34 |
35 | const createToolItems = (toolsList: ToolSelectProps['toolsList']) => {
36 | return toolsList.map((tool, index) => (
37 |
40 | ));
41 | };
42 |
43 | /** Tool Select Component */
44 | export const ToolSelect: React.FC = ({
45 | selectedTool,
46 | setSelectedTool,
47 | toolsList,
48 | setToolsList,
49 | }) => {
50 | const classes = useStyles();
51 | useEffect(() => {
52 | getInitialState(setToolsList);
53 | }, [setToolsList]);
54 |
55 | return (
56 |
61 |
62 | Tool Type
63 |
64 |
78 |
79 | );
80 | };
81 |
82 | export default ToolSelect;
83 |
--------------------------------------------------------------------------------
/resultstoresearch/e2e/cypress/integration/app.spec.ts:
--------------------------------------------------------------------------------
1 | context("ResultStoreSearch Home Page", () => {
2 | beforeEach(() => {
3 | cy.visit("/");
4 | });
5 |
6 | it("Should display an error if the query is invalid", () => {
7 | cy.get('input[id="search-bar"]').type("incorrect query");
8 | cy.get('input[id="search-bar"]').type("{enter}");
9 | cy.get('p[id="search-error"]').contains("Invalid query string");
10 | });
11 |
12 | it("Should render the invocations in the table", () => {
13 | cy.get('input[id="search-bar"]').type("a");
14 | cy.get('input[id="search-bar"]').type("{enter}");
15 | cy.get('div[aria-label="row"]').contains(
16 | "invocations/51be7217-9798-4448-adf8-1e4428c71e9e"
17 | );
18 | cy.get('div[aria-label="row"]').contains("TESTING");
19 | cy.get('div[aria-label="row"]').contains("dank,meme");
20 | cy.get('div[aria-label="row"]').contains("00:06");
21 | cy.get('div[aria-label="row"]').contains("lewiscraig@");
22 | });
23 |
24 | it("Should display tool1 and tool2 in dropdown and have 1 invocation", () => {
25 | cy.get('input[id="search-bar"]').type("a");
26 | cy.get('input[id="search-bar"]').type("{enter}");
27 | cy.get('div[id="tool-select"]').click();
28 | cy.get('li[data-value="tool1"]').contains("tool1");
29 | cy.get('li[data-value="tool2"').contains("tool2");
30 | cy.get('li[data-value="tool2"]').click();
31 | cy.get('input[id="search-bar"]').type("i");
32 | cy.get('input[id="search-bar"]').type("{enter}");
33 | cy.get('input[id="search-bar"]').type("i");
34 | cy.get('input[id="search-bar"]').type("{enter}");
35 | cy.get('div[id="InvocationTable"]')
36 | .find('div[aria-label="row"]')
37 | .should("have.length", 1);
38 | });
39 |
40 | it("Should display tooltip on hover", () => {
41 | cy.get('svg[aria-label="SearchHelp"]').trigger("mouseover");
42 | cy.get('div[class="MuiTooltip-popper"]').contains(
43 | 'Fields that support equals ("=") restrictions:'
44 | );
45 | });
46 |
47 | it("Should open the file modal on file button click", () => {
48 | cy.get('input[id="search-bar"]').type("a");
49 | cy.get('input[id="search-bar"]').type("{enter}");
50 | cy.get('button[title="Close"]').click();
51 | cy.get('div[aria-rowindex="1"]').trigger("mouseover");
52 | cy.get('button[id="FileButton-0"]').click();
53 | cy.get('div[id="FileModal"]').should("have.length", 1);
54 | });
55 |
56 | it("Should render files in the file table", () => {
57 | cy.get('input[id="search-bar"]').type("a");
58 | cy.get('input[id="search-bar"]').type("{enter}");
59 | cy.get('button[title="Close"]').click();
60 | cy.get('div[aria-rowindex="1"]').trigger("mouseover");
61 | cy.get('button[id="FileButton-0"]').click();
62 | cy.get('div[id="InvocationModalRow"]').click();
63 | cy.get('div[id="FileTable"]').contains("test-file");
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/mock/mock_proxy.py:
--------------------------------------------------------------------------------
1 | from resultstoresearch.resultstoresearchapi import (
2 | resultstore_download_pb2_grpc, resultstore_download_pb2)
3 | from resultstoresearch.mock.mock_responses import (
4 | mock_search_invocations_response,
5 | mock_search_invocations_response_with_tools, mock_file, mock_target)
6 | import logging
7 | import grpc
8 | import os
9 |
10 |
11 | class MockProxyServer(resultstore_download_pb2_grpc.ResultStoreDownloadServicer
12 | ):
13 | def SearchInvocations(self, request, context):
14 | """
15 | Proxies the SearchInvocations gRPC call forward
16 |
17 | Args:
18 | request (SearchInvocationsRequest): The search request
19 | context (grpc.Context)
20 |
21 | Returns:
22 | SearchInvocationsResponse
23 | """
24 | if request.query == 'incorrect query':
25 | context.set_details('Invalid query string')
26 | context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
27 | return resultstore_download_pb2.SearchInvocationsResponse()
28 | elif request.tool:
29 | return mock_search_invocations_response_with_tools()
30 | return mock_search_invocations_response()
31 |
32 | def ListTargets(self, request, context):
33 | """
34 | Mocks listing of targets for a given invocation
35 |
36 | Args:
37 | request (ListTargetsRequest): The ListTargets request
38 | context (grpc.Context)
39 |
40 | Returns:
41 | ListTargetsResponse
42 | """
43 | return [mock_target()]
44 |
45 | def ListTargetSubFiles(self, request, context):
46 | """
47 | Mocks listing of files under a given target
48 |
49 | Args:
50 | request (ListTargetSubFilesRequest): The ListTargetSubFiles request
51 | context (grpc.Context)
52 |
53 | Returns:
54 | ListTargetSubFilesResponse
55 | """
56 | return [mock_file(), mock_file()]
57 |
58 | def GetInitialState(self, request, context):
59 | """
60 | Gets the initial state of the client
61 |
62 | Args:
63 | request (GetInitialStateRequest): The initial state request
64 | context (grpc.Context)
65 |
66 | Returns:
67 | GetInitialStateResponse
68 | """
69 | return resultstore_download_pb2.GetInitialStateResponse(
70 | tools_list=['tool1', 'tool2'])
71 |
72 | def DownloadFile(self, request, context):
73 | """
74 | Mocks Downloading a file from bigstore
75 |
76 | Args:
77 | request (DownloadFileRequest): The DownloadFile request
78 | context (grpc.Context)
79 |
80 | Returns:
81 | DownloadFileResponse
82 | """
83 | with open('./mock/dummy_file.html', 'r') as file:
84 | data = file.read()
85 | return resultstore_download_pb2.DownloadFileResponse(
86 | file_data=data)
87 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/mock/mock_responses.py:
--------------------------------------------------------------------------------
1 | from resultstoresearch.resultstoresearchapi import (
2 | invocation_pb2, common_pb2, timestamp_pb2, duration_pb2,
3 | resultstore_download_pb2, file_pb2, wrappers_pb2, target_pb2)
4 | """
5 | Used by mock proxy to generate mock responses
6 | """
7 |
8 |
9 | def mock_search_invocations_response():
10 | response = resultstore_download_pb2.SearchInvocationsResponse(
11 | invocations=[mock_invocation(),
12 | mock_invocation('invo1', 'tool1')],
13 | tools_list=['tool1', 'tool2'])
14 | return response
15 |
16 |
17 | def mock_search_invocations_response_with_tools():
18 | response = resultstore_download_pb2.SearchInvocationsResponse(
19 | invocations=[mock_invocation('invo1', 'tool1')],
20 | tools_list=['tool1', 'tool2'])
21 | return response
22 |
23 |
24 | def mock_invocation(
25 | invocation_name='invocations/51be7217-9798-4448-adf8-1e4428c71e9e',
26 | tool_tag=''):
27 | invocation = invocation_pb2.Invocation(
28 | name=invocation_name,
29 | status_attributes=mock_status_attributes(),
30 | timing=mock_timing(),
31 | invocation_attributes=mock_invocation_attributes(),
32 | workspace_info=mock_workspace_info(tool_tag),
33 | files=[mock_file()])
34 | return invocation
35 |
36 |
37 | def mock_status_attributes():
38 | status_attributes = common_pb2.StatusAttributes(
39 | status=common_pb2.Status.Value('TESTING'), description='TESTING')
40 | return status_attributes
41 |
42 |
43 | def mock_timing():
44 | timing = common_pb2.Timing(start_time=mock_timestamp(),
45 | duration=mock_duration())
46 | return timing
47 |
48 |
49 | def mock_timestamp():
50 | timestamp = timestamp_pb2.Timestamp(seconds=1589929143, nanos=0)
51 | return timestamp
52 |
53 |
54 | def mock_duration():
55 | duration = duration_pb2.Duration(seconds=6, nanos=0)
56 | return duration
57 |
58 |
59 | def mock_invocation_attributes():
60 | invocation_attributes = invocation_pb2.InvocationAttributes(
61 | users=(['lewiscraig']), labels=(['dank', 'meme']))
62 | return invocation_attributes
63 |
64 |
65 | def mock_workspace_info(tool_tag=''):
66 | workspace_info = invocation_pb2.WorkspaceInfo(
67 | hostname='piestation.mtv.corp.google.com',
68 | command_lines=mock_command_lines(),
69 | tool_tag=tool_tag)
70 | return workspace_info
71 |
72 |
73 | def mock_command_lines():
74 | command_line = invocation_pb2.CommandLine(label='SiVal Test Runner',
75 | tool='ManifestRunner')
76 | return [command_line]
77 |
78 |
79 | def mock_target():
80 | return target_pb2.Target(name='mock-target', files=[mock_file()])
81 |
82 |
83 | def mock_file():
84 | return file_pb2.File(uid='test-file',
85 | length=mock_int_64_value(),
86 | content_type='text/html')
87 |
88 |
89 | def mock_int_64_value():
90 | return wrappers_pb2.Int64Value(value=45)
91 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/api/file_pb.d.ts:
--------------------------------------------------------------------------------
1 | import * as jspb from "google-protobuf"
2 |
3 | import * as wrappers_pb from './wrappers_pb';
4 |
5 | export class File extends jspb.Message {
6 | getUid(): string;
7 | setUid(value: string): File;
8 |
9 | getUri(): string;
10 | setUri(value: string): File;
11 |
12 | getLength(): wrappers_pb.Int64Value | undefined;
13 | setLength(value?: wrappers_pb.Int64Value): File;
14 | hasLength(): boolean;
15 | clearLength(): File;
16 |
17 | getContentType(): string;
18 | setContentType(value: string): File;
19 |
20 | getArchiveEntry(): ArchiveEntry | undefined;
21 | setArchiveEntry(value?: ArchiveEntry): File;
22 | hasArchiveEntry(): boolean;
23 | clearArchiveEntry(): File;
24 |
25 | getContentViewer(): string;
26 | setContentViewer(value: string): File;
27 |
28 | getHidden(): boolean;
29 | setHidden(value: boolean): File;
30 |
31 | getDescription(): string;
32 | setDescription(value: string): File;
33 |
34 | getDigest(): string;
35 | setDigest(value: string): File;
36 |
37 | getHashType(): File.HashType;
38 | setHashType(value: File.HashType): File;
39 |
40 | serializeBinary(): Uint8Array;
41 | toObject(includeInstance?: boolean): File.AsObject;
42 | static toObject(includeInstance: boolean, msg: File): File.AsObject;
43 | static serializeBinaryToWriter(message: File, writer: jspb.BinaryWriter): void;
44 | static deserializeBinary(bytes: Uint8Array): File;
45 | static deserializeBinaryFromReader(message: File, reader: jspb.BinaryReader): File;
46 | }
47 |
48 | export namespace File {
49 | export type AsObject = {
50 | uid: string,
51 | uri: string,
52 | length?: wrappers_pb.Int64Value.AsObject,
53 | contentType: string,
54 | archiveEntry?: ArchiveEntry.AsObject,
55 | contentViewer: string,
56 | hidden: boolean,
57 | description: string,
58 | digest: string,
59 | hashType: File.HashType,
60 | }
61 |
62 | export enum HashType {
63 | HASH_TYPE_UNSPECIFIED = 0,
64 | MD5 = 1,
65 | SHA1 = 2,
66 | SHA256 = 3,
67 | }
68 | }
69 |
70 | export class ArchiveEntry extends jspb.Message {
71 | getPath(): string;
72 | setPath(value: string): ArchiveEntry;
73 |
74 | getLength(): wrappers_pb.Int64Value | undefined;
75 | setLength(value?: wrappers_pb.Int64Value): ArchiveEntry;
76 | hasLength(): boolean;
77 | clearLength(): ArchiveEntry;
78 |
79 | getContentType(): string;
80 | setContentType(value: string): ArchiveEntry;
81 |
82 | serializeBinary(): Uint8Array;
83 | toObject(includeInstance?: boolean): ArchiveEntry.AsObject;
84 | static toObject(includeInstance: boolean, msg: ArchiveEntry): ArchiveEntry.AsObject;
85 | static serializeBinaryToWriter(message: ArchiveEntry, writer: jspb.BinaryWriter): void;
86 | static deserializeBinary(bytes: Uint8Array): ArchiveEntry;
87 | static deserializeBinaryFromReader(message: ArchiveEntry, reader: jspb.BinaryReader): ArchiveEntry;
88 | }
89 |
90 | export namespace ArchiveEntry {
91 | export type AsObject = {
92 | path: string,
93 | length?: wrappers_pb.Int64Value.AsObject,
94 | contentType: string,
95 | }
96 | }
97 |
98 |
--------------------------------------------------------------------------------
/resultstoresearch/client/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `yarn start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `yarn test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `yarn build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `yarn eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `yarn build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/bazel
2 | # Edit at https://www.gitignore.io/?templates=bazel
3 |
4 | ### Bazel ###
5 | # gitignore template for Bazel build system
6 | # website: https://bazel.build/
7 |
8 | # Ignore all bazel-* symlinks. There is no full list since this can change
9 | # based on the name of the directory bazel is cloned into.
10 | /bazel-*
11 |
12 | # End of https://www.gitignore.io/api/bazel
13 |
14 | # Created by https://www.gitignore.io/api/python
15 | # Edit at https://www.gitignore.io/?templates=python
16 |
17 | ### Python ###
18 | # Byte-compiled / optimized / DLL files
19 | __pycache__/
20 | *.py[cod]
21 | *$py.class
22 |
23 | # C extensions
24 | *.so
25 |
26 | # Distribution / packaging
27 | .Python
28 | build/
29 | develop-eggs/
30 | dist/
31 | downloads/
32 | eggs/
33 | .eggs/
34 | lib/
35 | lib64/
36 | parts/
37 | sdist/
38 | var/
39 | wheels/
40 | pip-wheel-metadata/
41 | share/python-wheels/
42 | *.egg-info/
43 | .installed.cfg
44 | *.egg
45 | MANIFEST
46 |
47 | # PyInstaller
48 | # Usually these files are written by a python script from a template
49 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
50 | *.manifest
51 | *.spec
52 |
53 | # Installer logs
54 | pip-log.txt
55 | pip-delete-this-directory.txt
56 |
57 | # Unit test / coverage reports
58 | htmlcov/
59 | .tox/
60 | .nox/
61 | .coverage
62 | .coverage.*
63 | .cache
64 | nosetests.xml
65 | coverage.xml
66 | *.cover
67 | .hypothesis/
68 | .pytest_cache/
69 |
70 | # Translations
71 | *.mo
72 | *.pot
73 |
74 | # Scrapy stuff:
75 | .scrapy
76 |
77 | # Sphinx documentation
78 | docs/_build/
79 |
80 | # PyBuilder
81 | target/
82 |
83 | # pyenv
84 | .python-version
85 |
86 | # pipenv
87 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
88 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
89 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
90 | # install all needed dependencies.
91 | #Pipfile.lock
92 |
93 | # celery beat schedule file
94 | celerybeat-schedule
95 |
96 | # SageMath parsed files
97 | *.sage.py
98 |
99 | # Spyder project settings
100 | .spyderproject
101 | .spyproject
102 |
103 | # Rope project settings
104 | .ropeproject
105 |
106 | # Mr Developer
107 | .mr.developer.cfg
108 | .project
109 | .pydevproject
110 |
111 | # mkdocs documentation
112 | /site
113 |
114 | # mypy
115 | .mypy_cache/
116 | .dmypy.json
117 | dmypy.json
118 |
119 | # Pyre type checker
120 | .pyre/
121 |
122 | # Node Modules
123 | resultstoresearch/client/node_modules
124 | resultstoresearch/e2e/node_modules
125 | resultstoresearch/e2e/cypress/videos
126 | resultstoresearch/e2e/cypress/screenshots
127 |
128 | # vscode
129 | /.vscode
130 |
131 | # Docker
132 | resultstoresearch/ci/.env
133 |
134 | # Cypress
135 | resultstoresearch/e2e/cypress/screenshots
136 | resultstoresearch/e2e/cypress/videos
137 |
138 | # Docs
139 | resultstoresearch/client/docs
140 |
141 | # End of https://www.gitignore.io/api/python
142 |
143 | .env
144 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/components/StatusIcon/index.tsx:
--------------------------------------------------------------------------------
1 | // StatusIcon Component
2 | /**
3 | * Icon used to signify status of an invocation
4 | * @packageDocumentation
5 | */
6 | import React from 'react';
7 | import CheckIcon from '@material-ui/icons/Check';
8 | import BuildIcon from '@material-ui/icons/Build';
9 | import DirectionsRunIcon from '@material-ui/icons/DirectionsRun';
10 | import TimerIcon from '@material-ui/icons/Timer';
11 | import HelpOutlineIcon from '@material-ui/icons/HelpOutline';
12 | import ErrorIcon from '@material-ui/icons/Error';
13 |
14 | /** StatusIcon Props */
15 | interface Props {
16 | /** Type of status to be displayed */
17 | name:
18 | | 'PASS'
19 | | 'BUILDING'
20 | | 'BUILT'
21 | | 'FAILED_TO_BUILD'
22 | | 'TESTING'
23 | | 'FAILED'
24 | | 'TIMED_OUT'
25 | | 'CANCELLED'
26 | | 'TOOL_FAILED'
27 | | 'UNKNOWN'
28 | | 'SKIPPED';
29 | /** Size of display icon svg */
30 | size?: number;
31 | /** Display icon style */
32 | style?: React.CSSProperties;
33 | }
34 |
35 | const StatusIcon: React.FC = ({ name, style }) => {
36 | switch (name) {
37 | case 'PASS': {
38 | return (
39 |
44 | );
45 | }
46 | case 'BUILDING': {
47 | return (
48 |
53 | );
54 | }
55 | case 'TESTING': {
56 | return (
57 |
62 | );
63 | }
64 | case 'TIMED_OUT': {
65 | return (
66 |
71 | );
72 | }
73 | case 'UNKNOWN': {
74 | return (
75 |
80 | );
81 | }
82 | case 'FAILED': {
83 | return (
84 |
89 | );
90 | }
91 | default: {
92 | return (
93 |
98 | );
99 | }
100 | }
101 | };
102 |
103 | export default StatusIcon;
104 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Resultstore Search
2 |
3 | Service to search and render invocations and tests in resultstore.
4 |
5 | ## Client Documentation
6 |
7 | Client component documentation can be viewed [here](https://google.github.io/resultstoreui/)
8 |
9 | ## Prerequisites
10 |
11 | 1. Docker and docker-compose installed [here](https://www.docker.com/)
12 | 2. Generate [service account](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
13 | 3. Enable the following permissions on the service account
14 |
15 | ```
16 | Cloud Source Tools Core - Developer
17 | Cloud Datastore User
18 | Storage Object Viewer
19 | Viewer
20 | ```
21 |
22 | 4. Generate a [client id](https://developers.google.com/identity/sign-in/web/sign-in#create_authorization_credentials)
23 | 5. Configure .env file in ./resultstoresearch/ci following example.env
24 | 6. Add eligible users to the cloudsourcetoolscore.developer role in your GCP project
25 |
26 | ## Usage
27 |
28 | Locally:
29 |
30 | ```shell
31 | ./startup
32 | ```
33 |
34 | Navigate to [localhost](http://localhost/)
35 |
36 | ## Overview
37 |
38 | ### Main Page
39 |
40 | Page where users can search, filter, and view invocation information
41 |
42 | 
43 |
44 | ### Top Bar
45 |
46 | 
47 |
48 | #### Tool Type Selection
49 |
50 | Dropdown thats allows a user to select a tool type to filter search results by.
51 |
52 | 
53 |
54 | #### Search Bar
55 |
56 | Enter queries to search for invocations. The search bar features an autocomplete typeahead for fields that can be filtered on.
57 |
58 | 
59 |
60 | #### Search Button
61 |
62 | Initiates a search for invocations based on the query in the search bar
63 |
64 | 
65 |
66 | #### Flaky Test Button
67 |
68 | Initiates the flaky test interface for the current query in the search bar.
69 |
70 | 
71 |
72 | #### Google Login / Logout Button
73 |
74 | Google login / logout button for authentication
75 |
76 | 
77 |
78 | ### Invocation Table
79 |
80 | Table that lists the result of an invocation search
81 |
82 | #### File Modal
83 |
84 | Users can view files associated with the current invocation
85 |
86 | 
87 |
88 | ## Flaky Test Page
89 |
90 | Users can view the results of tests over time with different invocations.
91 |
92 | - Grey: No test was run
93 | - Green: Test Success
94 | - Red: Test Failed
95 |
96 | 
97 |
--------------------------------------------------------------------------------
/resultstoreui/resultstoreapi/cloud/devtools/resultstore/v2/gapic/result_store_download_client_config.py:
--------------------------------------------------------------------------------
1 | config = {
2 | "interfaces": {
3 | "google.devtools.resultstore.v2.ResultStoreDownload": {
4 | "retry_codes": {
5 | "idempotent": [
6 | "DEADLINE_EXCEEDED",
7 | "UNAVAILABLE"
8 | ],
9 | "non_idempotent": []
10 | },
11 | "retry_params": {
12 | "default": {
13 | "initial_retry_delay_millis": 100,
14 | "retry_delay_multiplier": 1.3,
15 | "max_retry_delay_millis": 60000,
16 | "initial_rpc_timeout_millis": 20000,
17 | "rpc_timeout_multiplier": 1.0,
18 | "max_rpc_timeout_millis": 20000,
19 | "total_timeout_millis": 600000
20 | }
21 | },
22 | "methods": {
23 | "GetInvocation": {
24 | "timeout_millis": 60000,
25 | "retry_codes_name": "idempotent",
26 | "retry_params_name": "default"
27 | },
28 | "SearchInvocations": {
29 | "timeout_millis": 60000,
30 | "retry_codes_name": "idempotent",
31 | "retry_params_name": "default"
32 | },
33 | "GetInvocationDownloadMetadata": {
34 | "timeout_millis": 60000,
35 | "retry_codes_name": "idempotent",
36 | "retry_params_name": "default"
37 | },
38 | "GetConfiguration": {
39 | "timeout_millis": 60000,
40 | "retry_codes_name": "idempotent",
41 | "retry_params_name": "default"
42 | },
43 | "ListConfigurations": {
44 | "timeout_millis": 60000,
45 | "retry_codes_name": "idempotent",
46 | "retry_params_name": "default"
47 | },
48 | "GetTarget": {
49 | "timeout_millis": 60000,
50 | "retry_codes_name": "idempotent",
51 | "retry_params_name": "default"
52 | },
53 | "ListTargets": {
54 | "timeout_millis": 60000,
55 | "retry_codes_name": "idempotent",
56 | "retry_params_name": "default"
57 | },
58 | "GetConfiguredTarget": {
59 | "timeout_millis": 60000,
60 | "retry_codes_name": "idempotent",
61 | "retry_params_name": "default"
62 | },
63 | "ListConfiguredTargets": {
64 | "timeout_millis": 60000,
65 | "retry_codes_name": "idempotent",
66 | "retry_params_name": "default"
67 | },
68 | "GetAction": {
69 | "timeout_millis": 60000,
70 | "retry_codes_name": "idempotent",
71 | "retry_params_name": "default"
72 | },
73 | "ListActions": {
74 | "timeout_millis": 60000,
75 | "retry_codes_name": "idempotent",
76 | "retry_params_name": "default"
77 | },
78 | "GetFileSet": {
79 | "timeout_millis": 60000,
80 | "retry_codes_name": "idempotent",
81 | "retry_params_name": "default"
82 | },
83 | "ListFileSets": {
84 | "timeout_millis": 60000,
85 | "retry_codes_name": "idempotent",
86 | "retry_params_name": "default"
87 | },
88 | "TraverseFileSets": {
89 | "timeout_millis": 60000,
90 | "retry_codes_name": "idempotent",
91 | "retry_params_name": "default"
92 | }
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoreapi/cloud/devtools/resultstore/v2/gapic/result_store_download_client_config.py:
--------------------------------------------------------------------------------
1 | config = {
2 | "interfaces": {
3 | "google.devtools.resultstore.v2.ResultStoreDownload": {
4 | "retry_codes": {
5 | "idempotent": [
6 | "DEADLINE_EXCEEDED",
7 | "UNAVAILABLE"
8 | ],
9 | "non_idempotent": []
10 | },
11 | "retry_params": {
12 | "default": {
13 | "initial_retry_delay_millis": 100,
14 | "retry_delay_multiplier": 1.3,
15 | "max_retry_delay_millis": 60000,
16 | "initial_rpc_timeout_millis": 20000,
17 | "rpc_timeout_multiplier": 1.0,
18 | "max_rpc_timeout_millis": 20000,
19 | "total_timeout_millis": 600000
20 | }
21 | },
22 | "methods": {
23 | "GetInvocation": {
24 | "timeout_millis": 60000,
25 | "retry_codes_name": "idempotent",
26 | "retry_params_name": "default"
27 | },
28 | "SearchInvocations": {
29 | "timeout_millis": 60000,
30 | "retry_codes_name": "idempotent",
31 | "retry_params_name": "default"
32 | },
33 | "GetInvocationDownloadMetadata": {
34 | "timeout_millis": 60000,
35 | "retry_codes_name": "idempotent",
36 | "retry_params_name": "default"
37 | },
38 | "GetConfiguration": {
39 | "timeout_millis": 60000,
40 | "retry_codes_name": "idempotent",
41 | "retry_params_name": "default"
42 | },
43 | "ListConfigurations": {
44 | "timeout_millis": 60000,
45 | "retry_codes_name": "idempotent",
46 | "retry_params_name": "default"
47 | },
48 | "GetTarget": {
49 | "timeout_millis": 60000,
50 | "retry_codes_name": "idempotent",
51 | "retry_params_name": "default"
52 | },
53 | "ListTargets": {
54 | "timeout_millis": 60000,
55 | "retry_codes_name": "idempotent",
56 | "retry_params_name": "default"
57 | },
58 | "GetConfiguredTarget": {
59 | "timeout_millis": 60000,
60 | "retry_codes_name": "idempotent",
61 | "retry_params_name": "default"
62 | },
63 | "ListConfiguredTargets": {
64 | "timeout_millis": 60000,
65 | "retry_codes_name": "idempotent",
66 | "retry_params_name": "default"
67 | },
68 | "GetAction": {
69 | "timeout_millis": 60000,
70 | "retry_codes_name": "idempotent",
71 | "retry_params_name": "default"
72 | },
73 | "ListActions": {
74 | "timeout_millis": 60000,
75 | "retry_codes_name": "idempotent",
76 | "retry_params_name": "default"
77 | },
78 | "GetFileSet": {
79 | "timeout_millis": 60000,
80 | "retry_codes_name": "idempotent",
81 | "retry_params_name": "default"
82 | },
83 | "ListFileSets": {
84 | "timeout_millis": 60000,
85 | "retry_codes_name": "idempotent",
86 | "retry_params_name": "default"
87 | },
88 | "TraverseFileSets": {
89 | "timeout_millis": 60000,
90 | "retry_codes_name": "idempotent",
91 | "retry_params_name": "default"
92 | }
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/docs/code-of-conduct.md:
--------------------------------------------------------------------------------
1 | # Google Open Source Community Guidelines
2 |
3 | At Google, we recognize and celebrate the creativity and collaboration of open
4 | source contributors and the diversity of skills, experiences, cultures, and
5 | opinions they bring to the projects and communities they participate in.
6 |
7 | Every one of Google's open source projects and communities are inclusive
8 | environments, based on treating all individuals respectfully, regardless of
9 | gender identity and expression, sexual orientation, disabilities,
10 | neurodiversity, physical appearance, body size, ethnicity, nationality, race,
11 | age, religion, or similar personal characteristic.
12 |
13 | We value diverse opinions, but we value respectful behavior more.
14 |
15 | Respectful behavior includes:
16 |
17 | * Being considerate, kind, constructive, and helpful.
18 | * Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or
19 | physically threatening behavior, speech, and imagery.
20 | * Not engaging in unwanted physical contact.
21 |
22 | Some Google open source projects [may adopt][] an explicit project code of
23 | conduct, which may have additional detailed expectations for participants. Most
24 | of those projects will use our [modified Contributor Covenant][].
25 |
26 | [may adopt]: https://opensource.google/docs/releasing/preparing/#conduct
27 | [modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/
28 |
29 | ## Resolve peacefully
30 |
31 | We do not believe that all conflict is necessarily bad; healthy debate and
32 | disagreement often yields positive results. However, it is never okay to be
33 | disrespectful.
34 |
35 | If you see someone behaving disrespectfully, you are encouraged to address the
36 | behavior directly with those involved. Many issues can be resolved quickly and
37 | easily, and this gives people more control over the outcome of their dispute.
38 | If you are unable to resolve the matter for any reason, or if the behavior is
39 | threatening or harassing, report it. We are dedicated to providing an
40 | environment where participants feel welcome and safe.
41 |
42 | ## Reporting problems
43 |
44 | Some Google open source projects may adopt a project-specific code of conduct.
45 | In those cases, a Google employee will be identified as the Project Steward,
46 | who will receive and handle reports of code of conduct violations. In the event
47 | that a project hasn’t identified a Project Steward, you can report problems by
48 | emailing opensource@google.com.
49 |
50 | We will investigate every complaint, but you may not receive a direct response.
51 | We will use our discretion in determining when and how to follow up on reported
52 | incidents, which may range from not taking action to permanent expulsion from
53 | the project and project-sponsored spaces. We will notify the accused of the
54 | report and provide them an opportunity to discuss it before any action is
55 | taken. The identity of the reporter will be omitted from the details of the
56 | report supplied to the accused. In potentially harmful situations, such as
57 | ongoing harassment or threats to anyone's safety, we may take action without
58 | notice.
59 |
60 | *This document was adapted from the [IndieWeb Code of Conduct][] and can also
61 | be found at .*
62 |
63 | [IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct
64 |
--------------------------------------------------------------------------------
/resultstoresearch/resultstoresearch/v1/file.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package resultstoresearch.v1;
4 |
5 | import "wrappers.proto";
6 |
7 | // The metadata for a file or an archive file entry.
8 | message File {
9 | // If known, the hash function used to compute this digest.
10 | enum HashType {
11 | // Unknown
12 | HASH_TYPE_UNSPECIFIED = 0;
13 |
14 | // MD5
15 | MD5 = 1;
16 |
17 | // SHA-1
18 | SHA1 = 2;
19 |
20 | // SHA-256
21 | SHA256 = 3;
22 | }
23 |
24 | // The identifier of the file or archive entry.
25 | // User-provided, must be unique for the repeated field it is in. When an
26 | // Append RPC is called with a Files field populated, if a File already exists
27 | // with this ID, that File will be overwritten with the new File proto.
28 | string uid = 1;
29 |
30 | // The URI of a file.
31 | // This could also be the URI of an entire archive.
32 | // Most log data doesn't need to be stored forever, so a ttl is suggested.
33 | // Note that if you ever move or delete the file at this URI, the link from
34 | // the server will be broken.
35 | string uri = 2;
36 |
37 | // (Optional) The length of the file in bytes. Allows the filesize to be
38 | // shown in the UI. Omit if file is still being written or length is
39 | // not known. This could also be the length of an entire archive.
40 | Int64Value length = 3;
41 |
42 | // (Optional) The content-type (aka MIME-type) of the file. This is sent to
43 | // the web browser so it knows how to handle the file. (e.g. text/plain,
44 | // image/jpeg, text/html, etc). For zip archives, use "application/zip".
45 | string content_type = 4;
46 |
47 | // (Optional) If the above path, length, and content_type are referring to an
48 | // archive, and you wish to refer to a particular entry within that archive,
49 | // put the particular archive entry data here.
50 | ArchiveEntry archive_entry = 5;
51 |
52 | // (Optional) A url to a content display app/site for this file or archive
53 | // entry.
54 | string content_viewer = 6;
55 |
56 | // (Optional) Whether to hide this file or archive entry in the UI. Defaults
57 | // to false. A checkbox lets users see hidden files, but they're hidden by
58 | // default.
59 | bool hidden = 7;
60 |
61 | // (Optional) A short description of what this file or archive entry
62 | // contains. This description should help someone viewing the list of these
63 | // files to understand the purpose of this file and what they would want to
64 | // view it for.
65 | string description = 8;
66 |
67 | // (Optional) digest of this file in hexadecimal-like string if known.
68 | string digest = 9;
69 |
70 | // (Optional) The algorithm corresponding to the digest if known.
71 | HashType hash_type = 10;
72 | }
73 |
74 | // Information specific to an entry in an archive.
75 | message ArchiveEntry {
76 | // The relative path of the entry within the archive.
77 | string path = 1;
78 |
79 | // (Optional) The uncompressed length of the archive entry in bytes. Allows
80 | // the entry size to be shown in the UI. Omit if the length is not known.
81 | Int64Value length = 2;
82 |
83 | // (Optional) The content-type (aka MIME-type) of the archive entry. (e.g.
84 | // text/plain, image/jpeg, text/html, etc). This is sent to the web browser
85 | // so it knows how to handle the entry.
86 | string content_type = 3;
87 | }
88 |
--------------------------------------------------------------------------------
/resultstoreui/resultstoreui.py:
--------------------------------------------------------------------------------
1 | from base64 import b64encode
2 | from absl import (flags, app)
3 | from resultstore_client import ResultStoreClient
4 | from credentials import Credentials
5 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import common_pb2
6 |
7 | FLAGS = flags.FLAGS
8 |
9 |
10 | def initialize_flags():
11 | flags.DEFINE_string(
12 | 'command', '',
13 | 'Available commands to execute: get-invocation, create-invocation, single-upload'
14 | )
15 | flags.DEFINE_string('config_id', 'default', 'Config Id')
16 | flags.DEFINE_string('target_name', '', 'Target Name')
17 | flags.DEFINE_string('invocation_id', '', 'Invocation ID')
18 | flags.DEFINE_string('authorization_token', '', 'Authorization Token')
19 | flags.DEFINE_string('action_type', 'TEST', 'Action Type')
20 | flags.DEFINE_string('invocation_name', '', 'Invocation Name')
21 | flags.DEFINE_string('bigstore_project_name',
22 | 'google.com:gchips-productivity',
23 | 'The project name for the bigstore client')
24 | flags.DEFINE_enum('status', 'PASSED', common_pb2.Status.keys(),
25 | 'Status of this action (if command not provided)')
26 | flags.DEFINE_string('bucket_name', 'sival-logs',
27 | 'Google Cloud Storage Bucket Name')
28 | flags.DEFINE_list('files', [], 'files to be uploaded with the action')
29 | flags.DEFINE_string(
30 | 'channel_target', 'resultstore.googleapis.com',
31 | 'The host and port of the service that the channel is created to')
32 | flags.DEFINE_bool(
33 | 'create_config', True,
34 | 'Boolean to control creation of configuration during single or batch upload'
35 | )
36 | flags.DEFINE_string('resume_token', '',
37 | 'Current resume token for batch uplaods')
38 | flags.DEFINE_string('next_resume_token', '',
39 | 'Next resume token for batch uploads')
40 |
41 |
42 | def main(argv):
43 | resultstore_creds = Credentials()
44 | resultstore_client = ResultStoreClient(resultstore_creds, FLAGS)
45 | resume_token = b64encode(bytes(FLAGS.resume_token, 'utf-8'))
46 | next_resume_token = b64encode(bytes(FLAGS.next_resume_token, 'utf-8'))
47 | with resultstore_creds.create_secure_channel(
48 | FLAGS.channel_target) as channel:
49 | if not FLAGS.command:
50 | raise Exception(
51 | 'No command specified! Please specific a command with --command'
52 | )
53 | elif FLAGS.command == 'get-invocation':
54 | resultstore_client.get_invocation(FLAGS.invocation_name)
55 | elif FLAGS.command == 'create-invocation':
56 | resultstore_client.create_invocation()
57 | elif FLAGS.command == 'single-upload':
58 | resultstore_client.single_upload()
59 | elif FLAGS.command == 'batch-upload':
60 | resultstore_client.batch_upload_wrapper(resume_token,
61 | next_resume_token)
62 | elif FLAGS.command == 'finalize-batch-upload':
63 | resultstore_client.finalize_batch_upload(resume_token,
64 | next_resume_token,
65 | FLAGS.invocation_id)
66 | else:
67 | raise Exception('Command not found: {}'.format(FLAGS.command))
68 |
69 |
70 | if __name__ == '__main__':
71 | initialize_flags()
72 | app.run(main)
73 |
--------------------------------------------------------------------------------
/resultstoreui/resultstoreapi/cloud/devtools/resultstore/v2/types.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Copyright 2020 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 |
18 | from __future__ import absolute_import
19 | import sys
20 |
21 | from google.api_core.protobuf_helpers import get_messages
22 |
23 | from google.cloud.devtools.resultstore.v2.proto import action_pb2
24 | from google.cloud.devtools.resultstore.v2.proto import common_pb2
25 | from google.cloud.devtools.resultstore.v2.proto import configuration_pb2
26 | from google.cloud.devtools.resultstore.v2.proto import configured_target_pb2
27 | from google.cloud.devtools.resultstore.v2.proto import coverage_pb2
28 | from google.cloud.devtools.resultstore.v2.proto import coverage_summary_pb2
29 | from google.cloud.devtools.resultstore.v2.proto import download_metadata_pb2
30 | from google.cloud.devtools.resultstore.v2.proto import file_pb2
31 | from google.cloud.devtools.resultstore.v2.proto import file_processing_error_pb2
32 | from google.cloud.devtools.resultstore.v2.proto import file_set_pb2
33 | from google.cloud.devtools.resultstore.v2.proto import invocation_pb2
34 | from google.cloud.devtools.resultstore.v2.proto import resultstore_download_pb2
35 | from google.cloud.devtools.resultstore.v2.proto import resultstore_file_download_pb2
36 | from google.cloud.devtools.resultstore.v2.proto import resultstore_upload_pb2
37 | from google.cloud.devtools.resultstore.v2.proto import target_pb2
38 | from google.cloud.devtools.resultstore.v2.proto import test_suite_pb2
39 | from google.cloud.devtools.resultstore.v2.proto import upload_metadata_pb2
40 | from google.protobuf import duration_pb2
41 | from google.protobuf import empty_pb2
42 | from google.protobuf import field_mask_pb2
43 | from google.protobuf import timestamp_pb2
44 | from google.protobuf import wrappers_pb2
45 |
46 |
47 | _shared_modules = [
48 | duration_pb2,
49 | empty_pb2,
50 | field_mask_pb2,
51 | timestamp_pb2,
52 | wrappers_pb2,
53 | ]
54 |
55 | _local_modules = [
56 | action_pb2,
57 | common_pb2,
58 | configuration_pb2,
59 | configured_target_pb2,
60 | coverage_pb2,
61 | coverage_summary_pb2,
62 | download_metadata_pb2,
63 | file_pb2,
64 | file_processing_error_pb2,
65 | file_set_pb2,
66 | invocation_pb2,
67 | resultstore_download_pb2,
68 | resultstore_file_download_pb2,
69 | resultstore_upload_pb2,
70 | target_pb2,
71 | test_suite_pb2,
72 | upload_metadata_pb2,
73 | ]
74 |
75 | names = []
76 |
77 | for module in _shared_modules: # pragma: NO COVER
78 | for name, message in get_messages(module).items():
79 | setattr(sys.modules[__name__], name, message)
80 | names.append(name)
81 | for module in _local_modules:
82 | for name, message in get_messages(module).items():
83 | message.__module__ = 'google.cloud.devtools.resultstore.v2.types'
84 | setattr(sys.modules[__name__], name, message)
85 | names.append(name)
86 |
87 |
88 | __all__ = tuple(sorted(names))
89 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoreapi/cloud/devtools/resultstore/v2/types.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Copyright 2020 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 |
18 | from __future__ import absolute_import
19 | import sys
20 |
21 | from google.api_core.protobuf_helpers import get_messages
22 |
23 | from google.cloud.devtools.resultstore.v2.proto import action_pb2
24 | from google.cloud.devtools.resultstore.v2.proto import common_pb2
25 | from google.cloud.devtools.resultstore.v2.proto import configuration_pb2
26 | from google.cloud.devtools.resultstore.v2.proto import configured_target_pb2
27 | from google.cloud.devtools.resultstore.v2.proto import coverage_pb2
28 | from google.cloud.devtools.resultstore.v2.proto import coverage_summary_pb2
29 | from google.cloud.devtools.resultstore.v2.proto import download_metadata_pb2
30 | from google.cloud.devtools.resultstore.v2.proto import file_pb2
31 | from google.cloud.devtools.resultstore.v2.proto import file_processing_error_pb2
32 | from google.cloud.devtools.resultstore.v2.proto import file_set_pb2
33 | from google.cloud.devtools.resultstore.v2.proto import invocation_pb2
34 | from google.cloud.devtools.resultstore.v2.proto import resultstore_download_pb2
35 | from google.cloud.devtools.resultstore.v2.proto import resultstore_file_download_pb2
36 | from google.cloud.devtools.resultstore.v2.proto import resultstore_upload_pb2
37 | from google.cloud.devtools.resultstore.v2.proto import target_pb2
38 | from google.cloud.devtools.resultstore.v2.proto import test_suite_pb2
39 | from google.cloud.devtools.resultstore.v2.proto import upload_metadata_pb2
40 | from google.protobuf import duration_pb2
41 | from google.protobuf import empty_pb2
42 | from google.protobuf import field_mask_pb2
43 | from google.protobuf import timestamp_pb2
44 | from google.protobuf import wrappers_pb2
45 |
46 |
47 | _shared_modules = [
48 | duration_pb2,
49 | empty_pb2,
50 | field_mask_pb2,
51 | timestamp_pb2,
52 | wrappers_pb2,
53 | ]
54 |
55 | _local_modules = [
56 | action_pb2,
57 | common_pb2,
58 | configuration_pb2,
59 | configured_target_pb2,
60 | coverage_pb2,
61 | coverage_summary_pb2,
62 | download_metadata_pb2,
63 | file_pb2,
64 | file_processing_error_pb2,
65 | file_set_pb2,
66 | invocation_pb2,
67 | resultstore_download_pb2,
68 | resultstore_file_download_pb2,
69 | resultstore_upload_pb2,
70 | target_pb2,
71 | test_suite_pb2,
72 | upload_metadata_pb2,
73 | ]
74 |
75 | names = []
76 |
77 | for module in _shared_modules: # pragma: NO COVER
78 | for name, message in get_messages(module).items():
79 | setattr(sys.modules[__name__], name, message)
80 | names.append(name)
81 | for module in _local_modules:
82 | for name, message in get_messages(module).items():
83 | message.__module__ = 'google.cloud.devtools.resultstore.v2.types'
84 | setattr(sys.modules[__name__], name, message)
85 | names.append(name)
86 |
87 |
88 | __all__ = tuple(sorted(names))
89 |
--------------------------------------------------------------------------------
/resultstoresearch/client/src/api/coverage_summary_pb.d.ts:
--------------------------------------------------------------------------------
1 | import * as jspb from "google-protobuf"
2 |
3 | import * as common_pb from './common_pb';
4 |
5 | export class LineCoverageSummary extends jspb.Message {
6 | getInstrumentedLineCount(): number;
7 | setInstrumentedLineCount(value: number): LineCoverageSummary;
8 |
9 | getExecutedLineCount(): number;
10 | setExecutedLineCount(value: number): LineCoverageSummary;
11 |
12 | serializeBinary(): Uint8Array;
13 | toObject(includeInstance?: boolean): LineCoverageSummary.AsObject;
14 | static toObject(includeInstance: boolean, msg: LineCoverageSummary): LineCoverageSummary.AsObject;
15 | static serializeBinaryToWriter(message: LineCoverageSummary, writer: jspb.BinaryWriter): void;
16 | static deserializeBinary(bytes: Uint8Array): LineCoverageSummary;
17 | static deserializeBinaryFromReader(message: LineCoverageSummary, reader: jspb.BinaryReader): LineCoverageSummary;
18 | }
19 |
20 | export namespace LineCoverageSummary {
21 | export type AsObject = {
22 | instrumentedLineCount: number,
23 | executedLineCount: number,
24 | }
25 | }
26 |
27 | export class BranchCoverageSummary extends jspb.Message {
28 | getTotalBranchCount(): number;
29 | setTotalBranchCount(value: number): BranchCoverageSummary;
30 |
31 | getExecutedBranchCount(): number;
32 | setExecutedBranchCount(value: number): BranchCoverageSummary;
33 |
34 | getTakenBranchCount(): number;
35 | setTakenBranchCount(value: number): BranchCoverageSummary;
36 |
37 | serializeBinary(): Uint8Array;
38 | toObject(includeInstance?: boolean): BranchCoverageSummary.AsObject;
39 | static toObject(includeInstance: boolean, msg: BranchCoverageSummary): BranchCoverageSummary.AsObject;
40 | static serializeBinaryToWriter(message: BranchCoverageSummary, writer: jspb.BinaryWriter): void;
41 | static deserializeBinary(bytes: Uint8Array): BranchCoverageSummary;
42 | static deserializeBinaryFromReader(message: BranchCoverageSummary, reader: jspb.BinaryReader): BranchCoverageSummary;
43 | }
44 |
45 | export namespace BranchCoverageSummary {
46 | export type AsObject = {
47 | totalBranchCount: number,
48 | executedBranchCount: number,
49 | takenBranchCount: number,
50 | }
51 | }
52 |
53 | export class LanguageCoverageSummary extends jspb.Message {
54 | getLanguage(): common_pb.Language;
55 | setLanguage(value: common_pb.Language): LanguageCoverageSummary;
56 |
57 | getLineSummary(): LineCoverageSummary | undefined;
58 | setLineSummary(value?: LineCoverageSummary): LanguageCoverageSummary;
59 | hasLineSummary(): boolean;
60 | clearLineSummary(): LanguageCoverageSummary;
61 |
62 | getBranchSummary(): BranchCoverageSummary | undefined;
63 | setBranchSummary(value?: BranchCoverageSummary): LanguageCoverageSummary;
64 | hasBranchSummary(): boolean;
65 | clearBranchSummary(): LanguageCoverageSummary;
66 |
67 | serializeBinary(): Uint8Array;
68 | toObject(includeInstance?: boolean): LanguageCoverageSummary.AsObject;
69 | static toObject(includeInstance: boolean, msg: LanguageCoverageSummary): LanguageCoverageSummary.AsObject;
70 | static serializeBinaryToWriter(message: LanguageCoverageSummary, writer: jspb.BinaryWriter): void;
71 | static deserializeBinary(bytes: Uint8Array): LanguageCoverageSummary;
72 | static deserializeBinaryFromReader(message: LanguageCoverageSummary, reader: jspb.BinaryReader): LanguageCoverageSummary;
73 | }
74 |
75 | export namespace LanguageCoverageSummary {
76 | export type AsObject = {
77 | language: common_pb.Language,
78 | lineSummary?: LineCoverageSummary.AsObject,
79 | branchSummary?: BranchCoverageSummary.AsObject,
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/resultstoreui/resultstore_test_utils.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import MagicMock
2 | from resultstore_client import ResultStoreClient
3 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import (
4 | resultstore_download_pb2_grpc, resultstore_download_pb2, invocation_pb2,
5 | configuration_pb2, target_pb2, configured_target_pb2, action_pb2)
6 |
7 |
8 | def create_return_invocation(request):
9 | return invocation_pb2.Invocation(
10 | id={'invocation_id': request.invocation_id})
11 |
12 |
13 | def create_return_target(request):
14 | return target_pb2.Target(name="invocations/{}/targets/{}".format(
15 | request.target.id.invocation_id, request.target.id.target_id),
16 | id={'target_id': request.target.id.target_id})
17 |
18 |
19 | def create_return_configuration(request):
20 | return configuration_pb2.Configuration(
21 | name="invocations/{}/configs/{}".format(
22 | request.configuration.id.invocation_id,
23 | request.configuration.id.configuration_id),
24 | id={'configuration_id': request.configuration.id.configuration_id})
25 |
26 |
27 | def create_return_configured_target(request):
28 | return configured_target_pb2.ConfiguredTarget(
29 | name="invocations/{}/targets/{}/configuredTargets/{}".format(
30 | request.configured_target.id.invocation_id,
31 | request.configured_target.id.target_id,
32 | request.configured_target.id.configuration_id),
33 | id={
34 | 'configuration_id': request.configured_target.id.configuration_id,
35 | 'target_id': request.configured_target.id.target_id,
36 | 'invocation_id': request.configured_target.id.invocation_id
37 | })
38 |
39 |
40 | def create_return_action(request):
41 | return action_pb2.Action(
42 | name="invocations/{}/targets/{}/configuredTargets/{}/actions/{}".
43 | format(request.action.id.invocation_id, request.action.id.target_id,
44 | request.action.id.configuration_id,
45 | request.action.id.action_id),
46 | id={
47 | 'configuration_id': request.action.id.configuration_id,
48 | 'target_id': request.action.id.target_id,
49 | 'invocation_id': request.action.id.invocation_id,
50 | 'action_id': request.action.id.action_id
51 | })
52 |
53 |
54 | def create_finalized_configured_target(request):
55 | split_name = request.name.split('/')
56 | return configured_target_pb2.ConfiguredTarget(name=request.name,
57 | id={
58 | "invocation_id":
59 | split_name[1],
60 | "target_id":
61 | split_name[3],
62 | "configuration_id":
63 | split_name[5]
64 | })
65 |
66 |
67 | def create_finalized_target(request):
68 | split_name = request.name.split('/')
69 | return target_pb2.Target(name=request.name,
70 | id={
71 | "invocation_id": split_name[1],
72 | "target_id": split_name[3],
73 | })
74 |
75 |
76 | def initialize_client(flags, credentials=MagicMock()):
77 | flags.authorization_token = ''
78 | credentials.get_active_channel = MagicMock(return_value=None)
79 | return ResultStoreClient(credentials, flags)
80 |
--------------------------------------------------------------------------------
/resultstoreui/resultstoreapi/cloud/devtools/resultstore_v2/proto/resultstore_file_download_pb2_grpc.py:
--------------------------------------------------------------------------------
1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2 | import grpc
3 |
4 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import resultstore_file_download_pb2 as google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2
5 |
6 |
7 | class ResultStoreFileDownloadStub(object):
8 | """This API allows download of File messages referenced in
9 | ResultStore resources.
10 | """
11 |
12 | def __init__(self, channel):
13 | """Constructor.
14 |
15 | Args:
16 | channel: A grpc.Channel.
17 | """
18 | self.GetFile = channel.unary_stream(
19 | '/google.devtools.resultstore.v2.ResultStoreFileDownload/GetFile',
20 | request_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileRequest.SerializeToString,
21 | response_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileResponse.FromString,
22 | )
23 | self.GetFileTail = channel.unary_unary(
24 | '/google.devtools.resultstore.v2.ResultStoreFileDownload/GetFileTail',
25 | request_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailRequest.SerializeToString,
26 | response_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailResponse.FromString,
27 | )
28 |
29 |
30 | class ResultStoreFileDownloadServicer(object):
31 | """This API allows download of File messages referenced in
32 | ResultStore resources.
33 | """
34 |
35 | def GetFile(self, request, context):
36 | """Retrieves the File with the given uri.
37 | returns a stream of bytes to be stitched together in order.
38 |
39 | An error will be reported in the following cases:
40 | - If the File is not found.
41 | - If the given File uri is badly formatted.
42 | """
43 | context.set_code(grpc.StatusCode.UNIMPLEMENTED)
44 | context.set_details('Method not implemented!')
45 | raise NotImplementedError('Method not implemented!')
46 |
47 | def GetFileTail(self, request, context):
48 | """Retrieves the tail of a File with the given uri.
49 |
50 | An error will be reported in the following cases:
51 | - If the File is not found.
52 | - If the given File uri is badly formatted.
53 | """
54 | context.set_code(grpc.StatusCode.UNIMPLEMENTED)
55 | context.set_details('Method not implemented!')
56 | raise NotImplementedError('Method not implemented!')
57 |
58 |
59 | def add_ResultStoreFileDownloadServicer_to_server(servicer, server):
60 | rpc_method_handlers = {
61 | 'GetFile': grpc.unary_stream_rpc_method_handler(
62 | servicer.GetFile,
63 | request_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileRequest.FromString,
64 | response_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileResponse.SerializeToString,
65 | ),
66 | 'GetFileTail': grpc.unary_unary_rpc_method_handler(
67 | servicer.GetFileTail,
68 | request_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailRequest.FromString,
69 | response_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailResponse.SerializeToString,
70 | ),
71 | }
72 | generic_handler = grpc.method_handlers_generic_handler(
73 | 'google.devtools.resultstore.v2.ResultStoreFileDownload', rpc_method_handlers)
74 | server.add_generic_rpc_handlers((generic_handler,))
75 |
--------------------------------------------------------------------------------
/resultstoresearch/resultstoresearch/v1/coverage.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package resultstoresearch.v1;
4 |
5 | // Describes line coverage for a file
6 | message LineCoverage {
7 | // Which source lines in the file represent the start of a statement that was
8 | // instrumented to detect whether it was executed by the test.
9 | //
10 | // This is a bitfield where i-th bit corresponds to the i-th line. Divide line
11 | // number by 8 to get index into byte array. Mod line number by 8 to get bit
12 | // number (0 = LSB, 7 = MSB).
13 | //
14 | // A 1 denotes the line was instrumented.
15 | // A 0 denotes the line was not instrumented.
16 | bytes instrumented_lines = 1;
17 |
18 | // Which of the instrumented source lines were executed by the test. Should
19 | // include lines that were not instrumented.
20 | //
21 | // This is a bitfield where i-th bit corresponds to the i-th line. Divide line
22 | // number by 8 to get index into byte array. Mod line number by 8 to get bit
23 | // number (0 = LSB, 7 = MSB).
24 | //
25 | // A 1 denotes the line was executed.
26 | // A 0 denotes the line was not executed.
27 | bytes executed_lines = 2;
28 | }
29 |
30 | // Describes branch coverage for a file
31 | message BranchCoverage {
32 | // The field branch_present denotes the lines containing at least one branch.
33 | //
34 | // This is a bitfield where i-th bit corresponds to the i-th line. Divide line
35 | // number by 8 to get index into byte array. Mod line number by 8 to get bit
36 | // number (0 = LSB, 7 = MSB).
37 | //
38 | // A 1 denotes the line contains at least one branch.
39 | // A 0 denotes the line contains no branches.
40 | bytes branch_present = 1;
41 |
42 | // Contains the number of branches present, only for the lines which have the
43 | // corresponding bit set in branch_present, in a relative order ignoring
44 | // lines which do not have any branches.
45 | repeated int32 branches_in_line = 2;
46 |
47 | // As each branch can have any one of the following three states: not
48 | // executed, executed but not taken, executed and taken.
49 | //
50 | // This is a bitfield where i-th bit corresponds to the i-th branch. Divide
51 | // branch number by 8 to get index into byte array. Mod branch number by 8 to
52 | // get bit number (0 = LSB, 7 = MSB).
53 | //
54 | // i-th bit of the following two byte arrays are used to denote the above
55 | // mentioned states.
56 | //
57 | // not executed: i-th bit of executed == 0 && i-th bit of taken == 0
58 | // executed but not taken: i-th bit of executed == 1 && i-th bit of taken == 0
59 | // executed and taken: i-th bit of executed == 1 && i-th bit of taken == 1
60 | bytes executed = 3;
61 |
62 | // Described above.
63 | bytes taken = 4;
64 | }
65 |
66 | // Describes code coverage for a particular file under test.
67 | message FileCoverage {
68 | // Path of source file within the SourceContext of this Invocation.
69 | string path = 1;
70 |
71 | // Details of lines in a file required to calculate line coverage.
72 | LineCoverage line_coverage = 2;
73 |
74 | // Details of branches in a file required to calculate branch coverage.
75 | BranchCoverage branch_coverage = 3;
76 | }
77 |
78 | // Describes code coverage for a build or test Action. This is used to store
79 | // baseline coverage for build Actions and test coverage for test Actions.
80 | message ActionCoverage {
81 | // List of coverage info for all source files that the TestResult covers.
82 | repeated FileCoverage file_coverages = 2;
83 | }
84 |
85 | // Describes aggregate code coverage for a collection of build or test Actions.
86 | // A line or branch is covered if and only if it is covered in any of the build
87 | // or test actions.
88 | message AggregateCoverage {
89 | // Aggregated coverage info for all source files that the actions cover.
90 | repeated FileCoverage file_coverages = 1;
91 | }
92 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoreapi/cloud/devtools/resultstore_v2/proto/resultstore_file_download_pb2_grpc.py:
--------------------------------------------------------------------------------
1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2 | import grpc
3 |
4 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import resultstore_file_download_pb2 as google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2
5 |
6 |
7 | class ResultStoreFileDownloadStub(object):
8 | """This API allows download of File messages referenced in
9 | ResultStore resources.
10 | """
11 |
12 | def __init__(self, channel):
13 | """Constructor.
14 |
15 | Args:
16 | channel: A grpc.Channel.
17 | """
18 | self.GetFile = channel.unary_stream(
19 | '/google.devtools.resultstore.v2.ResultStoreFileDownload/GetFile',
20 | request_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileRequest.SerializeToString,
21 | response_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileResponse.FromString,
22 | )
23 | self.GetFileTail = channel.unary_unary(
24 | '/google.devtools.resultstore.v2.ResultStoreFileDownload/GetFileTail',
25 | request_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailRequest.SerializeToString,
26 | response_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailResponse.FromString,
27 | )
28 |
29 |
30 | class ResultStoreFileDownloadServicer(object):
31 | """This API allows download of File messages referenced in
32 | ResultStore resources.
33 | """
34 |
35 | def GetFile(self, request, context):
36 | """Retrieves the File with the given uri.
37 | returns a stream of bytes to be stitched together in order.
38 |
39 | An error will be reported in the following cases:
40 | - If the File is not found.
41 | - If the given File uri is badly formatted.
42 | """
43 | context.set_code(grpc.StatusCode.UNIMPLEMENTED)
44 | context.set_details('Method not implemented!')
45 | raise NotImplementedError('Method not implemented!')
46 |
47 | def GetFileTail(self, request, context):
48 | """Retrieves the tail of a File with the given uri.
49 |
50 | An error will be reported in the following cases:
51 | - If the File is not found.
52 | - If the given File uri is badly formatted.
53 | """
54 | context.set_code(grpc.StatusCode.UNIMPLEMENTED)
55 | context.set_details('Method not implemented!')
56 | raise NotImplementedError('Method not implemented!')
57 |
58 |
59 | def add_ResultStoreFileDownloadServicer_to_server(servicer, server):
60 | rpc_method_handlers = {
61 | 'GetFile': grpc.unary_stream_rpc_method_handler(
62 | servicer.GetFile,
63 | request_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileRequest.FromString,
64 | response_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileResponse.SerializeToString,
65 | ),
66 | 'GetFileTail': grpc.unary_unary_rpc_method_handler(
67 | servicer.GetFileTail,
68 | request_deserializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailRequest.FromString,
69 | response_serializer=google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_resultstore__file__download__pb2.GetFileTailResponse.SerializeToString,
70 | ),
71 | }
72 | generic_handler = grpc.method_handlers_generic_handler(
73 | 'google.devtools.resultstore.v2.ResultStoreFileDownload', rpc_method_handlers)
74 | server.add_generic_rpc_handlers((generic_handler,))
75 |
--------------------------------------------------------------------------------
/gRPC-build/BUILD.bazel:
--------------------------------------------------------------------------------
1 | # This file was automatically generated by BuildFileGenerator
2 |
3 | # This is an API workspace, having public visibility by default makes perfect sense.
4 | package(default_visibility = ["//visibility:public"])
5 |
6 | ##############################################################################
7 | # Common
8 | ##############################################################################
9 | load("@rules_proto//proto:defs.bzl", "proto_library")
10 | load("@com_google_googleapis_imports//:imports.bzl", "proto_library_with_info")
11 |
12 | proto_library(
13 | name = "resultstore_proto",
14 | srcs = [
15 | "action.proto",
16 | "common.proto",
17 | "configuration.proto",
18 | "configured_target.proto",
19 | "coverage_summary.proto",
20 | "coverage.proto",
21 | "download_metadata.proto",
22 | "file_processing_error.proto",
23 | "file_set.proto",
24 | "file.proto",
25 | "invocation.proto",
26 | "resultstore_download.proto",
27 | "resultstore_file_download.proto",
28 | "resultstore_upload.proto",
29 | "target.proto",
30 | "test_suite.proto",
31 | "upload_metadata.proto"
32 | ],
33 | deps = [
34 | "//google/api:annotations_proto",
35 | "//google/api:client_proto",
36 | "//google/api:field_behavior_proto",
37 | "//google/api:resource_proto",
38 | "//google/rpc:status_proto",
39 | "@com_google_protobuf//:any_proto",
40 | "@com_google_protobuf//:duration_proto",
41 | "@com_google_protobuf//:field_mask_proto",
42 | "@com_google_protobuf//:empty_proto",
43 | "@com_google_protobuf//:timestamp_proto",
44 | "@com_google_protobuf//:wrappers_proto",
45 | ],
46 | )
47 |
48 | proto_library_with_info(
49 | name = "resultstore_proto_with_info",
50 | deps = [
51 | ":resultstore_proto",
52 | "//google/cloud:common_resources_proto",
53 | ],
54 | )
55 |
56 | load(
57 | "@com_google_googleapis_imports//:imports.bzl",
58 | "moved_proto_library",
59 | "py_gapic_assembly_pkg",
60 | "py_gapic_library",
61 | "py_grpc_library",
62 | "py_proto_library",
63 | )
64 |
65 | moved_proto_library(
66 | name = "resultstore_moved_proto",
67 | srcs = [":resultstore_proto"],
68 | deps = [
69 | "//google/api:annotations_proto",
70 | "//google/api:client_proto",
71 | "//google/api:field_behavior_proto",
72 | "//google/api:resource_proto",
73 | "//google/rpc:status_proto",
74 | "@com_google_protobuf//:any_proto",
75 | "@com_google_protobuf//:duration_proto",
76 | "@com_google_protobuf//:field_mask_proto",
77 | "@com_google_protobuf//:empty_proto",
78 | "@com_google_protobuf//:timestamp_proto",
79 | "@com_google_protobuf//:wrappers_proto",
80 | ],
81 | )
82 |
83 | py_proto_library(
84 | name = "resultstore_py_proto",
85 | plugin = "@protoc_docs_plugin//:docs_plugin",
86 | deps = [":resultstore_moved_proto"],
87 | )
88 |
89 | py_grpc_library(
90 | name = "resultstore_py_grpc",
91 | srcs = [":resultstore_moved_proto"],
92 | deps = [":resultstore_py_proto"],
93 | )
94 |
95 | py_gapic_library(
96 | name = "resultstore_py_gapic",
97 | src = ":resultstore_proto_with_info",
98 | gapic_yaml = "resultstore_gapic.yaml",
99 | package = "google.devtools.resultstore.v2",
100 | service_yaml = "resultstore_v2.yaml",
101 | deps = [
102 | ":resultstore_py_grpc",
103 | ":resultstore_py_proto",
104 | ],
105 | )
106 |
107 | # Open Source Packages
108 | py_gapic_assembly_pkg(
109 | name = "devtools-resultstore-v2-py",
110 | deps = [
111 | ":resultstore_py_gapic",
112 | ":resultstore_py_grpc",
113 | ":resultstore_py_proto",
114 | ],
115 | )
116 |
--------------------------------------------------------------------------------
/resultstoreui/README.md:
--------------------------------------------------------------------------------
1 | # ResultStoreUI
2 |
3 | ## Usage
4 |
5 | This tool can be run using either
6 |
7 | ```shell
8 | bazel run resultstoreui
9 | ```
10 |
11 | or
12 |
13 | ```shell
14 | python3 resultstoreui.py
15 | ```
16 |
17 | and specifying the following flags
18 |
19 | - `--command`: The main command to be run for the current invocation of the cli
20 | eg.
21 |
22 | - `get-invocation` : Attempts to get the invocation specified with the `--invocation_name` flag.
23 |
24 | ```shell
25 | bazel run resultstoreui -- --command="get-invocation" --invocation_name="invocations/d9910974-4d59-4fee-8188-a891de97814a"
26 | ```
27 |
28 | - `create-invocation`: Attempts to create a new invocation using the optionally provided `--authorization_token` or generating one to be associated with requests made with this invocation in the future. Specifying a `--resume_token` will put the invocation into batch mode.
29 |
30 | ```shell
31 | bazel run resultstoreui -- --command="create-invocation" --authorization_token="77f3d6ca-0577-429f-ba59-02090d27a15b"
32 | ```
33 |
34 | - `single-upload`: Uploads a single target, config, configured target and files to the specified `--invocation-id`
35 |
36 | ```shell
37 | bazel run resultstoreui -- --command="single_upload"
38 | --invocation_id="d9910974-4d59-4fee-8188-a891de97814a"
39 | --authorization_token="77f3d6ca-0577-429f-ba59-02090d27a15b"
40 | --files="/path/to/file1, /path/to/file2"
41 | ```
42 |
43 | - `batch-upload`: Batch uploads targets, configs, configured targets and files to an invocation in batch mode.
44 |
45 | ```shell
46 | bazel run resultstoreui -- --command="batch-upload"
47 | --invocation_id="d9910974-4d59-4fee-8188-a891de97814a"
48 | --authorization_token="77f3d6ca-0577-429f-ba59-02090d27a15b"
49 | --resume_token="current-resume-token"
50 | --next_resume_token="next-resume-token"
51 | --files="/path/to/file1, /path/to/file2"
52 | ```
53 |
54 | - `finalize-batch-upload` : Finalizes an invocation in batch mode
55 |
56 | ```shell
57 | bazel run resultstoreui -- --command="finalize-batch-upload"
58 | --invocation_id="d9910974-4d59-4fee-8188-a891de97814a"
59 | --resume_token="current-resume-token"
60 | --next_resume_token="next-resume-token"
61 | --authorization_token="77f3d6ca-0577-429f-ba59-02090d27a15b"
62 | ```
63 |
64 | - `--channel_target`: The host and port of the service that the channel is created to
65 | - `--config_id` : config_id to be used when creating a config
66 | - `--target_name`: target_name to be used when creating a target
67 | - `--invocation_id`: invocation to edit
68 | - `--authorization_token`: authorization token to be used during the current command
69 | - `--action_type`: action_type for the current action to be created
70 | - `--invocation_name`: action to get when using the `get-invocation` command
71 | - `--bigstore_project_name`: bigstore project to upload files to
72 | - `--bucket_name`: Bucket name inside bigstore to upload files to
73 | - `--files`: comma separated list of paths to files to upload for the current target
74 | - `--status`: Current status of the action being uploaded
75 | - `--create_config`: Boolean to specify creatione of a configuration during single-upload or batch-upload
76 | - `--resume_token`: Current resume token for batch uploads
77 | - `--next_resume_token`: Next resume token for batch uploads
78 |
79 | ## Running Tests
80 |
81 | Tests can be run with either
82 |
83 | ```shell
84 | bazel run test_resultstoreui
85 | ```
86 |
87 | or
88 |
89 | ```shell
90 | python3 resultstore_client_test.py
91 | ```
92 |
93 | ## Rebuilding gRPC Client Files
94 |
95 | 1. Clone https://github.com/googleapis/googleapis
96 |
97 | 2. Copy the build file from gRPC-build to the `google/devtools/resultstore/v2/` subdirectory
98 |
99 | 3. `bazel build //...`
100 |
101 | 4. Navigate to your local bazel cache under `${HOME}/.cache/bazel/_bazel_${USER}/BUILD_ID/execroot/com_google_googleapis`
102 |
103 | 5. Copy the google subdirectory and replace the current resultstoreapi folder with the newly generated files
104 |
--------------------------------------------------------------------------------
/resultstoresearch/resultstoresearch/v1/target.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package resultstoresearch.v1;
4 |
5 | import "common.proto";
6 | import "file.proto";
7 |
8 | // Each Target represents data for a given target in a given Invocation.
9 | // ConfiguredTarget and Action resources under each Target contain the bulk of
10 | // the data.
11 | message Target {
12 | // The resource ID components that identify the Target.
13 | message Id {
14 | // The Invocation ID.
15 | string invocation_id = 1;
16 |
17 | // The Target ID.
18 | string target_id = 2;
19 | }
20 |
21 | // The resource name. Its format must be:
22 | // invocations/${INVOCATION_ID}/targets/${url_encode(TARGET_ID)}
23 | string name = 1;
24 |
25 | // The resource ID components that identify the Target. They must match the
26 | // resource name after proper encoding.
27 | Id id = 2;
28 |
29 | // This is the aggregate status of the target.
30 | StatusAttributes status_attributes = 3;
31 |
32 | // When this target started and its duration.
33 | Timing timing = 4;
34 |
35 | // Attributes that apply to all targets.
36 | TargetAttributes target_attributes = 5;
37 |
38 | // Attributes that apply to all test actions under this target.
39 | TestAttributes test_attributes = 6;
40 |
41 | // Arbitrary name-value pairs.
42 | // This is implemented as a multi-map. Multiple properties are allowed with
43 | // the same key. Properties will be returned in lexicographical order by key.
44 | repeated Property properties = 7;
45 |
46 | // A list of file references for target level files.
47 | // The file IDs must be unique within this list. Duplicate file IDs will
48 | // result in an error. Files will be returned in lexicographical order by ID.
49 | // Use this field to specify outputs not related to a configuration.
50 | repeated File files = 8;
51 |
52 | // Provides a hint to clients as to whether to display the Target to users.
53 | // If true then clients likely want to display the Target by default.
54 | // Once set to true, this may not be set back to false.
55 | bool visible = 10;
56 | }
57 |
58 | // Attributes that apply to all targets.
59 | message TargetAttributes {
60 | // If known, indicates the type of this target. In bazel this corresponds
61 | // to the rule-suffix.
62 | TargetType type = 1;
63 |
64 | // If known, the main language of this target, e.g. java, cc, python, etc.
65 | Language language = 2;
66 |
67 | // The tags attribute of the build rule. These should be short, descriptive
68 | // words, and there should only be a few of them.
69 | // This is implemented as a set. All tags will be unique. Any duplicate tags
70 | // will be ignored. Tags will be returned in lexicographical order.
71 | repeated string tags = 3;
72 | }
73 |
74 | // Attributes that apply only to test actions under this target.
75 | message TestAttributes {
76 | // Indicates how big the user indicated the test action was.
77 | TestSize size = 1;
78 | }
79 |
80 | // These correspond to the suffix of the rule name. Eg cc_test has type TEST.
81 | enum TargetType {
82 | // Unspecified by the build system.
83 | TARGET_TYPE_UNSPECIFIED = 0;
84 |
85 | // An application e.g. ios_application.
86 | APPLICATION = 1;
87 |
88 | // A binary target e.g. cc_binary.
89 | BINARY = 2;
90 |
91 | // A library target e.g. java_library
92 | LIBRARY = 3;
93 |
94 | // A package
95 | PACKAGE = 4;
96 |
97 | // Any test target, in bazel that means a rule with a '_test' suffix.
98 | TEST = 5;
99 | }
100 |
101 | // Indicates how big the user indicated the test action was.
102 | enum TestSize {
103 | // Unspecified by the user.
104 | TEST_SIZE_UNSPECIFIED = 0;
105 |
106 | // Unit test taking less than 1 minute.
107 | SMALL = 1;
108 |
109 | // Integration tests taking less than 5 minutes.
110 | MEDIUM = 2;
111 |
112 | // End-to-end tests taking less than 15 minutes.
113 | LARGE = 3;
114 |
115 | // Even bigger than LARGE.
116 | ENORMOUS = 4;
117 |
118 | // Something that doesn't fit into the above categories.
119 | OTHER_SIZE = 5;
120 | }
121 |
--------------------------------------------------------------------------------
/resultstoreui/resultstoreapi/cloud/devtools/resultstore_v2/proto/download_metadata_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: google/cloud/devtools/resultstore_v2/proto/download_metadata.proto
4 |
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import message as _message
7 | from google.protobuf import reflection as _reflection
8 | from google.protobuf import symbol_database as _symbol_database
9 | # @@protoc_insertion_point(imports)
10 |
11 | _sym_db = _symbol_database.Default()
12 |
13 |
14 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import common_pb2 as google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_common__pb2
15 |
16 |
17 | DESCRIPTOR = _descriptor.FileDescriptor(
18 | name='google/cloud/devtools/resultstore_v2/proto/download_metadata.proto',
19 | package='google.devtools.resultstore.v2',
20 | syntax='proto3',
21 | serialized_options=b'\n\"com.google.devtools.resultstore.v2P\001ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstore',
22 | serialized_pb=b'\nBgoogle/cloud/devtools/resultstore_v2/proto/download_metadata.proto\x12\x1egoogle.devtools.resultstore.v2\x1a\x37google/cloud/devtools/resultstore_v2/proto/common.proto\"e\n\x10\x44ownloadMetadata\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x43\n\rupload_status\x18\x02 \x01(\x0e\x32,.google.devtools.resultstore.v2.UploadStatusBq\n\"com.google.devtools.resultstore.v2P\x01ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstoreb\x06proto3'
23 | ,
24 | dependencies=[google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_common__pb2.DESCRIPTOR,])
25 |
26 |
27 |
28 |
29 | _DOWNLOADMETADATA = _descriptor.Descriptor(
30 | name='DownloadMetadata',
31 | full_name='google.devtools.resultstore.v2.DownloadMetadata',
32 | filename=None,
33 | file=DESCRIPTOR,
34 | containing_type=None,
35 | fields=[
36 | _descriptor.FieldDescriptor(
37 | name='name', full_name='google.devtools.resultstore.v2.DownloadMetadata.name', index=0,
38 | number=1, type=9, cpp_type=9, label=1,
39 | has_default_value=False, default_value=b"".decode('utf-8'),
40 | message_type=None, enum_type=None, containing_type=None,
41 | is_extension=False, extension_scope=None,
42 | serialized_options=None, file=DESCRIPTOR),
43 | _descriptor.FieldDescriptor(
44 | name='upload_status', full_name='google.devtools.resultstore.v2.DownloadMetadata.upload_status', index=1,
45 | number=2, type=14, cpp_type=8, label=1,
46 | has_default_value=False, default_value=0,
47 | message_type=None, enum_type=None, containing_type=None,
48 | is_extension=False, extension_scope=None,
49 | serialized_options=None, file=DESCRIPTOR),
50 | ],
51 | extensions=[
52 | ],
53 | nested_types=[],
54 | enum_types=[
55 | ],
56 | serialized_options=None,
57 | is_extendable=False,
58 | syntax='proto3',
59 | extension_ranges=[],
60 | oneofs=[
61 | ],
62 | serialized_start=159,
63 | serialized_end=260,
64 | )
65 |
66 | _DOWNLOADMETADATA.fields_by_name['upload_status'].enum_type = google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_common__pb2._UPLOADSTATUS
67 | DESCRIPTOR.message_types_by_name['DownloadMetadata'] = _DOWNLOADMETADATA
68 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
69 |
70 | DownloadMetadata = _reflection.GeneratedProtocolMessageType('DownloadMetadata', (_message.Message,), {
71 | 'DESCRIPTOR' : _DOWNLOADMETADATA,
72 | '__module__' : 'resultstoreapi.cloud.devtools.resultstore_v2.proto.download_metadata_pb2'
73 | ,
74 | '__doc__': """The download metadata for an invocation
75 |
76 |
77 | Attributes:
78 | name:
79 | The name of the download metadata. Its format will be:
80 | invocations/${INVOCATION_ID}/downloadMetadata
81 | upload_status:
82 | Indicates the upload status of the invocation, whether it is
83 | post-processing, or immutable, etc.
84 | """,
85 | # @@protoc_insertion_point(class_scope:google.devtools.resultstore.v2.DownloadMetadata)
86 | })
87 | _sym_db.RegisterMessage(DownloadMetadata)
88 |
89 |
90 | DESCRIPTOR._options = None
91 | # @@protoc_insertion_point(module_scope)
92 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoreapi/cloud/devtools/resultstore_v2/proto/download_metadata_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: google/cloud/devtools/resultstore_v2/proto/download_metadata.proto
4 |
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import message as _message
7 | from google.protobuf import reflection as _reflection
8 | from google.protobuf import symbol_database as _symbol_database
9 | # @@protoc_insertion_point(imports)
10 |
11 | _sym_db = _symbol_database.Default()
12 |
13 |
14 | from resultstoreapi.cloud.devtools.resultstore_v2.proto import common_pb2 as google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_common__pb2
15 |
16 |
17 | DESCRIPTOR = _descriptor.FileDescriptor(
18 | name='google/cloud/devtools/resultstore_v2/proto/download_metadata.proto',
19 | package='google.devtools.resultstore.v2',
20 | syntax='proto3',
21 | serialized_options=b'\n\"com.google.devtools.resultstore.v2P\001ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstore',
22 | serialized_pb=b'\nBgoogle/cloud/devtools/resultstore_v2/proto/download_metadata.proto\x12\x1egoogle.devtools.resultstore.v2\x1a\x37google/cloud/devtools/resultstore_v2/proto/common.proto\"e\n\x10\x44ownloadMetadata\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x43\n\rupload_status\x18\x02 \x01(\x0e\x32,.google.devtools.resultstore.v2.UploadStatusBq\n\"com.google.devtools.resultstore.v2P\x01ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstoreb\x06proto3'
23 | ,
24 | dependencies=[google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_common__pb2.DESCRIPTOR,])
25 |
26 |
27 |
28 |
29 | _DOWNLOADMETADATA = _descriptor.Descriptor(
30 | name='DownloadMetadata',
31 | full_name='google.devtools.resultstore.v2.DownloadMetadata',
32 | filename=None,
33 | file=DESCRIPTOR,
34 | containing_type=None,
35 | fields=[
36 | _descriptor.FieldDescriptor(
37 | name='name', full_name='google.devtools.resultstore.v2.DownloadMetadata.name', index=0,
38 | number=1, type=9, cpp_type=9, label=1,
39 | has_default_value=False, default_value=b"".decode('utf-8'),
40 | message_type=None, enum_type=None, containing_type=None,
41 | is_extension=False, extension_scope=None,
42 | serialized_options=None, file=DESCRIPTOR),
43 | _descriptor.FieldDescriptor(
44 | name='upload_status', full_name='google.devtools.resultstore.v2.DownloadMetadata.upload_status', index=1,
45 | number=2, type=14, cpp_type=8, label=1,
46 | has_default_value=False, default_value=0,
47 | message_type=None, enum_type=None, containing_type=None,
48 | is_extension=False, extension_scope=None,
49 | serialized_options=None, file=DESCRIPTOR),
50 | ],
51 | extensions=[
52 | ],
53 | nested_types=[],
54 | enum_types=[
55 | ],
56 | serialized_options=None,
57 | is_extendable=False,
58 | syntax='proto3',
59 | extension_ranges=[],
60 | oneofs=[
61 | ],
62 | serialized_start=159,
63 | serialized_end=260,
64 | )
65 |
66 | _DOWNLOADMETADATA.fields_by_name['upload_status'].enum_type = google_dot_cloud_dot_devtools_dot_resultstore__v2_dot_proto_dot_common__pb2._UPLOADSTATUS
67 | DESCRIPTOR.message_types_by_name['DownloadMetadata'] = _DOWNLOADMETADATA
68 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
69 |
70 | DownloadMetadata = _reflection.GeneratedProtocolMessageType('DownloadMetadata', (_message.Message,), {
71 | 'DESCRIPTOR' : _DOWNLOADMETADATA,
72 | '__module__' : 'resultstoreapi.cloud.devtools.resultstore_v2.proto.download_metadata_pb2'
73 | ,
74 | '__doc__': """The download metadata for an invocation
75 |
76 |
77 | Attributes:
78 | name:
79 | The name of the download metadata. Its format will be:
80 | invocations/${INVOCATION_ID}/downloadMetadata
81 | upload_status:
82 | Indicates the upload status of the invocation, whether it is
83 | post-processing, or immutable, etc.
84 | """,
85 | # @@protoc_insertion_point(class_scope:google.devtools.resultstore.v2.DownloadMetadata)
86 | })
87 | _sym_db.RegisterMessage(DownloadMetadata)
88 |
89 |
90 | DESCRIPTOR._options = None
91 | # @@protoc_insertion_point(module_scope)
92 |
--------------------------------------------------------------------------------
/resultstoreui/resultstoreapi/cloud/devtools/resultstore_v2/proto/upload_metadata_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: google/cloud/devtools/resultstore_v2/proto/upload_metadata.proto
4 |
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import message as _message
7 | from google.protobuf import reflection as _reflection
8 | from google.protobuf import symbol_database as _symbol_database
9 | # @@protoc_insertion_point(imports)
10 |
11 | _sym_db = _symbol_database.Default()
12 |
13 |
14 |
15 |
16 | DESCRIPTOR = _descriptor.FileDescriptor(
17 | name='google/cloud/devtools/resultstore_v2/proto/upload_metadata.proto',
18 | package='google.devtools.resultstore.v2',
19 | syntax='proto3',
20 | serialized_options=b'\n\"com.google.devtools.resultstore.v2P\001ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstore',
21 | serialized_pb=b'\n@google/cloud/devtools/resultstore_v2/proto/upload_metadata.proto\x12\x1egoogle.devtools.resultstore.v2\"L\n\x0eUploadMetadata\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0cresume_token\x18\x02 \x01(\t\x12\x16\n\x0euploader_state\x18\x03 \x01(\x0c\x42q\n\"com.google.devtools.resultstore.v2P\x01ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstoreb\x06proto3'
22 | )
23 |
24 |
25 |
26 |
27 | _UPLOADMETADATA = _descriptor.Descriptor(
28 | name='UploadMetadata',
29 | full_name='google.devtools.resultstore.v2.UploadMetadata',
30 | filename=None,
31 | file=DESCRIPTOR,
32 | containing_type=None,
33 | fields=[
34 | _descriptor.FieldDescriptor(
35 | name='name', full_name='google.devtools.resultstore.v2.UploadMetadata.name', index=0,
36 | number=1, type=9, cpp_type=9, label=1,
37 | has_default_value=False, default_value=b"".decode('utf-8'),
38 | message_type=None, enum_type=None, containing_type=None,
39 | is_extension=False, extension_scope=None,
40 | serialized_options=None, file=DESCRIPTOR),
41 | _descriptor.FieldDescriptor(
42 | name='resume_token', full_name='google.devtools.resultstore.v2.UploadMetadata.resume_token', index=1,
43 | number=2, type=9, cpp_type=9, label=1,
44 | has_default_value=False, default_value=b"".decode('utf-8'),
45 | message_type=None, enum_type=None, containing_type=None,
46 | is_extension=False, extension_scope=None,
47 | serialized_options=None, file=DESCRIPTOR),
48 | _descriptor.FieldDescriptor(
49 | name='uploader_state', full_name='google.devtools.resultstore.v2.UploadMetadata.uploader_state', index=2,
50 | number=3, type=12, cpp_type=9, label=1,
51 | has_default_value=False, default_value=b"",
52 | message_type=None, enum_type=None, containing_type=None,
53 | is_extension=False, extension_scope=None,
54 | serialized_options=None, file=DESCRIPTOR),
55 | ],
56 | extensions=[
57 | ],
58 | nested_types=[],
59 | enum_types=[
60 | ],
61 | serialized_options=None,
62 | is_extendable=False,
63 | syntax='proto3',
64 | extension_ranges=[],
65 | oneofs=[
66 | ],
67 | serialized_start=100,
68 | serialized_end=176,
69 | )
70 |
71 | DESCRIPTOR.message_types_by_name['UploadMetadata'] = _UPLOADMETADATA
72 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
73 |
74 | UploadMetadata = _reflection.GeneratedProtocolMessageType('UploadMetadata', (_message.Message,), {
75 | 'DESCRIPTOR' : _UPLOADMETADATA,
76 | '__module__' : 'resultstoreapi.cloud.devtools.resultstore_v2.proto.upload_metadata_pb2'
77 | ,
78 | '__doc__': """The upload metadata for an invocation
79 |
80 |
81 | Attributes:
82 | name:
83 | The name of the upload metadata. Its format will be:
84 | invocations/${INVOCATION_ID}/uploadMetadata
85 | resume_token:
86 | The resume token of the last batch that was committed in the
87 | most recent batch upload. More information with resume_token
88 | could be found in resultstore_upload.proto
89 | uploader_state:
90 | Client-specific data used to resume batch upload if an error
91 | occurs and retry action is needed.
92 | """,
93 | # @@protoc_insertion_point(class_scope:google.devtools.resultstore.v2.UploadMetadata)
94 | })
95 | _sym_db.RegisterMessage(UploadMetadata)
96 |
97 |
98 | DESCRIPTOR._options = None
99 | # @@protoc_insertion_point(module_scope)
100 |
--------------------------------------------------------------------------------
/resultstoresearch/server/resultstoresearch/resultstoreapi/cloud/devtools/resultstore_v2/proto/upload_metadata_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: google/cloud/devtools/resultstore_v2/proto/upload_metadata.proto
4 |
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import message as _message
7 | from google.protobuf import reflection as _reflection
8 | from google.protobuf import symbol_database as _symbol_database
9 | # @@protoc_insertion_point(imports)
10 |
11 | _sym_db = _symbol_database.Default()
12 |
13 |
14 |
15 |
16 | DESCRIPTOR = _descriptor.FileDescriptor(
17 | name='google/cloud/devtools/resultstore_v2/proto/upload_metadata.proto',
18 | package='google.devtools.resultstore.v2',
19 | syntax='proto3',
20 | serialized_options=b'\n\"com.google.devtools.resultstore.v2P\001ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstore',
21 | serialized_pb=b'\n@google/cloud/devtools/resultstore_v2/proto/upload_metadata.proto\x12\x1egoogle.devtools.resultstore.v2\"L\n\x0eUploadMetadata\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0cresume_token\x18\x02 \x01(\t\x12\x16\n\x0euploader_state\x18\x03 \x01(\x0c\x42q\n\"com.google.devtools.resultstore.v2P\x01ZIgoogle.golang.org/genproto/googleapis/devtools/resultstore/v2;resultstoreb\x06proto3'
22 | )
23 |
24 |
25 |
26 |
27 | _UPLOADMETADATA = _descriptor.Descriptor(
28 | name='UploadMetadata',
29 | full_name='google.devtools.resultstore.v2.UploadMetadata',
30 | filename=None,
31 | file=DESCRIPTOR,
32 | containing_type=None,
33 | fields=[
34 | _descriptor.FieldDescriptor(
35 | name='name', full_name='google.devtools.resultstore.v2.UploadMetadata.name', index=0,
36 | number=1, type=9, cpp_type=9, label=1,
37 | has_default_value=False, default_value=b"".decode('utf-8'),
38 | message_type=None, enum_type=None, containing_type=None,
39 | is_extension=False, extension_scope=None,
40 | serialized_options=None, file=DESCRIPTOR),
41 | _descriptor.FieldDescriptor(
42 | name='resume_token', full_name='google.devtools.resultstore.v2.UploadMetadata.resume_token', index=1,
43 | number=2, type=9, cpp_type=9, label=1,
44 | has_default_value=False, default_value=b"".decode('utf-8'),
45 | message_type=None, enum_type=None, containing_type=None,
46 | is_extension=False, extension_scope=None,
47 | serialized_options=None, file=DESCRIPTOR),
48 | _descriptor.FieldDescriptor(
49 | name='uploader_state', full_name='google.devtools.resultstore.v2.UploadMetadata.uploader_state', index=2,
50 | number=3, type=12, cpp_type=9, label=1,
51 | has_default_value=False, default_value=b"",
52 | message_type=None, enum_type=None, containing_type=None,
53 | is_extension=False, extension_scope=None,
54 | serialized_options=None, file=DESCRIPTOR),
55 | ],
56 | extensions=[
57 | ],
58 | nested_types=[],
59 | enum_types=[
60 | ],
61 | serialized_options=None,
62 | is_extendable=False,
63 | syntax='proto3',
64 | extension_ranges=[],
65 | oneofs=[
66 | ],
67 | serialized_start=100,
68 | serialized_end=176,
69 | )
70 |
71 | DESCRIPTOR.message_types_by_name['UploadMetadata'] = _UPLOADMETADATA
72 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
73 |
74 | UploadMetadata = _reflection.GeneratedProtocolMessageType('UploadMetadata', (_message.Message,), {
75 | 'DESCRIPTOR' : _UPLOADMETADATA,
76 | '__module__' : 'resultstoreapi.cloud.devtools.resultstore_v2.proto.upload_metadata_pb2'
77 | ,
78 | '__doc__': """The upload metadata for an invocation
79 |
80 |
81 | Attributes:
82 | name:
83 | The name of the upload metadata. Its format will be:
84 | invocations/${INVOCATION_ID}/uploadMetadata
85 | resume_token:
86 | The resume token of the last batch that was committed in the
87 | most recent batch upload. More information with resume_token
88 | could be found in resultstore_upload.proto
89 | uploader_state:
90 | Client-specific data used to resume batch upload if an error
91 | occurs and retry action is needed.
92 | """,
93 | # @@protoc_insertion_point(class_scope:google.devtools.resultstore.v2.UploadMetadata)
94 | })
95 | _sym_db.RegisterMessage(UploadMetadata)
96 |
97 |
98 | DESCRIPTOR._options = None
99 | # @@protoc_insertion_point(module_scope)
100 |
--------------------------------------------------------------------------------