payload: {"action":"created","comment":{"url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/comments/333175710","pull_request_review_id":299622979,"id":333175710,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMzMzE3NTcxMA==","diff_hunk":"@@ -0,0 +1,757 @@\n+// Copyright 2018 Google LLC\n+//\n+// Licensed under the Apache License, Version 2.0 (the \"License\");\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+//\n+//     https://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \"AS IS\" BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+\n+package gensample\n+\n+import (\n+\t\"bytes\"\n+\t\"crypto/sha256\"\n+\t\"encoding/base32\"\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"go/format\"\n+\t\"log\"\n+\t\"os\"\n+\t\"sort\"\n+\t\"strings\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\t\"github.com/golang/protobuf/protoc-gen-go/descriptor\"\n+\t\"github.com/googleapis/gapic-generator-go/internal/errors\"\n+\t\"github.com/googleapis/gapic-generator-go/internal/gensample/schema_v1p2\"\n+\t\"github.com/googleapis/gapic-generator-go/internal/license\"\n+\t\"github.com/googleapis/gapic-generator-go/internal/pbinfo\"\n+\t\"github.com/googleapis/gapic-generator-go/internal/printer\"\n+\tyaml \"gopkg.in/yaml.v2\"\n+)\n+\n+const expectedSampleConfigType = \"com.google.api.codegen.samplegen.v1p2.SampleConfigProto\"\n+const expectedSampleConfigVersion = \"1.2.0\"\n+\n+// InitGen creates a new sample generator.\n+// sampleFnames is the filenames of all sample config files.\n+// gapicFname is the filename of gapic config.\n+// clientPkg is the Go package of the generated gapic client library.\n+// nofmt set to true will instruct the generator not to format the generated code. This could be useful for debugging purpose.\n+func InitGen(desc []*descriptor.FileDescriptorProto, sampleFnames []string, gapicFname string, clientPkg string, nofmt bool) (*generator, error) {\n+\n+\tgen := generator{\n+\t\timports:      map[pbinfo.ImportSpec]bool{},\n+\t\tdesc:         desc,\n+\t\tdescInfo:     pbinfo.Of(desc),\n+\t\tsampleConfig: schema_v1p2.SampleConfig{},\n+\t}\n+\n+\tif p := strings.IndexByte(clientPkg, ';'); p >= 0 {\n+\t\tgen.clientPkg = pbinfo.ImportSpec{Path: (clientPkg)[:p], Name: (clientPkg)[p+1:]}\n+\t} else {\n+\t\treturn nil, errors.E(nil, \"need -clientPkg in 'url/to/client/pkg;name' format, got %q\", clientPkg)\n+\t}\n+\n+\tvar wg sync.WaitGroup\n+\terrChan := make(chan error, 2)\n+\n+\twg.Add(1)\n+\tgo func() {\n+\t\tdefer wg.Done()\n+\t\terrChan <- gen.readGapicConfigFile(gapicFname)\n+\t}()\n+\n+\twg.Add(1)\n+\tgo func() {\n+\t\tdefer wg.Done()\n+\t\terrChan <- gen.readSampleConfigFiles(sampleFnames)\n+\t}()\n+\twg.Wait()\n+\treturn &gen, nil\n+}\n+\n+// GenMethodSamples generators samples from protos and configurations stored in the generator,\n+// and writes the generated samples to generator.Outputs.\n+func (gen *generator) GenMethodSamples() error {\n+\tgen.disambiguateSampleIDs()\n+\tgen.Outputs = make(map[string][]byte)\n+\n+\tfor _, samp := range gen.sampleConfig.Samples {\n+\t\tvar iface GAPICInterface\n+\t\tvar method GAPICMethod\n+\t\tfor _, iface = range gen.gapic.Interfaces {\n+\t\t\tif iface.Name == samp.Service {\n+\t\t\t\tfor _, method = range iface.Methods {\n+\t\t\t\t\tif method.Name == samp.Rpc {\n+\t\t\t\t\t\tbreak\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\n+\t\tif method.Name != samp.Rpc {\n+\t\t\treturn errors.E(nil, \"generating sample %q: rpc %q not found\", samp.ID, samp.Rpc)\n+\t\t}\n+\t\tif iface.Name != samp.Service {\n+\t\t\treturn errors.E(nil, \"generating sample %q: service %q not found\", samp.ID, samp.Service)\n+\t\t}\n+\n+\t\tgen.reset()\n+\t\tif err := gen.genSample(*samp, method); err != nil {\n+\t\t\terr = errors.E(err, \"generating: %s.%s:%s\", iface.Name, method.Name, samp.ID)\n+\t\t\tlog.Fatal(err)\n+\t\t}\n+\n+\t\tcontent, err := gen.commit(!gen.nofmt, time.Now().Year())\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\n+\t\tfname := samp.ID + \".go\"\n+\t\tgen.Outputs[fname] = content\n+\t}\n+\treturn nil\n+}\n+\n+type generator struct {\n+\t// desc is the proto descriptors of the API\n+\tdesc         []*descriptor.FileDescriptorProto\n+\n+\t// descInfo has some pre-processed information for the proto descriptors,\n+\t// so that looking up message or method configs is easier\n+\tdescInfo     pbinfo.Info\n+\tgapic        GAPICConfig\n+\n+\t// sampleConfig is the sample configurations, in v1.2 schema\n+\tsampleConfig schema_v1p2.SampleConfig\n+\n+\t// clientPkg is the go package of the generated Gapic client\n+\tclientPkg    pbinfo.ImportSpec\n+\n+\t// if set to true, the generator will not format the generated code\n+\tnofmt        bool\n+\n+\tpt      printer.P\n+\timports map[pbinfo.ImportSpec]bool\n+\tOutputs map[string][]byte\n+}\n+\n+// readSampleConfigFiles loads sample configs from local files and stores\n+// them in generator.sampleConfig.\n+func (gen *generator) readSampleConfigFiles(paths []string) error {\n+\tfor _, path := range paths {\n+\t\tf, err := os.Open(path)\n+\t\tif err != nil {\n+\t\t\treturn errors.E(err, \"cannot open sample config file: %s\", path)\n+\t\t}\n+\t\tdecoder := yaml.NewDecoder(f)\n+\t\tconfig, err := readSampleConfig(decoder, path)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\tgen.sampleConfig.Samples = append(gen.sampleConfig.Samples, config.Samples...)\n+\t}\n+\treturn nil\n+}\n+\n+// readGapicConfigFile loads gapic config from a local file and stores it in\n+// generator.gapic.\n+func (gen *generator) readGapicConfigFile(gapicFname string) error {\n+\t// ignore gapicFname if unspecified\n+\tif gapicFname == \"\" {\n+\t\treturn nil\n+\t}\n+\tf, err := os.Open(gapicFname)\n+\tif err != nil {\n+\t\treturn errors.E(err, \"cannot read GAPIC config file: %q\", gapicFname)\n+\t}\n+\tdefer f.Close()\n+\n+\tif err := yaml.NewDecoder(f).Decode(&gen.gapic); err != nil {\n+\t\treturn errors.E(err, \"error reading GAPIC config file: %q\", gapicFname)\n+\t}\n+\treturn nil\n+}\n+\n+func (g *generator) reset() {\n+\tg.pt.Reset()\n+\tfor imp := range g.imports {\n+\t\tdelete(g.imports, imp)\n+\t}\n+}\n+\n+// commit writes the internal data representation of the generator to bytes.\n+// What it does can be summarized as:\n+// 1) dumps license with the given year\n+// 2) dumps package and imports\n+// 3) dumps generated code in generator.printer\n+// 4) formats the code if gofmt is true\n+func (g *generator) commit(gofmt bool, year int) ([]byte, error) {\n+\t// We'll gofmt unless user asks us not to, so no need to think too hard about sorting\n+\t// \"correctly\". We just want a deterministic output here.\n+\tvar imports []pbinfo.ImportSpec\n+\tfor imp := range g.imports {\n+\t\timports = append(imports, imp)\n+\t}\n+\tsort.Slice(imports, func(i, j int) bool {\n+\t\t// All non-stdlib imports come after stdlib imports.\n+\t\tiDot := strings.IndexByte(imports[i].Path, '.') >= 0\n+\t\tjDot := strings.IndexByte(imports[j].Path, '.') >= 0\n+\t\tif iDot != jDot {\n+\t\t\treturn jDot\n+\t\t}\n+\n+\t\tif imports[i].Path != imports[j].Path {\n+\t\t\treturn imports[i].Path < imports[j].Path\n+\t\t}\n+\t\treturn imports[i].Name < imports[j].Name\n+\t})\n+\n+\tfirstNonStd := sort.Search(len(imports), func(i int) bool { return strings.IndexByte(imports[i].Path, '.') >= 0 })\n+\n+\tvar file bytes.Buffer\n+\tfmt.Fprintf(&file, license.Apache, year)\n+\tfile.WriteString(\"package main\\n\")\n+\tfile.WriteString(\"import(\\n\")\n+\tfor i, imp := range imports {\n+\t\tif i == firstNonStd {\n+\t\t\tfile.WriteByte('\\n')\n+\t\t}\n+\t\tfmt.Fprintf(&file, \"%s %q\\n\", imp.Name, imp.Path)\n+\t}\n+\tfile.WriteString(\")\\n\")\n+\tfile.Write(g.pt.Bytes())\n+\n+\tb := file.Bytes()\n+\tif gofmt {\n+\t\tb2, err := format.Source(b)\n+\t\tif err != nil {\n+\t\t\treturn nil, errors.E(err, \"syntax error, run with -nofmt to find out why?\")\n+\t\t}\n+\t\tb = b2\n+\t}\n+\treturn b, nil\n+}\n+\n+// disambiguateSampleIDs assigns unique sample IDs to each sample config.\n+// User-specified sample IDs (or region tags) are used if they are unique.\n+// Otherwise, the generator will generate a unique ID from the content\n+// of the sample, or fail if it is unable to do so (when multiple samples\n+// have identical contents).\n+func (g *generator) disambiguateSampleIDs() error {\n+\tidCount := make(map[string]int)\n+\thashes := make(map[string]bool)\n+\tsamples := g.sampleConfig.Samples\n+\tfor i := range samples {\n+\t\t// default ID to region tag\n+\t\tif samples[i].ID == \"\" {\n+\t\t\tsamples[i].ID = samples[i].RegionTag\n+\t\t}\n+\t\tif samples[i].ID != \"\" {\n+\t\t\tidCount[samples[i].ID]++\n+\t\t}\n+\t}\n+\n+\tfor i := range samples {\n+\t\t// Generate a sample ID when the user-provided ID is empty or not unique\n+\t\tif samples[i].ID == \"\" || idCount[samples[i].ID] > 1 {\n+\t\t\tjsonStr, err := json.Marshal(samples[i])\n+\t\t\tif err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t\tcheckSum := sha256.Sum256([]byte(jsonStr))\n+\t\t\tencodedStr := base32.StdEncoding.EncodeToString(checkSum[:])\n+\t\t\tsuffix := string([]rune(encodedStr)[0:8])\n+\t\t\tif _, found := hashes[suffix]; found {\n+\t\t\t\treturn errors.E(nil, \"unable to get a unique hash: multiple samples with identical contents\")\n+\t\t\t}\n+\t\t\thashes[suffix] = true\n+\t\t\tsamples[i].ID += suffix\n+\t\t}\n+\t}\n+\treturn nil\n+}\n+\n+// genSample generates one sample from sample config and gapic config.\n+// TODO(hzyi): this method is getting long. Split it up.\n+func (g *generator) genSample(sampConf schema_v1p2.Sample, methConf GAPICMethod) error {\n+\tifaceName := sampConf.Service\n+\n+\t// Preparation\n+\tg.imports[g.clientPkg] = true\n+\tserv := g.descInfo.Serv[\".\"+ifaceName]\n+\tif serv == nil {\n+\t\treturn errors.E(nil, \"can't find service: %q\", ifaceName)\n+\t}\n+\n+\t// We still need method-level GAPIC config for LRO types and Resource name bindings\n+\t// until we start to parse proto annotations\n+\tvar meth *descriptor.MethodDescriptorProto\n+\tfor _, m := range serv.GetMethod() {\n+\t\tif m.GetName() == methConf.Name {\n+\t\t\tmeth = m\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\tif meth == nil {\n+\t\treturn errors.E(nil, \"service %q doesn't have method %q\", serv.GetName(), methConf.Name)\n+\t}\n+\n+\tinType := g.descInfo.Type[meth.GetInputType()]\n+\tif inType == nil {\n+\t\treturn errors.E(nil, \"can't find input type %q\", meth.GetInputType())\n+\t}\n+\tinSpec, err := g.descInfo.ImportSpec(inType)\n+\tif err != nil {\n+\t\treturn errors.E(err, \"can't import input type: %q\", inType)\n+\t}\n+\tg.imports[inSpec] = true\n+\n+\tinitInfo, err := g.getInitInfo(inType, methConf, sampConf.Request)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tp := g.pt.Printf\n+\n+\t// Region tag\n+\targStr, err := argListStr(initInfo, g)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tp(\"\")\n+\tp(\"// [START %s]\", sampConf.RegionTag)\n+\tp(\"\")\n+\n+\t// comments above the sample function\n+\trequiresNewLine := false\n+\n+\twriteCommentLines := func(comment string) {\n+\t\tcomment = wrapComment(strings.TrimSpace(comment))\n+\t\twriteComment(comment, nil, g)\n+\t}\n+\n+\tif sampConf.Description != \"\" {\n+\t\twriteCommentLines(fmt.Sprintf(\"sample%s: %s\", meth.GetName(), sampConf.Description))\n+\t\trequiresNewLine = true\n+\t}\n+\n+\tfor i, argName := range initInfo.argNames {\n+\t\tcomment := initInfo.argTrees[i].comment\n+\t\tif comment == \"\" {\n+\t\t\tcontinue\n+\t\t}\n+\t\tif requiresNewLine {\n+\t\t\twriteCommentLines(\"\")\n+\t\t}\n+\t\trequiresNewLine = true\n+\t\twriteCommentLines(fmt.Sprintf(\"%s: %s\", argName, comment))\n+\t}\n+\n+\t// function signature and client initialization\n+\tp(\"func sample%s(%s) error {\", meth.GetName(), argStr)\n+\tp(\"  ctx := context.Background()\")\n+\tp(\"  c, err := %s.New%sClient(ctx)\", g.clientPkg.Name, pbinfo.ReduceServName(serv.GetName(), g.clientPkg.Name))\n+\tp(\"  if err != nil {\")\n+\tp(\"    return err\")\n+\tp(\"  }\")\n+\tp(\"\")\n+\tg.imports[pbinfo.ImportSpec{Path: \"context\"}] = true\n+\n+\t// Set up the request object\n+\tif err := g.handleRequest(initInfo); err != nil {\n+\t\treturn err\n+\t}\n+\n+\t// Make the RPC call and handle output\n+\tif meth.GetOutputType() == \".google.protobuf.Empty\" {\n+\t\terr = g.emptyOut(meth, sampConf.Response)\n+\t} else if meth.GetOutputType() == \".google.longrunning.Operation\" {\n+\t\terr = g.lro(meth, methConf, sampConf.Response)\n+\t} else if meth.GetServerStreaming() || meth.GetClientStreaming() {\n+\t\t// TODO(hzyi): github.com/googleapis/gapic-generator-go/issues/177\n+\t\terr = errors.E(nil, \"streaming methods not supported yet\")\n+\t} else if pf, err2 := pagingField(g.descInfo, meth); err2 != nil {\n+\t\terr = errors.E(err2, \"can't determine whether method is paging\")\n+\t} else if pf != nil {\n+\t\terr = g.paging(meth, pf, sampConf.Response)\n+\t} else {\n+\t\terr = g.unary(meth, sampConf.Response)\n+\t}\n+\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tp(\"return nil\")\n+\tp(\"}\")\n+\tp(\"\")\n+\tp(\"// [END %s]\", sampConf.RegionTag)\n+\tp(\"\")\n+\n+\t// main\n+\tif err := writeMain(g, initInfo.argNames, initInfo.flagNames, initInfo.argTrees, meth.GetName()); err != nil {\n+\t\treturn err\n+\t}\n+\n+\treturn nil\n+}\n+\n+// getInitInfo extracts information from request configs to prepare for generation of the request setup part of the sample.\n+func (g *generator) getInitInfo(inType pbinfo.ProtoType, methConf GAPICMethod, fieldConfs []schema_v1p2.RequestConfig) (initInfo, error) {\n+\tvar (\n+\t\targNames  []string\n+\t\tflagNames []string\n+\t\targTrees  []*initTree\n+\t\tfiles     []*fileInfo\n+\t)\n+\n+\titree := initTree{\n+\t\ttyp: initType{desc: inType},\n+\t}\n+\n+\t// Set up resource names. We need this info when setting up request object.\n+\t// TODO(hzyi): handle collection_oneofs\n+\tfor field, entName := range methConf.FieldNamePatterns {\n+\t\tvar pat string\n+\t\tfor _, col := range g.gapic.Collections {\n+\t\t\tif col.EntityName == entName {\n+\t\t\t\tpat = col.NamePattern\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\t\tif pat == \"\" {\n+\t\t\treturn initInfo{}, errors.E(nil, \"undefined resource name: %q\", entName)\n+\t\t}\n+\n+\t\tnamePat, err := parseNamePattern(pat)\n+\t\tif err != nil {\n+\t\t\treturn initInfo{}, err\n+\t\t}\n+\n+\t\tsubTree, err := itree.get(field, g.descInfo)\n+\t\tif err != nil {\n+\t\t\treturn initInfo{}, errors.E(err, \"cannot set up resource name: %q\", entName)\n+\t\t}\n+\t\tif typ := subTree.typ; typ.prim != descriptor.FieldDescriptorProto_TYPE_STRING {\n+\t\t\treturn initInfo{}, errors.E(err, \"cannot set up resource name for %q, need field to be string, got %v\", field, typ)\n+\t\t}\n+\t\tsubTree.typ.prim = 0\n+\t\tsubTree.typ.namePat = &namePat\n+\t}\n+\n+\t// Set up request object.\n+\tfor _, fieldConf := range fieldConfs {\n+\t\tif err := itree.parseInit(fieldConf.Field, fieldConf.Value, fieldConf.Comment, g.descInfo); err != nil {\n+\t\t\treturn initInfo{}, errors.E(err, \"can't set default value: %s=%s\", fieldConf.Field, fieldConf.Value)\n+\t\t}\n+\t}\n+\n+\t// Some parts of request object are from arguments.\n+\tfor _, fieldConf := range fieldConfs {\n+\t\tisInputParam := fieldConf.InputParameter != \"\"\n+\t\tif fieldConf.ValueIsFile {\n+\t\t\tvar varName string\n+\t\t\tvar err error\n+\t\t\tif isInputParam {\n+\t\t\t\tvarName = snakeToCamel(fieldConf.InputParameter) + fileContentSuffix\n+\t\t\t} else {\n+\t\t\t\tvarName, err = fileVarName(fieldConf.Field)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn initInfo{}, errors.E(err, \"can't determine variable name to store bytes from local file\")\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tsubTree, err := itree.parseSampleArgPath(\n+\t\t\t\tfieldConf.Field,\n+\t\t\t\tg.descInfo,\n+\t\t\t\tvarName,\n+\t\t\t)\n+\t\t\tif err != nil {\n+\t\t\t\treturn initInfo{}, errors.E(err, \"can't set sample function argument: %q\", fieldConf.Field)\n+\t\t\t}\n+\t\t\tif subTree.typ.prim != descriptor.FieldDescriptorProto_TYPE_BYTES {\n+\t\t\t\treturn initInfo{}, errors.E(nil, \"can only assign file contents to bytes field\")\n+\t\t\t}\n+\t\t\tsubTree.typ.prim = descriptor.FieldDescriptorProto_TYPE_STRING\n+\t\t\tsubTree.typ.valFmt = nil\n+\t\t\tif subTree.leafVal == \"\" {\n+\t\t\t\treturn initInfo{}, errors.E(nil, \"default value not given: %q\", fieldConf.Field)\n+\t\t\t}\n+\t\t\tfileName := subTree.leafVal\n+\t\t\tif isInputParam {\n+\t\t\t\tfileName = snakeToCamel(fieldConf.InputParameter)\n+\t\t\t\targNames = append(argNames, fileName)\n+\t\t\t\tflagNames = append(flagNames, fieldConf.InputParameter)\n+\t\t\t\targTrees = append(argTrees, subTree)\n+\t\t\t}\n+\t\t\tfiles = append(files, &fileInfo{fileName, varName, fieldConf.Comment})\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tif !isInputParam {\n+\t\t\tcontinue\n+\t\t}\n+\t\tname := snakeToCamel(fieldConf.InputParameter)\n+\t\tsubTree, err := itree.parseSampleArgPath(fieldConf.Field, g.descInfo, name)\n+\t\tif err != nil {\n+\t\t\treturn initInfo{}, errors.E(err, \"can't set sample function argument: %q\", fieldConf.Field)\n+\t\t}\n+\n+\t\targNames = append(argNames, name)\n+\t\tflagNames = append(flagNames, fieldConf.InputParameter)\n+\t\targTrees = append(argTrees, subTree)\n+\t}\n+\n+\tinitInfo := initInfo{\n+\t\targNames:  argNames,\n+\t\targTrees:  argTrees,\n+\t\tflagNames: flagNames,\n+\t\tfiles:     files,\n+\t\treqTree:   itree,\n+\t}\n+\n+\treturn initInfo, nil\n+}\n+\n+// argListStr returns a comma-separated string of the list of arguments that sample function takes.\n+func argListStr(init initInfo, g *generator) (string, error) {\n+\tif len(init.argNames) > 0 {\n+\t\tvar sb strings.Builder\n+\t\tfor i, name := range init.argNames {\n+\t\t\ttyp, err := g.getGoTypeName(init.argTrees[i].typ)\n+\t\t\tif err != nil {\n+\t\t\t\treturn \"\", err\n+\t\t\t}\n+\t\t\tfmt.Fprintf(&sb, \", %s %s\", name, typ)\n+\t\t}\n+\t\treturn sb.String()[2:], nil\n+\t}\n+\treturn \"\", nil\n+}\n+\n+func (g *generator) handleRequest(initInfo initInfo) error {\n+\tvar buf bytes.Buffer\n+\n+\tfor i, name := range initInfo.argNames {\n+\t\tfmt.Fprintf(&buf, \"%s := \", name)\n+\t\tif err := initInfo.argTrees[i].Print(&buf, g); err != nil {\n+\t\t\treturn errors.E(err, \"can't initialize parameter: %s\", name)\n+\t\t}\n+\t\tbuf.WriteByte('\\n')\n+\t}\n+\tprependLines(&buf, \"// \", false)\n+\n+\tfor _, info := range initInfo.files {\n+\t\thandleReadFile(info, &buf, g)\n+\t}\n+\n+\tbuf.WriteString(\"req := \")\n+\tif err := initInfo.reqTree.Print(&buf, g); err != nil {\n+\t\treturn errors.E(err, \"can't initialize request object\")\n+\t}\n+\tbuf.WriteByte('\\n')\n+\tprependLines(&buf, \"\\t\", true)\n+\n+\tif _, err := buf.WriteTo(g.pt.Writer()); err != nil {\n+\t\treturn err\n+\t}\n+\treturn nil\n+}\n+\n+func (g *generator) unary(meth *descriptor.MethodDescriptorProto, respConfs []schema_v1p2.ResponseConfig) error {\n+\tp := g.pt.Printf\n+\n+\tp(\"resp, err := c.%s(ctx, req)\", meth.GetName())\n+\tp(\"if err != nil {\")\n+\tp(\"  return err\")\n+\tp(\"}\")\n+\tp(\"\")\n+\n+\treturn g.handleOut(meth, respConfs, &initType{desc: g.descInfo.Type[meth.GetOutputType()]})\n+}\n+\n+func (g *generator) emptyOut(meth *descriptor.MethodDescriptorProto, respConfs []schema_v1p2.ResponseConfig) error {\n+\tp := g.pt.Printf\n+\n+\tp(\"if err := c.%s(ctx, req); err != nil {\", meth.GetName())\n+\tp(\"  return err\")\n+\tp(\"}\")\n+\tp(\"\")\n+\n+\treturn g.handleOut(meth, respConfs, nil)\n+}\n+\n+func (g *generator) paging(meth *descriptor.MethodDescriptorProto, pf *descriptor.FieldDescriptorProto, respConfs []schema_v1p2.ResponseConfig) error {\n+\tp := g.pt.Printf\n+\n+\tp(\"it := c.%s(ctx, req)\", meth.GetName())\n+\tp(\"for {\")\n+\tp(\"  resp, err := it.Next()\")\n+\tp(\"  if err == iterator.Done {\")\n+\tp(\"    break\")\n+\tp(\"  }\")\n+\tp(\"  if err != nil {\")\n+\tp(\"    return err\")\n+\tp(\"  }\")\n+\n+\tvar typ initType\n+\tif tn := pf.GetTypeName(); tn != \"\" {\n+\t\ttyp = initType{desc: g.descInfo.Type[tn]}\n+\t} else {\n+\t\ttyp = initType{prim: pf.GetType()}\n+\t}\n+\n+\terr := g.handleOut(meth, respConfs, &typ)\n+\n+\tp(\"}\")\n+\tp(\"\")\n+\tg.imports[pbinfo.ImportSpec{Path: \"google.golang.org/api/iterator\"}] = true\n+\n+\treturn err\n+}\n+\n+func (g *generator) lro(meth *descriptor.MethodDescriptorProto, methConf GAPICMethod, respConfs []schema_v1p2.ResponseConfig) error {\n+\tp := g.pt.Printf\n+\n+\tp(\"op, err := c.%s(ctx, req)\", meth.GetName())\n+\tp(\"if err != nil {\")\n+\tp(\"  return err\")\n+\tp(\"}\")\n+\tp(\"\")\n+\tp(\"resp, err := op.Wait(ctx)\")\n+\tp(\"if err != nil {\")\n+\tp(\"  return err\")\n+\tp(\"}\")\n+\tp(\"\")\n+\n+\tretType := methConf.LongRunning.ReturnType\n+\tif retType == \"\" {\n+\t\treturn errors.E(nil, \"LRO return type not given\")\n+\t}\n+\n+\ttyp := initType{desc: g.descInfo.Type[\".\"+retType]}\n+\treturn g.handleOut(meth, respConfs, &typ)\n+}\n+\n+func (g *generator) handleOut(meth *descriptor.MethodDescriptorProto, respConfs []schema_v1p2.ResponseConfig, respTyp *initType) error {\n+\tst := newSymTab(nil)\n+\tif respTyp != nil {\n+\t\tst.universe[\"$resp\"] = true\n+\t\tst.scope[\"$resp\"] = *respTyp\n+\t}\n+\n+\tfor _, out := range respConfs {\n+\t\tif err := writeOutputSpec(out, st, g); err != nil {\n+\t\t\treturn errors.E(err, \"cannot write output handling code\")\n+\t\t}\n+\t}\n+\n+\tif respTyp != nil && len(respConfs) == 0 {\n+\t\tg.pt.Printf(\"fmt.Println(resp)\")\n+\t\tg.imports[pbinfo.ImportSpec{Path: \"fmt\"}] = true\n+\t}\n+\treturn nil\n+}\n+\n+// readSampleConfig loads sample configs from a file.\n+func readSampleConfig(decoder *yaml.Decoder, fname string) (schema_v1p2.SampleConfig, error) {\n+\tvar config schema_v1p2.SampleConfig\n+\tfor true {\n+\t\tvar sc schema_v1p2.SampleConfig\n+\t\terr := decoder.Decode(&sc)\n+\t\tif err != nil && err.Error() == \"EOF\" {\n+\t\t\t// last YAML document, all done\n+\t\t\tbreak\n+\t\t}\n+\t\tif err != nil {\n+\t\t\treturn config, err\n+\t\t}\n+\t\tif sc.Type != expectedSampleConfigType {\n+\t\t\t// ignore non sample config YAMLs\n+\t\t\tcontinue\n+\t\t}\n+\t\tif sc.Version != expectedSampleConfigVersion {\n+\t\t\t// ignore unsupported versions\n+\t\t\tcontinue\n+\t\t}\n+\t\tconfig.Samples = append(config.Samples, sc.Samples...)\n+\t}\n+\tif len(config.Samples) == 0 {\n+\t\treturn config, errors.E(nil, \"Found no valid sample config in %q\", fname)\n+\t}\n+\treturn config, nil\n+}\n+\n+// prependLines adds prefix to every line in b. A line is defined as a possibly empty run\n+// of non-newlines terminated by a newline character.\n+// If b doesn't end with a newline, prependLines panics.","path":"internal/gensample/gensample.go","position":null,"original_position":697,"commit_id":"11a83c4e25059bfe16bb1bfc98c3524f46cebdb3","original_commit_id":"6d8b85eae9d1c5bd8d0a0880ad73d289bd3f4266","user":{"login":"hzyi-google","id":33737743,"node_id":"MDQ6VXNlcjMzNzM3NzQz","avatar_url":"https://avatars0.githubusercontent.com/u/33737743?v=4","gravatar_id":"","url":"https://api.github.com/users/hzyi-google","html_url":"https://github.com/hzyi-google","followers_url":"https://api.github.com/users/hzyi-google/followers","following_url":"https://api.github.com/users/hzyi-google/following{/other_user}","gists_url":"https://api.github.com/users/hzyi-google/gists{/gist_id}","starred_url":"https://api.github.com/users/hzyi-google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hzyi-google/subscriptions","organizations_url":"https://api.github.com/users/hzyi-google/orgs","repos_url":"https://api.github.com/users/hzyi-google/repos","events_url":"https://api.github.com/users/hzyi-google/events{/privacy}","received_events_url":"https://api.github.com/users/hzyi-google/received_events","type":"User","site_admin":false},"body":"Just used three times altogether, I'll fix them here :)","created_at":"2019-10-09T18:49:05Z","updated_at":"2019-10-09T18:49:05Z","html_url":"https://github.com/googleapis/gapic-generator-go/pull/218#discussion_r333175710","pull_request_url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/comments/333175710"},"html":{"href":"https://github.com/googleapis/gapic-generator-go/pull/218#discussion_r333175710"},"pull_request":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218"}},"in_reply_to_id":331806903},"pull_request":{"url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218","id":323541257,"node_id":"MDExOlB1bGxSZXF1ZXN0MzIzNTQxMjU3","html_url":"https://github.com/googleapis/gapic-generator-go/pull/218","diff_url":"https://github.com/googleapis/gapic-generator-go/pull/218.diff","patch_url":"https://github.com/googleapis/gapic-generator-go/pull/218.patch","issue_url":"https://api.github.com/repos/googleapis/gapic-generator-go/issues/218","number":218,"state":"open","locked":false,"title":"Have gengapic protoc plugin invoke samplegen","user":{"login":"hzyi-google","id":33737743,"node_id":"MDQ6VXNlcjMzNzM3NzQz","avatar_url":"https://avatars0.githubusercontent.com/u/33737743?v=4","gravatar_id":"","url":"https://api.github.com/users/hzyi-google","html_url":"https://github.com/hzyi-google","followers_url":"https://api.github.com/users/hzyi-google/followers","following_url":"https://api.github.com/users/hzyi-google/following{/other_user}","gists_url":"https://api.github.com/users/hzyi-google/gists{/gist_id}","starred_url":"https://api.github.com/users/hzyi-google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hzyi-google/subscriptions","organizations_url":"https://api.github.com/users/hzyi-google/orgs","repos_url":"https://api.github.com/users/hzyi-google/repos","events_url":"https://api.github.com/users/hzyi-google/events{/privacy}","received_events_url":"https://api.github.com/users/hzyi-google/received_events","type":"User","site_admin":false},"body":"- Move most of `cmd/gen-go-sample` to `intenal/gensample`, but leave `main.go` still in `cmd/gen-go-sample`. This makes sure that samplegen can continue to run as a standalone program, and gapic-gen and invoke samplegen\r\n\r\n- Add `--sample`, `--gapic-config` and `--sample-only` flag to docker entry point, and pass them along to `gensample` and `gengapic`.\r\n  - When `--sample-only` is present, toggle off `gengapic` and `gapic_validator_out`, so that we can generate samples for APIs that are not yet properly annotated.\r\n  - `gensample` will consume gapic config and sample config.","created_at":"2019-10-02T01:28:58Z","updated_at":"2019-10-09T18:49:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"258e9c1d2184949030c806d6a29e4f84560bed90","assignee":null,"assignees":[],"requested_reviewers":[{"login":"software-dov","id":2960535,"node_id":"MDQ6VXNlcjI5NjA1MzU=","avatar_url":"https://avatars3.githubusercontent.com/u/2960535?v=4","gravatar_id":"","url":"https://api.github.com/users/software-dov","html_url":"https://github.com/software-dov","followers_url":"https://api.github.com/users/software-dov/followers","following_url":"https://api.github.com/users/software-dov/following{/other_user}","gists_url":"https://api.github.com/users/software-dov/gists{/gist_id}","starred_url":"https://api.github.com/users/software-dov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/software-dov/subscriptions","organizations_url":"https://api.github.com/users/software-dov/orgs","repos_url":"https://api.github.com/users/software-dov/repos","events_url":"https://api.github.com/users/software-dov/events{/privacy}","received_events_url":"https://api.github.com/users/software-dov/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":1426101115,"node_id":"MDU6TGFiZWwxNDI2MTAxMTE1","url":"https://api.github.com/repos/googleapis/gapic-generator-go/labels/cla:%20yes","name":"cla: yes","color":"0B7601","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218/commits","review_comments_url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218/comments","review_comment_url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/comments{/number}","comments_url":"https://api.github.com/repos/googleapis/gapic-generator-go/issues/218/comments","statuses_url":"https://api.github.com/repos/googleapis/gapic-generator-go/statuses/11a83c4e25059bfe16bb1bfc98c3524f46cebdb3","head":{"label":"hzyi-google:plugin","ref":"plugin","sha":"11a83c4e25059bfe16bb1bfc98c3524f46cebdb3","user":{"login":"hzyi-google","id":33737743,"node_id":"MDQ6VXNlcjMzNzM3NzQz","avatar_url":"https://avatars0.githubusercontent.com/u/33737743?v=4","gravatar_id":"","url":"https://api.github.com/users/hzyi-google","html_url":"https://github.com/hzyi-google","followers_url":"https://api.github.com/users/hzyi-google/followers","following_url":"https://api.github.com/users/hzyi-google/following{/other_user}","gists_url":"https://api.github.com/users/hzyi-google/gists{/gist_id}","starred_url":"https://api.github.com/users/hzyi-google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hzyi-google/subscriptions","organizations_url":"https://api.github.com/users/hzyi-google/orgs","repos_url":"https://api.github.com/users/hzyi-google/repos","events_url":"https://api.github.com/users/hzyi-google/events{/privacy}","received_events_url":"https://api.github.com/users/hzyi-google/received_events","type":"User","site_admin":false},"repo":{"id":152153457,"node_id":"MDEwOlJlcG9zaXRvcnkxNTIxNTM0NTc=","name":"gapic-generator-go","full_name":"hzyi-google/gapic-generator-go","private":false,"owner":{"login":"hzyi-google","id":33737743,"node_id":"MDQ6VXNlcjMzNzM3NzQz","avatar_url":"https://avatars0.githubusercontent.com/u/33737743?v=4","gravatar_id":"","url":"https://api.github.com/users/hzyi-google","html_url":"https://github.com/hzyi-google","followers_url":"https://api.github.com/users/hzyi-google/followers","following_url":"https://api.github.com/users/hzyi-google/following{/other_user}","gists_url":"https://api.github.com/users/hzyi-google/gists{/gist_id}","starred_url":"https://api.github.com/users/hzyi-google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hzyi-google/subscriptions","organizations_url":"https://api.github.com/users/hzyi-google/orgs","repos_url":"https://api.github.com/users/hzyi-google/repos","events_url":"https://api.github.com/users/hzyi-google/events{/privacy}","received_events_url":"https://api.github.com/users/hzyi-google/received_events","type":"User","site_admin":false},"html_url":"https://github.com/hzyi-google/gapic-generator-go","description":"Generate Go API client libraries from Protocol Buffers.","fork":true,"url":"https://api.github.com/repos/hzyi-google/gapic-generator-go","forks_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/forks","keys_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/teams","hooks_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/hooks","issue_events_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/issues/events{/number}","events_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/events","assignees_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/assignees{/user}","branches_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/branches{/branch}","tags_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/tags","blobs_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/statuses/{sha}","languages_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/languages","stargazers_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/stargazers","contributors_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/contributors","subscribers_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/subscribers","subscription_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/subscription","commits_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/contents/{+path}","compare_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/merges","archive_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/downloads","issues_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/issues{/number}","pulls_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/pulls{/number}","milestones_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/milestones{/number}","notifications_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/labels{/name}","releases_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/releases{/id}","deployments_url":"https://api.github.com/repos/hzyi-google/gapic-generator-go/deployments","created_at":"2018-10-08T22:15:59Z","updated_at":"2018-10-08T22:16:01Z","pushed_at":"2019-10-09T18:48:26Z","git_url":"git://github.com/hzyi-google/gapic-generator-go.git","ssh_url":"git@github.com:hzyi-google/gapic-generator-go.git","clone_url":"https://github.com/hzyi-google/gapic-generator-go.git","svn_url":"https://github.com/hzyi-google/gapic-generator-go","homepage":"","size":6227,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"googleapis:master","ref":"master","sha":"53cc3d3bc0c6e2ce665d7ca707d1be09a8e236ae","user":{"login":"googleapis","id":16785467,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE2Nzg1NDY3","avatar_url":"https://avatars3.githubusercontent.com/u/16785467?v=4","gravatar_id":"","url":"https://api.github.com/users/googleapis","html_url":"https://github.com/googleapis","followers_url":"https://api.github.com/users/googleapis/followers","following_url":"https://api.github.com/users/googleapis/following{/other_user}","gists_url":"https://api.github.com/users/googleapis/gists{/gist_id}","starred_url":"https://api.github.com/users/googleapis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/googleapis/subscriptions","organizations_url":"https://api.github.com/users/googleapis/orgs","repos_url":"https://api.github.com/users/googleapis/repos","events_url":"https://api.github.com/users/googleapis/events{/privacy}","received_events_url":"https://api.github.com/users/googleapis/received_events","type":"Organization","site_admin":false},"repo":{"id":149170309,"node_id":"MDEwOlJlcG9zaXRvcnkxNDkxNzAzMDk=","name":"gapic-generator-go","full_name":"googleapis/gapic-generator-go","private":false,"owner":{"login":"googleapis","id":16785467,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE2Nzg1NDY3","avatar_url":"https://avatars3.githubusercontent.com/u/16785467?v=4","gravatar_id":"","url":"https://api.github.com/users/googleapis","html_url":"https://github.com/googleapis","followers_url":"https://api.github.com/users/googleapis/followers","following_url":"https://api.github.com/users/googleapis/following{/other_user}","gists_url":"https://api.github.com/users/googleapis/gists{/gist_id}","starred_url":"https://api.github.com/users/googleapis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/googleapis/subscriptions","organizations_url":"https://api.github.com/users/googleapis/orgs","repos_url":"https://api.github.com/users/googleapis/repos","events_url":"https://api.github.com/users/googleapis/events{/privacy}","received_events_url":"https://api.github.com/users/googleapis/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/googleapis/gapic-generator-go","description":"Generate Go API client libraries from Protocol Buffers.","fork":false,"url":"https://api.github.com/repos/googleapis/gapic-generator-go","forks_url":"https://api.github.com/repos/googleapis/gapic-generator-go/forks","keys_url":"https://api.github.com/repos/googleapis/gapic-generator-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/googleapis/gapic-generator-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/googleapis/gapic-generator-go/teams","hooks_url":"https://api.github.com/repos/googleapis/gapic-generator-go/hooks","issue_events_url":"https://api.github.com/repos/googleapis/gapic-generator-go/issues/events{/number}","events_url":"https://api.github.com/repos/googleapis/gapic-generator-go/events","assignees_url":"https://api.github.com/repos/googleapis/gapic-generator-go/assignees{/user}","branches_url":"https://api.github.com/repos/googleapis/gapic-generator-go/branches{/branch}","tags_url":"https://api.github.com/repos/googleapis/gapic-generator-go/tags","blobs_url":"https://api.github.com/repos/googleapis/gapic-generator-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/googleapis/gapic-generator-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/googleapis/gapic-generator-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/googleapis/gapic-generator-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/googleapis/gapic-generator-go/statuses/{sha}","languages_url":"https://api.github.com/repos/googleapis/gapic-generator-go/languages","stargazers_url":"https://api.github.com/repos/googleapis/gapic-generator-go/stargazers","contributors_url":"https://api.github.com/repos/googleapis/gapic-generator-go/contributors","subscribers_url":"https://api.github.com/repos/googleapis/gapic-generator-go/subscribers","subscription_url":"https://api.github.com/repos/googleapis/gapic-generator-go/subscription","commits_url":"https://api.github.com/repos/googleapis/gapic-generator-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/googleapis/gapic-generator-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/googleapis/gapic-generator-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/googleapis/gapic-generator-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/googleapis/gapic-generator-go/contents/{+path}","compare_url":"https://api.github.com/repos/googleapis/gapic-generator-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/googleapis/gapic-generator-go/merges","archive_url":"https://api.github.com/repos/googleapis/gapic-generator-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/googleapis/gapic-generator-go/downloads","issues_url":"https://api.github.com/repos/googleapis/gapic-generator-go/issues{/number}","pulls_url":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls{/number}","milestones_url":"https://api.github.com/repos/googleapis/gapic-generator-go/milestones{/number}","notifications_url":"https://api.github.com/repos/googleapis/gapic-generator-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/googleapis/gapic-generator-go/labels{/name}","releases_url":"https://api.github.com/repos/googleapis/gapic-generator-go/releases{/id}","deployments_url":"https://api.github.com/repos/googleapis/gapic-generator-go/deployments","created_at":"2018-09-17T18:31:01Z","updated_at":"2019-10-08T22:04:40Z","pushed_at":"2019-10-09T18:48:28Z","git_url":"git://github.com/googleapis/gapic-generator-go.git","ssh_url":"git@github.com:googleapis/gapic-generator-go.git","clone_url":"https://github.com/googleapis/gapic-generator-go.git","svn_url":"https://github.com/googleapis/gapic-generator-go","homepage":"","size":730,"stargazers_count":30,"watchers_count":30,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":11,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":11,"open_issues":11,"watchers":30,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218"},"html":{"href":"https://github.com/googleapis/gapic-generator-go/pull/218"},"issue":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/issues/218"},"comments":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/issues/218/comments"},"review_comments":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218/comments"},"review_comment":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/pulls/218/commits"},"statuses":{"href":"https://api.github.com/repos/googleapis/gapic-generator-go/statuses/11a83c4e25059bfe16bb1bfc98c3524f46cebdb3"}},"author_association":"CONTRIBUTOR"}}
other: {"actor":{"display_login":"hzyi-google"}}