Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var BuildCmd = &cobra.Command{ Use: "build", Short: "build an integration", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { integrationDir := args[0] logger := log.NewCommandLogger(cmd) defer logger.Close() integrationDir, _ = filepath.Abs(integrationDir) integration := filepath.Base(integrationDir) fp := filepath.Join(integrationDir, "integration.go") if !fileutil.FileExists(fp) { log.Fatal(logger, "couldn't find the integration at "+fp) } distDir, _ := cmd.Flags().GetString("dir") distDir, _ = filepath.Abs(distDir) os.MkdirAll(distDir, 0700) dist := filepath.Join(distDir) modfp := filepath.Join(integrationDir, "go.mod") mod, err := ioutil.ReadFile(modfp) if err != nil { log.Fatal(logger, "error reading plugin go.mod", "err", err) } ioutil.WriteFile(modfp, []byte(string(mod)+"\nreplace github.com/pinpt/agent => ../agent"), 0644) bundle, _ := cmd.Flags().GetBool("bundle") var bundleRewriter rewriteFunc if bundle { yfn := filepath.Join(integrationDir, "integration.yaml") if !fileutil.FileExists(yfn) { log.Fatal(logger, "missing required file at "+yfn) } ygofn := filepath.Join(integrationDir, "integration.go") if !fileutil.FileExists(ygofn) { log.Fatal(logger, "missing required file at "+ygofn) } buf, err := ioutil.ReadFile(yfn) if err != nil { log.Fatal(logger, "error opening required file at "+yfn, "err", err) } gobuf, err := ioutil.ReadFile(ygofn) if err != nil { log.Fatal(logger, "error opening required file at "+ygofn, "err", err) } var descriptor sdk.Descriptor if err := yaml.Unmarshal(buf, &descriptor); err != nil { log.Fatal(logger, "error parsing config file at "+yfn, "err", err) } version := getBuildCommitForIntegration(integrationDir) bbuf := base64.StdEncoding.EncodeToString(buf) tmpl, err := generateMainTemplate(ygofn, string(gobuf), bbuf, datetime.ISODate(), version) if err != nil { log.Fatal(logger, "error generating build", "err", err) } ioutil.WriteFile(ygofn, []byte(tmpl), 0644) bundleRewriter = func() { ioutil.WriteFile(ygofn, gobuf, 0644) } defer bundleRewriter() } theenv := os.Environ() oses, _ := cmd.Flags().GetStringArray("os") for _, theos := range oses { arches, _ := cmd.Flags().GetStringArray("arch") for _, arch := range arches { env := append(theenv, []string{"GOOS=" + theos, "GOARCH=" + arch}...) outfn := filepath.Join(dist, theos, arch, integration) os.MkdirAll(filepath.Dir(outfn), 0700) c := exec.Command("go", "build", "-o", outfn) c.Stderr = os.Stderr c.Stdout = os.Stdout c.Stdin = os.Stdin c.Dir = integrationDir c.Env = env if err := c.Run(); err != nil { bundleRewriter() ioutil.WriteFile(modfp, mod, 0644) os.Exit(1) } log.Debug(logger, "file built to "+outfn) } } ioutil.WriteFile(modfp, mod, 0644) if bundleRewriter != nil { bundleRewriter() } }, }
BuildCmd represents the build command
View Source
var DevCmd = createDevCommand("dev", "dev-export", "run an integration in development mode", false, func(cmd *cobra.Command, devargs []string) []string { historical, _ := cmd.Flags().GetBool("historical") if historical { devargs = append(devargs, "--historical=true") } webhookEnabled, _ := cmd.Flags().GetBool("webhook") if webhookEnabled { devargs = append(devargs, "--webhook") } secret, _ := cmd.Flags().GetString("secret") if secret != "" { devargs = append(devargs, "--secret", secret) } consoleout, _ := cmd.Flags().GetBool("console-out") if consoleout { devargs = append(devargs, "--console-out") } record, _ := cmd.Flags().GetString("record") replay, _ := cmd.Flags().GetString("replay") if record != "" { record, _ = filepath.Abs(record) devargs = append(devargs, "--record", record) } if replay != "" { replay, _ = filepath.Abs(replay) devargs = append(devargs, "--replay", replay) } return devargs })
DevCmd represents the dev command
View Source
var EnrollCmd = &cobra.Command{ Use: "enroll", Short: "enroll to create a developer account", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() logger := log.NewCommandLogger(cmd) defer logger.Close() channel, _ := cmd.Flags().GetString("channel") config, err := loadDevConfig(channel) if err != nil { log.Fatal(logger, "unable to load developer config", "err", err) } if config.expired() { log.Fatal(logger, "your login session has expired. please login again") } if config.Channel != channel { log.Fatal(logger, "your login session was for a different channel. please login again") } banner() fmt.Println() fmt.Println("🚀 Time to enroll you in the Pinpoint Developer Program") fmt.Println() fmt.Println("We need a few bits of information to continue ...") fmt.Println() var result struct { Name string `json:"name" survey:"name"` Identifier string `json:"identifier" survey:"identifier"` Description string `json:"description" survey:"description"` Avatar string `json:"avatar_url" survey:"avatar_url"` URL string `json:"url" survey:"url"` Certificate string `json:"csr"` } if err := survey.Ask([]*survey.Question{ { Name: "name", Prompt: &survey.Input{ Message: "Your Publisher Name:", Help: "Your name such as Pinpoint Software, Inc", }, Validate: survey.Required, }, { Name: "identifier", Prompt: &survey.Input{ Message: "Your Publisher Short Identifier:", Help: "Your short identifier must be unique and should contain no spaces or special characters such as pinpt", }, Validate: createValidateIdentifier(channel, config.APIKey, config.CustomerID), }, { Name: "avatar_url", Prompt: &survey.Input{ Message: "Your Publisher Avatar:", Help: "A url to your avatar image in PNG, GIF or JPEG format", }, Validate: validateAvatar, }, { Name: "url", Prompt: &survey.Input{ Message: "Your Publisher URL:", Help: "The URL to your homepage or URL to your integration", }, Validate: validateURL, }, { Name: "description", Prompt: &survey.Input{ Message: "Your Publisher Bio:", Help: "A short description of your bio or company background", }, Validate: survey.ComposeValidators(survey.Required, survey.MaxLength(255), survey.MinLength(20)), }, }, &result); err != nil { os.Exit(1) } fmt.Println() log.Info(logger, "generating new private key") privateKey, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { log.Fatal(logger, "error generating private key", "err", err) } privateKeyBuf := pem.EncodeToMemory(&pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey), }) config.PrivateKey = string(privateKeyBuf) if err := config.save(); err != nil { log.Fatal(logger, "error saving config", "err", err) } buf, err := generateCertificateRequest(logger, privateKey, config.CustomerID) if err != nil { log.Fatal(logger, "error generating certificate request", "err", err) } result.Certificate = string(buf) resp, err := api.Put(ctx, channel, api.RegistryService, "enroll", config.APIKey, strings.NewReader(pjson.Stringify(result))) if err != nil { log.Fatal(logger, "error sending cert request", "err", err) } respBuf, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(logger, "error reading response body", "err", err) } resp.Body.Close() if resp.StatusCode != http.StatusCreated { log.Fatal(logger, "error from api", "err", string(respBuf)) } log.Info(logger, "recieved certificate from Pinpoint") config.Certificate = string(respBuf) config.PublisherRefType = result.Identifier if err := config.save(); err != nil { log.Fatal(logger, "error saving config", "err", err) } log.Info(logger, "successfully enrolled. you can now publish integrations! go forth and build 🎉", "customer_id", config.CustomerID) }, }
EnrollCmd represents the enroll command
View Source
var GenCmd = &cobra.Command{ Use: "generate", Short: "generates an integration", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { banner() fmt.Println("Welcome to the Pinpoint Integration generator!") fmt.Println() logger := log.NewCommandLogger(cmd) defer logger.Close() var err error var result generator.Info if err = promptSettings(&result); err != nil { log.Error(logger, "error with settings", "err", err) os.Exit(1) } gopath := os.Getenv("GOPATH") if gopath == "" { var buf strings.Builder c := exec.Command("go", "env", "GOPATH") c.Stdout = &buf if err := c.Run(); err != nil { log.Fatal(logger, "error finding your GOPATH. is Golang installed and on your PATH?", "err", err) } gopath = strings.TrimSpace(buf.String()) } result.Dir = filepath.Join(gopath, "src", result.Pkg) if !fileutil.FileExists(result.Dir) { os.MkdirAll(result.Dir, 0700) } if err = generator.Generate(result.Dir, result); err != nil { log.Fatal(logger, "error with generator", "err", err) } appDir := filepath.Join(result.Dir, "app") sdkInstall := exec.Command("npm", "install", "@pinpt/agent.websdk", "@pinpt/uic.next", "--save", "--loglevel", "error") sdkInstall.Dir = appDir sdkInstall.Stderr = os.Stderr sdkInstall.Stdin = os.Stdin sdkInstall.Stdin = os.Stdin sdkInstall.Run() npmInstall := exec.Command("npm", "install", "--loglevel", "error") npmInstall.Dir = appDir npmInstall.Stderr = os.Stderr npmInstall.Stdin = os.Stdin npmInstall.Stdin = os.Stdin npmInstall.Run() fmt.Println() fmt.Println("🎉 project created! open " + result.Dir + " in your editor and start coding!") fmt.Println() }, }
GenCmd represents the dev command
View Source
var LoginCmd = &cobra.Command{ Use: "login", Short: "login to your developer account", Run: func(cmd *cobra.Command, args []string) { logger := log.NewCommandLogger(cmd) defer logger.Close() var config *devConfig channel, _ := cmd.Flags().GetString("channel") baseurl := api.BackendURL(api.AuthService, channel) url := sdk.JoinURL(baseurl, "/oauth2/pinpoint/agent/authorize?apikey=true") var ok bool var errmsg string err := util.WaitForRedirect(url, func(w http.ResponseWriter, r *http.Request) { config, _ = loadDevConfig(channel) q := r.URL.Query() err := q.Get("error") if err != "" { _errdesc := q.Get("error_description") if _errdesc == "" || _errdesc == "undefined" { _errdesc = err } errmsg = _errdesc httpmessage.RenderStatus(w, r, http.StatusUnauthorized, "Login Failed", "Login failed. "+_errdesc) return } customerID := q.Get("customer_id") if customerID == "" { log.Fatal(logger, "the authorization server didn't return a valid customer_id") } if config != nil { if config.CustomerID == customerID { log.Info(logger, "refreshing token", "customer_id", customerID) } else { log.Info(logger, "logging into new customer, you will need to generate a new private key before publishing 🔑", "customer_id", customerID) } } else { config = &devConfig{} } expires := q.Get("expires") if expires != "" { e, _ := strconv.ParseInt(expires, 10, 64) config.Expires = datetime.DateFromEpoch(e) } else { config.Expires = time.Now().Add(time.Hour * 23) } config.APIKey = q.Get("apikey") config.RefreshKey = q.Get("refresh_token") config.CustomerID = customerID config.Channel = channel if err := config.save(); err != nil { log.Error(logger, "error saving config", "err", err) } ok = true httpmessage.RenderStatus(w, r, http.StatusOK, "Login Success", "You have logged in successfully and can now close this window") }) if err != nil { log.Fatal(logger, "error waiting for browser", "err", err) } if !ok { log.Fatal(logger, "error logging in", "err", errmsg) } log.Info(logger, "logged in", "customer_id", config.CustomerID) }, }
LoginCmd represents the login command
View Source
var LogoutCmd = &cobra.Command{ Use: "logout", Short: "logout of your developer account", Run: func(cmd *cobra.Command, args []string) { var c devConfig c.remove() }, }
LogoutCmd represents the logout command
View Source
var PackageCmd = &cobra.Command{ Use: "package", Short: "package an integration", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { integrationDir := args[0] logger := log.NewCommandLogger(cmd) defer logger.Close() integrationDir, _ = filepath.Abs(integrationDir) distDir, _ := cmd.Flags().GetString("dir") distDir, _ = filepath.Abs(distDir) bundleDir := filepath.Join(distDir, "bundle") dataDir := filepath.Join(bundleDir, "data") appDir := filepath.Join(integrationDir, "app") channel, _ := cmd.Flags().GetString("channel") os.MkdirAll(bundleDir, 0700) os.MkdirAll(dataDir, 0700) buf, err := ioutil.ReadFile(filepath.Join(integrationDir, "integration.yaml")) if err != nil { log.Fatal(logger, "error loading integration.yaml", "err", err) } descriptor, err := sdk.LoadDescriptor(base64.StdEncoding.EncodeToString(buf), "", "") if err != nil { log.Fatal(logger, "error loading descriptor", "err", err) } if err := ioutil.WriteFile(filepath.Join(bundleDir, "integration.json"), []byte(pjson.Stringify(descriptor)), 0644); err != nil { log.Fatal(logger, "error writing integration json", "err", err) } dataFn := filepath.Join(bundleDir, "data.zip") uiFn := filepath.Join(bundleDir, "ui.zip") bundleFn := filepath.Join(distDir, "bundle.zip") oss, _ := cmd.Flags().GetStringArray("os") arches, _ := cmd.Flags().GetStringArray("arch") cargs := []string{"build", integrationDir, "--dir", dataDir} for _, o := range oss { cargs = append(cargs, "--os", o) } for _, a := range arches { cargs = append(cargs, "--arch", a) } c := exec.Command(os.Args[0], cargs...) c.Stdout = os.Stdout c.Stderr = os.Stderr c.Stdin = os.Stdin if err := c.Run(); err != nil { log.Fatal(logger, "error running command", "command", c.String(), "err", err) } c = exec.Command("npm", "install", "--loglevel", "error") c.Dir = appDir c.Stdout = os.Stdout c.Stderr = os.Stderr c.Stdin = os.Stdin if err := c.Run(); err != nil { log.Fatal(logger, "error running command", "command", c.String(), "err", err) } c = exec.Command("npm", "run", "build", "--loglevel", "error") c.Dir = appDir c.Stdout = os.Stdout c.Stderr = os.Stderr c.Stdin = os.Stdin if err := c.Run(); err != nil { log.Fatal(logger, "error running command", "command", c.String(), "err", err) } if _, err := fileutil.ZipDir(uiFn, filepath.Join(appDir, "build"), regexp.MustCompile(".*")); err != nil { log.Fatal(logger, "error building zip file", "err", err) } sha := getBuildCommitForIntegration(integrationDir) if err := ioutil.WriteFile(filepath.Join(bundleDir, "version.txt"), []byte(sha), 0644); err != nil { log.Fatal(logger, "error writing version file to bundle dir", "err", err) } if devCfg, err := loadDevConfig(channel); err == nil { if devCfg.Certificate != "" { if err := ioutil.WriteFile(filepath.Join(bundleDir, "cert.pem"), []byte(devCfg.Certificate), 0644); err != nil { log.Fatal(logger, "error writing developer certificate to bundle dir", "err", err) } } else { log.Debug(logger, "no developer certificate found, not including in bundle", "err", err) } } else { log.Warn(logger, "unable to load developer config, the bundle will not contain your developer certificate", "err", err) } if _, err := fileutil.ZipDir(dataFn, dataDir, regexp.MustCompile(".*")); err != nil { log.Fatal(logger, "error building zip file", "err", err) } if _, err := fileutil.ZipDir(bundleFn, bundleDir, regexp.MustCompile(".(zip|asc|txt|pem|json)$")); err != nil { log.Fatal(logger, "error building zip file", "err", err) } os.RemoveAll(bundleDir) log.Info(logger, "bundle packaged to "+bundleFn) }, }
PackageCmd represents the package command
View Source
var PublishCmd = &cobra.Command{ Use: "publish <integration dir>", Short: "publish an integration to the registry", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { integrationDir := args[0] logger := log.NewCommandLogger(cmd) defer logger.Close() channel, _ := cmd.Flags().GetString("channel") tmpdir, err := ioutil.TempDir("", "") if err != nil { log.Fatal(logger, "error creating temp dir", "err", err) } defer os.RemoveAll(tmpdir) c, err := loadDevConfig(channel) if err != nil { log.Fatal(logger, "error opening developer config", "err", err) } if c.PrivateKey == "" { log.Fatal(logger, "missing private key in config, please enroll before publishing") } if c.expired() { log.Fatal(logger, "your login session has expired. please login again") } privateKey, err := util.ParsePrivateKey(c.PrivateKey) if err != nil { log.Fatal(logger, "unable to parse private key in config") } log.Info(logger, "building package") cm := exec.Command(os.Args[0], "package", integrationDir, "--dir", tmpdir, "--channel", channel) cm.Stdout = os.Stdout cm.Stderr = os.Stderr cm.Stdin = os.Stdin if err := cm.Run(); err != nil { log.Fatal(logger, "error running package command", "err", err) } bundle := filepath.Join(tmpdir, "bundle.zip") if !fileutil.FileExists(bundle) { log.Fatal(logger, "error bundle does not exist", "err", err) } signature, err := signFile(bundle, privateKey) if err != nil { log.Fatal(logger, "error getting signature for bundle", "err", err) } of, err := os.Open(bundle) if err != nil { log.Fatal(logger, "error opening bundle", "err", err) } defer of.Close() stat, _ := os.Stat(bundle) ctx, cancel := context.WithCancel(context.Background()) defer cancel() opts := []api.WithOption{ api.WithContentType("application/zip"), api.WithHeader("x-pinpt-signature", signature), func(req *http.Request) error { req.ContentLength = stat.Size() return nil }, } apikey, _ := cmd.Flags().GetString("apikey") secret, _ := cmd.Flags().GetString("secret") if secret != "" { opts = append(opts, api.WithHeader("x-api-key", secret)) } else if apikey == "" { apikey = c.APIKey if apikey == "" { log.Fatal(logger, "you must login or provide the apikey using --apikey before continuing") } } descriptorFn := filepath.Join(integrationDir, "integration.yaml") descriptorBuf, err := ioutil.ReadFile(descriptorFn) if err != nil { log.Fatal(logger, "error reading descriptor", "err", err, "file", descriptorFn) } descriptor, err := sdk.LoadDescriptor(base64.StdEncoding.EncodeToString(descriptorBuf), "", "") if err != nil { log.Fatal(logger, "error loading descriptor", "err", err, "file", descriptorFn) } version := getBuildCommitForIntegration(integrationDir) basepath := fmt.Sprintf("publish/%s/%s/%s", c.PublisherRefType, descriptor.RefType, version) log.Info(logger, "uploading", "size", pnum.ToBytesSize(stat.Size())) resp, err := api.Put(ctx, channel, api.RegistryService, basepath, apikey, of, opts...) if err != nil || resp.StatusCode != http.StatusAccepted { var buf []byte if resp != nil { buf, _ = ioutil.ReadAll(resp.Body) } log.Fatal(logger, "error publishing your bundle", "err", err, "body", string(buf)) } log.Info(logger, "🚀 published", "integration", descriptor.RefType, "version", version) }, }
PublishCmd represents the publish command
View Source
var UtilCmd = &cobra.Command{
Use: "util",
Short: "base for all util commands",
}
UtilCmd is for dev utilities
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.