Path: blob/main/components/local-app/cmd/workspace-create.go
2497 views
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package cmd56import (7"fmt"8"log/slog"9"strings"1011"github.com/bufbuild/connect-go"12v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1"13"github.com/gitpod-io/local-app/pkg/config"14"github.com/gitpod-io/local-app/pkg/helper"15"github.com/gitpod-io/local-app/pkg/prettyprint"16"github.com/spf13/cobra"17)1819// workspaceCreateCmd creates a new workspace20var workspaceCreateCmd = &cobra.Command{21Use: "create <repo-url>",22Short: "Creates a new workspace based on a given context",23Args: cobra.ExactArgs(1),24RunE: func(cmd *cobra.Command, args []string) error {25cmd.SilenceUsage = true26repoURL := args[0]2728cfg := config.FromContext(cmd.Context())29gpctx, err := cfg.GetActiveContext()30if err != nil {31return err32}33gitpod, err := getGitpodClient(cmd.Context())34if err != nil {35return err36}3738if workspaceCreateOpts.WorkspaceClass != "" {39resp, err := gitpod.Workspaces.ListWorkspaceClasses(cmd.Context(), connect.NewRequest(&v1.ListWorkspaceClassesRequest{}))40if err != nil {41return prettyprint.MarkExceptional(prettyprint.AddResolution(fmt.Errorf("cannot list workspace classes: %w", err),42"don't pass an explicit workspace class, i.e. omit the --class flag",43))44}45var (46classes []string47found bool48)49for _, cls := range resp.Msg.GetResult() {50classes = append(classes, cls.Id)51if cls.Id == workspaceCreateOpts.WorkspaceClass {52found = true53}54}55if !found {56return prettyprint.AddResolution(fmt.Errorf("workspace class %s not found", workspaceCreateOpts.WorkspaceClass),57fmt.Sprintf("use one of the available workspace classes: %s", strings.Join(classes, ", ")),58)59}60}6162if workspaceCreateOpts.Editor != "" {63resp, err := gitpod.Editors.ListEditorOptions(cmd.Context(), connect.NewRequest(&v1.ListEditorOptionsRequest{}))64if err != nil {65return prettyprint.MarkExceptional(prettyprint.AddResolution(fmt.Errorf("cannot list editor options: %w", err),66"don't pass an explicit editor, i.e. omit the --editor flag",67))68}69var (70editors []string71found bool72)73for _, editor := range resp.Msg.GetResult() {74editors = append(editors, editor.Id)75if editor.Id == workspaceCreateOpts.Editor {76found = true77}78}79if !found {80return prettyprint.AddResolution(fmt.Errorf("editor %s not found", workspaceCreateOpts.Editor),81fmt.Sprintf("use one of the available editor options: %s", strings.Join(editors, ", ")),82)83}84}8586var (87orgId = gpctx.OrganizationID88ctx = cmd.Context()89)9091slog.Debug("Attempting to create workspace...", "org", orgId, "repo", repoURL)92newWorkspace, err := gitpod.Workspaces.CreateAndStartWorkspace(ctx, connect.NewRequest(93&v1.CreateAndStartWorkspaceRequest{94Source: &v1.CreateAndStartWorkspaceRequest_ContextUrl{ContextUrl: repoURL},95OrganizationId: orgId,96StartSpec: &v1.StartWorkspaceSpec{97IdeSettings: &v1.IDESettings{98DefaultIde: workspaceCreateOpts.Editor,99UseLatestVersion: false,100},101WorkspaceClass: workspaceCreateOpts.WorkspaceClass,102},103// Without this flag we might not create a new workspace because there's already one running on the same commit.104IgnoreRunningWorkspaceOnSameCommit: true,105// Note(cw): the CLI cannot handle running prebuilds yet, so we ignore them for now.106IgnoreRunningPrebuild: true,107AllowUsingPreviousPrebuilds: true,108},109))110if err != nil {111return err112}113114workspaceID := newWorkspace.Msg.WorkspaceId115if len(workspaceID) == 0 {116return prettyprint.MarkExceptional(prettyprint.AddResolution(fmt.Errorf("workspace was not created"),117"try to create the workspace again",118))119}120121if workspaceCreateOpts.StartOpts.DontWait {122// There is no more information to print other than the workspace ID. No need to faff with tabular pretty printing.123fmt.Println(workspaceID)124return nil125}126127_, err = helper.ObserveWorkspaceUntilStarted(ctx, gitpod, workspaceID)128if err != nil {129return err130}131132if workspaceCreateOpts.StartOpts.OpenSSH {133return helper.SSHConnectToWorkspace(ctx, gitpod, workspaceID, false)134}135if workspaceCreateOpts.StartOpts.OpenEditor {136return helper.OpenWorkspaceInPreferredEditor(ctx, gitpod, workspaceID)137}138139return nil140},141}142143var workspaceCreateOpts struct {144StartOpts workspaceStartOptions145146WorkspaceClass string147Editor string148}149150func classCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {151ctx := cmd.Context()152gitpod, err := getGitpodClient(ctx)153if err != nil {154return nil, cobra.ShellCompDirectiveError155}156resp, err := gitpod.Workspaces.ListWorkspaceClasses(ctx, connect.NewRequest(&v1.ListWorkspaceClassesRequest{}))157if err != nil {158return nil, cobra.ShellCompDirectiveError159}160items := resp.Msg.GetResult()161completionStr := []string{}162for _, cls := range items {163defaultDesc := ""164if cls.IsDefault {165defaultDesc = "(default)"166}167completionStr = append(completionStr, fmt.Sprintf("%s\t%s%s - %s", cls.Id, cls.DisplayName, defaultDesc, cls.Description))168}169return completionStr, cobra.ShellCompDirectiveNoFileComp170}171172func editorCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {173ctx := cmd.Context()174gitpod, err := getGitpodClient(ctx)175if err != nil {176return nil, cobra.ShellCompDirectiveError177}178resp, err := gitpod.Editors.ListEditorOptions(ctx, connect.NewRequest(&v1.ListEditorOptionsRequest{}))179if err != nil {180return nil, cobra.ShellCompDirectiveError181}182items := resp.Msg.GetResult()183completionStr := []string{}184for _, editor := range items {185completionStr = append(completionStr, fmt.Sprintf("%s\t%s", editor.Id, editor.Title))186}187return completionStr, cobra.ShellCompDirectiveNoFileComp188}189190func init() {191workspaceCmd.AddCommand(workspaceCreateCmd)192addWorkspaceStartOptions(workspaceCreateCmd, &workspaceCreateOpts.StartOpts)193194workspaceCreateCmd.Flags().StringVar(&workspaceCreateOpts.WorkspaceClass, "class", "", "the workspace class")195workspaceCreateCmd.Flags().StringVar(&workspaceCreateOpts.Editor, "editor", "code", "the editor to use")196197_ = workspaceCreateCmd.RegisterFlagCompletionFunc("class", classCompletionFunc)198_ = workspaceCreateCmd.RegisterFlagCompletionFunc("editor", editorCompletionFunc)199}200201202