github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow@v0.28.1-0.20240311201729-34c6856b157f/pkg/command/run.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one
     3   * or more contributor license agreements.  See the NOTICE file
     4   * distributed with this work for additional information
     5   * regarding copyright ownership.  The ASF licenses this file
     6   * to you under the Apache License, Version 2.0 (the
     7   * "License"); you may not use this file except in compliance
     8   * with the License.  You may obtain a copy of the License at
     9   *
    10   *  http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing,
    13   * software distributed under the License is distributed on an
    14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   * KIND, either express or implied.  See the License for the
    16   * specific language governing permissions and limitations
    17   * under the License.
    18   */
    19  
    20  package command
    21  
    22  import (
    23  	"fmt"
    24  	"os"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/common"
    29  	"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/metadata"
    30  	"github.com/ory/viper"
    31  	"github.com/spf13/cobra"
    32  )
    33  
    34  type RunCmdConfig struct {
    35  	PortMapping string
    36  	OpenDevUI   bool
    37  }
    38  
    39  func NewRunCommand() *cobra.Command {
    40  	cmd := &cobra.Command{
    41  		Use:   "run",
    42  		Short: "Run a SonataFlow project in development mode",
    43  		Long: `
    44  	 Run a SonataFlow project in development mode.
    45  
    46  	 By default, it runs over ` + metadata.DevModeImage + ` on Docker.
    47  	 Alternatively, you can run the same image with Podman.
    48  		
    49  		 `,
    50  		Example: `
    51  	# Run the workflow inside the current local directory
    52  	{{.Name}} run
    53  
    54  	 # Run the current local directory mapping a different host port to the running container port.
    55  	{{.Name}} run --port 8081
    56  
    57   	# Disable automatic browser launch of SonataFlow  Dev UI 
    58  	{{.Name}} run --open-dev-ui=false
    59  		 `,
    60  		SuggestFor: []string{"rnu", "start"}, //nolint:misspell
    61  		PreRunE:    common.BindEnv("port", "open-dev-ui"),
    62  	}
    63  
    64  	cmd.RunE = func(cmd *cobra.Command, args []string) error {
    65  		return run()
    66  	}
    67  
    68  	cmd.Flags().StringP("port", "p", "8080", "Maps a different host port to the running container port.")
    69  	cmd.Flags().Bool("open-dev-ui", true, "Disable automatic browser launch of SonataFlow  Dev UI")
    70  	cmd.SetHelpFunc(common.DefaultTemplatedHelp)
    71  
    72  	return cmd
    73  }
    74  
    75  func run() error {
    76  	cfg, err := runDevCmdConfig()
    77  	if err != nil {
    78  		return fmt.Errorf("initializing create config: %w", err)
    79  	}
    80  
    81  	if common.IsSonataFlowProject() {
    82  		if err := runSWFProject(cfg); err != nil {
    83  			return err
    84  		}
    85  		return nil
    86  	} else if common.IsQuarkusSonataFlowProject() {
    87  		return fmt.Errorf("looks like you are inside a Quarkus project. If that is the case, you should run it with \"quarkus run\" command")
    88  	} else {
    89  		return fmt.Errorf("cannot find SonataFlow project")
    90  	}
    91  }
    92  
    93  func runDevCmdConfig() (cfg RunCmdConfig, err error) {
    94  	cfg = RunCmdConfig{
    95  		PortMapping: viper.GetString("port"),
    96  		OpenDevUI:   viper.GetBool("open-dev-ui"),
    97  	}
    98  	return
    99  }
   100  
   101  func runSWFProject(cfg RunCmdConfig) error {
   102  
   103  	if errPodman := common.CheckPodman(); errPodman == nil {
   104  		if err := runSWFProjectDevMode(common.Podman, cfg); err != nil {
   105  			return err
   106  		}
   107  	} else if errDocker := common.CheckDocker(); errDocker == nil {
   108  		if err := runSWFProjectDevMode(common.Docker, cfg); err != nil {
   109  			return err
   110  		}
   111  	} else {
   112  		return fmt.Errorf("there is no docker or podman available")
   113  	}
   114  	return nil
   115  }
   116  
   117  func runSWFProjectDevMode(containerTool string, cfg RunCmdConfig) (err error) {
   118  	fmt.Println("⏳ Starting your SonataFlow project in dev mode...")
   119  	path, err := os.Getwd()
   120  	if err != nil {
   121  		fmt.Errorf("❌ Error running SonataFlow project: %w", err)
   122  	}
   123  
   124  	common.GracefullyStopTheContainerWhenInterrupted(containerTool)
   125  
   126  	var wg sync.WaitGroup
   127  	wg.Add(1)
   128  
   129  	go func() {
   130  		defer wg.Done()
   131  		if err := common.RunContainerCommand(containerTool, cfg.PortMapping, path); err != nil {
   132  			fmt.Errorf("❌ Error running SonataFlow project: %w", err)
   133  		}
   134  	}()
   135  
   136  	readyCheckURL := fmt.Sprintf("http://localhost:%s/q/health/ready", cfg.PortMapping)
   137  	pollInterval := 5 * time.Second
   138  	common.ReadyCheck(readyCheckURL, pollInterval, cfg.PortMapping, cfg.OpenDevUI)
   139  
   140  	wg.Wait()
   141  	return err
   142  }