From 2a315311667a4d81b5eab3bb527ee8d219bb4cb4 Mon Sep 17 00:00:00 2001 From: Graham Dumpleton Date: Fri, 4 Aug 2023 11:39:59 +1000 Subject: [PATCH] Add ability to describe how workshop image is published. --- .../11-session-manager/01-crds-workshop.yaml | 13 +++ .../pkg/cmd/workshop_publish_cmd.go | 99 +++++++++++++------ 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/carvel-packages/training-platform/bundle/config/11-session-manager/01-crds-workshop.yaml b/carvel-packages/training-platform/bundle/config/11-session-manager/01-crds-workshop.yaml index c3215a4d..7e24a4da 100644 --- a/carvel-packages/training-platform/bundle/config/11-session-manager/01-crds-workshop.yaml +++ b/carvel-packages/training-platform/bundle/config/11-session-manager/01-crds-workshop.yaml @@ -60,6 +60,19 @@ spec: type: string files: type: string + publish: + type: object + properties: + image: + type: string + includePaths: + type: array + items: + type: string + excludePaths: + type: array + items: + type: string workshop: type: object properties: diff --git a/client-programs/pkg/cmd/workshop_publish_cmd.go b/client-programs/pkg/cmd/workshop_publish_cmd.go index ca942894..b9a098e1 100644 --- a/client-programs/pkg/cmd/workshop_publish_cmd.go +++ b/client-programs/pkg/cmd/workshop_publish_cmd.go @@ -87,41 +87,84 @@ func publishWorkshopDirectory(directory string, image string, repository string) rootDirectory := directory - if image == "" { - workshopFilePath := filepath.Join(directory, "resources", "workshop.yaml") + includePaths := []string{directory} + excludePaths := []string{".git"} - workshopFileData, err := os.ReadFile(workshopFilePath) + workshopFilePath := filepath.Join(directory, "resources", "workshop.yaml") - if err != nil { - return errors.Wrapf(err, "cannot open workshop definition %q", workshopFilePath) - } + workshopFileData, err := os.ReadFile(workshopFilePath) - decoder := serializer.NewCodecFactory(scheme.Scheme).UniversalDecoder() + if err != nil { + return errors.Wrapf(err, "cannot open workshop definition %q", workshopFilePath) + } - workshop := &unstructured.Unstructured{} + decoder := serializer.NewCodecFactory(scheme.Scheme).UniversalDecoder() - err = runtime.DecodeInto(decoder, workshopFileData, workshop) + workshop := &unstructured.Unstructured{} - if err != nil { - return errors.Wrap(err, "couldn't parse workshop definition") - } + err = runtime.DecodeInto(decoder, workshopFileData, workshop) - fileArtifacts, found, err := unstructured.NestedSlice(workshop.Object, "spec", "workshop", "files") + if err != nil { + return errors.Wrap(err, "couldn't parse workshop definition") + } + + if image == "" { + image, _, _ = unstructured.NestedString(workshop.Object, "spec", "publish", "image") + image = strings.ReplaceAll(image, "$(image_repository)", repository) + } - if err != nil || !found { - return errors.Errorf("cannot find image specification in %q", workshopFilePath) + if paths, found, _ := unstructured.NestedStringSlice(workshop.Object, "spec", "publish", "includePaths"); found && len(paths) != 0 { + includePaths = make([]string, 0, len(paths)) + for _, filePath := range paths { + fullPath := filepath.Clean(filepath.Join(directory, filePath)) + includePaths = append(includePaths, fullPath) } + } + + if paths, found, _ := unstructured.NestedStringSlice(workshop.Object, "spec", "publish", "excludePaths"); found { + excludePaths = paths + } - for _, artifactEntry := range fileArtifacts { - if imageDetails, ok := artifactEntry.(map[string]interface{})["image"]; ok { - if unpackPath, ok := artifactEntry.(map[string]interface{})["path"]; !ok || (ok && (unpackPath == nil || unpackPath.(string) == "" || unpackPath.(string) == ".")) { - if imageUrl, ok := imageDetails.(map[string]interface{})["url"]; ok { - image = strings.ReplaceAll(imageUrl.(string), "$(image_repository)", repository) + if image == "" { + fileArtifacts, found, _ := unstructured.NestedSlice(workshop.Object, "spec", "workshop", "files") + + if found { + for _, artifactEntry := range fileArtifacts { + if imageDetails, ok := artifactEntry.(map[string]interface{})["image"]; ok { + if unpackPath, ok := artifactEntry.(map[string]interface{})["path"]; !ok || (ok && (unpackPath == nil || unpackPath.(string) == "" || unpackPath.(string) == ".")) { + if imageUrl, ok := imageDetails.(map[string]interface{})["url"]; ok { + image = strings.ReplaceAll(imageUrl.(string), "$(image_repository)", repository) + + if newRootPath, ok := artifactEntry.(map[string]interface{})["newRootPath"]; ok { + suffix := "/" + newRootPath.(string) + if strings.HasSuffix(directory, suffix) { + rootDirectory = strings.TrimSuffix(directory, suffix) + includePaths = []string{rootDirectory} + } + } + } + } + } + } + } - if newRootPath, ok := artifactEntry.(map[string]interface{})["newRootPath"]; ok { - suffix := "/" + newRootPath.(string) - if strings.HasSuffix(directory, suffix) { - rootDirectory = strings.TrimSuffix(directory, suffix) + if image == "" { + fileArtifacts, found, _ := unstructured.NestedSlice(workshop.Object, "spec", "environment", "assets", "files") + + if found { + for _, artifactEntry := range fileArtifacts { + if imageDetails, ok := artifactEntry.(map[string]interface{})["image"]; ok { + if unpackPath, ok := artifactEntry.(map[string]interface{})["path"]; !ok || (ok && (unpackPath == nil || unpackPath.(string) == "" || unpackPath.(string) == ".")) { + if imageUrl, ok := imageDetails.(map[string]interface{})["url"]; ok { + image = strings.ReplaceAll(imageUrl.(string), "$(image_repository)", repository) + + if newRootPath, ok := artifactEntry.(map[string]interface{})["newRootPath"]; ok { + suffix := "/" + newRootPath.(string) + if strings.HasSuffix(directory, suffix) { + rootDirectory = strings.TrimSuffix(directory, suffix) + includePaths = []string{rootDirectory} + } + } } } } @@ -131,7 +174,7 @@ func publishWorkshopDirectory(directory string, image string, repository string) } if image == "" { - return errors.New("cannot determine name of image to publish as") + return errors.Errorf("cannot find image specification in %q", workshopFilePath) } // Now publish workshop directory contents as OCI image artifact. @@ -151,10 +194,10 @@ func publishWorkshopDirectory(directory string, image string, repository string) var pushOptions = imgpkgcmd.NewPushOptions(confUI) pushOptions.ImageFlags.Image = image - pushOptions.FileFlags.Files = append(pushOptions.FileFlags.Files, rootDirectory) - pushOptions.FileFlags.ExcludedFilePaths = append(pushOptions.FileFlags.ExcludedFilePaths, ".git") + pushOptions.FileFlags.Files = append(pushOptions.FileFlags.Files, includePaths...) + pushOptions.FileFlags.ExcludedFilePaths = append(pushOptions.FileFlags.ExcludedFilePaths, excludePaths...) - err := pushOptions.Run() + err = pushOptions.Run() if err != nil { return errors.Wrap(err, "unable to push image artifact for workshop")