Skip to content

Commit

Permalink
kie-issues#1269: kn-plugin-workflow: Improve gen-manifests (apache#2373)
Browse files Browse the repository at this point in the history
  • Loading branch information
treblereel authored Jun 10, 2024
1 parent b2e668f commit 6e268a7
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 1 deletion.
128 changes: 128 additions & 0 deletions packages/kn-plugin-workflow/e2e-tests/gen_manifest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//go:build e2e_tests

/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package e2e_tests

import (
"fmt"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/command"
)

type GenManifestTestInputCreate struct {
args []string
checks []func(t *testing.T, content string)
}

var tests = []GenManifestTestInputCreate{
{args: []string{"gen-manifest", "--image", "my_image"},
checks: []func(t *testing.T, content string){
func(t *testing.T, content string) {
require.Contains(t, content, " image: my_image", "Expected image to be my_image")
},
},
},
{args: []string{"gen-manifest", "--profile", "gitops"},
checks: []func(t *testing.T, content string){
func(t *testing.T, content string) {
require.Contains(t, content, " sonataflow.org/profile: gitops", "Expected profile to be gitops")
},
},
},
{args: []string{"gen-manifest", "--profile", "dev"},
checks: []func(t *testing.T, content string){
func(t *testing.T, content string) {
require.Contains(t, content, " sonataflow.org/profile: dev", "Expected profile to be dev")
},
},
},
{args: []string{"gen-manifest", "--profile", "preview"},
checks: []func(t *testing.T, content string){
func(t *testing.T, content string) {
require.Contains(t, content, " sonataflow.org/profile: preview", "Expected profile to be preview")
},
},
},
{args: []string{"gen-manifest", "--namespace", "my_namespace", "--skip-namespace"},
checks: []func(t *testing.T, content string){
func(t *testing.T, content string) {
require.NotContains(t, content, " namespace: my_namespace", "Unexpected namespace: my_namespace")
},
},
},
{args: []string{"gen-manifest", "--skip-namespace"},
checks: []func(t *testing.T, content string){
func(t *testing.T, content string) {
require.NotContains(t, content, " namespace: default", "Unexpected namespace: default")
},
},
},
}

func TestGenManifestProjectSuccess(t *testing.T) {
var test = CfgTestInputCreate{
input: command.CreateCmdConfig{ProjectName: "new-project"},
}
t.Run(fmt.Sprintf("Test gen-manifest success"), func(t *testing.T) {
defer CleanUpAndChdirTemp(t)

RunCreateTest(t, test)

projectName := GetCreateProjectName(t, CfgTestInputCreate{
input: command.CreateCmdConfig{ProjectName: "new-project"},
})
projectDir := filepath.Join(TempTestsPath, projectName)
err := os.Chdir(projectDir)
require.NoErrorf(t, err, "Expected nil error, got %v", err)

for _, run := range tests {
_, err = ExecuteKnWorkflow(run.args...)
require.NoErrorf(t, err, "Expected nil error, got %v", err)
manifestDir := getGenManifestDir(projectDir, t)

yaml := readFileAsString(t, filepath.Join(manifestDir, "01-sonataflow_hello.yaml"))

for _, check := range run.checks {
check(t, yaml)
}
}
})
}

func getGenManifestDir(projectDir string, t *testing.T) string {
manifestDir := filepath.Join(projectDir, "manifests")
require.DirExistsf(t, manifestDir, "Expected project directory '%s' to be created", manifestDir)

expectedFiles := []string{"01-sonataflow_hello.yaml"}
VerifyFilesExist(t, manifestDir, expectedFiles)

return manifestDir
}

func readFileAsString(t *testing.T, path string) string {
content, err := os.ReadFile(path)
if err != nil {
t.Fatalf("Failed to read file %s", path)
}
return string(content)
}
2 changes: 1 addition & 1 deletion packages/kn-plugin-workflow/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ replace github.com/apache/incubator-kie-tools/packages/sonataflow-operator/api v
replace github.com/apache/incubator-kie-tools/packages/sonataflow-operator/workflowproj v0.0.0 => ./node_modules/@kie-tools/sonataflow-operator/workflowproj

require (
github.com/apache/incubator-kie-tools/packages/sonataflow-operator/api v0.0.0
github.com/apache/incubator-kie-tools/packages/sonataflow-operator/workflowproj v0.0.0
github.com/beevik/etree v1.2.0
github.com/docker/docker v24.0.9+incompatible
Expand All @@ -23,7 +24,6 @@ require (

require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/apache/incubator-kie-tools/packages/sonataflow-operator/api v0.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
Expand Down
11 changes: 11 additions & 0 deletions packages/kn-plugin-workflow/pkg/command/deploy_undeploy_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/common"
"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/metadata"
"github.com/apache/incubator-kie-tools/packages/sonataflow-operator/workflowproj"
apimetadata "github.com/apache/incubator-kie-tools/packages/sonataflow-operator/api/metadata"
)

type DeployUndeployCmdConfig struct {
Expand All @@ -42,6 +43,8 @@ type DeployUndeployCmdConfig struct {
SchemasDir string
CustomManifestsFileDir string
DefaultDashboardsFolder string
Profile string
Image string
SchemasFilesPath []string
SpecsFilesPath []string
SubFlowsFilesPath []string
Expand Down Expand Up @@ -203,11 +206,19 @@ func generateManifests(cfg *DeployUndeployCmdConfig) error {
handler.AddResourceAt(filepath.Base(dashboardFile), metadata.DashboardsDefaultDirName, specIO)
}

if len(cfg.Profile) > 0 {
handler.Profile(apimetadata.ProfileType(cfg.Profile))
}

_, err = handler.AsObjects()
if err != nil {
return err
}

if cfg.Image != "" {
handler.Image(cfg.Image)
}

err = handler.SaveAsKubernetesManifests(cfg.CustomGeneratedManifestDir)
if err != nil {
return err
Expand Down
56 changes: 56 additions & 0 deletions packages/kn-plugin-workflow/pkg/command/gen_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/common"
"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/metadata"
apiMetadata "github.com/apache/incubator-kie-tools/packages/sonataflow-operator/api/metadata"
"github.com/ory/viper"
"github.com/spf13/cobra"
)
Expand All @@ -46,6 +48,9 @@ func NewGenManifest() *cobra.Command {
# Specify a custom target namespace. (default: kubeclt current namespace; --namespace "" to don't set namespace on your manifest)
{{.Name}} deploy --namespace <your_namespace>
# Skip namespace creation
{{.Name}} gen-manifest --skip-namespace
# Persist the generated Operator manifests on a specific custom path
{{.Name}} gen-manifest --custom-generated-manifest-dir=<full_directory_path>
Expand All @@ -58,6 +63,12 @@ func NewGenManifest() *cobra.Command {
# Specify a custom support schemas directory. (default: ./schemas)
{{.Name}} gen-manifest --schemas-dir=<full_directory_path>
# Specify a profile to use for the deployment. (default: dev)
{{.Name}} gen-manifest --profile=<profile_name>
# Specify a custom image to use for the deployment.
{{.Name}} gen-manifest --image=<image_name>
`,
PreRunE: common.BindEnv("namespace", "custom-generated-manifests-dir", "specs-dir", "schemas-dir", "subflows-dir"),
SuggestFor: []string{"gen-manifests", "generate-manifest"}, //nolint:misspell
Expand All @@ -68,10 +79,13 @@ func NewGenManifest() *cobra.Command {
}

cmd.Flags().StringP("namespace", "n", "", "Target namespace of your deployment. (default: kubeclt current namespace; \"\" to don't set namespace on your manifest)")
cmd.Flags().BoolP("skip-namespace", "k", false, "Skip namespace creation")
cmd.Flags().StringP("custom-generated-manifests-dir", "c", "", "Target directory of your generated Operator manifests.")
cmd.Flags().StringP("specs-dir", "p", "", "Specify a custom specs files directory")
cmd.Flags().StringP("subflows-dir", "s", "", "Specify a custom subflows files directory")
cmd.Flags().StringP("schemas-dir", "t", "", "Specify a custom schemas files directory")
cmd.Flags().StringP("profile", "f", "dev", "Specify a profile to use for the deployment")
cmd.Flags().StringP("image", "i", "", "Specify a custom image to use for the deployment")

cmd.SetHelpFunc(common.DefaultTemplatedHelp)

Expand Down Expand Up @@ -109,6 +123,8 @@ func runGenManifestCmdConfig(cmd *cobra.Command) (cfg DeployUndeployCmdConfig, e
SchemasDir: viper.GetString("schemas-dir"),
SubflowsDir: viper.GetString("subflows-dir"),
CustomGeneratedManifestDir: viper.GetString("custom-generated-manifests-dir"),
Profile: viper.GetString("profile"),
Image: viper.GetString("image"),
}

if cmd.Flags().Changed("namespace") && len(cfg.NameSpace) == 0 {
Expand All @@ -117,6 +133,26 @@ func runGenManifestCmdConfig(cmd *cobra.Command) (cfg DeployUndeployCmdConfig, e
cfg.EmptyNameSpace = true
}

if skipNamespace, _ := cmd.Flags().GetBool("skip-namespace"); skipNamespace {
cfg.NameSpace = ""
cfg.EmptyNameSpace = true
}

if cmd.Flags().Changed("profile") && len(cfg.Profile) == 0 {
profile, _ := cmd.Flags().GetString("profile")
if err := isValidProfile(profile); err != nil{
return cfg, err
}
cfg.Profile = profile
}

if cmd.Flags().Changed("image") {
image, _ := cmd.Flags().GetString("image")
if image != "" {
cfg.Image = image
}
}

if len(cfg.SubflowsDir) == 0 {
dir, err := os.Getwd()
cfg.SubflowsDir = dir + "/subflows"
Expand Down Expand Up @@ -197,3 +233,23 @@ func resolveManifestDir(folderName string) (string, error) {

return absPath, nil
}

func isValidProfile(profile string) error {
var allProfiles = []apiMetadata.ProfileType{
apiMetadata.DevProfile,
apiMetadata.ProdProfile,
apiMetadata.PreviewProfile,
apiMetadata.GitOpsProfile,
}

for _, t := range allProfiles {
if t.String() == profile {
return nil
}
}
keys := make([]string, 0, len(allProfiles))
for k := range allProfiles {
keys = append(keys, allProfiles[k].String())
}
return fmt.Errorf("❌ ERROR: invalid profile: %s, valid profiles are: %s", profile, strings.Join(keys, ","))
}
7 changes: 7 additions & 0 deletions packages/sonataflow-operator/workflowproj/workflowproj.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ type WorkflowProjectHandler interface {
SaveAsKubernetesManifests(path string) error
// AsObjects returns a reference to the WorkflowProject holding the Kubernetes Manifests based on your files.
AsObjects() (*WorkflowProject, error)
// Image overrides the default image in the generated SonataFlow manifest
Image(image string) WorkflowProjectHandler
}

// WorkflowProject is a structure to hold every Kubernetes object generated by the given WorkflowProjectHandler handler.
Expand Down Expand Up @@ -302,6 +304,11 @@ func (w *workflowProjectHandler) addResourceConfigMapToProject(cm *corev1.Config
return nil
}

func (w *workflowProjectHandler) Image(image string) WorkflowProjectHandler {
w.project.Workflow.Spec.PodTemplate.Container.Image = image
return w
}

// IsDevProfile detects if the workflow is using the Dev profile or not
func IsDevProfile(workflow *operatorapi.SonataFlow) bool {
profile := workflow.Annotations[metadata.Profile]
Expand Down

0 comments on commit 6e268a7

Please sign in to comment.