Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var BundleCmd = &cobra.Command{ Use: "bundle", Short: "Creates a new app bundle", Example: ` pixlet bundle ./my-app`, Long: `This command will create a new app bundle from an app directory. The directory should contain an app manifest and source file. The output of this command will be a gzip compressed tar file that can be uploaded to Tidbyt for deployment.`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { bundleInput := args[0] info, err := os.Stat(bundleInput) if err != nil { return fmt.Errorf("input directory invalid: %w", err) } if !info.IsDir() { return fmt.Errorf("input must be a directory") } info, err = os.Stat(bundleOutput) if err != nil { return fmt.Errorf("output directory invalid: %w", err) } if !info.IsDir() { return fmt.Errorf("output must be a directory") } ab, err := bundle.FromDir(bundleInput) if err != nil { return fmt.Errorf("could not init bundle: %w", err) } return ab.WriteBundleToPath(bundleOutput) }, }
View Source
var CreateCmd = &cobra.Command{ Use: "create", Short: "Creates a new app", Long: `This command will prompt for all of the information we need to generate a new Tidbyt app. No flags are necessary unless you are creating a private app, which is only available with our Tidbyt For Teams offering.`, RunE: func(cmd *cobra.Command, args []string) error { apiToken := config.OAuthTokenFromConfig(cmd.Context()) if apiToken == "" { return fmt.Errorf("login with `pixlet login` or use `pixlet set-auth` to configure auth") } app, err := community.ManifestPrompt() if err != nil { return fmt.Errorf("app creation, couldn't get user input: %w", err) } app.ID, err = createPrivateApp(apiToken, createOrg) if err != nil { if strings.Contains(err.Error(), "user is not authorized to create apps") { return fmt.Errorf("user is not authorized to create apps for organization %s, please reach out to your Tidbyt For Teams account representative to enable this feature for your account", createOrg) } return fmt.Errorf("remote app creation failed: %w", err) } g, err := generator.NewGenerator(generator.Local, createDir) if err != nil { return fmt.Errorf("app creation failed %w", err) } starlarkPath, err := g.GenerateApp(app) if err != nil { return fmt.Errorf("app creation failed: %w", err) } starlarkPathAbs, err := filepath.Abs(starlarkPath) if err != nil { return fmt.Errorf("app was created, but we don't know where: %w", err) } fmt.Println("") fmt.Println("App created at:") fmt.Printf("\t%s\n", starlarkPathAbs) fmt.Println("") fmt.Println("To start the app, run:") fmt.Printf("\tpixlet serve %s\n", starlarkPath) fmt.Println("") fmt.Println("For docs, head to:") fmt.Printf("\thttps://tidbyt.dev\n") fmt.Println("") fmt.Println("To upload and deploy your app:") if createDir == "." { fmt.Printf("\tpixlet private upload\n") } else { fmt.Printf("\tpixlet private upload --app-dir %s\n", createDir) } return nil }, }
CreateCmd prompts the user for info and generates a new app.
View Source
var DeleteCmd = &cobra.Command{ Use: "delete", Short: "Deletes a private app", Long: `Deletes a private app, and attempt to uninstall it from owner's devices.`, RunE: func(cmd *cobra.Command, args []string) error { apiToken := config.OAuthTokenFromConfig(cmd.Context()) if apiToken == "" { return fmt.Errorf("login with `pixlet login` or use `pixlet set-auth` to configure auth") } requestURL := fmt.Sprintf("%s/v0/apps/%s", deleteURL, deleteAppID) req, err := http.NewRequest("DELETE", requestURL, nil) if err != nil { return fmt.Errorf("could not create http request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) client := http.Client{ Timeout: 10 * time.Second, } resp, err := client.Do(req) if err != nil { return fmt.Errorf("could not make HTTP request to %s: %w", requestURL, err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("could not read response body: %w", err) } if resp.StatusCode != 200 { return fmt.Errorf("request returned status %d with message: %s", resp.StatusCode, body) } return nil }, }
View Source
var DeployCmd = &cobra.Command{ Use: "deploy", Short: "Deploys a private app version", Example: ` pixlet deploy --app <app-id> --version v0.0.1`, Long: `This command will deploy a private app to the Tidbyt backend.`, RunE: func(cmd *cobra.Command, args []string) error { apiToken := config.OAuthTokenFromConfig(cmd.Context()) if apiToken == "" { return fmt.Errorf("login with `pixlet login` or use `pixlet set-auth` to configure auth") } if deployAppID == "" { return fmt.Errorf("app must not be blank") } if deployVersion == "" { return fmt.Errorf("version must not be blank") } d := &TidbytAppDeploy{ AppID: deployAppID, Version: deployVersion, } b, err := json.Marshal(d) if err != nil { return fmt.Errorf("could not create http request: %w", err) } requestURL := fmt.Sprintf("%s/v0/apps/%s/deploy", deployURL, deployAppID) req, err := http.NewRequest(http.MethodPost, requestURL, bytes.NewBuffer(b)) if err != nil { return fmt.Errorf("could not create http request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) client := http.Client{ Timeout: 30 * time.Second, } resp, err := client.Do(req) if err != nil { return fmt.Errorf("could not make HTTP request to %s: %w", requestURL, err) } defer resp.Body.Close() if resp.StatusCode != 200 { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("request returned status %d with message: %s", resp.StatusCode, body) } return nil }, }
View Source
var ListCmd = &cobra.Command{ Use: "list", Short: "Lists private apps and versions", Long: `Lists private apps, or available versions of a single private app.`, RunE: func(cmd *cobra.Command, args []string) error { apiToken := config.OAuthTokenFromConfig(cmd.Context()) if apiToken == "" { return fmt.Errorf("login with `pixlet login` or use `pixlet set-auth` to configure auth") } appID := "" if len(args) > 0 { appID = args[0] } var requestURL string if appID != "" { requestURL = fmt.Sprintf("%s/v0/apps/%s/versions", listURL, appID) } else { requestURL = fmt.Sprintf("%s/v0/apps", listURL) } req, err := http.NewRequest("GET", requestURL, nil) if err != nil { return fmt.Errorf("could not create http request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) client := http.Client{ Timeout: 10 * time.Second, } resp, err := client.Do(req) if err != nil { return fmt.Errorf("could not make HTTP request to %s: %w", requestURL, err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if resp.StatusCode != 200 { return fmt.Errorf("request returned status %d with message: %s", resp.StatusCode, body) } if err != nil { return fmt.Errorf("could not read response body: %w", err) } if appID != "" { err = listVersions(body) if err != nil { return fmt.Errorf("could not list versions: %w", err) } } else { err = listApps(body) if err != nil { return fmt.Errorf("could not list apps: %w", err) } } return nil }, }
View Source
var LogsCmd = &cobra.Command{ Use: "logs", Short: "Logs for private app", Long: `Prints recent log lines for a private app`, RunE: func(cmd *cobra.Command, args []string) error { apiToken := config.OAuthTokenFromConfig(cmd.Context()) if apiToken == "" { return fmt.Errorf("login with `pixlet login` or use `pixlet set-auth` to configure auth") } if logsAppID == "" { return fmt.Errorf("must specify app ID") } requestURL := fmt.Sprintf("%s/v0/apps/%s/logs", logsURL, logsAppID) req, err := http.NewRequest("GET", requestURL, nil) if err != nil { return fmt.Errorf("could not create http request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) client := http.Client{ Timeout: 10 * time.Second, } resp, err := client.Do(req) if err != nil { return fmt.Errorf("could not make HTTP request to %s: %w", requestURL, err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if resp.StatusCode != 200 { return fmt.Errorf("request returned status %d with message: %s", resp.StatusCode, body) } if err != nil { return fmt.Errorf("could not read response body: %w", err) } var logs TidbytLogsResponse err = json.Unmarshal(body, &logs) if err != nil { return fmt.Errorf("could not parse response body: %w", err) } for _, line := range logs.Lines { fmt.Printf("%s %s\n", line.Timestamp, line.Message) } return nil }, }
View Source
var PrivateCmd = &cobra.Command{
Use: "private",
Short: "Utilities to manage private apps",
Long: `The private subcommand provides a set of utilities for managing
private apps. Requires Tidbyt Plus or Tidbyt for Teams.`,
}
View Source
var UploadCmd = &cobra.Command{ Use: "upload", Short: "Uploads an app to Tidbyt", Example: " pixlet private upload --app-dir app/startrek/ --version v0.0.1", Long: `This command uploads your private app. By default, the app is assumed to be in the current directory, is given timestamp as version, and is deployed. These defaults can be overridden with the --app-dir, --version, and --skip-deploy flags.`, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { if uploadVersion == "" { return fmt.Errorf("version must not be blank") } if uploadDir == "" { return fmt.Errorf("app-dir must not be blank") } info, err := os.Stat(uploadDir) if err != nil { return fmt.Errorf("bad app-dir: %w", err) } if !info.IsDir() { return fmt.Errorf("app-dir must be a directory") } buf := &bytes.Buffer{} ab, err := bundle.FromDir(uploadDir) if err != nil { return fmt.Errorf("could not init bundle: %w", err) } err = ab.WriteBundle(buf) if err != nil { return err } apiToken := config.OAuthTokenFromConfig(cmd.Context()) if apiToken == "" { return fmt.Errorf("login with `pixlet login` or use `pixlet set-auth` to configure auth") } uploadBundle := &TidbytBundleUpload{ AppID: ab.Manifest.ID, Version: uploadVersion, Bundle: base64.StdEncoding.EncodeToString(buf.Bytes()), } body, err := json.Marshal(uploadBundle) if err != nil { return fmt.Errorf("could not marshal request: %w", err) } requestURL := fmt.Sprintf("%s/v0/apps/%s/upload", uploadURL, ab.Manifest.ID) req, err := http.NewRequest(http.MethodPost, requestURL, bytes.NewReader(body)) if err != nil { return fmt.Errorf("could not create upload request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) client := http.Client{ Timeout: 30 * time.Second, } resp, err := client.Do(req) if err != nil { return fmt.Errorf("could not make HTTP request to %s: %w", requestURL, err) } defer resp.Body.Close() if resp.StatusCode != 200 { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("request returned status %d with message: %s", resp.StatusCode, body) } if uploadSkipDeploy { fmt.Printf("Uploaded version %s of app %s\n", uploadVersion, ab.Manifest.ID) return nil } d := &TidbytAppDeploy{ AppID: ab.Manifest.ID, Version: uploadVersion, } body, err = json.Marshal(d) if err != nil { return fmt.Errorf("could not create deploy request: %w", err) } requestURL = fmt.Sprintf("%s/v0/apps/%s/deploy", uploadURL, ab.Manifest.ID) req, err = http.NewRequest(http.MethodPost, requestURL, bytes.NewBuffer(body)) if err != nil { return fmt.Errorf("could not create http request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiToken)) resp, err = client.Do(req) if err != nil { return fmt.Errorf("could not make HTTP request to %s: %w", requestURL, err) } defer resp.Body.Close() if resp.StatusCode != 200 { body, _ := io.ReadAll(resp.Body) return fmt.Errorf("request returned status %d with message: %s", resp.StatusCode, body) } fmt.Printf("Uploaded and deployed version %s of app %s\n", uploadVersion, ab.Manifest.ID) return nil }, }
Functions ¶
This section is empty.
Types ¶
type TidbytAppDeploy ¶
type TidbytAppVersion ¶ added in v0.29.0
type TidbytBundleUpload ¶
type TidbytCreateAppReply ¶
type TidbytCreateAppReply struct {
AppID string `json:"appID"`
}
type TidbytCreateAppRequest ¶
type TidbytLogsResponse ¶ added in v0.29.1
Click to show internal directories.
Click to hide internal directories.