github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/initializer/prompt/prompt.go (about)

     1  /*
     2  Copyright 2020 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package prompt
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/AlecAivazis/survey/v2"
    27  
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/util"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    30  )
    31  
    32  // For testing
    33  var (
    34  	BuildConfigFunc         = buildConfig
    35  	ChooseBuildersFunc      = chooseBuilders
    36  	PortForwardResourceFunc = portForwardResource
    37  	askOne                  = survey.AskOne
    38  	ask                     = survey.Ask
    39  )
    40  
    41  func buildConfig(image string, choices []string) (string, error) {
    42  	var selectedBuildConfig string
    43  	prompt := &survey.Select{
    44  		Message:  fmt.Sprintf("Choose the builder to build image %s", image),
    45  		Options:  choices,
    46  		PageSize: 15,
    47  	}
    48  	err := survey.AskOne(prompt, &selectedBuildConfig, nil)
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  
    53  	return selectedBuildConfig, nil
    54  }
    55  
    56  func WriteSkaffoldConfig(out io.Writer, pipeline []byte, generatedManifests map[string][]byte, filePath string) (bool, error) {
    57  	fmt.Fprintln(out, string(pipeline))
    58  
    59  	for path, manifest := range generatedManifests {
    60  		fmt.Fprintln(out, path, "-", string(manifest))
    61  	}
    62  
    63  	manifestString := ""
    64  	if len(generatedManifests) > 0 {
    65  		manifestString = ", along with the generated k8s manifests,"
    66  	}
    67  
    68  	var response bool
    69  	prompt := &survey.Confirm{
    70  		Message: fmt.Sprintf("Do you want to write this configuration%s to %s?", manifestString, filePath),
    71  	}
    72  	err := askOne(prompt, &response, nil)
    73  	if err != nil {
    74  		return true, fmt.Errorf("reading user confirmation: %w", err)
    75  	}
    76  
    77  	return !response, nil
    78  }
    79  
    80  // chooseBuilders prompts the user to select which builders they'd like to create associated kubernetes manifests for
    81  func chooseBuilders(builders []string) ([]string, error) {
    82  	chosen := []string{}
    83  	prompt := &survey.MultiSelect{
    84  		Message: "Which builders would you like to create kubernetes resources for?",
    85  		Options: builders,
    86  	}
    87  	err := askOne(prompt, &chosen)
    88  	if err != nil {
    89  		return []string{}, fmt.Errorf("getting user choices")
    90  	}
    91  
    92  	return chosen, err
    93  }
    94  
    95  // PortForwardResource prompts the user to give a port to forward the current resource on
    96  func portForwardResource(out io.Writer, imageName string) (int, error) {
    97  	var response string
    98  	prompt := &survey.Question{
    99  		Prompt: &survey.Input{Message: fmt.Sprintf("Select port to forward for %s (leave blank for none):", imageName)},
   100  		Validate: func(val interface{}) error {
   101  			str := val.(string)
   102  			if _, err := strconv.Atoi(str); err != nil && str != "" {
   103  				return errors.New("response must be a number, or empty")
   104  			}
   105  			return nil
   106  		},
   107  	}
   108  	err := ask([]*survey.Question{prompt}, &response)
   109  	if err != nil {
   110  		return 0, fmt.Errorf("reading user input: %w", err)
   111  	}
   112  
   113  	response = strings.ToLower(strings.TrimSpace(response))
   114  	if response == "" {
   115  		return 0, nil
   116  	}
   117  
   118  	responseInt, _ := strconv.Atoi(response)
   119  	return responseInt, nil
   120  }
   121  
   122  // ConfirmInitOptions prompts the user to confirm that they are okay with what skaffold will do if they
   123  // run with the current config
   124  func ConfirmInitOptions(out io.Writer, config *latest.SkaffoldConfig) (bool, error) {
   125  	builders := strings.Join(util.ListBuilders(&config.Build), ",")
   126  	deployers := strings.Join(util.ListDeployers(&config.Deploy), ",")
   127  
   128  	fmt.Fprintf(out, `If you choose to continue, skaffold will do the following:
   129    - Create a skaffold config file for you
   130    - Build your application using %s
   131    - Deploy your application to your current kubernetes context using %s
   132  
   133  `, builders, deployers)
   134  
   135  	var response bool
   136  	prompt := &survey.Confirm{
   137  		Message: "Would you like to continue?",
   138  	}
   139  	err := askOne(prompt, &response, nil)
   140  	if err != nil {
   141  		return true, err
   142  	}
   143  
   144  	// invert response because "no" == done and "yes" == !done
   145  	return !response, nil
   146  }