Batch Changes support for Perforce (#52127)

# Add Batch Changes support for Perforce

# Test plan

## Local dev setup

Launch SG with Batch Changes enabled by running `sg start batches`

## Site Configuration

<img width="845" alt="enable Batch Changes and disable sub-repo
permissions"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/533e8299-dbc2-4d6d-9ae1-f186ca4625e7">

In Site Configuration, add `"batchChanges.enablePerforce": true` to
`experimentalFeatures` and disable `subRepoPermissions`. Currently,
Batch Changes does not work on Perforce when `subRepoPermissions` is
enabled.

## Add Perforce code host(s)

If you already have some, no need to add more, but you'll need at least
one Perforce code host for this exercise!

## Add Batch Changes credentials for the code host

<img width="864" alt="add Batch Changes credentials for the code host"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/78c5fb5b-b3a0-4869-a73f-b67196ba1ba9">

In Batch Changes --> Settings, click the green Add Credentials button,
enter a username and ticket for a Perforce user who is allowed to shelve
changelists on the code host

## Create a new batch change

<img width="627" alt="create batch change"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/43587040-4cd0-44ea-acac-4a4c79b00cfd">

Click the Batch Changes tab at the top of the window, then the big blue
`Create batch change` button. Give it a fancy name

<img width="1247" alt="batch change spec"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/947be557-f903-4537-8830-7bee27fb43e7">

Complete the batch spec, making sure to specify your repo and file(s)
found in there.
Click the big green `Preview workspaces` button and make sure it's
finding what you expect.

<img width="1073" alt="batch change preview"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/7b74b48f-45c8-4a38-852d-d1a57777f1e1">

In the preview page, click the green `Preview` button to proceed.

<img width="1071" alt="batch change apply page"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/c6d93cdb-527c-432f-84f3-80460448ba88">

Choose `Publish on apply` for the `Select action on apply`, then click
`Apply` and `OK` on the confirmation dialog, then after a bit, you'll
see the batch change status page, showing the changelist id of the
shelved changelist.

<img width="832" alt="batch change status"
src="https://github.com/sourcegraph/sourcegraph/assets/129280/02d4cbf2-592d-4b99-9e1f-c260d907b145">

---------

Co-authored-by: Idan Varsano <varsanojidan@gmail.com>
This commit is contained in:
Peter Guy 2023-06-20 16:12:58 -07:00 committed by GitHub
parent f798f943b8
commit 5ea0d1bcf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 8740 additions and 577 deletions

View File

@ -60,6 +60,7 @@ const scopeRequirements: Record<ExternalServiceKind, JSX.Element> = {
</span>
),
[ExternalServiceKind.GERRIT]: <span />,
[ExternalServiceKind.PERFORCE]: <span>with the ability to shelve changelists.</span>,
// These are just for type completeness and serve as placeholders for a bright future.
[ExternalServiceKind.GITOLITE]: <span>Unsupported</span>,
[ExternalServiceKind.GOMODULES]: <span>Unsupported</span>,
@ -68,7 +69,6 @@ const scopeRequirements: Record<ExternalServiceKind, JSX.Element> = {
[ExternalServiceKind.RUBYPACKAGES]: <span>Unsupported</span>,
[ExternalServiceKind.JVMPACKAGES]: <span>Unsupported</span>,
[ExternalServiceKind.NPMPACKAGES]: <span>Unsupported</span>,
[ExternalServiceKind.PERFORCE]: <span>Unsupported</span>,
[ExternalServiceKind.PHABRICATOR]: <span>Unsupported</span>,
[ExternalServiceKind.AWSCODECOMMIT]: <span>Unsupported</span>,
[ExternalServiceKind.PAGURE]: <span>Unsupported</span>,
@ -143,7 +143,11 @@ export const AddCredentialModal: React.FunctionComponent<React.PropsWithChildren
)
const patLabel =
externalServiceKind === ExternalServiceKind.BITBUCKETCLOUD ? 'App password' : 'Personal access token'
externalServiceKind === ExternalServiceKind.PERFORCE
? 'Ticket'
: externalServiceKind === ExternalServiceKind.BITBUCKETCLOUD
? 'App password'
: 'Personal access token'
return (
<Modal onDismiss={onCancel} aria-labelledby={labelId}>

View File

@ -72,6 +72,7 @@ go_library(
"//internal/limiter",
"//internal/metrics",
"//internal/observation",
"//internal/perforce",
"//internal/ratelimit",
"//internal/search/streaming/http",
"//internal/security",

View File

@ -1,6 +1,7 @@
package server
import (
"bufio"
"bytes"
"context"
"encoding/json"
@ -18,8 +19,11 @@ import (
"github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/internal/gitserver/gitdomain"
"github.com/sourcegraph/sourcegraph/internal/lazyregexp"
"github.com/sourcegraph/sourcegraph/internal/unpack"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/sourcegraph/sourcegraph/internal/perforce"
"github.com/sourcegraph/sourcegraph/internal/vcs"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
@ -129,7 +133,7 @@ func (s *Server) createCommitFromPatch(ctx context.Context, req protocol.CreateC
resp.SetError(repo, "", "", errors.Wrap(err, "gitserver: make tmp repo"))
return http.StatusInternalServerError, resp
}
defer cleanUpTmpRepo(logger, tmpRepoDir)
//defer cleanUpTmpRepo(logger, tmpRepoDir)
argsToString := func(args []string) string {
return strings.Join(args, " ")
@ -285,37 +289,49 @@ func (s *Server) createCommitFromPatch(ctx context.Context, req protocol.CreateC
}
if req.Push != nil {
cmd = exec.CommandContext(ctx, "git", "push", "--force", remoteURL.String(), fmt.Sprintf("%s:%s", cmtHash, ref))
cmd.Dir = repoGitDir
// If the protocol is SSH and a private key was given, we want to
// use it for communication with the code host.
if remoteURL.IsSSH() && req.Push.PrivateKey != "" && req.Push.Passphrase != "" {
// We set up an agent here, which sets up a socket that can be provided to
// SSH via the $SSH_AUTH_SOCK environment variable and the goroutine to drive
// it in the background.
// This is used to pass the private key to be used when pushing to the remote,
// without the need to store it on the disk.
agent, err := newSSHAgent(logger, []byte(req.Push.PrivateKey), []byte(req.Push.Passphrase))
if remoteURL.Scheme == "perforce" {
// the remote URL is a Perforce URL
// shelve the changelist instead of pushing to a Git host
cid, err := s.shelveChangelist(ctx, req, remoteURL, tmpGitPathEnv, altObjectsEnv)
if err != nil {
resp.SetError(repo, "", "", errors.Wrap(err, "gitserver: error creating ssh-agent"))
resp.SetError(repo, "", "", err)
return http.StatusInternalServerError, resp
}
go agent.Listen()
// Make sure we shut this down once we're done.
defer agent.Close()
cmd.Env = append(
os.Environ(),
[]string{
fmt.Sprintf("SSH_AUTH_SOCK=%s", agent.Socket()),
}...,
)
}
resp.ChangelistId = cid
} else {
cmd = exec.CommandContext(ctx, "git", "push", "--force", remoteURL.String(), fmt.Sprintf("%s:%s", cmtHash, ref))
cmd.Dir = repoGitDir
if out, err = run(cmd, "pushing ref"); err != nil {
logger.Error("Failed to push", log.String("commit", cmtHash), log.String("output", string(out)))
return http.StatusInternalServerError, resp
// If the protocol is SSH and a private key was given, we want to
// use it for communication with the code host.
if remoteURL.IsSSH() && req.Push.PrivateKey != "" && req.Push.Passphrase != "" {
// We set up an agent here, which sets up a socket that can be provided to
// SSH via the $SSH_AUTH_SOCK environment variable and the goroutine to drive
// it in the background.
// This is used to pass the private key to be used when pushing to the remote,
// without the need to store it on the disk.
agent, err := newSSHAgent(logger, []byte(req.Push.PrivateKey), []byte(req.Push.Passphrase))
if err != nil {
resp.SetError(repo, "", "", errors.Wrap(err, "gitserver: error creating ssh-agent"))
return http.StatusInternalServerError, resp
}
go agent.Listen()
// Make sure we shut this down once we're done.
defer agent.Close()
cmd.Env = append(
os.Environ(),
[]string{
fmt.Sprintf("SSH_AUTH_SOCK=%s", agent.Socket()),
}...,
)
}
if out, err = run(cmd, "pushing ref"); err != nil {
logger.Error("Failed to push", log.String("commit", cmtHash), log.String("output", string(out)))
return http.StatusInternalServerError, resp
}
}
}
resp.Rev = "refs/" + strings.TrimPrefix(ref, "refs/")
@ -344,6 +360,399 @@ func styleMessage(message string) bool {
return !strings.HasPrefix(message, "Change-Id: I")
}
func (s *Server) shelveChangelist(ctx context.Context, req protocol.CreateCommitFromPatchRequest, remoteURL *vcs.URL, tmpGitPathEnv, altObjectsEnv string) (string, error) {
repo := string(req.Repo)
baseCommit := string(req.BaseCommit)
p4user, p4passwd, p4host, p4depot, _ := decomposePerforceRemoteURL(remoteURL)
if p4depot == "" {
// the remoteURL was constructed without a path to indicate the depot
// make a db call to fill that in
remoteURL, err := s.getRemoteURL(ctx, req.Repo)
if err != nil {
return "", errors.Wrap(err, "failed getting a remote url")
}
// and decompose again
_, _, _, p4depot, _ = decomposePerforceRemoteURL(remoteURL)
}
logger := s.Logger.Scoped("shelveChangelist", "").
With(
log.String("repo", repo),
log.String("baseCommit", baseCommit),
log.String("targetRef", req.TargetRef),
log.String("depot", p4depot),
)
// use the name of the target branch as the perforce client name
p4client := strings.TrimPrefix(req.TargetRef, "refs/heads/")
// do all work in (another) temporary directory
tmpClientDir, err := s.tempDir("perforce-client-")
if err != nil {
return "", errors.Wrap(err, "gitserver: make tmp repo for Perforce client")
}
defer cleanUpTmpRepo(logger, tmpClientDir)
// we'll need these environment variables for subsequent commands
commonEnv := append(os.Environ(), []string{
tmpGitPathEnv,
altObjectsEnv,
fmt.Sprintf("P4PORT=%s", p4host),
fmt.Sprintf("P4USER=%s", p4user),
fmt.Sprintf("P4PASSWD=%s", p4passwd),
fmt.Sprintf("P4CLIENT=%s", p4client),
}...)
p4Cmd := p4Command{
ctx: ctx,
workingDir: tmpClientDir,
env: commonEnv,
}
// check to see if there's a changelist for this target branch already
cid, err := p4Cmd.changelistIdFromClientSpecNameP4(p4client)
if err == nil && cid != "" {
return cid, nil
}
// get the commit message from the base commit so that we can extract the base changelist id from it
cmd := exec.CommandContext(ctx, "git", "show", "--no-patch", "--pretty=format:%B", baseCommit)
cmd.Dir = tmpClientDir
cmd.Env = commonEnv
out, err := cmd.Output()
if err != nil {
errorMessage := "unable to retrieve base commit message"
logger.Error(errorMessage, log.String("baseCommit", baseCommit), log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// extract the base changelist id from the commit message
baseCID, err := perforce.GetP4ChangelistID(string(out))
if err != nil {
errorMessage := "unable to retrieve base changelist id"
logger.Error(errorMessage, log.String("commitMessage", string(out)), log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// get the list of files involved in the commit
cmd = exec.CommandContext(ctx, "git", "diff-tree", "--no-commit-id", "--name-only", "-r", baseCommit)
cmd.Dir = tmpClientDir
cmd.Env = commonEnv
out, err = cmd.CombinedOutput()
if err != nil {
errorMessage := "unable to retrieve files in base commit"
logger.Error(errorMessage, log.String("output", string(out)), log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
fileList := strings.Split(strings.TrimSpace(string(out)), "\n")
if len(fileList) <= 0 {
errorMessage := "no files in base commit"
logger.Error(errorMessage, log.String("output", string(out)), log.String("baseCommit", baseCommit), log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// format a description for the client spec and the changelist
// from the commit message(s)
// be sure to indent lines so that it fits the Perforce form format
desc := "batch change"
if len(req.CommitInfo.Messages) > 0 {
desc = strings.ReplaceAll(strings.Join(req.CommitInfo.Messages, "\n"), "\n", "\n\t")
}
// parse the depot path from the repo name
// depot := strings.SplitN()
// create a Perforce client spec to use for creating the changelist
err = p4Cmd.createClientSpecP4(p4depot, p4client, p4user, desc)
if err != nil {
errorMessage := "error creating a client spec"
logger.Error(errorMessage, log.String("output", digErrorMessage(err)), log.Error(errors.New(errorMessage)))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// get the files from the Perforce server
// mark them for editing
err = p4Cmd.cloneAndEditFilesP4(fileList, baseCID)
if err != nil {
errorMessage := "error getting files from depot"
logger.Error(errorMessage, log.String("output", digErrorMessage(err)), log.Error(errors.New(errorMessage)))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// delete the files involved with the batch change in case the batch change involves a file deletion
// ignore all errors for now; just assume that it's going to work
for _, fileName := range fileList {
os.RemoveAll(fileName)
}
// overlay with files from the commit
// 1. create an archive from the commit
// 2. pipe the archive to `tar -x` to extract it into the temp dir
// archive the commit
archiveCmd := exec.CommandContext(ctx, "git", "archive", "--format=tar", "--verbose", baseCommit)
archiveCmd.Dir = tmpClientDir
archiveCmd.Env = commonEnv
// connect the archive to the untar process
stdout, err := archiveCmd.StdoutPipe()
if err != nil {
errorMessage := "unable to read changed files"
logger.Error(errorMessage, log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
reader := bufio.NewReader(stdout)
// start the archive; it'll send stdout (the tar archive) to `unpack.Tar` via the `io.Reader`
if err := archiveCmd.Start(); err != nil {
errorMessage := "unable to read changed files"
logger.Error(errorMessage, log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
err = unpack.Tar(reader, tmpClientDir, unpack.Opts{SkipDuplicates: true})
if err != nil {
errorMessage := "unable to read changed files"
logger.Error(errorMessage, log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// make sure the untar process completes before moving on
if err := archiveCmd.Wait(); err != nil {
errorMessage := "unable to overlay changed files"
logger.Error(errorMessage, log.Error(err))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// ensure that there are changes to shelve
if changes, err := p4Cmd.areThereChangedFilesP4(); err != nil {
errorMessage := "unable to verify that there are changed files"
logger.Error(errorMessage, log.String("output", digErrorMessage(err)), log.Error(errors.New(errorMessage)))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
} else if !changes {
errorMessage := "no changes to shelve"
logger.Error(errorMessage, log.Error(errors.New(errorMessage)))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// submit the changes as a shelved changelist
// create a changelist form with the description
changeForm, err := p4Cmd.generateChangeFormP4(desc)
if err != nil {
errorMessage := "failed generating a change form"
logger.Error(errorMessage, log.String("output", digErrorMessage(err)), log.Error(errors.New(errorMessage)))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// feed the changelist form into `p4 shelve`
// capture the output to parse for a changelist id
cid, err = p4Cmd.shelveChangelistP4(changeForm)
if err != nil {
errorMessage := "failed shelving the changelist"
logger.Error(errorMessage, log.String("output", digErrorMessage(err)), log.Error(errors.New(errorMessage)))
return "", errors.Wrap(err, "gitserver: "+errorMessage)
}
// return the changelist id as a string - it'll be returned as a string to the caller in lieu of an int pointer
// because protobuf doesn't do scalar pointers
return cid, nil
}
type p4Command struct {
ctx context.Context
workingDir string
env []string
}
func (p p4Command) commandContext(args ...string) *exec.Cmd {
cmd := exec.CommandContext(p.ctx, "p4", args...)
cmd.Dir = p.workingDir
cmd.Env = p.env
return cmd
}
// Uses `p4 changes` to see if there is a changelist already associated with the given client spec
func (p p4Command) changelistIdFromClientSpecNameP4(p4client string) (string, error) {
cmd := p.commandContext("changes",
"-r", // list in reverse order, which means that the given changelist id will be the first one listed
"-m", "1", // limit output to one record, so that the given changelist is the only one listed
"-l", // use a long listing, which includes the whole commit message
"-c", p4client,
)
out, err := cmd.CombinedOutput()
if err != nil {
return "", errors.Wrap(err, string(out))
}
pcl, err := perforce.ParseChangelistOutput(string(out))
if err != nil {
return "", errors.Wrap(err, string(out))
}
return pcl.ID, nil
}
const clientSpecForm = `Client: %s
Owner: %s
Description:
%s
Root: %s
Options: noallwrite noclobber nocompress unlocked nomodtime normdir
SubmitOptions: submitunchanged
LineEnd: local
View: %s... //%s/...
`
// Uses `p4 client` to create a client spec used to sync files with the depot
// Returns an error if `p4 client` fails
// error -> error from exec.Cmd
// __|- error -> combined output from `p4 client`
func (p p4Command) createClientSpecP4(p4depot, p4client, p4user, description string) error {
clientSpec := fmt.Sprintf(
clientSpecForm,
p4client,
p4user,
description,
p.workingDir,
p4depot,
p4client,
)
cmd := p.commandContext("client", "-i")
cmd.Stdin = bytes.NewReader([]byte(clientSpec))
out, err := cmd.CombinedOutput()
if err != nil {
return errors.Wrap(err, string(out))
}
return nil
}
// clones/downloads given files at the given base changelist
// returns an error if the sync or edit fails
// error -> error from exec.Cmd
// __|- error -> combined output from sync or edit
func (p p4Command) cloneAndEditFilesP4(fileList []string, baseChangelistId string) error {
// want to specify the file at the base changelist revision
// build a slice of file names with the changelist id appended
filesWithCid := append([]string(nil), fileList...)
for i := 0; i < len(filesWithCid); i++ {
filesWithCid[i] = filesWithCid[i] + "@" + baseChangelistId
}
if err := p.cloneFilesP4(filesWithCid); err != nil {
return err
}
if err := p.editFilesP4(fileList); err != nil {
return err
}
return nil
}
// Uses `p4 sync` to copy/clone the given files from the depot to the local workspace
// Returns an error if `p4 sync` fails
// error -> error from exec.Cmd
// __|- error -> combined output from `p4 sync`
func (p p4Command) cloneFilesP4(filesWithCid []string) error {
cmd := p.commandContext("sync")
cmd.Args = append(cmd.Args, filesWithCid...)
out, err := cmd.CombinedOutput()
if err != nil {
return errors.Wrap(err, string(out))
}
return nil
}
// Uses `p4 edit` to mark files as being edited
// Returns an error if `p4 edit` fails
// error -> error from exec.Cmd
// __|- error -> combined output from `p4 edit`
func (p p4Command) editFilesP4(fileList []string) error {
cmd := p.commandContext("edit")
cmd.Args = append(cmd.Args, fileList...)
out, err := cmd.CombinedOutput()
if err != nil {
return errors.Wrap(err, string(out))
}
return nil
}
// Uses `p4 diff` to get a list of the files that have changed in the workspace
// Returns true if the file list has 1+ files in it
// Returns false if the file list is empty
// Returns an error if `p4 diff` fails
// error -> error from exec.Cmd
// __|- error -> combined output from `p4 diff`
func (p p4Command) areThereChangedFilesP4() (bool, error) {
// use p4 diff to list the changes
diffCmd := p.commandContext("diff", "-f", "-sa")
// capture the output of `p4 diff` and count the lines
// so that the output can be returned in an error message
out, err := diffCmd.CombinedOutput()
if err != nil {
return false, errors.Wrap(err, string(out))
}
return len(strings.Split(string(out), "\n")) > 0, nil
}
// Uses `p4 change -o` to generate a form for the default changelist
// Injects the given `description` into the form.
// All lines of `description` after the first must begin with a tab character.
// Returns an error if `p4 change` fails
// error -> error from exec.Cmd
// __|- error -> combined output from `p4 change`
func (p p4Command) generateChangeFormP4(description string) (string, error) {
cmd := p.commandContext("change", "-o")
out, err := cmd.CombinedOutput()
if err != nil {
return "", errors.Wrap(err, string(out))
}
// add the commit message to the change form
return strings.Replace(string(out), "<enter description here>", description, 1), nil
}
var cidPattern = lazyregexp.New(`Change (\d+) files shelved`)
// Uses `p4 shelve` to shelve a changelist with the given form
// Returns an error if `p4 shelve` fails
// error -> error from exec.Cmd
// __|- error -> combined output from `p4 shelve`
// Returns an error if the output of `p4 shelve` does not contain a changelist id
// error -> "p4 shelve output does not contain a changelist id"
// __|- error -> combined output from `p4 shelve`
func (p p4Command) shelveChangelistP4(changeForm string) (string, error) {
cmd := p.commandContext("shelve", "-i")
changeBuffer := bytes.Buffer{}
changeBuffer.Write([]byte(changeForm))
cmd.Stdin = &changeBuffer
out, err := cmd.CombinedOutput()
if err != nil {
return "", errors.Wrap(err, string(out))
}
matches := cidPattern.FindStringSubmatch(string(out))
if len(matches) != 2 {
return "", errors.Wrap(errors.New("p4 shelve output does not contain a changelist id"), string(out))
}
return matches[1], nil
}
// return the deepest error message
// from a wrapped error
// "deepest" is somewhat facetious, as it does only one unwrap
func digErrorMessage(err error) string {
if err == nil {
return ""
}
msg := err.Error()
innerError := errors.Unwrap(err)
if innerError != nil {
msg = innerError.Error()
}
return msg
}
func cleanUpTmpRepo(logger log.Logger, path string) {
err := os.RemoveAll(path)
if err != nil {

View File

@ -1867,7 +1867,7 @@ func (s *Server) handleP4Exec(w http.ResponseWriter, r *http.Request) {
}
// Make sure the subcommand is explicitly allowed
allowlist := []string{"protects", "groups", "users", "group"}
allowlist := []string{"protects", "groups", "users", "group", "changes"}
allowed := false
for _, arg := range allowlist {
if req.Args[0] == arg {

View File

@ -215,7 +215,7 @@ func (gs *GRPCServer) P4Exec(req *proto.P4ExecRequest, ss proto.GitserverService
}
// Make sure the subcommand is explicitly allowed
allowlist := []string{"protects", "groups", "users", "group"}
allowlist := []string{"protects", "groups", "users", "group", "changes"}
allowed := false
for _, arg := range allowlist {
if req.Args[0] == arg {

View File

@ -1597,62 +1597,14 @@ def go_dependencies():
version = "v1.5.0",
)
go_repository(
name = "com_github_dave_astrid",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/astrid",
sum = "h1:YI1gOOdmMk3xodBao7fehcvoZsEeOyy/cfhlpCSPgM4=",
version = "v0.0.0-20170323122508-8c2895878b14",
)
go_repository(
name = "com_github_dave_brenda",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/brenda",
sum = "h1:Sl1LlwXnbw7xMhq3y2x11McFu43AjDcwkllxxgZ3EZw=",
version = "v1.1.0",
)
go_repository(
name = "com_github_dave_courtney",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/courtney",
sum = "h1:8aR1os2ImdIQf3Zj4oro+lD/L4Srb5VwGefqZ/jzz7U=",
version = "v0.3.0",
)
go_repository(
name = "com_github_dave_gopackages",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/gopackages",
sum = "h1:l99YKCdrK4Lvb/zTupt0GMPfNbncAGf8Cv/t1sYLOg0=",
version = "v0.0.0-20170318123100-46e7023ec56e",
)
go_repository(
name = "com_github_dave_jennifer",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/jennifer",
sum = "h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg=",
version = "v1.5.0",
)
go_repository(
name = "com_github_dave_kerr",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/kerr",
sum = "h1:xURkGi4RydhyaYR6PzcyHTueQudxY4LgxN1oYEPJHa0=",
version = "v0.0.0-20170318121727-bc25dd6abe8e",
)
go_repository(
name = "com_github_dave_patsy",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/patsy",
sum = "h1:1o36L4EKbZzazMk8iGC4kXpVnZ6TPxR2mZ9qVKjNNAs=",
version = "v0.0.0-20210517141501-957256f50cba",
)
go_repository(
name = "com_github_dave_rebecca",
build_file_proto_mode = "disable_global",
importpath = "github.com/dave/rebecca",
sum = "h1:jxVfdOxRirbXL28vXMvUvJ1in3djwkVKXCq339qhBL0=",
version = "v0.9.1",
sum = "h1:T4T/67t6RAA5AIV6+NP8Uk/BIsXgDoqEowgycdQQLuk=",
version = "v1.6.1",
)
go_repository(
name = "com_github_davecgh_go_spew",
build_file_proto_mode = "disable_global",
@ -1958,8 +1910,8 @@ def go_dependencies():
name = "com_github_dustin_go_humanize",
build_file_proto_mode = "disable_global",
importpath = "github.com/dustin/go-humanize",
sum = "h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=",
version = "v1.0.0",
sum = "h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=",
version = "v1.0.1",
)
go_repository(
@ -2545,8 +2497,8 @@ def go_dependencies():
name = "com_github_go_logr_logr",
build_file_proto_mode = "disable_global",
importpath = "github.com/go-logr/logr",
sum = "h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=",
version = "v1.2.3",
sum = "h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=",
version = "v1.2.4",
)
go_repository(
name = "com_github_go_logr_stdr",
@ -2741,8 +2693,8 @@ def go_dependencies():
name = "com_github_go_task_slim_sprig",
build_file_proto_mode = "disable_global",
importpath = "github.com/go-task/slim-sprig",
sum = "h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=",
version = "v0.0.0-20210107165309-348f09dbbbc0",
sum = "h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=",
version = "v0.0.0-20230315185526-52ccab3ef572",
)
go_repository(
@ -5372,16 +5324,16 @@ def go_dependencies():
name = "com_github_onsi_ginkgo_v2",
build_file_proto_mode = "disable_global",
importpath = "github.com/onsi/ginkgo/v2",
sum = "h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=",
version = "v2.1.6",
sum = "h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=",
version = "v2.9.7",
)
go_repository(
name = "com_github_onsi_gomega",
build_file_proto_mode = "disable_global",
importpath = "github.com/onsi/gomega",
sum = "h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=",
version = "v1.20.1",
sum = "h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=",
version = "v1.27.8",
)
go_repository(
@ -9050,8 +9002,8 @@ def go_dependencies():
name = "org_golang_x_mod",
build_file_proto_mode = "disable_global",
importpath = "golang.org/x/mod",
sum = "h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=",
version = "v0.8.0",
sum = "h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=",
version = "v0.10.0",
)
go_repository(
name = "org_golang_x_net",
@ -9072,8 +9024,8 @@ def go_dependencies():
name = "org_golang_x_sync",
build_file_proto_mode = "disable_global",
importpath = "golang.org/x/sync",
sum = "h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=",
version = "v0.1.0",
sum = "h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=",
version = "v0.2.0",
)
go_repository(
name = "org_golang_x_sys",
@ -9107,8 +9059,8 @@ def go_dependencies():
name = "org_golang_x_tools",
build_file_proto_mode = "disable_global",
importpath = "golang.org/x/tools",
sum = "h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=",
version = "v0.6.0",
sum = "h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=",
version = "v0.9.3",
)
go_repository(
name = "org_golang_x_xerrors",

View File

@ -66,7 +66,7 @@ func (c *batchChangesCodeHostResolver) RequiresSSH() bool {
func (c *batchChangesCodeHostResolver) RequiresUsername() bool {
switch c.codeHost.ExternalServiceType {
case extsvc.TypeBitbucketCloud, extsvc.TypeAzureDevOps, extsvc.TypeGerrit:
case extsvc.TypeBitbucketCloud, extsvc.TypeAzureDevOps, extsvc.TypePerforce:
return true
}

View File

@ -1231,6 +1231,13 @@ func (r *Resolver) generateAuthenticatorForCredential(ctx context.Context, exter
PublicKey: keypair.PublicKey,
Passphrase: keypair.Passphrase,
}
} else if externalServiceType == extsvc.TypePerforce {
a = &extsvcauth.BasicAuthWithSSH{
BasicAuth: extsvcauth.BasicAuth{Username: *username, Password: credential},
PrivateKey: keypair.PrivateKey,
PublicKey: keypair.PublicKey,
Passphrase: keypair.Passphrase,
}
} else {
a = &extsvcauth.OAuthBearerTokenWithSSH{
OAuthBearerToken: extsvcauth.OAuthBearerToken{Token: credential},

View File

@ -181,6 +181,7 @@ func (e *executor) pushChangesetPatch(ctx context.Context, triggerUpdateWebhook
// Create a commit and push it
// Figure out which authenticator we should use to modify the changeset.
css, err := e.changesetSource(ctx)
if err != nil {
return afterDone, err
}
@ -213,6 +214,12 @@ func (e *executor) pushChangesetPatch(ctx context.Context, triggerUpdateWebhook
}
}
// update the changeset's external_id column if a changelist id is returned
// because that's going to make it back to the UI so that the user can see the changelist id and take action on it
if resp != nil && resp.ChangelistId != "" {
e.ch.ExternalID = resp.ChangelistId
}
if err = e.runAfterCommit(ctx, css, resp, remoteRepo, opts); err != nil {
return afterDone, errors.Wrap(err, "running after commit routine")
}

View File

@ -11,6 +11,7 @@ go_library(
"gerrit.go",
"github.go",
"gitlab.go",
"perforce.go",
"sources.go",
"util.go",
],
@ -39,6 +40,7 @@ go_library(
"//internal/extsvc/github/auth",
"//internal/extsvc/gitlab",
"//internal/extsvc/versions",
"//internal/gitserver",
"//internal/gitserver/gitdomain",
"//internal/gitserver/protocol",
"//internal/httpcli",
@ -64,6 +66,7 @@ go_test(
"gitlab_test.go",
"main_test.go",
"mocks_test.go",
"perforce_test.go",
"sources_test.go",
],
data = glob(["testdata/**"]),
@ -77,6 +80,7 @@ go_test(
"//enterprise/internal/github_apps/store",
"//enterprise/internal/github_apps/types",
"//internal/api",
"//internal/authz",
"//internal/conf",
"//internal/database",
"//internal/errcode",
@ -89,6 +93,8 @@ go_test(
"//internal/extsvc/github",
"//internal/extsvc/gitlab",
"//internal/extsvc/versions",
"//internal/gitserver",
"//internal/gitserver/gitdomain",
"//internal/gitserver/protocol",
"//internal/httpcli",
"//internal/httptestutil",
@ -105,6 +111,7 @@ go_test(
"@com_github_grafana_regexp//:regexp",
"@com_github_inconshreveable_log15//:log15",
"@com_github_masterminds_semver//:semver",
"@com_github_sourcegraph_go_diff//diff",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//mock",
"@com_github_stretchr_testify//require",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
package sources
import (
"context"
"fmt"
"net/url"
btypes "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/types"
"github.com/sourcegraph/sourcegraph/internal/extsvc/auth"
"github.com/sourcegraph/sourcegraph/internal/gitserver"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/sourcegraph/sourcegraph/internal/httpcli"
"github.com/sourcegraph/sourcegraph/internal/jsonc"
"github.com/sourcegraph/sourcegraph/internal/types"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/schema"
)
type PerforceSource struct {
server schema.PerforceConnection
gitServerClient gitserver.Client
perforceCreds *gitserver.PerforceCredentials
}
func NewPerforceSource(ctx context.Context, svc *types.ExternalService, _ *httpcli.Factory) (*PerforceSource, error) {
rawConfig, err := svc.Config.Decrypt(ctx)
if err != nil {
return nil, errors.Errorf("external service id=%d config error: %s", svc.ID, err)
}
var c schema.PerforceConnection
if err := jsonc.Unmarshal(rawConfig, &c); err != nil {
return nil, errors.Wrapf(err, "external service id=%d", svc.ID)
}
return &PerforceSource{server: c, gitServerClient: gitserver.NewClient()}, nil
}
// GitserverPushConfig returns an authenticated push config used for pushing commits to the code host.
func (s PerforceSource) GitserverPushConfig(repo *types.Repo) (*protocol.PushConfig, error) {
// Return a PushConfig with a crafted URL that includes the Perforce scheme and the credentials
// The perforce scheme will tell `createCommitFromPatch` that this repo is a Perforce repo
// so it can handle it differently from Git repos.
// TODO: @peterguy: this seems to be the correct way to include the depot; confirm with more examples from code host configurations
depot := ""
u, err := url.Parse(repo.URI)
if err == nil {
depot = "//" + u.Path + "/"
}
remoteURL := fmt.Sprintf("perforce://%s:%s@%s%s", s.perforceCreds.Username, s.perforceCreds.Password, s.server.P4Port, depot)
return &protocol.PushConfig{
RemoteURL: remoteURL,
}, nil
}
// WithAuthenticator returns a copy of the original Source configured to use the
// given authenticator, provided that authenticator type is supported by the
// code host.
func (s PerforceSource) WithAuthenticator(a auth.Authenticator) (ChangesetSource, error) {
switch av := a.(type) {
case *auth.BasicAuthWithSSH:
s.perforceCreds = &gitserver.PerforceCredentials{
Username: av.Username,
Password: av.Password,
Host: s.server.P4Port,
}
case *auth.BasicAuth:
s.perforceCreds = &gitserver.PerforceCredentials{
Username: av.Username,
Password: av.Password,
Host: s.server.P4Port,
}
default:
return s, errors.New("unexpected auther type for Perforce Source")
}
return s, nil
}
// ValidateAuthenticator validates the currently set authenticator is usable.
// Returns an error, when validating the Authenticator yielded an error.
func (s PerforceSource) ValidateAuthenticator(ctx context.Context) error {
if s.perforceCreds == nil {
return errors.New("no credentials set for Perforce Source")
}
rc, _, err := s.gitServerClient.P4Exec(ctx, s.perforceCreds.Host, s.perforceCreds.Username, s.perforceCreds.Password, "users")
if err == nil {
_ = rc.Close()
return nil
}
return err
}
// LoadChangeset loads the given Changeset from the source and updates it. If
// the Changeset could not be found on the source, a ChangesetNotFoundError is
// returned.
func (s PerforceSource) LoadChangeset(ctx context.Context, cs *Changeset) error {
if s.perforceCreds == nil {
return errors.New("no credentials set for Perforce Source")
}
cl, err := s.gitServerClient.P4GetChangelist(ctx, cs.ExternalID, *s.perforceCreds)
if err != nil {
return errors.Wrap(err, "getting changelist")
}
return errors.Wrap(s.setChangesetMetadata(cl, cs), "setting perforce changeset metadata")
}
// CreateChangeset will create the Changeset on the source. If it already
// exists, *Changeset will be populated and the return value will be true.
func (s PerforceSource) CreateChangeset(ctx context.Context, cs *Changeset) (bool, error) {
return false, s.LoadChangeset(ctx, cs)
}
// CreateDraftChangeset creates the given changeset on the code host in draft mode.
// Perforce does not support draft changelists
func (s PerforceSource) CreateDraftChangeset(_ context.Context, _ *Changeset) (bool, error) {
return false, errors.New("not implemented")
}
func (s PerforceSource) setChangesetMetadata(cl *protocol.PerforceChangelist, cs *Changeset) error {
if err := cs.SetMetadata(cl); err != nil {
return errors.Wrap(err, "setting changeset metadata")
}
return nil
}
// UndraftChangeset will update the Changeset on the source to be not in draft mode anymore.
func (s PerforceSource) UndraftChangeset(_ context.Context, _ *Changeset) error {
// TODO: @peterguy implement this function?
// not sure what it means in Perforce - submit the changelist?
return errors.New("not implemented")
}
// CloseChangeset will close the Changeset on the source, where "close"
// means the appropriate final state on the codehost.
// deleted on Perforce, maybe?
func (s PerforceSource) CloseChangeset(_ context.Context, _ *Changeset) error {
// TODO: @peterguy implement this function
// delete changelist?
return errors.New("not implemented")
}
// UpdateChangeset can update Changesets.
func (s PerforceSource) UpdateChangeset(_ context.Context, _ *Changeset) error {
// TODO: @peterguy implement this function
// not sure what this means for Perforce
return errors.New("not implemented")
}
// ReopenChangeset will reopen the Changeset on the source, if it's closed.
// If not, it's a noop.
func (s PerforceSource) ReopenChangeset(_ context.Context, _ *Changeset) error {
// TODO: @peterguy implement function
// noop for Perforce?
return errors.New("not implemented")
}
// CreateComment posts a comment on the Changeset.
func (s PerforceSource) CreateComment(_ context.Context, _ *Changeset, _ string) error {
// TODO: @peterguy implement function
// comment on changelist?
return errors.New("not implemented")
}
// MergeChangeset merges a Changeset on the code host, if in a mergeable state.
// If squash is true, and the code host supports squash merges, the source
// must attempt a squash merge. Otherwise, it is expected to perform a regular
// merge. If the changeset cannot be merged, because it is in an unmergeable
// state, ChangesetNotMergeableError must be returned.
func (s PerforceSource) MergeChangeset(_ context.Context, _ *Changeset, _ bool) error {
// TODO: @peterguy implement function
// submit CL? Or no-op because we want to keep CLs pending and let the Perforce users manage them in other tools?
return errors.New("not implemented")
}
func (s PerforceSource) BuildCommitOpts(repo *types.Repo, _ *btypes.Changeset, spec *btypes.ChangesetSpec, pushOpts *protocol.PushConfig) protocol.CreateCommitFromPatchRequest {
return BuildCommitOptsCommon(repo, spec, pushOpts)
}

View File

@ -0,0 +1,149 @@
package sources
import (
"context"
"io"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/sourcegraph/sourcegraph/internal/gitserver"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/sourcegraph/sourcegraph/schema"
btypes "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/types"
"github.com/sourcegraph/sourcegraph/internal/types"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
var (
testPerforceProjectName = "testdepot"
testPerforceChangeID = "111"
testPerforceCredentials = gitserver.PerforceCredentials{Username: "user", Password: "pass", Host: "https://perforce.sgdev.org:1666"}
)
func TestPerforceSource_ValidateAuthenticator(t *testing.T) {
ctx := context.Background()
for name, want := range map[string]error{
"nil": nil,
"error": errors.New("error"),
} {
t.Run(name, func(t *testing.T) {
s, client := mockPerforceSource()
client.P4ExecFunc.SetDefaultReturn(fakeCloser{}, http.Header{}, want)
assert.Equal(t, want, s.ValidateAuthenticator(ctx))
})
}
}
func TestPerforceSource_LoadChangeset(t *testing.T) {
ctx := context.Background()
t.Run("error getting changelist", func(t *testing.T) {
cs, _ := mockPerforceChangeset()
s, client := mockPerforceSource()
want := errors.New("error")
client.P4GetChangelistFunc.SetDefaultHook(func(ctx context.Context, changeID string, credentials gitserver.PerforceCredentials) (*protocol.PerforceChangelist, error) {
assert.Equal(t, changeID, testPerforceChangeID)
assert.Equal(t, testPerforceCredentials, credentials)
return new(protocol.PerforceChangelist), want
})
err := s.LoadChangeset(ctx, cs)
assert.NotNil(t, err)
assert.ErrorIs(t, err, want)
})
t.Run("success", func(t *testing.T) {
cs, _ := mockPerforceChangeset()
s, client := mockPerforceSource()
change := mockPerforceChange()
client.P4GetChangelistFunc.SetDefaultHook(func(ctx context.Context, changeID string, credentials gitserver.PerforceCredentials) (*protocol.PerforceChangelist, error) {
assert.Equal(t, changeID, testPerforceChangeID)
assert.Equal(t, testPerforceCredentials, credentials)
return change, nil
})
err := s.LoadChangeset(ctx, cs)
assert.Nil(t, err)
})
}
func TestPerforceSource_CreateChangeset(t *testing.T) {
ctx := context.Background()
t.Run("error getting pull request", func(t *testing.T) {
cs, _ := mockPerforceChangeset()
s, client := mockPerforceSource()
want := errors.New("error")
client.P4GetChangelistFunc.SetDefaultHook(func(ctx context.Context, changeID string, credentials gitserver.PerforceCredentials) (*protocol.PerforceChangelist, error) {
assert.Equal(t, changeID, testPerforceChangeID)
assert.Equal(t, testPerforceCredentials, credentials)
return new(protocol.PerforceChangelist), want
})
b, err := s.CreateChangeset(ctx, cs)
assert.NotNil(t, err)
assert.ErrorIs(t, err, want)
assert.False(t, b)
})
t.Run("success", func(t *testing.T) {
cs, _ := mockPerforceChangeset()
s, client := mockPerforceSource()
change := mockPerforceChange()
client.P4GetChangelistFunc.SetDefaultHook(func(ctx context.Context, changeID string, credentials gitserver.PerforceCredentials) (*protocol.PerforceChangelist, error) {
assert.Equal(t, changeID, testPerforceChangeID)
assert.Equal(t, testPerforceCredentials, credentials)
return change, nil
})
b, err := s.CreateChangeset(ctx, cs)
assert.Nil(t, err)
assert.False(t, b)
})
}
// mockPerforceChangeset creates a plausible non-forked changeset, repo,
// and Perforce specific repo.
func mockPerforceChangeset() (*Changeset, *types.Repo) {
repo := &types.Repo{Metadata: &testProject}
cs := &Changeset{
Title: "title",
Body: "description",
Changeset: &btypes.Changeset{},
RemoteRepo: repo,
TargetRepo: repo,
BaseRef: "refs/heads/targetbranch",
}
cs.Changeset.ExternalID = testPerforceChangeID
return cs, repo
}
// mockPerforceChange returns a plausible changelist that would be
// returned from Perforce.
func mockPerforceChange() *protocol.PerforceChangelist {
return &protocol.PerforceChangelist{
ID: testPerforceChangeID,
Author: "Peter Guy",
State: protocol.PerforceChangelistStatePending,
}
}
func mockPerforceSource() (*PerforceSource, *MockGitserverClient) {
client := NewStrictMockGitserverClient()
s := &PerforceSource{gitServerClient: client, perforceCreds: &testPerforceCredentials, server: schema.PerforceConnection{P4Port: "https://perforce.sgdev.org:1666"}}
return s, client
}
type fakeCloser struct {
io.Reader
}
func (fakeCloser) Close() error { return nil }

View File

@ -420,7 +420,8 @@ func loadExternalService(ctx context.Context, s database.ExternalServiceStore, o
*schema.GitLabConnection,
*schema.BitbucketCloudConnection,
*schema.AzureDevOpsConnection,
*schema.GerritConnection:
*schema.GerritConnection,
*schema.PerforceConnection:
return e, nil
}
}
@ -444,6 +445,8 @@ func buildChangesetSource(ctx context.Context, cf *httpcli.Factory, externalServ
return NewAzureDevOpsSource(ctx, externalService, cf)
case extsvc.KindGerrit:
return NewGerritSource(ctx, externalService, cf)
case extsvc.KindPerforce:
return NewPerforceSource(ctx, externalService, cf)
default:
return nil, errors.Errorf("unsupported external service type %q", extsvc.KindToType(externalService.Kind))
}

View File

@ -28,6 +28,7 @@ go_library(
"//internal/extsvc/github",
"//internal/extsvc/gitlab",
"//internal/gitserver",
"//internal/gitserver/protocol",
"//internal/types",
"//lib/errors",
"@com_github_inconshreveable_log15//:log15",

View File

@ -12,6 +12,7 @@ import (
gerritbatches "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/sources/gerrit"
adobatches "github.com/sourcegraph/sourcegraph/internal/extsvc/azuredevops"
"github.com/sourcegraph/sourcegraph/internal/extsvc/gerrit"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/sourcegraph/go-diff/diff"
@ -120,8 +121,8 @@ func computeCheckState(c *btypes.Changeset, events ChangesetEvents) btypes.Chang
return computeBitbucketCloudBuildState(c.UpdatedAt, m, events)
case *azuredevops.AnnotatedPullRequest:
return computeAzureDevOpsBuildState(m)
case gerritbatches.AnnotatedChange:
// Gerrit doesn't have builds built-in, I think its better to be explicit by still
case *gerritbatches.AnnotatedChange, *protocol.PerforceChangelistState:
// Gerrit and Perforce don't have builds built-in, its better to be explicit by still
// including this case for clarity.
return btypes.ChangesetCheckStateUnknown
}
@ -585,6 +586,17 @@ func computeSingleChangesetExternalState(c *btypes.Changeset) (s btypes.Changese
default:
return "", errors.Errorf("unknown Gerrit Change state: %s", m.Change.Status)
}
case *protocol.PerforceChangelist:
switch m.State {
case protocol.PerforceChangelistStateClosed:
s = btypes.ChangesetExternalStateClosed
case protocol.PerforceChangelistStateSubmitted:
s = btypes.ChangesetExternalStateMerged
case protocol.PerforceChangelistStatePending, protocol.PerforceChangelistStateShelved:
s = btypes.ChangesetExternalStateOpen
default:
return "", errors.Errorf("unknown Gerrit Change state: %s", m.State)
}
default:
return "", errors.New("unknown changeset type")
}
@ -695,7 +707,8 @@ func computeSingleChangesetReviewState(c *btypes.Changeset) (s btypes.ChangesetR
states[btypes.ChangesetReviewStatePending] = true
}
}
case *protocol.PerforceChangelist:
states[btypes.ChangesetReviewStatePending] = true
default:
return "", errors.New("unknown changeset type")
}

View File

@ -53,6 +53,7 @@ go_library(
"//internal/extsvc/github",
"//internal/extsvc/gitlab",
"//internal/featureflag",
"//internal/gitserver/protocol",
"//internal/metrics",
"//internal/observation",
"//internal/timeutil",

View File

@ -16,6 +16,7 @@ import (
gerritbatches "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/sources/gerrit"
"github.com/sourcegraph/sourcegraph/internal/extsvc/azuredevops"
"github.com/sourcegraph/sourcegraph/internal/extsvc/gerrit"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/keegancsmith/sqlf"
"github.com/lib/pq"
@ -1525,6 +1526,10 @@ func ScanChangeset(t *btypes.Changeset, s dbutil.Scanner) error {
m := new(gerritbatches.AnnotatedChange)
m.Change = &gerrit.Change{}
t.Metadata = m
case extsvc.TypePerforce:
t.Metadata = new(protocol.PerforceChangelist)
case extsvc.TypeGerrit:
t.Metadata = new(gerrit.Change)
default:
return errors.New("unknown external service type")
}

View File

@ -116,7 +116,7 @@ func listCodeHostsQuery(opts ListCodeHostsOpts) *sqlf.Query {
// Only show supported hosts.
supportedTypes := []*sqlf.Query{}
for extSvcType := range btypes.SupportedExternalServices {
for extSvcType := range btypes.GetSupportedExternalServices() {
supportedTypes = append(supportedTypes, sqlf.Sprintf("%s", extSvcType))
}
repoPreds = append(repoPreds, sqlf.Sprintf("repo.external_service_type IN (%s)", sqlf.Join(supportedTypes, ", ")))

View File

@ -45,6 +45,7 @@ go_library(
"//internal/extsvc/gitlab",
"//internal/extsvc/gitlab/webhooks",
"//internal/gitserver/gitdomain",
"//internal/gitserver/protocol",
"//internal/timeutil",
"//internal/types",
"//lib/batches",

View File

@ -10,13 +10,15 @@ import (
"github.com/goware/urlx"
"github.com/inconshreveable/log15"
"github.com/sourcegraph/go-diff/diff"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
gerritbatches "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/sources/gerrit"
"github.com/sourcegraph/sourcegraph/internal/extsvc/azuredevops"
adobatches "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/sources/azuredevops"
bbcs "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/sources/bitbucketcloud"
gerritbatches "github.com/sourcegraph/sourcegraph/enterprise/internal/batches/sources/gerrit"
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/extsvc"
"github.com/sourcegraph/sourcegraph/internal/extsvc/azuredevops"
"github.com/sourcegraph/sourcegraph/internal/extsvc/bitbucketcloud"
"github.com/sourcegraph/sourcegraph/internal/extsvc/bitbucketserver"
"github.com/sourcegraph/sourcegraph/internal/extsvc/gerrit"
@ -467,6 +469,12 @@ func (c *Changeset) SetMetadata(meta any) error {
c.ExternalServiceType = extsvc.TypeGerrit
c.ExternalBranch = gitdomain.EnsureRefPrefix(pr.Change.Branch)
c.ExternalUpdatedAt = pr.Change.Updated
case *protocol.PerforceChangelist:
c.Metadata = pr
c.ExternalID = pr.ID
c.ExternalServiceType = extsvc.TypePerforce
// Perforce does not have a last updated at field on its CL objects, so we set the creation time.
c.ExternalUpdatedAt = pr.CreationDate
default:
return errors.New("setmetadata unknown changeset type")
}
@ -501,6 +509,8 @@ func (c *Changeset) Title() (string, error) {
// Remove extra quotes added by the commit message
title = strings.TrimPrefix(strings.TrimSuffix(title, "\""), "\"")
return title, nil
case *protocol.PerforceChangelist:
return m.Title, nil
default:
return "", errors.New("title unknown changeset type")
}
@ -526,6 +536,8 @@ func (c *Changeset) AuthorName() (string, error) {
return m.CreatedBy.UniqueName, nil
case *gerritbatches.AnnotatedChange:
return m.Change.Owner.Name, nil
case *protocol.PerforceChangelist:
return m.Author, nil
default:
return "", errors.New("authorname unknown changeset type")
}
@ -559,6 +571,8 @@ func (c *Changeset) AuthorEmail() (string, error) {
return m.CreatedBy.UniqueName, nil
case *gerritbatches.AnnotatedChange:
return m.Change.Owner.Email, nil
case *protocol.PerforceChangelist:
return "", nil
default:
return "", errors.New("author email unknown changeset type")
}
@ -581,6 +595,8 @@ func (c *Changeset) ExternalCreatedAt() time.Time {
return m.CreationDate
case *gerritbatches.AnnotatedChange:
return m.Change.Created
case *protocol.PerforceChangelist:
return m.CreationDate
default:
return time.Time{}
}
@ -602,6 +618,8 @@ func (c *Changeset) Body() (string, error) {
case *gerritbatches.AnnotatedChange:
// Gerrit doesn't really differentiate between title/description.
return m.Change.Subject, nil
case *protocol.PerforceChangelist:
return "", nil
default:
return "", errors.New("body unknown changeset type")
}
@ -668,6 +686,8 @@ func (c *Changeset) URL() (s string, err error) {
return returnURL.String(), nil
case *gerritbatches.AnnotatedChange:
return m.CodeHostURL.JoinPath("c", url.PathEscape(m.Change.Project), "+", url.PathEscape(strconv.Itoa(m.Change.ChangeNumber))).String(), nil
case *protocol.PerforceChangelist:
return "", nil
default:
return "", errors.New("url unknown changeset type")
}
@ -886,6 +906,9 @@ func (c *Changeset) Events() (events []*ChangesetEvent, err error) {
Metadata: reviewer,
})
}
case *protocol.PerforceChangelist:
// We don't have any events we care about right now
break
}
return events, nil
@ -908,6 +931,8 @@ func (c *Changeset) HeadRefOid() (string, error) {
return "", nil
case *gerritbatches.AnnotatedChange:
return "", nil
case *protocol.PerforceChangelist:
return "", nil
default:
return "", errors.New("head ref oid unknown changeset type")
}
@ -929,6 +954,8 @@ func (c *Changeset) HeadRef() (string, error) {
return m.SourceRefName, nil
case *gerritbatches.AnnotatedChange:
return "", nil
case *protocol.PerforceChangelist:
return "", nil
default:
return "", errors.New("headref unknown changeset type")
}
@ -951,6 +978,8 @@ func (c *Changeset) BaseRefOid() (string, error) {
return "", nil
case *gerritbatches.AnnotatedChange:
return "", nil
case *protocol.PerforceChangelist:
return "", nil
default:
return "", errors.New("base ref oid unknown changeset type")
}
@ -972,6 +1001,9 @@ func (c *Changeset) BaseRef() (string, error) {
return m.TargetRefName, nil
case *gerritbatches.AnnotatedChange:
return "refs/heads/" + m.Change.Branch, nil
case *protocol.PerforceChangelist:
// TODO: @peterguy we may need to change this to something.
return "", nil
default:
return "", errors.New(" base ref unknown changeset type")
}

View File

@ -147,21 +147,19 @@ func (e *ChangesetEvent) Clone() *ChangesetEvent {
// Returns an empty string if not a review event or the author has been deleted.
func (e *ChangesetEvent) ReviewAuthor() string {
switch meta := e.Metadata.(type) {
case *github.PullRequestReview:
return meta.Author.Login
case *github.ReviewDismissedEvent:
return meta.Review.Author.Login
case *bitbucketserver.Activity:
return meta.User.Name
case *bitbucketserver.ParticipantStatusEvent:
return meta.User.Name
case *gitlab.ReviewApprovedEvent:
return meta.Author.Username
case *gitlab.ReviewUnapprovedEvent:
return meta.Author.Username
@ -170,18 +168,15 @@ func (e *ChangesetEvent) ReviewAuthor() string {
// for each author and isn't surfaced in the UI, we can use the UUID.
case *bitbucketcloud.Participant:
return meta.User.UUID
case *bitbucketcloud.PullRequestApprovedEvent:
return meta.Approval.User.UUID
case *bitbucketcloud.PullRequestUnapprovedEvent:
return meta.Approval.User.UUID
case *bitbucketcloud.PullRequestChangesRequestCreatedEvent:
return meta.ChangesRequest.User.UUID
case *bitbucketcloud.PullRequestChangesRequestRemovedEvent:
return meta.ChangesRequest.User.UUID
case *azuredevops.PullRequestApprovedEvent:
if len(meta.PullRequest.Reviewers) == 0 {
return meta.PullRequest.CreatedBy.UniqueName
@ -857,55 +852,42 @@ func (e *ChangesetEvent) Update(o *ChangesetEvent) error {
case *bitbucketcloud.Participant:
o := o.Metadata.(*bitbucketcloud.Participant)
*e = *o
case *bitbucketcloud.PullRequestStatus:
o := o.Metadata.(*bitbucketcloud.PullRequestStatus)
*e = *o
case *bitbucketcloud.PullRequestApprovedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestApprovedEvent)
*e = *o
case *bitbucketcloud.PullRequestChangesRequestCreatedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestChangesRequestCreatedEvent)
*e = *o
case *bitbucketcloud.PullRequestChangesRequestRemovedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestChangesRequestRemovedEvent)
*e = *o
case *bitbucketcloud.PullRequestCommentCreatedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestCommentCreatedEvent)
*e = *o
case *bitbucketcloud.PullRequestCommentDeletedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestCommentDeletedEvent)
*e = *o
case *bitbucketcloud.PullRequestCommentUpdatedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestCommentUpdatedEvent)
*e = *o
case *bitbucketcloud.PullRequestFulfilledEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestFulfilledEvent)
*e = *o
case *bitbucketcloud.PullRequestRejectedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestRejectedEvent)
*e = *o
case *bitbucketcloud.PullRequestUnapprovedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestUnapprovedEvent)
*e = *o
case *bitbucketcloud.PullRequestUpdatedEvent:
o := o.Metadata.(*bitbucketcloud.PullRequestUpdatedEvent)
*e = *o
case *bitbucketcloud.RepoCommitStatusCreatedEvent:
o := o.Metadata.(*bitbucketcloud.RepoCommitStatusCreatedEvent)
*e = *o
case *bitbucketcloud.RepoCommitStatusUpdatedEvent:
o := o.Metadata.(*bitbucketcloud.RepoCommitStatusUpdatedEvent)
*e = *o
@ -913,27 +895,21 @@ func (e *ChangesetEvent) Update(o *ChangesetEvent) error {
case *azuredevops.PullRequestUpdatedEvent:
o := o.Metadata.(*azuredevops.PullRequestUpdatedEvent)
*e = *o
case *azuredevops.PullRequestMergedEvent:
o := o.Metadata.(*azuredevops.PullRequestMergedEvent)
*e = *o
case *azuredevops.PullRequestApprovedEvent:
o := o.Metadata.(*azuredevops.PullRequestApprovedEvent)
*e = *o
case *azuredevops.PullRequestApprovedWithSuggestionsEvent:
o := o.Metadata.(*azuredevops.PullRequestApprovedWithSuggestionsEvent)
*e = *o
case *azuredevops.PullRequestWaitingForAuthorEvent:
o := o.Metadata.(*azuredevops.PullRequestWaitingForAuthorEvent)
*e = *o
case *azuredevops.PullRequestRejectedEvent:
o := o.Metadata.(*azuredevops.PullRequestRejectedEvent)
*e = *o
default:
return errors.Errorf("unknown changeset event metadata %T", e)
}

View File

@ -4,6 +4,7 @@ import (
"time"
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/conf"
"github.com/sourcegraph/sourcegraph/internal/extsvc"
)
@ -16,35 +17,42 @@ const (
type CodehostCapabilities map[CodehostCapability]bool
// SupportedExternalServices are the external service types currently supported
// GetSupportedExternalServices returns the external service types currently supported
// by the batch changes feature. Repos that are associated with external services
// whose type is not in this list will simply be filtered out from the search
// results.
var SupportedExternalServices = map[string]CodehostCapabilities{
extsvc.TypeGitHub: {CodehostCapabilityLabels: true, CodehostCapabilityDraftChangesets: true},
extsvc.TypeBitbucketServer: {},
extsvc.TypeGitLab: {CodehostCapabilityLabels: true, CodehostCapabilityDraftChangesets: true},
extsvc.TypeBitbucketCloud: {},
extsvc.TypeAzureDevOps: {CodehostCapabilityDraftChangesets: true},
extsvc.TypeGerrit: {CodehostCapabilityDraftChangesets: true},
func GetSupportedExternalServices() map[string]CodehostCapabilities {
supportedExternalServices := map[string]CodehostCapabilities{
extsvc.TypeGitHub: {CodehostCapabilityLabels: true, CodehostCapabilityDraftChangesets: true},
extsvc.TypeBitbucketServer: {},
extsvc.TypeGitLab: {CodehostCapabilityLabels: true, CodehostCapabilityDraftChangesets: true},
extsvc.TypeBitbucketCloud: {},
extsvc.TypeAzureDevOps: {CodehostCapabilityDraftChangesets: true},
extsvc.TypeGerrit: {CodehostCapabilityDraftChangesets: true},
}
if conf.Get().ExperimentalFeatures != nil && conf.Get().ExperimentalFeatures.BatchChangesEnablePerforce {
supportedExternalServices[extsvc.TypePerforce] = CodehostCapabilities{}
}
return supportedExternalServices
}
// IsRepoSupported returns whether the given ExternalRepoSpec is supported by
// the batch changes feature, based on the external service type.
func IsRepoSupported(spec *api.ExternalRepoSpec) bool {
_, ok := SupportedExternalServices[spec.ServiceType]
_, ok := GetSupportedExternalServices()[spec.ServiceType]
return ok
}
// IsKindSupported returns whether the given extsvc Kind is supported by
// batch changes.
func IsKindSupported(extSvcKind string) bool {
_, ok := SupportedExternalServices[extsvc.KindToType(extSvcKind)]
_, ok := GetSupportedExternalServices()[extsvc.KindToType(extSvcKind)]
return ok
}
func ExternalServiceSupports(extSvcType string, capability CodehostCapability) bool {
if es, ok := SupportedExternalServices[extSvcType]; ok {
if es, ok := GetSupportedExternalServices()[extSvcType]; ok {
val, ok := es[capability]
return ok && val
}

14
go.mod
View File

@ -242,10 +242,10 @@ require (
golang.org/x/crypto v0.7.0
golang.org/x/net v0.10.0
golang.org/x/oauth2 v0.8.0
golang.org/x/sync v0.1.0
golang.org/x/sync v0.2.0
golang.org/x/sys v0.8.0
golang.org/x/time v0.3.0
golang.org/x/tools v0.6.0
golang.org/x/tools v0.9.3
gonum.org/v1/gonum v0.12.0
google.golang.org/api v0.110.0
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc
@ -307,6 +307,8 @@ require (
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.9.7 // indirect
github.com/onsi/gomega v1.27.8 // indirect
github.com/pjbgf/sha1cd v0.2.3 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/prometheus v0.40.5 // indirect
@ -375,7 +377,7 @@ require (
github.com/containerd/typeurl v1.0.2 // indirect
github.com/coreos/go-iptables v0.6.0
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/dave/jennifer v1.5.0 // indirect
github.com/dave/jennifer v1.6.1 // indirect
github.com/di-wu/xsd-datetime v1.0.0
github.com/djherbis/buffer v1.2.0 // indirect
github.com/djherbis/nio/v3 v3.0.1 // indirect
@ -383,7 +385,7 @@ require (
github.com/docker/docker v23.0.1+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.0
github.com/dustin/go-humanize v1.0.1
github.com/elimity-com/scim v0.0.0-20220121082953-15165b1a61c8
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.9.1 // indirect
@ -400,7 +402,7 @@ require (
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
@ -536,7 +538,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.13.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
golang.org/x/mod v0.8.0
golang.org/x/mod v0.10.0
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect

37
go.sum
View File

@ -613,15 +613,8 @@ github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/danaugrs/go-tsne v0.0.0-20200708172100-6b7d1d577fd3/go.mod h1:tcVxJUGCaPp/YynlqJTfJtGc/LF9vn4WUZSSmaGu3dA=
github.com/dave/astrid v0.0.0-20170323122508-8c2895878b14/go.mod h1:Sth2QfxfATb/nW4EsrSi2KyJmbcniZ8TgTaji17D6ms=
github.com/dave/brenda v1.1.0/go.mod h1:4wCUr6gSlu5/1Tk7akE5X7UorwiQ8Rij0SKH3/BGMOM=
github.com/dave/courtney v0.3.0/go.mod h1:BAv3hA06AYfNUjfjQr+5gc6vxeBVOupLqrColj+QSD8=
github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ=
github.com/dave/jennifer v1.5.0 h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg=
github.com/dave/jennifer v1.5.0/go.mod h1:4MnyiFIlZS3l5tSDn8VnzE6ffAhYBMB2SZntBsZGUok=
github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e/go.mod h1:qZqlPyPvfsDJt+3wHJ1EvSXDuVjFTK0j2p/ca+gtsb8=
github.com/dave/patsy v0.0.0-20210517141501-957256f50cba/go.mod h1:qfR88CgEGLoiqDaE+xxDCi5QA5v4vUoW0UCX2Nd5Tlc=
github.com/dave/rebecca v0.9.1/go.mod h1:N6XYdMD/OKw3lkF3ywh8Z6wPGuwNFDNtWYEMFWEmXBA=
github.com/dave/jennifer v1.6.1 h1:T4T/67t6RAA5AIV6+NP8Uk/BIsXgDoqEowgycdQQLuk=
github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -694,8 +687,9 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNE
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
@ -836,8 +830,9 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
@ -980,6 +975,7 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
@ -1769,10 +1765,10 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -1785,7 +1781,8 @@ github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQ
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -2518,8 +2515,8 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -2649,8 +2646,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -2939,14 +2937,13 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -38,6 +38,7 @@ go_library(
"//internal/limiter",
"//internal/metrics",
"//internal/observation",
"//internal/perforce",
"//internal/search/streaming/http",
"//internal/trace",
"//lib/errors",

View File

@ -40,6 +40,7 @@ import (
"github.com/sourcegraph/sourcegraph/internal/lazyregexp"
"github.com/sourcegraph/sourcegraph/internal/limiter"
"github.com/sourcegraph/sourcegraph/internal/observation"
p4tools "github.com/sourcegraph/sourcegraph/internal/perforce"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
@ -276,6 +277,9 @@ type Client interface {
// P4Exec sends a p4 command with given arguments and returns an io.ReadCloser for the output.
P4Exec(_ context.Context, host, user, password string, args ...string) (io.ReadCloser, http.Header, error)
// P4GetChangelist gets the changelist specified by changelistID.
P4GetChangelist(_ context.Context, changelistID string, creds PerforceCredentials) (*protocol.PerforceChangelist, error)
// Remove removes the repository clone from gitserver.
Remove(context.Context, api.RepoName) error
@ -922,6 +926,39 @@ var deadlineExceededCounter = promauto.NewCounter(prometheus.CounterOpts{
Help: "Times that Client.sendExec() returned context.DeadlineExceeded",
})
func (c *clientImplementor) P4GetChangelist(ctx context.Context, changelistID string, creds PerforceCredentials) (*protocol.PerforceChangelist, error) {
reader, _, err := c.P4Exec(ctx, creds.Host, creds.Username, creds.Password,
"changes",
"-r", // list in reverse order, which means that the given changelist id will be the first one listed
"-m", "1", // limit output to one record, so that the given changelist is the only one listed
"-l", // use a long listing, which includes the whole commit message
"-e", changelistID, // start from this changelist and go up
)
if err != nil {
return nil, err
}
body, err := io.ReadAll(reader)
if err != nil {
return nil, errors.Wrap(err, "failed to read the output of p4 changes")
}
output := strings.TrimSpace(string(body))
if output == "" {
return nil, errors.New("invalid changelist " + changelistID)
}
pcl, err := p4tools.ParseChangelistOutput(output)
if err != nil {
return nil, errors.Wrap(err, "unable to parse change output")
}
return pcl, nil
}
type PerforceCredentials struct {
Host string
Username string
Password string
}
// BatchLog invokes the given callback with the `git log` output for a batch of repository
// and commit pairs. If the invoked callback returns a non-nil error, the operation will begin
// to abort processing further results.

View File

@ -136,6 +136,9 @@ type MockClient struct {
// P4ExecFunc is an instance of a mock function object controlling the
// behavior of the method P4Exec.
P4ExecFunc *ClientP4ExecFunc
// P4GetChangelistFunc is an instance of a mock function object
// controlling the behavior of the method P4GetChangelist.
P4GetChangelistFunc *ClientP4GetChangelistFunc
// ReadDirFunc is an instance of a mock function object controlling the
// behavior of the method ReadDir.
ReadDirFunc *ClientReadDirFunc
@ -372,6 +375,11 @@ func NewMockClient() *MockClient {
return
},
},
P4GetChangelistFunc: &ClientP4GetChangelistFunc{
defaultHook: func(context.Context, string, PerforceCredentials) (r0 *protocol.PerforceChangelist, r1 error) {
return
},
},
ReadDirFunc: &ClientReadDirFunc{
defaultHook: func(context.Context, authz.SubRepoPermissionChecker, api.RepoName, api.CommitID, string, bool) (r0 []fs.FileInfo, r1 error) {
return
@ -639,6 +647,11 @@ func NewStrictMockClient() *MockClient {
panic("unexpected invocation of MockClient.P4Exec")
},
},
P4GetChangelistFunc: &ClientP4GetChangelistFunc{
defaultHook: func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error) {
panic("unexpected invocation of MockClient.P4GetChangelist")
},
},
ReadDirFunc: &ClientReadDirFunc{
defaultHook: func(context.Context, authz.SubRepoPermissionChecker, api.RepoName, api.CommitID, string, bool) ([]fs.FileInfo, error) {
panic("unexpected invocation of MockClient.ReadDir")
@ -832,6 +845,9 @@ func NewMockClientFrom(i Client) *MockClient {
P4ExecFunc: &ClientP4ExecFunc{
defaultHook: i.P4Exec,
},
P4GetChangelistFunc: &ClientP4GetChangelistFunc{
defaultHook: i.P4GetChangelist,
},
ReadDirFunc: &ClientReadDirFunc{
defaultHook: i.ReadDir,
},
@ -5060,6 +5076,117 @@ func (c ClientP4ExecFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1, c.Result2}
}
// ClientP4GetChangelistFunc describes the behavior when the P4GetChangelist
// method of the parent MockClient instance is invoked.
type ClientP4GetChangelistFunc struct {
defaultHook func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error)
hooks []func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error)
history []ClientP4GetChangelistFuncCall
mutex sync.Mutex
}
// P4GetChangelist delegates to the next hook function in the queue and
// stores the parameter and result values of this invocation.
func (m *MockClient) P4GetChangelist(v0 context.Context, v1 string, v2 PerforceCredentials) (*protocol.PerforceChangelist, error) {
r0, r1 := m.P4GetChangelistFunc.nextHook()(v0, v1, v2)
m.P4GetChangelistFunc.appendCall(ClientP4GetChangelistFuncCall{v0, v1, v2, r0, r1})
return r0, r1
}
// SetDefaultHook sets function that is called when the P4GetChangelist
// method of the parent MockClient instance is invoked and the hook queue is
// empty.
func (f *ClientP4GetChangelistFunc) SetDefaultHook(hook func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error)) {
f.defaultHook = hook
}
// PushHook adds a function to the end of hook queue. Each invocation of the
// P4GetChangelist method of the parent MockClient instance invokes the hook
// at the front of the queue and discards it. After the queue is empty, the
// default hook function is invoked for any future action.
func (f *ClientP4GetChangelistFunc) PushHook(hook func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error)) {
f.mutex.Lock()
f.hooks = append(f.hooks, hook)
f.mutex.Unlock()
}
// SetDefaultReturn calls SetDefaultHook with a function that returns the
// given values.
func (f *ClientP4GetChangelistFunc) SetDefaultReturn(r0 *protocol.PerforceChangelist, r1 error) {
f.SetDefaultHook(func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error) {
return r0, r1
})
}
// PushReturn calls PushHook with a function that returns the given values.
func (f *ClientP4GetChangelistFunc) PushReturn(r0 *protocol.PerforceChangelist, r1 error) {
f.PushHook(func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error) {
return r0, r1
})
}
func (f *ClientP4GetChangelistFunc) nextHook() func(context.Context, string, PerforceCredentials) (*protocol.PerforceChangelist, error) {
f.mutex.Lock()
defer f.mutex.Unlock()
if len(f.hooks) == 0 {
return f.defaultHook
}
hook := f.hooks[0]
f.hooks = f.hooks[1:]
return hook
}
func (f *ClientP4GetChangelistFunc) appendCall(r0 ClientP4GetChangelistFuncCall) {
f.mutex.Lock()
f.history = append(f.history, r0)
f.mutex.Unlock()
}
// History returns a sequence of ClientP4GetChangelistFuncCall objects
// describing the invocations of this function.
func (f *ClientP4GetChangelistFunc) History() []ClientP4GetChangelistFuncCall {
f.mutex.Lock()
history := make([]ClientP4GetChangelistFuncCall, len(f.history))
copy(history, f.history)
f.mutex.Unlock()
return history
}
// ClientP4GetChangelistFuncCall is an object that describes an invocation
// of method P4GetChangelist on an instance of MockClient.
type ClientP4GetChangelistFuncCall struct {
// Arg0 is the value of the 1st argument passed to this method
// invocation.
Arg0 context.Context
// Arg1 is the value of the 2nd argument passed to this method
// invocation.
Arg1 string
// Arg2 is the value of the 3rd argument passed to this method
// invocation.
Arg2 PerforceCredentials
// Result0 is the value of the 1st result returned from this method
// invocation.
Result0 *protocol.PerforceChangelist
// Result1 is the value of the 2nd result returned from this method
// invocation.
Result1 error
}
// Args returns an interface slice containing the arguments of this
// invocation.
func (c ClientP4GetChangelistFuncCall) Args() []interface{} {
return []interface{}{c.Arg0, c.Arg1, c.Arg2}
}
// Results returns an interface slice containing the results of this
// invocation.
func (c ClientP4GetChangelistFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1}
}
// ClientReadDirFunc describes the behavior when the ReadDir method of the
// parent MockClient instance is invoked.
type ClientReadDirFunc struct {

View File

@ -2,6 +2,7 @@ package protocol
import (
"encoding/json"
"strings"
"time"
"go.opentelemetry.io/otel/attribute"
@ -778,6 +779,12 @@ type CreateCommitFromPatchResponse struct {
// Error is populated only on error
Error *CreateCommitFromPatchError
// ChangelistId is the numeric ID of the changelist that is shelved for the patch.
// only supplied for Perforce code hosts.
// it's a string because it's optional, but usng a scalar pointer is not allowed in protobuf
// so blank string means not provided
ChangelistId string
}
func (r *CreateCommitFromPatchResponse) ToProto() *proto.CreateCommitFromPatchBinaryResponse {
@ -788,8 +795,9 @@ func (r *CreateCommitFromPatchResponse) ToProto() *proto.CreateCommitFromPatchBi
err = nil
}
return &proto.CreateCommitFromPatchBinaryResponse{
Rev: r.Rev,
Error: err,
Rev: r.Rev,
Error: err,
ChangelistId: r.ChangelistId,
}
}
@ -801,6 +809,7 @@ func (r *CreateCommitFromPatchResponse) FromProto(p *proto.CreateCommitFromPatch
r.Error.FromProto(p.GetError())
}
r.Rev = p.GetRev()
r.ChangelistId = p.ChangelistId
}
// SetError adds the supplied error related details to e.
@ -891,3 +900,37 @@ func (r *GetObjectResponse) FromProto(p *proto.GetObjectResponse) {
}
}
type PerforceChangelist struct {
ID string
CreationDate time.Time
State PerforceChangelistState
Author string
Title string
Message string
}
type PerforceChangelistState string
const (
PerforceChangelistStateSubmitted PerforceChangelistState = "submitted"
PerforceChangelistStatePending PerforceChangelistState = "pending"
PerforceChangelistStateShelved PerforceChangelistState = "shelved"
// Perforce doesn't actually return a state for closed changelists, so this is one we use to indicate the changelist is closed.
PerforceChangelistStateClosed PerforceChangelistState = "closed"
)
func ParsePerforceChangelistState(state string) (PerforceChangelistState, error) {
switch strings.ToLower(strings.TrimSpace(state)) {
case "submitted":
return PerforceChangelistStateSubmitted, nil
case "pending":
return PerforceChangelistStatePending, nil
case "shelved":
return PerforceChangelistStateShelved, nil
case "closed":
return PerforceChangelistStateClosed, nil
default:
return "", errors.Newf("invalid Perforce changelist state: %s", state)
}
}

View File

@ -656,7 +656,7 @@ type CreateCommitFromPatchError struct {
RepositoryName string `protobuf:"bytes,1,opt,name=repository_name,json=repositoryName,proto3" json:"repository_name,omitempty"`
// internal_error is the error that occurred on the server
InternalError string `protobuf:"bytes,2,opt,name=internal_error,json=internalError,proto3" json:"internal_error,omitempty"`
// command is th git command that was attempted
// command is the git command that was attempted
Command string `protobuf:"bytes,3,opt,name=command,proto3" json:"command,omitempty"`
// combined_output is the combined stderr and stdout from running the command
CombinedOutput string `protobuf:"bytes,4,opt,name=combined_output,json=combinedOutput,proto3" json:"combined_output,omitempty"`
@ -733,6 +733,8 @@ type CreateCommitFromPatchBinaryResponse struct {
Rev string `protobuf:"bytes,1,opt,name=rev,proto3" json:"rev,omitempty"`
// error is populated only on error
Error *CreateCommitFromPatchError `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
// changelistid is the Perforce changelist id
ChangelistId string `protobuf:"bytes,3,opt,name=changelist_id,json=changelistId,proto3" json:"changelist_id,omitempty"`
}
func (x *CreateCommitFromPatchBinaryResponse) Reset() {
@ -781,6 +783,13 @@ func (x *CreateCommitFromPatchBinaryResponse) GetError() *CreateCommitFromPatchE
return nil
}
func (x *CreateCommitFromPatchBinaryResponse) GetChangelistId() string {
if x != nil {
return x.ChangelistId
}
return ""
}
type ExecRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -3649,415 +3658,417 @@ var file_gitserver_proto_rawDesc = []byte{
0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63,
0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x4f, 0x75,
0x74, 0x70, 0x75, 0x74, 0x22, 0x77, 0x0a, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f,
0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42, 0x69, 0x6e,
0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72,
0x65, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x76, 0x12, 0x3e, 0x0a,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63,
0x68, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x93, 0x01,
0x0a, 0x0b, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70,
0x6f, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x76, 0x69,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x6e, 0x73, 0x75,
0x72, 0x65, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72,
0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x14,
0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73,
0x74, 0x64, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6e, 0x6f, 0x54, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x22, 0x22, 0x0a, 0x0c, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x78, 0x0a, 0x0f, 0x4e, 0x6f, 0x74, 0x46, 0x6f,
0x75, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65,
0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x2a,
0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72,
0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6c, 0x6f, 0x6e, 0x65,
0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c,
0x6f, 0x6e, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
0x73, 0x22, 0x4c, 0x0a, 0x11, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x50,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72,
0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x22,
0x80, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x3d, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x09, 0x72, 0x65, 0x76, 0x69, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e,
0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x34, 0x0a,
0x16, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x46, 0x69,
0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x71, 0x75, 0x65,
0x72, 0x79, 0x22, 0x73, 0x0a, 0x11, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70,
0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x5f, 0x73,
0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x76, 0x53, 0x70,
0x65, 0x63, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x66, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x66, 0x47, 0x6c, 0x6f, 0x62, 0x12, 0x28, 0x0a,
0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x5f, 0x67, 0x6c, 0x6f,
0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x52, 0x65, 0x66, 0x47, 0x6c, 0x6f, 0x62, 0x22, 0x48, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04,
0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72,
0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x73,
0x65, 0x22, 0x4b, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x4d, 0x61,
0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70,
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x1f, 0x0a,
0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x08, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x4c,
0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x4e, 0x6f,
0x64, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x4b, 0x0a, 0x0f,
0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12,
0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x49, 0x0a, 0x12, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12,
0x74, 0x70, 0x75, 0x74, 0x22, 0x9c, 0x01, 0x0a, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42, 0x69,
0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03,
0x72, 0x65, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x76, 0x12, 0x3e,
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e,
0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74,
0x63, 0x68, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23,
0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x69, 0x73,
0x74, 0x49, 0x64, 0x22, 0x93, 0x01, 0x0a, 0x0b, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x73, 0x75, 0x72,
0x65, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0e, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04,
0x61, 0x72, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f,
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
0x6e, 0x6f, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x22, 0x0a, 0x0c, 0x45, 0x78, 0x65,
0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x78, 0x0a,
0x0f, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x72, 0x65, 0x70, 0x6f, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x6e,
0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
0x0f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65,
0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x50,
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x4c, 0x0a, 0x11, 0x45, 0x78, 0x65, 0x63, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x0b,
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a,
0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73,
0x74, 0x64, 0x65, 0x72, 0x72, 0x22, 0x80, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x3d, 0x0a, 0x09, 0x72,
0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f,
0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52,
0x09, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69,
0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x66, 0x66,
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44,
0x69, 0x66, 0x66, 0x12, 0x34, 0x0a, 0x16, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6d,
0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20,
0x01, 0x28, 0x08, 0x52, 0x14, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x69,
0x66, 0x69, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x71, 0x75, 0x65,
0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4e, 0x6f, 0x64,
0x65, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x73, 0x0a, 0x11, 0x52, 0x65, 0x76, 0x69,
0x73, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x19, 0x0a,
0x08, 0x72, 0x65, 0x76, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x72, 0x65, 0x76, 0x53, 0x70, 0x65, 0x63, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x66, 0x5f,
0x67, 0x6c, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x66, 0x47,
0x6c, 0x6f, 0x62, 0x12, 0x28, 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72,
0x65, 0x66, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65,
0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x52, 0x65, 0x66, 0x47, 0x6c, 0x6f, 0x62, 0x22, 0x48, 0x0a,
0x11, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f,
0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65,
0x5f, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x67, 0x6e,
0x6f, 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x4b, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69,
0x74, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65,
0x78, 0x70, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61,
0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65,
0x43, 0x61, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x0f, 0x44, 0x69, 0x66, 0x66, 0x4d, 0x61, 0x74, 0x63,
0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69,
0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x4b, 0x0a, 0x14,
0x44, 0x69, 0x66, 0x66, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65,
0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f,
0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69,
0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x42, 0x6f, 0x6f,
0x6c, 0x65, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x73,
0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2e,
0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72,
0x61, 0x74, 0x6f, 0x72, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x33,
0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x51, 0x75, 0x65, 0x72, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61,
0x6e, 0x64, 0x73, 0x22, 0x92, 0x05, 0x0a, 0x09, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4e, 0x6f, 0x64,
0x65, 0x12, 0x48, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x6d, 0x61, 0x74, 0x63,
0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x51, 0x0a, 0x11, 0x63,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6f,
0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x45,
0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72,
0x65, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42,
0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x42, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f,
0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69,
0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x6f,
0x6d, 0x6d, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x0f, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73,
0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x6d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66,
0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x64,
0x69, 0x66, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x12, 0x64, 0x69,
0x66, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65,
0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x10, 0x64, 0x69,
0x66, 0x66, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x35,
0x0a, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x19, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42,
0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x07, 0x62, 0x6f,
0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f,
0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e,
0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x42,
0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6d, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72,
0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x6d, 0x61,
0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x48, 0x00, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1d, 0x0a,
0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x68, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
0x48, 0x00, 0x52, 0x08, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x69, 0x74, 0x42, 0x09, 0x0a, 0x07,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa9, 0x06, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d,
0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x6f, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x06, 0x61, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x06,
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x41, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09,
0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72,
0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65,
0x6e, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
0x09, 0x52, 0x04, 0x72, 0x65, 0x66, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x73, 0x12, 0x41, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69,
0x6e, 0x67, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x64,
0x69, 0x66, 0x66, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69,
0x6e, 0x67, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6f, 0x64, 0x69,
0x66, 0x69, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09,
0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x1a,
0x65, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2e, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x62, 0x0a, 0x0d, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65,
0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
0x74, 0x12, 0x37, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x52, 0x61, 0x6e,
0x67, 0x65, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x77, 0x0a, 0x05, 0x52, 0x61,
0x6e, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4c, 0x6f,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x34, 0x0a,
0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x69, 0x74,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03,
0x65, 0x6e, 0x64, 0x1a, 0x4e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63,
0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x6f, 0x6c,
0x75, 0x6d, 0x6e, 0x22, 0x74, 0x0a, 0x0e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x65,
0x65, 0x69, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x65, 0x65,
0x69, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x70,
0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
0x70, 0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x22, 0x25, 0x0a, 0x0f, 0x41, 0x72, 0x63,
0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04,
0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
0x22, 0x2c, 0x0a, 0x16, 0x49, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x61,
0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65,
0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x22, 0x67,
0x0a, 0x17, 0x49, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x6f,
0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6c,
0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x6e, 0x65,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x12,
0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x43,
0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72,
0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x22,
0x29, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x30, 0x0a, 0x18, 0x52, 0x65,
0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x22, 0x7e, 0x0a, 0x11,
0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x5f, 0x70, 0x72,
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6c,
0x6f, 0x6e, 0x65, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a,
0x0e, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67,
0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x03,
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x22, 0xc8, 0x01, 0x0a,
0x19, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65,
0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x07, 0x72, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43,
0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x5b, 0x0a, 0x0c, 0x52, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43,
0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x27, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f,
0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f,
0x12, 0x2f, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63,
0x65, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f,
0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6c, 0x6f,
0x6e, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x53, 0x68, 0x61, 0x72, 0x64, 0x22, 0xa8, 0x01, 0x0a, 0x12,
0x52, 0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68,
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x43, 0x61, 0x73, 0x65, 0x22, 0x4c, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x65,
0x66, 0x6f, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x22, 0x4b, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65,
0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65,
0x64, 0x12, 0x3d, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x13, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53,
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x73, 0x0a, 0x12, 0x52,
0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x22, 0x0a, 0x0d, 0x67, 0x69, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x5f, 0x62, 0x79, 0x74,
0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x67, 0x69, 0x74, 0x44, 0x69, 0x72,
0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
0x22, 0x6f, 0x0a, 0x0d, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x34, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x70, 0x34, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x34, 0x75,
0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x34, 0x75, 0x73, 0x65,
0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x34, 0x70, 0x61, 0x73, 0x73, 0x77, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x34, 0x70, 0x61, 0x73, 0x73, 0x77, 0x64, 0x12, 0x12, 0x0a,
0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67,
0x73, 0x22, 0x24, 0x0a, 0x0e, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x47,
0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23,
0x0a, 0x0d, 0x67, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x48,
0x6f, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x0c, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52,
0x65, 0x70, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x48, 0x0a, 0x14, 0x4c, 0x69, 0x73,
0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x05, 0x72, 0x65,
0x70, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x6f,
0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x44, 0x0a, 0x11,
0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x69, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x22, 0xd8, 0x01, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64,
0x12, 0x36, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22,
0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69,
0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79,
0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x0a, 0x4f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x4f, 0x42, 0x4a, 0x45, 0x43,
0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54,
0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f,
0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x41, 0x47, 0x10,
0x02, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x54, 0x52, 0x45, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x42, 0x4a, 0x45, 0x43,
0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x4c, 0x4f, 0x42, 0x10, 0x04, 0x2a, 0x71, 0x0a,
0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1d, 0x0a,
0x19, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55,
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11,
0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x41, 0x4e,
0x44, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f,
0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x50, 0x45,
0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4e, 0x4f, 0x54, 0x10, 0x03,
0x32, 0xc3, 0x09, 0x0a, 0x10, 0x47, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f,
0x67, 0x12, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x42, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d,
0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42, 0x69, 0x6e, 0x61,
0x72, 0x79, 0x12, 0x30, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72,
0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x04, 0x45, 0x78, 0x65,
0x63, 0x12, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x09,
0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x0f,
0x49, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x12,
0x24, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49,
0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22,
0x49, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65,
0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e,
0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a,
0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x0f, 0x44, 0x69,
0x66, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70,
0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61,
0x73, 0x65, 0x22, 0x4b, 0x0a, 0x14, 0x44, 0x69, 0x66, 0x66, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78,
0x70, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x1f,
0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x43, 0x61, 0x73, 0x65, 0x22,
0x23, 0x0a, 0x0b, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x22, 0x73, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72,
0x4e, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04,
0x6b, 0x69, 0x6e, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x6e, 0x64, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x52,
0x08, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x6e, 0x64, 0x73, 0x22, 0x92, 0x05, 0x0a, 0x09, 0x51, 0x75,
0x65, 0x72, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x48, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65,
0x48, 0x00, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65,
0x73, 0x12, 0x51, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x5f, 0x6d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x69, 0x74, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65,
0x48, 0x00, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x74,
0x63, 0x68, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x62,
0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69,
0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x63,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x42, 0x0a, 0x0c, 0x63,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65,
0x48, 0x00, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12,
0x4b, 0x0a, 0x0f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68,
0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d,
0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0c,
0x64, 0x69, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x4e, 0x6f, 0x64,
0x65, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x69, 0x66, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73,
0x12, 0x52, 0x0a, 0x12, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66,
0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x6f, 0x64, 0x65,
0x48, 0x00, 0x52, 0x10, 0x64, 0x69, 0x66, 0x66, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x73,
0x46, 0x69, 0x6c, 0x65, 0x12, 0x35, 0x0a, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x18,
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x4e, 0x6f, 0x64, 0x65,
0x48, 0x00, 0x52, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6f,
0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x6f, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6d,
0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x31, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x19, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x48, 0x00, 0x52, 0x05, 0x6d, 0x61,
0x74, 0x63, 0x68, 0x12, 0x1d, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x68, 0x69, 0x74,
0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x48,
0x69, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa9, 0x06,
0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x10, 0x0a,
0x03, 0x6f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x69, 0x64, 0x12,
0x3b, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x23, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x41, 0x0a, 0x09,
0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x23, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12,
0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09,
0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x66,
0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x66, 0x73, 0x12, 0x1f, 0x0a,
0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x06, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x73, 0x12, 0x41,
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x27, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68,
0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x12, 0x3b, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x27, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68,
0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x12, 0x25,
0x0a, 0x0e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73,
0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64,
0x46, 0x69, 0x6c, 0x65, 0x73, 0x1a, 0x65, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2e, 0x0a, 0x04,
0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x62, 0x0a, 0x0d,
0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a,
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x67, 0x65,
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74,
0x63, 0x68, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,
0x1a, 0x77, 0x0a, 0x05, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x73, 0x74, 0x61,
0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61,
0x74, 0x63, 0x68, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x73, 0x74,
0x61, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x4c, 0x6f, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x1a, 0x4e, 0x0a, 0x08, 0x4c, 0x6f, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6c, 0x69, 0x6e,
0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x22, 0x74, 0x0a, 0x0e, 0x41, 0x72, 0x63,
0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72,
0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12,
0x18, 0x0a, 0x07, 0x74, 0x72, 0x65, 0x65, 0x69, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x74, 0x72, 0x65, 0x65, 0x69, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72,
0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61,
0x74, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x18, 0x04,
0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x22,
0x25, 0x0a, 0x0f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2c, 0x0a, 0x16, 0x49, 0x73, 0x52, 0x65, 0x70, 0x6f,
0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x72, 0x65, 0x70, 0x6f, 0x22, 0x67, 0x0a, 0x17, 0x49, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c,
0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x09, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a,
0x06, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63,
0x6c, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x26, 0x0a,
0x10, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x72, 0x65, 0x70, 0x6f, 0x22, 0x29, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f,
0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x22, 0x30, 0x0a, 0x18, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f,
0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05,
0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x65, 0x70,
0x6f, 0x73, 0x22, 0x7e, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50,
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x6e, 0x65,
0x5f, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x0f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72,
0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x5f, 0x70, 0x72, 0x6f,
0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x6f,
0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c,
0x6f, 0x6e, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x6e,
0x65, 0x64, 0x22, 0xc8, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65,
0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x4e, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x34, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65,
0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
0x1a, 0x5b, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65,
0x73, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x27, 0x0a,
0x11, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x82, 0x01, 0x0a,
0x11, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x6c, 0x6f, 0x6e, 0x65,
0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0e, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x53, 0x68, 0x61, 0x72,
0x64, 0x22, 0xa8, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74,
0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6c, 0x61, 0x73, 0x74,
0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, 0x12, 0x3d, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f,
0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x43,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x13, 0x0a, 0x11,
0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x22, 0x73, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x67, 0x69, 0x74, 0x5f, 0x64,
0x69, 0x72, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
0x67, 0x69, 0x74, 0x44, 0x69, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64,
0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x6f, 0x0a, 0x0d, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x34, 0x70, 0x6f, 0x72,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x34, 0x70, 0x6f, 0x72, 0x74, 0x12,
0x16, 0x0a, 0x06, 0x70, 0x34, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x70, 0x34, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x34, 0x70, 0x61, 0x73,
0x73, 0x77, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x34, 0x70, 0x61, 0x73,
0x73, 0x77, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0x24, 0x0a, 0x0e, 0x50, 0x34, 0x45, 0x78, 0x65,
0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a,
0x13, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x67, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65,
0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x69, 0x74,
0x6f, 0x6c, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x34, 0x0a, 0x0c, 0x47, 0x69, 0x74,
0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a,
0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22,
0x48, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65,
0x70, 0x6f, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x10, 0x47, 0x65, 0x74,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70,
0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61,
0x6d, 0x65, 0x22, 0x44, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xd8, 0x01, 0x0a, 0x09, 0x47, 0x69, 0x74,
0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82,
0x01, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a,
0x17, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53,
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4f, 0x42,
0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54,
0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54, 0x59, 0x50,
0x45, 0x5f, 0x54, 0x41, 0x47, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x42, 0x4a, 0x45, 0x43,
0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a,
0x10, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x4c, 0x4f,
0x42, 0x10, 0x04, 0x2a, 0x71, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x4b,
0x69, 0x6e, 0x64, 0x12, 0x1d, 0x0a, 0x19, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f,
0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44,
0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4b,
0x49, 0x4e, 0x44, 0x5f, 0x41, 0x4e, 0x44, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45,
0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4f, 0x52, 0x10, 0x02, 0x12,
0x15, 0x0a, 0x11, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x4b, 0x49, 0x4e, 0x44,
0x5f, 0x4e, 0x4f, 0x54, 0x10, 0x03, 0x32, 0xc3, 0x09, 0x0a, 0x10, 0x47, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x42,
0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x12, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74,
0x63, 0x68, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x12, 0x30, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f,
0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42, 0x69, 0x6e,
0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x67, 0x69, 0x74,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x63, 0x68, 0x42,
0x69, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x41, 0x0a, 0x04, 0x45, 0x78, 0x65, 0x63, 0x12, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x30, 0x01, 0x12, 0x4e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12,
0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47,
0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47,
0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x60, 0x0a, 0x0f, 0x49, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e,
0x65, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x24, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65,
0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x57,
0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x12, 0x21,
0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63,
0x68, 0x12, 0x1b, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01,
0x12, 0x4a, 0x0a, 0x07, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x1c, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69,
0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x06,
0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x12, 0x1b, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x76, 0x31, 0x2e, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x09, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f,
0x6e, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f,
0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x26, 0x2e, 0x67, 0x69, 0x74,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c,
0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72,
0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a,
0x0a, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x51, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1f,
0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x20, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74,
0x73, 0x12, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x67, 0x69,
0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x52, 0x65, 0x70,
0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f,
0x6c, 0x69, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c, 0x69, 0x74, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x69, 0x74, 0x6f, 0x6c,
0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a,
0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1b, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4a, 0x0a, 0x07, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76,
0x65, 0x12, 0x1c, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1d, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41,
0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x30, 0x01, 0x12, 0x47, 0x0a, 0x06, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x12, 0x1b, 0x2e, 0x67,
0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x34, 0x45, 0x78,
0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x34, 0x45, 0x78, 0x65, 0x63, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x09, 0x52,
0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x11, 0x52,
0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
0x12, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x43, 0x6c, 0x6f, 0x6e,
0x65, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x12, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68,
0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f,
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x52, 0x65, 0x70,
0x6f, 0x73, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61, 0x74,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x53, 0x74, 0x61,
0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61,
0x70, 0x68, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x69, 0x74, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -113,7 +113,7 @@ message CreateCommitFromPatchError {
string repository_name = 1;
// internal_error is the error that occurred on the server
string internal_error = 2;
// command is th git command that was attempted
// command is the git command that was attempted
string command = 3;
// combined_output is the combined stderr and stdout from running the command
string combined_output = 4;
@ -126,6 +126,8 @@ message CreateCommitFromPatchBinaryResponse {
string rev = 1;
// error is populated only on error
CreateCommitFromPatchError error = 2;
// changelistid is the Perforce changelist id
string changelist_id = 3;
}
message ExecRequest {
string repo = 1;

View File

@ -8,6 +8,7 @@ go_library(
visibility = ["//:__subpackages__"],
deps = [
"//internal/api",
"//internal/gitserver/protocol",
"//internal/lazyregexp",
"//lib/errors",
],
@ -17,5 +18,9 @@ go_test(
name = "perforce_test",
srcs = ["changelist_test.go"],
embed = [":perforce"],
deps = ["@com_github_stretchr_testify//require"],
deps = [
"//internal/gitserver/protocol",
"@com_github_google_go_cmp//cmp",
"@com_github_stretchr_testify//require",
],
)

View File

@ -3,7 +3,13 @@ package perforce
import (
"fmt"
"encoding/json"
"strings"
"time"
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
"github.com/sourcegraph/sourcegraph/internal/lazyregexp"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
@ -18,6 +24,7 @@ import (
// we can look for this pattern even when this is not in its own line by itself.
var gitP4Pattern = lazyregexp.New(`\[(?:git-p4|p4-fusion): depot-paths? = "(.*?)"\: change = (\d+)\]`)
// Parses a changelist id from the message trailer that `git p4` and `p4-fusion` add to the commit message
func GetP4ChangelistID(body string) (string, error) {
matches := gitP4Pattern.FindStringSubmatch(body)
if len(matches) != 3 {
@ -36,3 +43,89 @@ type ChangelistNotFoundError struct {
func (e *ChangelistNotFoundError) Error() string {
return fmt.Sprintf("revision not found: %s@%s", e.Repo, e.ID)
}
type BadChangelistError struct {
CID string
Repo api.RepoName
}
func (e *BadChangelistError) Error() string {
return fmt.Sprintf("invalid changelist ID %q for repo %q", e.Repo, e.CID)
}
// Example changelist info output in "long" format
// (from `p4 changes -l ...`)
// Change 1188 on 2023/06/09 by admin@yet-moar-lines *pending*
//
// Append still another line to all SECOND.md files
//
// "admin@yet-moar-lines" is the username @ the client spec name, which in this case is the branch name from the batch change
// the final field - "*pending*" in this example - is optional and not present when the changelist has been submitted ("merged", in Git parlance)
// Example changelist info in json format
// (from `p4 -ztags -Mj changes -l ...`)
// {"data":"Change 1178 on 2023/06/01 by admin@hello-third-world *pending*\n\n\tAppend Hello World to all THIRD.md files\n","level":0}
var changelistInfoPattern = lazyregexp.New(`^Change (\d+) on (\d{4}/\d{2}/\d{2}) by ([^ ]+)@([^ ]+)(?: [*](pending|submitted|shelved)[*])?(?: '(.+)')?$`)
type changelistJson struct {
Data string `json:"data"`
Level int `json:"level"`
}
// Parses the output of `p4 changes`
// Handles one changelist only
// Accepts any format: standard, long, json standard, json long
func ParseChangelistOutput(output string) (*protocol.PerforceChangelist, error) {
// output will be whitespace-trimmed and not empty
// if the given text is json format, extract the Data portion
// so that it will have the same format as the standard output
cidj := new(changelistJson)
err := json.Unmarshal([]byte(output), cidj)
if err == nil {
output = strings.TrimSpace(cidj.Data)
}
lines := strings.Split(output, "\n")
// the first line contains the changelist information
matches := changelistInfoPattern.FindStringSubmatch(lines[0])
if matches == nil || len(matches) < 5 {
return nil, errors.New("invalid changelist output")
}
pcl := new(protocol.PerforceChangelist)
pcl.ID = matches[1]
time, err := time.Parse("2006/01/02", matches[2])
if err != nil {
return nil, errors.Wrap(err, "invalid date: "+matches[2])
}
pcl.CreationDate = time
pcl.Author = matches[3]
pcl.Title = matches[4]
status := "submitted"
if len(matches) > 5 && matches[5] != "" {
status = matches[5]
}
cls, err := protocol.ParsePerforceChangelistState(status)
if err != nil {
return nil, err
}
pcl.State = cls
if len(matches) > 6 && matches[6] != "" {
// the commit message is inline with the info
pcl.Message = strings.TrimSpace(matches[6])
} else {
// the commit message is in subsequent lines of the output
var builder strings.Builder
for i := 2; i < len(lines); i++ {
if i > 2 {
builder.WriteString("\n")
}
builder.WriteString(strings.TrimSpace(lines[i]))
}
pcl.Message = builder.String()
}
return pcl, nil
}

View File

@ -3,8 +3,12 @@ package perforce
import (
"reflect"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"github.com/sourcegraph/sourcegraph/internal/gitserver/protocol"
)
func TestGetP4ChangelistID(t *testing.T) {
@ -51,3 +55,131 @@ func TestGetP4ChangelistID(t *testing.T) {
}
}
}
func TestParseChangelistOutput(t *testing.T) {
testCases := []struct {
output string
expectedChangelist *protocol.PerforceChangelist
shouldError bool
}{
{
output: `Change 1188 on 2023/06/09 by admin@test-first-one *pending*
Append still another line to all SECOND.md files
Here's a second line of message`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "1188",
CreationDate: time.Date(2023, 6, 9, 0, 0, 0, 0, time.UTC),
Author: "admin",
Title: "test-first-one",
State: protocol.PerforceChangelistStatePending,
Message: "Append still another line to all SECOND.md files\nHere's a second line of message",
},
},
{
output: `Change 1234567 on 2023/04/09 by someone@dsobsdfoibsdv
Append still another line to all SECOND.md files
Here's a second line of message`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "1234567",
CreationDate: time.Date(2023, 4, 9, 0, 0, 0, 0, time.UTC),
Author: "someone",
Title: "dsobsdfoibsdv",
State: protocol.PerforceChangelistStateSubmitted,
Message: "Append still another line to all SECOND.md files\nHere's a second line of message",
},
},
{
output: `{"data":"Change 1188 on 2023/06/09 by admin@json-with-status *pending*\n\n\tAppend still another line to all SECOND.md files\n\tand another line here\n","level":0}`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "1188",
CreationDate: time.Date(2023, 6, 9, 0, 0, 0, 0, time.UTC),
Author: "admin",
Title: "json-with-status",
State: protocol.PerforceChangelistStatePending,
Message: "Append still another line to all SECOND.md files\nand another line here",
},
},
{
output: `{"data":"Change 1188 on 2023/06/09 by admin@json-no-status\n\n\tAppend still another line to all SECOND.md files\n\tand another line here\n","level":0}`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "1188",
CreationDate: time.Date(2023, 6, 9, 0, 0, 0, 0, time.UTC),
Author: "admin",
Title: "json-no-status",
State: protocol.PerforceChangelistStateSubmitted,
Message: "Append still another line to all SECOND.md files\nand another line here",
},
},
{
output: `{"data":"Change 27 on 2023/05/03 by admin@buttercup\n\n\t generated change at 2023-05-02 17:44:59.012487 -0700 PDT m=+7.371337167\n","level":0}`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "27",
CreationDate: time.Date(2023, 5, 3, 0, 0, 0, 0, time.UTC),
Author: "admin",
Title: "buttercup",
State: protocol.PerforceChangelistStateSubmitted,
Message: `generated change at 2023-05-02 17:44:59.012487 -0700 PDT m=+7.371337167`,
},
},
{
output: `Change 27 on 2023/05/03 by admin@buttercup`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "27",
CreationDate: time.Date(2023, 5, 3, 0, 0, 0, 0, time.UTC),
Author: "admin",
Title: "buttercup",
State: protocol.PerforceChangelistStateSubmitted,
Message: "",
},
},
{
output: `{"data":"Change 55 on 2023/05/03 by admin@test5 ' generated change at 2023-05-'","level":0}`,
expectedChangelist: &protocol.PerforceChangelist{
ID: "55",
CreationDate: time.Date(2023, 5, 3, 0, 0, 0, 0, time.UTC),
Author: "admin",
Title: "test5",
State: protocol.PerforceChangelistStateSubmitted,
Message: `generated change at 2023-05-`,
},
},
{
output: `{"data":"Change 55 on 2023/56/42 by admin@buttercup ' generated change at 2023-05-'","level":0}`,
shouldError: true,
},
{
output: `Change 55 by admin@buttercup 'generated change at 2023-05-'`,
shouldError: true,
},
{
output: `{"data":"Change 1185 on 2023/06/09 by admin@yet-moar-lines *INVALID* 'Append still another line to al'","level":0}`,
shouldError: true,
},
{
output: `Change INVALID on 2023/06/09 by admin@yet-moar-lines *pending*
Append still another line to all SECOND.md files
`,
shouldError: true,
},
}
for _, testCase := range testCases {
changelist, err := ParseChangelistOutput(testCase.output)
if testCase.shouldError {
if err == nil {
t.Errorf("expected error but got nil")
}
continue
}
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if diff := cmp.Diff(testCase.expectedChangelist, changelist); diff != "" {
t.Errorf("parsed changelist did not match expected (-want +got):\n%s", diff)
}
}
}

View File

@ -23,6 +23,10 @@
interfaces:
- Client
prefix: Gerrit
- path: github.com/sourcegraph/sourcegraph/internal/gitserver
interfaces:
- Client
prefix: Gitserver
- filename: cmd/frontend/internal/httpapi/mocks_test.go
path: github.com/sourcegraph/sourcegraph/internal/httpcli
interfaces:

View File

@ -789,6 +789,8 @@ type ExpandedGitCommitDescription struct {
// ExperimentalFeatures description: Experimental features and settings.
type ExperimentalFeatures struct {
// BatchChangesEnablePerforce description: When enabled, batch changes will be executable on Perforce depots.
BatchChangesEnablePerforce bool `json:"batchChanges.enablePerforce,omitempty"`
// CustomGitFetch description: JSON array of configuration that maps from Git clone URL domain/path to custom git fetch command. To enable this feature set environment variable `ENABLE_CUSTOM_GIT_FETCH` as `true` on gitserver.
CustomGitFetch []*CustomGitFetchMapping `json:"customGitFetch,omitempty"`
// DebugLog description: Turns on debug logging for specific debugging scenarios.
@ -881,6 +883,7 @@ func (v *ExperimentalFeatures) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &m); err != nil {
return err
}
delete(m, "batchChanges.enablePerforce")
delete(m, "customGitFetch")
delete(m, "debug.log")
delete(m, "enableGRPC")

View File

@ -522,6 +522,12 @@
"!go": {
"pointer": true
}
},
"batchChanges.enablePerforce": {
"description": "When enabled, batch changes will be executable on Perforce depots.",
"type": "boolean",
"group": "BatchChanges",
"default": false
}
},
"examples": [