From 5c4c5a4fdeb5aeed56b00bf22bb0269133d056f9 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Fri, 16 Aug 2024 17:57:36 +0300 Subject: [PATCH 01/19] POC of fetching the node versions from images.json --- extension.toml | 23 ------------ generate.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/extension.toml b/extension.toml index 7b23cdc..659b1a5 100644 --- a/extension.toml +++ b/extension.toml @@ -9,26 +9,3 @@ description = "This extension installs the appropriate Node.js runtime via dnf" [metadata] pre-package = "./scripts/build.sh" include-files = ["bin/generate", "bin/detect", "bin/run", "extension.toml"] - [metadata.default-versions] - node = "20.*.*" - - [[metadata.dependencies]] - id = "node" - name = "Ubi Node Extension" - stacks = ["io.buildpacks.stacks.ubi8"] - source = "paketocommunity/run-nodejs-20-ubi-base" - version = "20.1000" - - [[metadata.dependencies]] - id = "node" - name = "Ubi Node Extension" - stacks = ["io.buildpacks.stacks.ubi8"] - source = "paketocommunity/run-nodejs-18-ubi-base" - version = "18.1000" - - [[metadata.dependencies]] - id = "node" - name = "Ubi Node Extension" - stacks = ["io.buildpacks.stacks.ubi8"] - source = "paketocommunity/run-nodejs-16-ubi-base" - version = "16.1000" diff --git a/generate.go b/generate.go index f9d66b6..2002bbb 100644 --- a/generate.go +++ b/generate.go @@ -3,6 +3,9 @@ package ubinodejsextension import ( "bytes" _ "embed" + "encoding/json" + "fmt" + "log" "os" "path/filepath" "regexp" @@ -10,6 +13,7 @@ import ( "strings" "text/template" + "github.com/BurntSushi/toml" "github.com/Masterminds/semver/v3" "github.com/paketo-buildpacks/libnodejs" "github.com/paketo-buildpacks/packit/v2" @@ -18,10 +22,34 @@ import ( "github.com/paketo-buildpacks/packit/v2/scribe" ) -var PACKAGES = "make gcc gcc-c++ libatomic_ops git openssl-devel nodejs npm nodejs-nodemon nss_wrapper which python3" +const PACKAGES = "make gcc gcc-c++ libatomic_ops git openssl-devel nodejs npm nodejs-nodemon nss_wrapper which python3" + +const DEFAULT_USER_ID = 1002 +const DEFAULT_GROUP_ID = 1000 + +// TODO +// Same struct as in images.json is on the stacks +// Also we dont need all these fields, remove the unused ones. +type StackImages struct { + Name string `json:"name"` + ConfigDir string `json:"config_dir"` + OutputDir string `json:"output_dir"` + BuildImage string `json:"build_image"` + RunImage string `json:"run_image"` + BuildReceiptFilename string `json:"build_receipt_filename"` + RunReceiptFilename string `json:"run_receipt_filename"` + CreateBuildImage bool `json:"create_build_image,omitempty"` + BaseBuildContainerImage string `json:"base_build_container_image,omitempty"` + BaseRunContainerImage string `json:"base_run_container_image"` + Type string `json:"type,omitempty"` +} -var DEFAULT_USER_ID = 1002 -var DEFAULT_GROUP_ID = 1000 +type ImagesJson struct { + SupportUsns bool `json:"support_usns"` + UpdateOnNewImage bool `json:"update_on_new_image"` + ReceiptsShowLimit int `json:"receipts_show_limit"` + StackImages []StackImages `json:"images"` +} type DuringBuildPermissions struct { CNB_USER_ID, CNB_GROUP_ID int @@ -65,10 +93,64 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Candidates(allNodeVersionsInPriorityOrder) - // Search and fetch the version from the extension.toml + imagesJsonPath, err := os.Open("/etc/buildpacks/images.json") + if err != nil { + return packit.GenerateResult{}, err + } + + var imagesJson ImagesJson + json.NewDecoder(imagesJsonPath).Decode(&imagesJson) + err = imagesJsonPath.Close() + if err != nil { + return packit.GenerateResult{}, err + } + nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) - extensionFilePath := filepath.Join(context.CNBPath, "extension.toml") - dependency, err := dependencyManager.Resolve(extensionFilePath, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) + + nodejsRegex, _ := regexp.Compile("^nodejs") + + var dependencies []map[string]interface{} + + for _, stack := range imagesJson.StackImages { + if !nodejsRegex.MatchString(stack.Name) { + continue + } + + //TODO fetch the stacks from the images.json + nodeVersion := strings.Split(stack.Name, "-")[1] + dependency := map[string]interface{}{ + "id": "node", + "stacks": []string{"io.buildpacks.stacks.ubi8"}, + "version": fmt.Sprintf("%s.1000", nodeVersion), + "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", nodeVersion), + } + dependencies = append(dependencies, dependency) + + } + + config := map[string]interface{}{ + "metadata": map[string]interface{}{ + "default-versions": map[string]string{ + "node": "20.*.*", + }, + "dependencies": dependencies, + }, + } + + buf := new(bytes.Buffer) + if err := toml.NewEncoder(buf).Encode(config); err != nil { + log.Fatal(err) + } + fmt.Println(buf.String()) + + err = os.WriteFile("./config.toml", buf.Bytes(), 0744) + if err != nil { + return packit.GenerateResult{}, err + } + + // Search and fetch the version from the config.toml + configFilePath := filepath.Join("./config.toml") + dependency, err := dependencyManager.Resolve(configFilePath, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) if err != nil { return packit.GenerateResult{}, err } From 082b4c6a4c38e45d2eee20bc36d2910c59d45a8c Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Tue, 3 Sep 2024 19:01:33 +0300 Subject: [PATCH 02/19] finalizing the implementation --- generate.go | 81 +++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/generate.go b/generate.go index 2002bbb..e9bec89 100644 --- a/generate.go +++ b/generate.go @@ -23,32 +23,19 @@ import ( ) const PACKAGES = "make gcc gcc-c++ libatomic_ops git openssl-devel nodejs npm nodejs-nodemon nss_wrapper which python3" - +const IMAGES_JSON_PATH = "/etc/buildpacks/images.json" const DEFAULT_USER_ID = 1002 const DEFAULT_GROUP_ID = 1000 -// TODO -// Same struct as in images.json is on the stacks -// Also we dont need all these fields, remove the unused ones. type StackImages struct { - Name string `json:"name"` - ConfigDir string `json:"config_dir"` - OutputDir string `json:"output_dir"` - BuildImage string `json:"build_image"` - RunImage string `json:"run_image"` - BuildReceiptFilename string `json:"build_receipt_filename"` - RunReceiptFilename string `json:"run_receipt_filename"` - CreateBuildImage bool `json:"create_build_image,omitempty"` - BaseBuildContainerImage string `json:"base_build_container_image,omitempty"` - BaseRunContainerImage string `json:"base_run_container_image"` - Type string `json:"type,omitempty"` + Name string `json:"name"` + Type string `json:"type,omitempty"` + IsDefaultRunImage bool `json:"is_default_run_image,omitempty"` + nodeVersion string } type ImagesJson struct { - SupportUsns bool `json:"support_usns"` - UpdateOnNewImage bool `json:"update_on_new_image"` - ReceiptsShowLimit int `json:"receipts_show_limit"` - StackImages []StackImages `json:"images"` + StackImages []StackImages `json:"images"` } type DuringBuildPermissions struct { @@ -93,7 +80,7 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Candidates(allNodeVersionsInPriorityOrder) - imagesJsonPath, err := os.Open("/etc/buildpacks/images.json") + imagesJsonPath, err := os.Open(IMAGES_JSON_PATH) if err != nil { return packit.GenerateResult{}, err } @@ -105,38 +92,52 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during return packit.GenerateResult{}, err } - nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) - + // Filter out the nodejs stacks based on the stack name nodejsRegex, _ := regexp.Compile("^nodejs") - var dependencies []map[string]interface{} - + nodejsStacks := []StackImages{} for _, stack := range imagesJson.StackImages { - if !nodejsRegex.MatchString(stack.Name) { - continue + + if nodejsRegex.MatchString(stack.Name) { + //Get the node version from the stack name + stack.nodeVersion = strings.Split(stack.Name, "-")[1] + + if stack.nodeVersion == "" { + return packit.GenerateResult{}, packit.Fail.WithMessage("Node.js version for stack %s not found", stack.Name) + } + + nodejsStacks = append(nodejsStacks, stack) } + } + + var dependencies []map[string]interface{} - //TODO fetch the stacks from the images.json - nodeVersion := strings.Split(stack.Name, "-")[1] + for _, stack := range nodejsStacks { dependency := map[string]interface{}{ "id": "node", - "stacks": []string{"io.buildpacks.stacks.ubi8"}, - "version": fmt.Sprintf("%s.1000", nodeVersion), - "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", nodeVersion), + "stacks": []string{context.Stack}, + "version": fmt.Sprintf("%s.1000", stack.nodeVersion), + "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", stack.nodeVersion), } dependencies = append(dependencies, dependency) + } + + defaultNodeVersion := getDefaultNodeVersion(imagesJson) + if defaultNodeVersion == "" { + return packit.GenerateResult{}, packit.Fail.WithMessage("Default Node.js version not found") } config := map[string]interface{}{ "metadata": map[string]interface{}{ "default-versions": map[string]string{ - "node": "20.*.*", + "node": fmt.Sprintf("%s.*.*", defaultNodeVersion), }, "dependencies": dependencies, }, } + //Generate config.toml to pass it on the Resolve function of the DependencyManager buf := new(bytes.Buffer) if err := toml.NewEncoder(buf).Encode(config); err != nil { log.Fatal(err) @@ -150,6 +151,8 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during // Search and fetch the version from the config.toml configFilePath := filepath.Join("./config.toml") + + nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) dependency, err := dependencyManager.Resolve(configFilePath, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) if err != nil { return packit.GenerateResult{}, err @@ -173,15 +176,12 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Process("Selected Node Engine Major version %d", selectedNodeMajorVersion) - // These variables have to be fetched from the env - CNB_STACK_ID := os.Getenv("CNB_STACK_ID") - // Generating build.Dockerfile buildDockerfileContent, err := FillPropsToTemplate(BuildDockerfileProps{ NODEJS_VERSION: selectedNodeMajorVersion, CNB_USER_ID: duringBuildPermissions.CNB_USER_ID, CNB_GROUP_ID: duringBuildPermissions.CNB_GROUP_ID, - CNB_STACK_ID: CNB_STACK_ID, + CNB_STACK_ID: context.Stack, PACKAGES: PACKAGES, }, buildDockerfileTemplate) @@ -222,6 +222,15 @@ func FillPropsToTemplate(properties interface{}, templateString string) (result return buf.String(), nil } +func getDefaultNodeVersion(imagesJson ImagesJson) string { + for _, stack := range imagesJson.StackImages { + if stack.IsDefaultRunImage == true { + return strings.Split(stack.Name, "-")[1] + } + } + return "" +} + func GetDuringBuildPermissions(filepath string) DuringBuildPermissions { defaultPermissions := DuringBuildPermissions{ From af7a1b8dfcdcd0ee9cc104647c1a7674116c8cb4 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Wed, 4 Sep 2024 14:31:56 +0300 Subject: [PATCH 03/19] adding error checking on imagesJson decoding --- generate.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/generate.go b/generate.go index e9bec89..78072e8 100644 --- a/generate.go +++ b/generate.go @@ -86,7 +86,11 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during } var imagesJson ImagesJson - json.NewDecoder(imagesJsonPath).Decode(&imagesJson) + err = json.NewDecoder(imagesJsonPath).Decode(&imagesJson) + if err != nil { + return packit.GenerateResult{}, err + } + err = imagesJsonPath.Close() if err != nil { return packit.GenerateResult{}, err @@ -122,12 +126,13 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during dependencies = append(dependencies, dependency) } - defaultNodeVersion := getDefaultNodeVersion(imagesJson) + defaultNodeVersion := getDefaultNodeVersion(nodejsStacks) if defaultNodeVersion == "" { return packit.GenerateResult{}, packit.Fail.WithMessage("Default Node.js version not found") } + //Construct config.toml file content to pass it on the Resolve function of the DependencyManager config := map[string]interface{}{ "metadata": map[string]interface{}{ "default-versions": map[string]string{ @@ -137,7 +142,6 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during }, } - //Generate config.toml to pass it on the Resolve function of the DependencyManager buf := new(bytes.Buffer) if err := toml.NewEncoder(buf).Encode(config); err != nil { log.Fatal(err) @@ -149,7 +153,6 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during return packit.GenerateResult{}, err } - // Search and fetch the version from the config.toml configFilePath := filepath.Join("./config.toml") nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) @@ -222,9 +225,9 @@ func FillPropsToTemplate(properties interface{}, templateString string) (result return buf.String(), nil } -func getDefaultNodeVersion(imagesJson ImagesJson) string { - for _, stack := range imagesJson.StackImages { - if stack.IsDefaultRunImage == true { +func getDefaultNodeVersion(stacks []StackImages) string { + for _, stack := range stacks { + if stack.IsDefaultRunImage { return strings.Split(stack.Name, "-")[1] } } From fdde2c3336cbf536d86943de63fa0114a897cda6 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Thu, 5 Sep 2024 14:16:17 +0300 Subject: [PATCH 04/19] using imagesManager to fetch imagejson file path --- generate.go | 98 ++++++++++++++++++++++++++++++++--------------------- run/main.go | 5 ++- 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/generate.go b/generate.go index 78072e8..b30f77d 100644 --- a/generate.go +++ b/generate.go @@ -7,7 +7,6 @@ import ( "fmt" "log" "os" - "path/filepath" "regexp" "strconv" "strings" @@ -23,7 +22,6 @@ import ( ) const PACKAGES = "make gcc gcc-c++ libatomic_ops git openssl-devel nodejs npm nodejs-nodemon nss_wrapper which python3" -const IMAGES_JSON_PATH = "/etc/buildpacks/images.json" const DEFAULT_USER_ID = 1002 const DEFAULT_GROUP_ID = 1000 @@ -34,6 +32,10 @@ type StackImages struct { nodeVersion string } +type ImagesManager struct { + imagesJsonPath string +} + type ImagesJson struct { StackImages []StackImages `json:"images"` } @@ -65,7 +67,7 @@ type DependencyManager interface { GenerateBillOfMaterials(dependencies ...postal.Dependency) []packit.BOMEntry } -func Generate(dependencyManager DependencyManager, logger scribe.Emitter, duringBuildPermissions DuringBuildPermissions) packit.GenerateFunc { +func Generate(dependencyManager DependencyManager, logger scribe.Emitter, duringBuildPermissions DuringBuildPermissions, imagesManager ImagesManager) packit.GenerateFunc { return func(context packit.GenerateContext) (packit.GenerateResult, error) { logger.Title("%s %s", context.Info.Name, context.Info.Version) @@ -80,30 +82,19 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Candidates(allNodeVersionsInPriorityOrder) - imagesJsonPath, err := os.Open(IMAGES_JSON_PATH) - if err != nil { - return packit.GenerateResult{}, err - } - - var imagesJson ImagesJson - err = json.NewDecoder(imagesJsonPath).Decode(&imagesJson) + imagesJsonData, err := parseImagesJsonFile(imagesManager.imagesJsonPath) if err != nil { - return packit.GenerateResult{}, err - } - - err = imagesJsonPath.Close() - if err != nil { - return packit.GenerateResult{}, err + return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to parse images.json file: %s", err) } // Filter out the nodejs stacks based on the stack name nodejsRegex, _ := regexp.Compile("^nodejs") nodejsStacks := []StackImages{} - for _, stack := range imagesJson.StackImages { + for _, stack := range imagesJsonData.StackImages { if nodejsRegex.MatchString(stack.Name) { - //Get the node version from the stack name + //Extract the node version from the stack name stack.nodeVersion = strings.Split(stack.Name, "-")[1] if stack.nodeVersion == "" { @@ -132,31 +123,13 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during return packit.GenerateResult{}, packit.Fail.WithMessage("Default Node.js version not found") } - //Construct config.toml file content to pass it on the Resolve function of the DependencyManager - config := map[string]interface{}{ - "metadata": map[string]interface{}{ - "default-versions": map[string]string{ - "node": fmt.Sprintf("%s.*.*", defaultNodeVersion), - }, - "dependencies": dependencies, - }, - } - - buf := new(bytes.Buffer) - if err := toml.NewEncoder(buf).Encode(config); err != nil { - log.Fatal(err) - } - fmt.Println(buf.String()) - - err = os.WriteFile("./config.toml", buf.Bytes(), 0744) + configTomlPath, err := createConfigTomlFile(defaultNodeVersion, dependencies) if err != nil { - return packit.GenerateResult{}, err + return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to create config.toml file: %s", err) } - configFilePath := filepath.Join("./config.toml") - nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) - dependency, err := dependencyManager.Resolve(configFilePath, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) + dependency, err := dependencyManager.Resolve(configTomlPath, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) if err != nil { return packit.GenerateResult{}, err } @@ -272,3 +245,50 @@ func GetDuringBuildPermissions(filepath string) DuringBuildPermissions { CNB_GROUP_ID: CNB_GROUP_ID, } } + +func NewImagesManager(imagesJsonPath string) ImagesManager { + return ImagesManager{ + imagesJsonPath: imagesJsonPath, + } +} + +func parseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { + filepath, err := os.Open(imagesJsonPath) + if err != nil { + return ImagesJson{}, err + } + + defer filepath.Close() + + var imagesJsonData ImagesJson + err = json.NewDecoder(filepath).Decode(&imagesJsonData) + if err != nil { + return ImagesJson{}, err + } + + return imagesJsonData, nil +} + +func createConfigTomlFile(defaultNodeVersion string, dependencies []map[string]interface{}) (string, error) { + configTomlPath := "./config.toml" + config := map[string]interface{}{ + "metadata": map[string]interface{}{ + "default-versions": map[string]string{ + "node": fmt.Sprintf("%s.*.*", defaultNodeVersion), + }, + "dependencies": dependencies, + }, + } + + buf := new(bytes.Buffer) + if err := toml.NewEncoder(buf).Encode(config); err != nil { + return "", err + } + + err := os.WriteFile(configTomlPath, buf.Bytes(), 0744) + if err != nil { + return "", err + } + + return configTomlPath, nil +} diff --git a/run/main.go b/run/main.go index 798cad2..d291f4f 100644 --- a/run/main.go +++ b/run/main.go @@ -11,13 +11,16 @@ import ( ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" ) +const IMAGES_JSON_PATH = "/etc/buildpacks/images.json" + func main() { dependencyManager := postal.NewService(cargo.NewTransport()) logEmitter := scribe.NewEmitter(os.Stdout).WithLevel(os.Getenv("BP_LOG_LEVEL")) duringBuildPermissions := ubinodejsextension.GetDuringBuildPermissions("/etc/passwd") + imagesManager := ubinodejsextension.NewImagesManager(IMAGES_JSON_PATH) packit.RunExtension( ubinodejsextension.Detect(), - ubinodejsextension.Generate(dependencyManager, logEmitter, duringBuildPermissions), + ubinodejsextension.Generate(dependencyManager, logEmitter, duringBuildPermissions, imagesManager), ) } From fe4b218720a318f7ce2a21bb092b36628b211b2c Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Thu, 5 Sep 2024 15:10:28 +0300 Subject: [PATCH 05/19] refactor: adding more stuff inside createTomlFileFunction --- generate.go | 70 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/generate.go b/generate.go index b30f77d..ceec654 100644 --- a/generate.go +++ b/generate.go @@ -87,34 +87,9 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to parse images.json file: %s", err) } - // Filter out the nodejs stacks based on the stack name - nodejsRegex, _ := regexp.Compile("^nodejs") - - nodejsStacks := []StackImages{} - for _, stack := range imagesJsonData.StackImages { - - if nodejsRegex.MatchString(stack.Name) { - //Extract the node version from the stack name - stack.nodeVersion = strings.Split(stack.Name, "-")[1] - - if stack.nodeVersion == "" { - return packit.GenerateResult{}, packit.Fail.WithMessage("Node.js version for stack %s not found", stack.Name) - } - - nodejsStacks = append(nodejsStacks, stack) - } - } - - var dependencies []map[string]interface{} - - for _, stack := range nodejsStacks { - dependency := map[string]interface{}{ - "id": "node", - "stacks": []string{context.Stack}, - "version": fmt.Sprintf("%s.1000", stack.nodeVersion), - "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", stack.nodeVersion), - } - dependencies = append(dependencies, dependency) + nodejsStacks, err := getNodejsStackImages(imagesJsonData) + if err != nil { + return packit.GenerateResult{}, err } defaultNodeVersion := getDefaultNodeVersion(nodejsStacks) @@ -123,7 +98,7 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during return packit.GenerateResult{}, packit.Fail.WithMessage("Default Node.js version not found") } - configTomlPath, err := createConfigTomlFile(defaultNodeVersion, dependencies) + configTomlPath, err := createConfigTomlFile(defaultNodeVersion, nodejsStacks, context.Stack) if err != nil { return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to create config.toml file: %s", err) } @@ -269,7 +244,20 @@ func parseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { return imagesJsonData, nil } -func createConfigTomlFile(defaultNodeVersion string, dependencies []map[string]interface{}) (string, error) { +func createConfigTomlFile(defaultNodeVersion string, nodejsStacks []StackImages, stackId string) (string, error) { + + var dependencies []map[string]interface{} + + for _, stack := range nodejsStacks { + dependency := map[string]interface{}{ + "id": "node", + "stacks": []string{stackId}, + "version": fmt.Sprintf("%s.1000", stack.nodeVersion), + "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", stack.nodeVersion), + } + dependencies = append(dependencies, dependency) + } + configTomlPath := "./config.toml" config := map[string]interface{}{ "metadata": map[string]interface{}{ @@ -292,3 +280,25 @@ func createConfigTomlFile(defaultNodeVersion string, dependencies []map[string]i return configTomlPath, nil } + +func getNodejsStackImages(imagesJsonData ImagesJson) ([]StackImages, error) { + + // Filter out the nodejs stacks based on the stack name + nodejsRegex, _ := regexp.Compile("^nodejs") + + nodejsStacks := []StackImages{} + for _, stack := range imagesJsonData.StackImages { + + if nodejsRegex.MatchString(stack.Name) { + //Extract the node version from the stack name + stack.nodeVersion = strings.Split(stack.Name, "-")[1] + + if stack.nodeVersion == "" { + packit.Fail.WithMessage("Node.js version for stack %s not found", stack.Name) + } + + nodejsStacks = append(nodejsStacks, stack) + } + } + return nodejsStacks, nil +} From 78ac7c9aba36c76d928985c248b504f11bc8c529 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Mon, 9 Sep 2024 14:57:56 +0300 Subject: [PATCH 06/19] proper name for the extension unit tests --- init_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/init_test.go b/init_test.go index fc4cdd2..1b4736b 100644 --- a/init_test.go +++ b/init_test.go @@ -7,11 +7,11 @@ import ( "github.com/sclevine/spec/report" ) -func TestUnitNode(t *testing.T) { - suite := spec.New("node", spec.Report(report.Terminal{})) +func TestUnitUbiNodejsExtension(t *testing.T) { + suite := spec.New("ubi-nodejs-extension", spec.Report(report.Terminal{})) suite("Detect", testDetect) suite("Generate", testGenerate) suite("Dockerfile Creation", testFillPropsToTemplate) - suite("Fetching during build permissions", testFetchingPermissionsFromEtchPasswdFile) + suite("Fetching during build permissions", testFetchingPermissionsFromEtcPasswdFile) suite.Run(t) } From 53e055f0ad20c63f772c9fc022a7885f88f626e8 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Mon, 9 Sep 2024 15:00:22 +0300 Subject: [PATCH 07/19] creating utils with tests and testdata --- internal/utils/init_test.go | 17 ++ internal/utils/testdata/images.json.parsed.go | 45 ++++ internal/utils/testdata/images_corrupted.json | 71 +++++ .../testdata/images_no_node_version.json | 91 +++++++ .../images_node_version_not_integer.json | 91 +++++++ internal/utils/testdata/images_sample.json | 91 +++++++ internal/utils/utils.go | 113 ++++++++ internal/utils/utils_test.go | 246 ++++++++++++++++++ 8 files changed, 765 insertions(+) create mode 100644 internal/utils/init_test.go create mode 100644 internal/utils/testdata/images.json.parsed.go create mode 100644 internal/utils/testdata/images_corrupted.json create mode 100644 internal/utils/testdata/images_no_node_version.json create mode 100644 internal/utils/testdata/images_node_version_not_integer.json create mode 100644 internal/utils/testdata/images_sample.json create mode 100644 internal/utils/utils.go create mode 100644 internal/utils/utils_test.go diff --git a/internal/utils/init_test.go b/internal/utils/init_test.go new file mode 100644 index 0000000..5e16ae0 --- /dev/null +++ b/internal/utils/init_test.go @@ -0,0 +1,17 @@ +package utils_test + +import ( + "testing" + + "github.com/sclevine/spec" + "github.com/sclevine/spec/report" +) + +func TestUnitUtils(t *testing.T) { + suite := spec.New("utils-ubi-nodejs-extension", spec.Report(report.Terminal{})) + suite("GetDefaultNodeVersion", testGetDefaultNodeVersion) + suite("CreateConfigTomlFileContent", testCreateConfigTomlFileContent) + suite("ParseImagesJsonFile", testParseImagesJsonFile) + suite("GetNodejsStackImages", testGetNodejsStackImages) + suite.Run(t) +} diff --git a/internal/utils/testdata/images.json.parsed.go b/internal/utils/testdata/images.json.parsed.go new file mode 100644 index 0000000..7df6484 --- /dev/null +++ b/internal/utils/testdata/images.json.parsed.go @@ -0,0 +1,45 @@ +package utils_testdata + +import "github.com/paketo-community/ubi-nodejs-extension/internal/utils" + +func GetParsedImages(filename string) utils.ImagesJson { + if filename == "images_sample.json" { + return utils.ImagesJson{ + StackImages: []utils.StackImages{ + { + Name: "default", + IsDefaultRunImage: false, + }, + { + Name: "java-8", + IsDefaultRunImage: false, + }, + { + Name: "java-11", + IsDefaultRunImage: false, + }, + { + Name: "java-17", + IsDefaultRunImage: false, + }, + { + Name: "java-21", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-16", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-18", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-20", + IsDefaultRunImage: true, + }, + }, + } + } + return utils.ImagesJson{} +} diff --git a/internal/utils/testdata/images_corrupted.json b/internal/utils/testdata/images_corrupted.json new file mode 100644 index 0000000..0e8fe72 --- /dev/null +++ b/internal/utils/testdata/images_corrupted.json @@ -0,0 +1,71 @@ +{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" + }, + ge": "build-java-11", + "run_image": "run-java-11", + "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }, + { + "name": "nodejs-16", + "config_dir": "stack-nodejs-16", + "output_dir": "build-nodejs-16", + "build_image": "build-nodejs-16", + "run_image": "run-nodejs-16", + "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" + }, + { + "name": "nodejs-18", + "config_dir": "stack-nodejs-18", + "output_dir": "build-nodejs-18", + "build_image": "build-nodejs-18", + "run_image": "run-nodejs-18", + "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" + }, + { + "name": "nodejs-20", + "is_default_run_image": true, + "config_dir": "stack-nodejs-20", + "output_dir": "build-nodejs-20", + "build_image": "build-nodejs-20", + "run_image": "run-nodejs-20", + "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" + } + ] + } + \ No newline at end of file diff --git a/internal/utils/testdata/images_no_node_version.json b/internal/utils/testdata/images_no_node_version.json new file mode 100644 index 0000000..0e5263f --- /dev/null +++ b/internal/utils/testdata/images_no_node_version.json @@ -0,0 +1,91 @@ +{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "build_image": "build", + "run_image": "run", + "build_receipt_filename": "build-receipt.cyclonedx.json", + "run_receipt_filename": "run-receipt.cyclonedx.json", + "create_build_image": true, + "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" + }, + { + "name": "java-8", + "config_dir": "stack-java-8", + "output_dir": "build-java-8", + "build_image": "build-java-8", + "run_image": "run-java-8", + "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" + }, + { + "name": "java-11", + "config_dir": "stack-java-11", + "output_dir": "build-java-11", + "build_image": "build-java-11", + "run_image": "run-java-11", + "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }, + { + "name": "nodejs-16", + "config_dir": "stack-nodejs-16", + "output_dir": "build-nodejs-16", + "build_image": "build-nodejs-16", + "run_image": "run-nodejs-16", + "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" + }, + { + "name": "nodejs-", + "config_dir": "stack-nodejs-18", + "output_dir": "build-nodejs-18", + "build_image": "build-nodejs-18", + "run_image": "run-nodejs-18", + "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" + }, + { + "name": "nodejs-20", + "is_default_run_image": true, + "config_dir": "stack-nodejs-20", + "output_dir": "build-nodejs-20", + "build_image": "build-nodejs-20", + "run_image": "run-nodejs-20", + "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" + } + ] + } + \ No newline at end of file diff --git a/internal/utils/testdata/images_node_version_not_integer.json b/internal/utils/testdata/images_node_version_not_integer.json new file mode 100644 index 0000000..81d4198 --- /dev/null +++ b/internal/utils/testdata/images_node_version_not_integer.json @@ -0,0 +1,91 @@ +{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "build_image": "build", + "run_image": "run", + "build_receipt_filename": "build-receipt.cyclonedx.json", + "run_receipt_filename": "run-receipt.cyclonedx.json", + "create_build_image": true, + "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" + }, + { + "name": "java-8", + "config_dir": "stack-java-8", + "output_dir": "build-java-8", + "build_image": "build-java-8", + "run_image": "run-java-8", + "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" + }, + { + "name": "java-11", + "config_dir": "stack-java-11", + "output_dir": "build-java-11", + "build_image": "build-java-11", + "run_image": "run-java-11", + "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }, + { + "name": "nodejs-16", + "config_dir": "stack-nodejs-16", + "output_dir": "build-nodejs-16", + "build_image": "build-nodejs-16", + "run_image": "run-nodejs-16", + "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" + }, + { + "name": "nodejs-18", + "config_dir": "stack-nodejs-18", + "output_dir": "build-nodejs-18", + "build_image": "build-nodejs-18", + "run_image": "run-nodejs-18", + "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" + }, + { + "name": "nodejs-hello", + "is_default_run_image": true, + "config_dir": "stack-nodejs-20", + "output_dir": "build-nodejs-20", + "build_image": "build-nodejs-20", + "run_image": "run-nodejs-20", + "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" + } + ] + } + \ No newline at end of file diff --git a/internal/utils/testdata/images_sample.json b/internal/utils/testdata/images_sample.json new file mode 100644 index 0000000..ef663e1 --- /dev/null +++ b/internal/utils/testdata/images_sample.json @@ -0,0 +1,91 @@ +{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "build_image": "build", + "run_image": "run", + "build_receipt_filename": "build-receipt.cyclonedx.json", + "run_receipt_filename": "run-receipt.cyclonedx.json", + "create_build_image": true, + "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" + }, + { + "name": "java-8", + "config_dir": "stack-java-8", + "output_dir": "build-java-8", + "build_image": "build-java-8", + "run_image": "run-java-8", + "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" + }, + { + "name": "java-11", + "config_dir": "stack-java-11", + "output_dir": "build-java-11", + "build_image": "build-java-11", + "run_image": "run-java-11", + "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }, + { + "name": "nodejs-16", + "config_dir": "stack-nodejs-16", + "output_dir": "build-nodejs-16", + "build_image": "build-nodejs-16", + "run_image": "run-nodejs-16", + "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" + }, + { + "name": "nodejs-18", + "config_dir": "stack-nodejs-18", + "output_dir": "build-nodejs-18", + "build_image": "build-nodejs-18", + "run_image": "run-nodejs-18", + "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" + }, + { + "name": "nodejs-20", + "is_default_run_image": true, + "config_dir": "stack-nodejs-20", + "output_dir": "build-nodejs-20", + "build_image": "build-nodejs-20", + "run_image": "run-nodejs-20", + "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" + } + ] + } + \ No newline at end of file diff --git a/internal/utils/utils.go b/internal/utils/utils.go new file mode 100644 index 0000000..d020704 --- /dev/null +++ b/internal/utils/utils.go @@ -0,0 +1,113 @@ +package utils + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "os" + "regexp" + "strconv" + "strings" + + "github.com/BurntSushi/toml" +) + +type StackImages struct { + Name string `json:"name"` + IsDefaultRunImage bool `json:"is_default_run_image,omitempty"` + NodeVersion string +} + +type ImagesJson struct { + StackImages []StackImages `json:"images"` +} + +func GetDefaultNodeVersion(stacks []StackImages) (string, error) { + var defaultNodeVersionsFound []string + for _, stack := range stacks { + if stack.IsDefaultRunImage { + defaultNodeVersionsFound = append(defaultNodeVersionsFound, strings.Split(stack.Name, "-")[1]) + } + } + if len(defaultNodeVersionsFound) == 1 { + return defaultNodeVersionsFound[0], nil + } else if len(defaultNodeVersionsFound) > 1 { + return "", errors.New("multiple default node.js versions found") + } else { + return "", errors.New("default node.js version not found") + } +} + +func CreateConfigTomlFileContent(defaultNodeVersion string, nodejsStacks []StackImages, stackId string) (bytes.Buffer, error) { + + var dependencies []map[string]interface{} + + for _, stack := range nodejsStacks { + dependency := map[string]interface{}{ + "id": "node", + "stacks": []string{stackId}, + "version": fmt.Sprintf("%s.1000", stack.NodeVersion), + "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", stack.NodeVersion), + } + dependencies = append(dependencies, dependency) + } + + config := map[string]interface{}{ + "metadata": map[string]interface{}{ + "default-versions": map[string]string{ + "node": fmt.Sprintf("%s.*.*", defaultNodeVersion), + }, + "dependencies": dependencies, + }, + } + + buf := new(bytes.Buffer) + if err := toml.NewEncoder(buf).Encode(config); err != nil { + return bytes.Buffer{}, err + } + + return *buf, nil +} + +func GetNodejsStackImages(imagesJsonData ImagesJson) ([]StackImages, error) { + + // Filter out the nodejs stacks based on the stack name + nodejsRegex, _ := regexp.Compile("^nodejs") + + nodejsStacks := []StackImages{} + for _, stack := range imagesJsonData.StackImages { + + if nodejsRegex.MatchString(stack.Name) { + //Extract the node version from the stack name + extractedNodeVersion := strings.Split(stack.Name, "-")[1] + + _, err := strconv.Atoi(extractedNodeVersion) + if err != nil { + return []StackImages{}, fmt.Errorf("extracted Node.js version [%s] for stack %s is not an integer", extractedNodeVersion, stack.Name) + } + + stack.NodeVersion = extractedNodeVersion + + nodejsStacks = append(nodejsStacks, stack) + } + } + return nodejsStacks, nil +} + +func ParseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { + filepath, err := os.Open(imagesJsonPath) + if err != nil { + return ImagesJson{}, err + } + + defer filepath.Close() + + var imagesJsonData ImagesJson + err = json.NewDecoder(filepath).Decode(&imagesJsonData) + if err != nil { + return ImagesJson{}, err + } + + return imagesJsonData, nil +} diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go new file mode 100644 index 0000000..cc317c9 --- /dev/null +++ b/internal/utils/utils_test.go @@ -0,0 +1,246 @@ +package utils_test + +import ( + _ "embed" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/gomega" + "github.com/paketo-community/ubi-nodejs-extension/internal/utils" + utils_testdata "github.com/paketo-community/ubi-nodejs-extension/internal/utils/testdata" + "github.com/sclevine/spec" +) + +func testGetDefaultNodeVersion(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + context("When passing an array of stacks with nodejs images", func() { + + context("and there is a default run image", func() { + it("should find the default node version", func() { + defaultNodeVersion, err := utils.GetDefaultNodeVersion([]utils.StackImages{ + { + Name: "nodejs-22", + IsDefaultRunImage: true, + NodeVersion: "22", + }, + { + Name: "nodejs-20", + IsDefaultRunImage: false, + NodeVersion: "20", + }, + }) + + Expect(err).ToNot(HaveOccurred()) + Expect(defaultNodeVersion).To(Equal("22")) + }) + }) + + context("and there are no default run images", func() { + it("should error", func() { + defaultNodeVersion, err := utils.GetDefaultNodeVersion([]utils.StackImages{ + { + Name: "nodejs-22", + IsDefaultRunImage: false, + NodeVersion: "22", + }, + { + Name: "nodejs-20", + IsDefaultRunImage: false, + NodeVersion: "20", + }, + }) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("default node.js version not found")) + Expect(defaultNodeVersion).To(Equal("")) + }) + }) + + context("and there are more than one default run images", func() { + it("should error", func() { + defaultNodeVersion, err := utils.GetDefaultNodeVersion([]utils.StackImages{ + { + Name: "nodejs-18", + IsDefaultRunImage: true, + NodeVersion: "18", + }, + { + Name: "nodejs-22", + IsDefaultRunImage: false, + NodeVersion: "22", + }, + { + Name: "nodejs-20", + IsDefaultRunImage: true, + NodeVersion: "20", + }, + }) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("multiple default node.js versions found")) + Expect(defaultNodeVersion).To(Equal("")) + }) + }) + }) +} + +func testCreateConfigTomlFileContent(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + context("When passing data properly to CreateConfigTomlFileContent function", func() { + + it("successfly create the content of config.toml", func() { + configTomlFileContent, err := utils.CreateConfigTomlFileContent("22", []utils.StackImages{ + { + Name: "nodejs-22", + IsDefaultRunImage: true, + NodeVersion: "22", + }, + { + Name: "nodejs-20", + IsDefaultRunImage: false, + }, + }, "io.buildpacks.stacks.ubix") + + Expect(err).ToNot(HaveOccurred()) + Expect(configTomlFileContent.String()).To(ContainSubstring(`[metadata] + [metadata.default-versions] + node = "22.*.*" + + [[metadata.dependencies]] + id = "node" + source = "paketocommunity/run-nodejs-22-ubi-base" + stacks = ["io.buildpacks.stacks.ubix"] + version = "22.1000" + + [[metadata.dependencies]] + id = "node" + source = "paketocommunity/run-nodejs--ubi-base" + stacks = ["io.buildpacks.stacks.ubix"] + version = ".1000"`)) + }) + }) +} + +func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + var imagesJsonDir string + it.Before(func() { + imagesJsonDir = t.TempDir() + }) + + it.After(func() { + Expect(os.RemoveAll(imagesJsonDir)).To(Succeed()) + }) + + it("successfully parses images.json file", func() { + cwd, err := os.Getwd() + if err != nil { + Expect(err).ToNot(HaveOccurred()) + } + + imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(cwd, "/testdata/images_sample.json")) + Expect(err).ToNot(HaveOccurred()) + + imagesParsed := utils_testdata.GetParsedImages("images_sample.json") + + Expect(imagesJsonData).To(Equal(imagesParsed)) + }) + + it("erros when images.json file does not exist", func() { + imagesJsonData, err := utils.ParseImagesJsonFile("/does/not/exist") + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no such file or directory")) + Expect(imagesJsonData).To(Equal(utils.ImagesJson{})) + }) + + it("erros when images.json file is corrupted", func() { + cwd, err := os.Getwd() + if err != nil { + Expect(err).ToNot(HaveOccurred()) + } + + imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(cwd, "/testdata/images_corrupted.json")) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid character")) + Expect(imagesJsonData).To(Equal(utils.ImagesJson{})) + }) +} + +func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + context("When passing the array with all the stacks", func() { + + it("should return only the nodejs stacks", func() { + allStacks := utils_testdata.GetParsedImages("images_sample.json") + nodejsStacks, err := utils.GetNodejsStackImages(allStacks) + Expect(err).ToNot(HaveOccurred()) + + Expect(nodejsStacks).To(Equal([]utils.StackImages{ + { + Name: "nodejs-16", + IsDefaultRunImage: false, + NodeVersion: "16", + }, + { + Name: "nodejs-18", + IsDefaultRunImage: false, + NodeVersion: "18", + }, + { + Name: "nodejs-20", + IsDefaultRunImage: true, + NodeVersion: "20", + }, + })) + }) + }) + + context("When node version is malformed or does not exist", func() { + + it("should error with a message", func() { + cwd, err := os.Getwd() + if err != nil { + Expect(err).ToNot(HaveOccurred()) + } + + for _, tt := range []struct { + errorMessage string + imagesJsonPath string + }{ + { + errorMessage: "extracted Node.js version [hello] for stack nodejs-hello is not an integer", + imagesJsonPath: "/testdata/images_node_version_not_integer.json", + }, + { + errorMessage: "extracted Node.js version [] for stack nodejs- is not an integer", + imagesJsonPath: "/testdata/images_no_node_version.json", + }, + } { + imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(cwd, tt.imagesJsonPath)) + Expect(err).ToNot(HaveOccurred()) + + nodejsStacks, err := utils.GetNodejsStackImages(imagesJsonData) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(tt.errorMessage)) + Expect(nodejsStacks).To(Equal([]utils.StackImages{})) + } + }) + }) +} From 02938ef992fd8748f9a0b0970552f2a50b4dbc33 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Mon, 9 Sep 2024 15:03:15 +0300 Subject: [PATCH 08/19] removing imagesManager and adding a path instead --- generate.go | 131 +++++----------------------------------------------- run/main.go | 3 +- 2 files changed, 13 insertions(+), 121 deletions(-) diff --git a/generate.go b/generate.go index ceec654..ad0a5c2 100644 --- a/generate.go +++ b/generate.go @@ -3,16 +3,14 @@ package ubinodejsextension import ( "bytes" _ "embed" - "encoding/json" - "fmt" - "log" "os" "regexp" "strconv" "strings" "text/template" - "github.com/BurntSushi/toml" + "github.com/paketo-community/ubi-nodejs-extension/internal/utils" + "github.com/Masterminds/semver/v3" "github.com/paketo-buildpacks/libnodejs" "github.com/paketo-buildpacks/packit/v2" @@ -24,21 +22,7 @@ import ( const PACKAGES = "make gcc gcc-c++ libatomic_ops git openssl-devel nodejs npm nodejs-nodemon nss_wrapper which python3" const DEFAULT_USER_ID = 1002 const DEFAULT_GROUP_ID = 1000 - -type StackImages struct { - Name string `json:"name"` - Type string `json:"type,omitempty"` - IsDefaultRunImage bool `json:"is_default_run_image,omitempty"` - nodeVersion string -} - -type ImagesManager struct { - imagesJsonPath string -} - -type ImagesJson struct { - StackImages []StackImages `json:"images"` -} +const CONFIG_TOML_PATH = "/tmp/config.toml" type DuringBuildPermissions struct { CNB_USER_ID, CNB_GROUP_ID int @@ -67,7 +51,7 @@ type DependencyManager interface { GenerateBillOfMaterials(dependencies ...postal.Dependency) []packit.BOMEntry } -func Generate(dependencyManager DependencyManager, logger scribe.Emitter, duringBuildPermissions DuringBuildPermissions, imagesManager ImagesManager) packit.GenerateFunc { +func Generate(dependencyManager DependencyManager, logger scribe.Emitter, duringBuildPermissions DuringBuildPermissions, imagesJsonPath string) packit.GenerateFunc { return func(context packit.GenerateContext) (packit.GenerateResult, error) { logger.Title("%s %s", context.Info.Name, context.Info.Version) @@ -82,29 +66,29 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Candidates(allNodeVersionsInPriorityOrder) - imagesJsonData, err := parseImagesJsonFile(imagesManager.imagesJsonPath) + imagesJsonData, err := utils.ParseImagesJsonFile(imagesJsonPath) if err != nil { return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to parse images.json file: %s", err) } - nodejsStacks, err := getNodejsStackImages(imagesJsonData) + nodejsStacks, err := utils.GetNodejsStackImages(imagesJsonData) if err != nil { return packit.GenerateResult{}, err } - defaultNodeVersion := getDefaultNodeVersion(nodejsStacks) + defaultNodeVersion, err := utils.GetDefaultNodeVersion(nodejsStacks) - if defaultNodeVersion == "" { - return packit.GenerateResult{}, packit.Fail.WithMessage("Default Node.js version not found") + if err != nil { + return packit.GenerateResult{}, err } - configTomlPath, err := createConfigTomlFile(defaultNodeVersion, nodejsStacks, context.Stack) + configTomlFileContent, err := utils.CreateConfigTomlFileContent(defaultNodeVersion, nodejsStacks, context.Stack) if err != nil { - return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to create config.toml file: %s", err) + return packit.GenerateResult{}, err } nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) - dependency, err := dependencyManager.Resolve(configTomlPath, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) + dependency, err := dependencyManager.Resolve(CONFIG_TOML_PATH, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) if err != nil { return packit.GenerateResult{}, err } @@ -173,15 +157,6 @@ func FillPropsToTemplate(properties interface{}, templateString string) (result return buf.String(), nil } -func getDefaultNodeVersion(stacks []StackImages) string { - for _, stack := range stacks { - if stack.IsDefaultRunImage { - return strings.Split(stack.Name, "-")[1] - } - } - return "" -} - func GetDuringBuildPermissions(filepath string) DuringBuildPermissions { defaultPermissions := DuringBuildPermissions{ @@ -220,85 +195,3 @@ func GetDuringBuildPermissions(filepath string) DuringBuildPermissions { CNB_GROUP_ID: CNB_GROUP_ID, } } - -func NewImagesManager(imagesJsonPath string) ImagesManager { - return ImagesManager{ - imagesJsonPath: imagesJsonPath, - } -} - -func parseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { - filepath, err := os.Open(imagesJsonPath) - if err != nil { - return ImagesJson{}, err - } - - defer filepath.Close() - - var imagesJsonData ImagesJson - err = json.NewDecoder(filepath).Decode(&imagesJsonData) - if err != nil { - return ImagesJson{}, err - } - - return imagesJsonData, nil -} - -func createConfigTomlFile(defaultNodeVersion string, nodejsStacks []StackImages, stackId string) (string, error) { - - var dependencies []map[string]interface{} - - for _, stack := range nodejsStacks { - dependency := map[string]interface{}{ - "id": "node", - "stacks": []string{stackId}, - "version": fmt.Sprintf("%s.1000", stack.nodeVersion), - "source": fmt.Sprintf("paketocommunity/run-nodejs-%s-ubi-base", stack.nodeVersion), - } - dependencies = append(dependencies, dependency) - } - - configTomlPath := "./config.toml" - config := map[string]interface{}{ - "metadata": map[string]interface{}{ - "default-versions": map[string]string{ - "node": fmt.Sprintf("%s.*.*", defaultNodeVersion), - }, - "dependencies": dependencies, - }, - } - - buf := new(bytes.Buffer) - if err := toml.NewEncoder(buf).Encode(config); err != nil { - return "", err - } - - err := os.WriteFile(configTomlPath, buf.Bytes(), 0744) - if err != nil { - return "", err - } - - return configTomlPath, nil -} - -func getNodejsStackImages(imagesJsonData ImagesJson) ([]StackImages, error) { - - // Filter out the nodejs stacks based on the stack name - nodejsRegex, _ := regexp.Compile("^nodejs") - - nodejsStacks := []StackImages{} - for _, stack := range imagesJsonData.StackImages { - - if nodejsRegex.MatchString(stack.Name) { - //Extract the node version from the stack name - stack.nodeVersion = strings.Split(stack.Name, "-")[1] - - if stack.nodeVersion == "" { - packit.Fail.WithMessage("Node.js version for stack %s not found", stack.Name) - } - - nodejsStacks = append(nodejsStacks, stack) - } - } - return nodejsStacks, nil -} diff --git a/run/main.go b/run/main.go index d291f4f..fd097e0 100644 --- a/run/main.go +++ b/run/main.go @@ -17,10 +17,9 @@ func main() { dependencyManager := postal.NewService(cargo.NewTransport()) logEmitter := scribe.NewEmitter(os.Stdout).WithLevel(os.Getenv("BP_LOG_LEVEL")) duringBuildPermissions := ubinodejsextension.GetDuringBuildPermissions("/etc/passwd") - imagesManager := ubinodejsextension.NewImagesManager(IMAGES_JSON_PATH) packit.RunExtension( ubinodejsextension.Detect(), - ubinodejsextension.Generate(dependencyManager, logEmitter, duringBuildPermissions, imagesManager), + ubinodejsextension.Generate(dependencyManager, logEmitter, duringBuildPermissions, IMAGES_JSON_PATH), ) } From 9071d7978eae4e75ae063961c24fc52e4f1bf36c Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Mon, 9 Sep 2024 15:03:47 +0300 Subject: [PATCH 09/19] saving config.toml file --- generate.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/generate.go b/generate.go index ad0a5c2..312917d 100644 --- a/generate.go +++ b/generate.go @@ -87,6 +87,12 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during return packit.GenerateResult{}, err } + //save config.toml file + err = os.WriteFile(CONFIG_TOML_PATH, configTomlFileContent.Bytes(), 0644) + if err != nil { + return packit.GenerateResult{}, err + } + nodeVersion, _ := highestPriorityNodeVersion.Metadata["version"].(string) dependency, err := dependencyManager.Resolve(CONFIG_TOML_PATH, highestPriorityNodeVersion.Name, nodeVersion, context.Stack) if err != nil { From a8bceb7b5a9fb7028717212e54f582cbaf810394 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Mon, 9 Sep 2024 21:20:35 +0300 Subject: [PATCH 10/19] refactor: generate tests --- generate_test.go | 732 ++++++++++++++++++++++------------------------- 1 file changed, 337 insertions(+), 395 deletions(-) diff --git a/generate_test.go b/generate_test.go index c3ae76d..b606b1a 100644 --- a/generate_test.go +++ b/generate_test.go @@ -90,7 +90,7 @@ RUN echo "CNB_STACK_ID: "`, ubinodejsextension.PACKAGES))) }) } -func testFetchingPermissionsFromEtchPasswdFile(t *testing.T, context spec.G, it spec.S) { +func testFetchingPermissionsFromEtcPasswdFile(t *testing.T, context spec.G, it spec.S) { var ( Expect = NewWithT(t).Expect @@ -128,7 +128,8 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin Expect(duringBuilderPermissions).To(Equal( ubinodejsextension.DuringBuildPermissions{ CNB_USER_ID: 1234, - CNB_GROUP_ID: 2345}, + CNB_GROUP_ID: 2345, + }, )) }) }) @@ -186,20 +187,15 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin func testGenerate(t *testing.T, context spec.G, it spec.S) { var ( - Expect = NewWithT(t).Expect - workingDir string - planPath string - testBuildPlan packit.BuildpackPlan - buf = new(bytes.Buffer) - generateResult packit.GenerateResult - err error - cnbDir string - BuildDockerfileProps = ubinodejsextension.BuildDockerfileProps{ - CNB_USER_ID: 1002, - CNB_GROUP_ID: 1000, - CNB_STACK_ID: "", - PACKAGES: ubinodejsextension.PACKAGES, - } + Expect = NewWithT(t).Expect + workingDir string + imagesJsonTmpDir string + imagesJsonPath string + planPath string + testBuildPlan packit.BuildpackPlan + buf = new(bytes.Buffer) + generateResult packit.GenerateResult + err error generate packit.GenerateFunc buffer *bytes.Buffer logger scribe.Emitter @@ -212,17 +208,18 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { dependencyManager = postal.NewService(cargo.NewTransport()) }) - context("Generate called with NO node in buildplan", func() { + context("Generate called with NO node in build plan", func() { it.Before(func() { - - workingDir = t.TempDir() - Expect(err).NotTo(HaveOccurred()) - - generate = ubinodejsextension.Generate(dependencyManager, logger, ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + "/path/to/images.json") err = toml.NewEncoder(buf).Encode(testBuildPlan) Expect(err).NotTo(HaveOccurred()) + workingDir := t.TempDir() Expect(os.WriteFile(filepath.Join(workingDir, "plan"), buf.Bytes(), 0600)).To(Succeed()) err = os.Chdir(workingDir) @@ -233,7 +230,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(os.RemoveAll(workingDir)).To(Succeed()) }) - it("Node no longer requested in buildplan", func() { + it("the extension should exit with an error", func() { generateResult, err = generate(packit.GenerateContext{ WorkingDir: workingDir, @@ -241,22 +238,21 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Entries: []packit.BuildpackPlanEntry{}, }, }) + Expect(err).To(HaveOccurred()) - Expect(generateResult.BuildDockerfile).To(BeNil()) + Expect(err.Error()).To(ContainSubstring("Node.js no longer requested by build plan")) + Expect(generateResult).To(Equal(packit.GenerateResult{})) }) }, spec.Sequential()) - context("Generate called with node in the buildplan", func() { + context("Generate called with node in the build plan", func() { it.Before(func() { - workingDir = t.TempDir() - cnbDir, err = os.MkdirTemp("", "cnb") - - generate = ubinodejsextension.Generate(dependencyManager, logger, ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}) - err = toml.NewEncoder(buf).Encode(testBuildPlan) Expect(err).NotTo(HaveOccurred()) + workingDir = t.TempDir() + planPath = filepath.Join(workingDir, "plan") t.Setenv("CNB_BP_PLAN_PATH", planPath) @@ -268,179 +264,110 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it.After(func() { Expect(os.RemoveAll(workingDir)).To(Succeed()) + Expect(os.RemoveAll(imagesJsonTmpDir)).To(Succeed()) }) it("Specific version of node requested", func() { - extensionToml, _ := readExtensionTomlTemplateFile() + imagesJsonContent := generateImagesJsonFile("18") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) versionTests := []struct { - Name string - Metadata map[string]interface{} - RunDockerfileProps ubinodejsextension.RunDockerfileProps - BuildDockerfileProps ubinodejsextension.BuildDockerfileProps - buildDockerfileExpectedNodejsVersion int + requestedNodeVersion string + expectedNodeVersion int }{ { - Name: "node", - Metadata: map[string]interface{}{ - "version": "16 - 18", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: "16 - 18", + expectedNodeVersion: 18, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "16.0.0 - 18.0.0", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "16.0.0 - 18.0.0", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "<18.5.1", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "<18.5.1", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": ">18.5.1", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: ">18.5.1", + expectedNodeVersion: 18, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "16 <18.5.1", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "16 <18.5.1", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "<1.0.0 || >=2.5.2 <3.0.0 || >=2.3.1 <18.4.5", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "<1.0.0 || >=2.5.2 <3.0.0 || >=2.3.1 <18.4.5", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "v18", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: "v18", + expectedNodeVersion: 18, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "16", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "16", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "18", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: "18", + expectedNodeVersion: 18, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "~16", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "~16", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "^18.0.x", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: "^18.0.x", + expectedNodeVersion: 18, }, } for _, tt := range versionTests { - generateResult, err = generate(packit.GenerateContext{ - WorkingDir: workingDir, - CNBPath: cnbDir, - Plan: packit.BuildpackPlan{ - Entries: []packit.BuildpackPlanEntry{ - { - Name: tt.Name, - Metadata: tt.Metadata, + buildplan := packit.BuildpackPlan{ + Entries: []packit.BuildpackPlanEntry{ + { + Name: "node", + Metadata: map[string]interface{}{ + "version": tt.requestedNodeVersion, + "version-source": "BP_NODE_VERSION", }, }, }, - Stack: "io.buildpacks.stacks.ubi8", + } + + generateResult, err = generate(packit.GenerateContext{ + WorkingDir: workingDir, + Plan: buildplan, + Stack: "io.buildpacks.stacks.ubi8", }) Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.RunDockerfileProps, runDockerfileTemplate) - tt.BuildDockerfileProps.NODEJS_VERSION = uint64(tt.buildDockerfileExpectedNodejsVersion) - buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.BuildDockerfileProps, buildDockerfileTemplate) + runDockerFileProps := ubinodejsextension.RunDockerfileProps{ + Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), + } + runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) + + buildDockerfileProps := ubinodejsextension.BuildDockerfileProps{ + CNB_USER_ID: 1002, + CNB_GROUP_ID: 1000, + CNB_STACK_ID: "io.buildpacks.stacks.ubi8", + PACKAGES: ubinodejsextension.PACKAGES, + NODEJS_VERSION: uint64(tt.expectedNodeVersion), + } + + buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(buildDockerfileProps, buildDockerfileTemplate) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -448,85 +375,84 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { buf.Reset() _, _ = io.Copy(buf, generateResult.BuildDockerfile) Expect(buf.String()).To(Equal(buildDockerfileContent)) - } + } }) it("should return the default when node version has NOT been requested", func() { - extensionToml, _ := readExtensionTomlTemplateFile("16") + imagesJsonContent := generateImagesJsonFile("16") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) versionTests := []struct { - Name string - Metadata map[string]interface{} - RunDockerfileProps ubinodejsextension.RunDockerfileProps - BuildDockerfileProps ubinodejsextension.BuildDockerfileProps - buildDockerfileExpectedNodejsVersion int + requestedNodeVersion string + versionSource string + Metadata map[string]interface{} + expectedNodeVersion int }{ { - Name: "node", - Metadata: map[string]interface{}{ - "version": "", - "version-source": "", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "", + versionSource: "", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-16-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 16, + requestedNodeVersion: "", + versionSource: "BP_NODE_VERSION", + expectedNodeVersion: 16, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "x", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: "x", + versionSource: "BP_NODE_VERSION", + expectedNodeVersion: 18, }, } for _, tt := range versionTests { - generateResult, err = generate(packit.GenerateContext{ - WorkingDir: workingDir, - CNBPath: cnbDir, - Plan: packit.BuildpackPlan{ - Entries: []packit.BuildpackPlanEntry{ - { - Name: tt.Name, - Metadata: tt.Metadata, + buildplan := packit.BuildpackPlan{ + Entries: []packit.BuildpackPlanEntry{ + { + Name: "node", + Metadata: map[string]interface{}{ + "version": tt.requestedNodeVersion, + "version-source": tt.versionSource, }, }, }, - Stack: "io.buildpacks.stacks.ubi8", + } + + generateResult, err = generate(packit.GenerateContext{ + WorkingDir: workingDir, + Plan: buildplan, + Stack: "io.buildpacks.stacks.ubi8", }) Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.RunDockerfileProps, runDockerfileTemplate) - tt.BuildDockerfileProps.NODEJS_VERSION = uint64(tt.buildDockerfileExpectedNodejsVersion) - buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.BuildDockerfileProps, buildDockerfileTemplate) + runDockerFileProps := ubinodejsextension.RunDockerfileProps{ + Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), + } + + runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) + buildDockerfileProps := ubinodejsextension.BuildDockerfileProps{ + CNB_USER_ID: 1002, + CNB_GROUP_ID: 1000, + CNB_STACK_ID: "io.buildpacks.stacks.ubi8", + PACKAGES: ubinodejsextension.PACKAGES, + NODEJS_VERSION: uint64(tt.expectedNodeVersion), + } + + buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(buildDockerfileProps, buildDockerfileTemplate) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -540,67 +466,68 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("should return the higher node version when it requests for >=nodeVersion", func() { - extensionToml, _ := readExtensionTomlTemplateFile() + imagesJsonContent := generateImagesJsonFile("18") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) versionTests := []struct { - Name string - Metadata map[string]interface{} - RunDockerfileProps ubinodejsextension.RunDockerfileProps - BuildDockerfileProps ubinodejsextension.BuildDockerfileProps - buildDockerfileExpectedNodejsVersion int + requestedNodeVersion string + expectedNodeVersion int }{ { - Name: "node", - Metadata: map[string]interface{}{ - "version": ">16", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: ">16", + expectedNodeVersion: 18, }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": ">13", - "version-source": "BP_NODE_VERSION", - }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - }, - BuildDockerfileProps: BuildDockerfileProps, - buildDockerfileExpectedNodejsVersion: 18, + requestedNodeVersion: ">13", + expectedNodeVersion: 18, }, } for _, tt := range versionTests { - - generateResult, err = generate(packit.GenerateContext{ - WorkingDir: workingDir, - CNBPath: cnbDir, - Plan: packit.BuildpackPlan{ - Entries: []packit.BuildpackPlanEntry{ - { - Name: tt.Name, - Metadata: tt.Metadata, + buildplan := packit.BuildpackPlan{ + Entries: []packit.BuildpackPlanEntry{ + { + Name: "node", + Metadata: map[string]interface{}{ + "version": tt.requestedNodeVersion, + "version-source": "BP_NODE_VERSION", }, }, }, - Stack: "io.buildpacks.stacks.ubi8", + } + + generateResult, err = generate(packit.GenerateContext{ + WorkingDir: workingDir, + Plan: buildplan, + Stack: "io.buildpacks.stacks.ubi8", }) Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.RunDockerfileProps, runDockerfileTemplate) - tt.BuildDockerfileProps.NODEJS_VERSION = uint64(tt.buildDockerfileExpectedNodejsVersion) - buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.BuildDockerfileProps, buildDockerfileTemplate) + runDockerFileProps := ubinodejsextension.RunDockerfileProps{ + Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), + } + runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) + + buildDockerfileProps := ubinodejsextension.BuildDockerfileProps{ + CNB_USER_ID: 1002, + CNB_GROUP_ID: 1000, + CNB_STACK_ID: "io.buildpacks.stacks.ubi8", + PACKAGES: ubinodejsextension.PACKAGES, + NODEJS_VERSION: uint64(tt.expectedNodeVersion), + } + + buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(buildDockerfileProps, buildDockerfileTemplate) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -609,86 +536,66 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { _, _ = io.Copy(buf, generateResult.BuildDockerfile) Expect(buf.String()).To(Equal(buildDockerfileContent)) } - }) it("Should error on below cases of requested node", func() { - extensionToml, _ := readExtensionTomlTemplateFile() + imagesJsonContent := generateImagesJsonFile("18") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) versionTests := []struct { - Name string - Metadata map[string]interface{} + requestedNodeVersion string }{ { - Name: "node", - Metadata: map[string]interface{}{ - "version": "17 - 18.0.0", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: "17 - 18.0.0", }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "15", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: "15", }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "18.0.0", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: "18.0.0", }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "v18.999.0", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: "v18.999.0", }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": ">18", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: ">18", }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "~16.2", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: "~16.2", }, { - Name: "node", - Metadata: map[string]interface{}{ - "version": "16.5.x", - "version-source": "BP_NODE_VERSION", - }, + requestedNodeVersion: "16.5.x", }, } for _, tt := range versionTests { - generateResult, err = generate(packit.GenerateContext{ - WorkingDir: workingDir, - CNBPath: cnbDir, - Plan: packit.BuildpackPlan{ - Entries: []packit.BuildpackPlanEntry{ - { - Name: tt.Name, - Metadata: tt.Metadata, + buildplan := packit.BuildpackPlan{ + Entries: []packit.BuildpackPlanEntry{ + { + Name: "node", + Metadata: map[string]interface{}{ + "version": tt.requestedNodeVersion, + "version-source": "BP_NODE_VERSION", }, }, }, - Stack: "io.buildpacks.stacks.ubi8", + } + + generateResult, err = generate(packit.GenerateContext{ + WorkingDir: workingDir, + Plan: buildplan, + Stack: "io.buildpacks.stacks.ubi8", }) Expect(err).To(HaveOccurred()) @@ -702,9 +609,6 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it.Before(func() { workingDir = t.TempDir() - cnbDir, err = os.MkdirTemp("", "cnb") - - generate = ubinodejsextension.Generate(dependencyManager, logger, ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}) err = toml.NewEncoder(buf).Encode(testBuildPlan) Expect(err).NotTo(HaveOccurred()) @@ -720,15 +624,22 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it.After(func() { Expect(os.RemoveAll(workingDir)).To(Succeed()) + Expect(os.RemoveAll(imagesJsonTmpDir)).To(Succeed()) }) it("Should respect the priorities and return the proper Node.js version", func() { - extensionToml, _ := readExtensionTomlTemplateFile() + imagesJsonContent := generateImagesJsonFile("18") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) entriesTests := []struct { Entries []packit.BuildpackPlanEntry @@ -793,7 +704,6 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generateResult, err = generate(packit.GenerateContext{ WorkingDir: workingDir, - CNBPath: cnbDir, Plan: packit.BuildpackPlan{ Entries: tt.Entries, }, @@ -812,48 +722,12 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { }) - it("Should error in case there are no entries in the buildpack plan.", func() { - - extensionToml, _ := readExtensionTomlTemplateFile() - - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) - - entriesTests := []struct { - Entries []packit.BuildpackPlanEntry - }{ - { - Entries: []packit.BuildpackPlanEntry{}, - }, - } - - for _, tt := range entriesTests { - - generateResult, err = generate(packit.GenerateContext{ - WorkingDir: workingDir, - CNBPath: cnbDir, - Plan: packit.BuildpackPlan{ - Entries: tt.Entries, - }, - Stack: "io.buildpacks.stacks.ubi8", - }) - - Expect(err).To(HaveOccurred()) - - } - - }) }, spec.Sequential()) context("When BP_UBI_RUN_IMAGE_OVERRIDE env has been set", func() { it.Before(func() { - workingDir = t.TempDir() - cnbDir, err = os.MkdirTemp("", "cnb") - - generate = ubinodejsextension.Generate(dependencyManager, logger, ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}) err = toml.NewEncoder(buf).Encode(testBuildPlan) Expect(err).NotTo(HaveOccurred()) @@ -873,11 +747,17 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should have the same value as the BP_UBI_RUN_IMAGE_OVERRIDE if is not empty string", func() { - extensionToml, _ := readExtensionTomlTemplateFile() + imagesJsonContent := generateImagesJsonFile("18") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) entriesTests := []struct { Entries []packit.BuildpackPlanEntry @@ -899,7 +779,6 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generateResult, err = generate(packit.GenerateContext{ WorkingDir: workingDir, - CNBPath: cnbDir, Plan: packit.BuildpackPlan{ Entries: tt.Entries, }, @@ -923,11 +802,17 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should fallback to the run image which corresponds to the selected node version during build", func() { - extensionToml, _ := readExtensionTomlTemplateFile() + imagesJsonContent := generateImagesJsonFile("18") + imagesJsonTmpDir = t.TempDir() + imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - cnbDir, err = os.MkdirTemp("", "cnb") - Expect(err).NotTo(HaveOccurred()) - Expect(os.WriteFile(cnbDir+"/extension.toml", []byte(extensionToml), 0600)).To(Succeed()) + generate = ubinodejsextension.Generate( + dependencyManager, + logger, + ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + imagesJsonPath, + ) entriesTests := []struct { Entries []packit.BuildpackPlanEntry @@ -951,7 +836,6 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generateResult, err = generate(packit.GenerateContext{ WorkingDir: workingDir, - CNBPath: cnbDir, Plan: packit.BuildpackPlan{ Entries: tt.Entries, }, @@ -976,40 +860,98 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { } -func readExtensionTomlTemplateFile(defaultNodeVersion ...string) (string, error) { - var version string - if len(defaultNodeVersion) == 0 { - version = "18.*.*" - } else { - version = defaultNodeVersion[0] - } +func generateImagesJsonFile(defaultNodeVersion string) string { - template := ` -api = "0.7" - -[extension] -id = "redhat-runtimes/nodejs" -name = "RedHat Runtimes Node.js Dependency Extension" -version = "0.0.1" -description = "This extension installs the appropriate nodejs runtime via dnf" - -[metadata] - [metadata.default-versions] - node = "%s" - - [[metadata.dependencies]] - id = "node" - name = "Ubi Node Extension" - stacks = ["io.buildpacks.stacks.ubi8"] - source = "paketocommunity/run-nodejs-18-ubi-base" - version = "18.1000" - - [[metadata.dependencies]] - id = "node" - name = "Ubi Node Extension" - stacks = ["io.buildpacks.stacks.ubi8"] - source = "paketocommunity/run-nodejs-16-ubi-base" - version = "16.1000" - ` - return fmt.Sprintf(template, version), nil + var isDefaultNodeRunImage16 bool + var isDefaultNodeRunImage18 bool + + if defaultNodeVersion == "16" { + isDefaultNodeRunImage16 = true + isDefaultNodeRunImage18 = false + } else if defaultNodeVersion == "18" { + isDefaultNodeRunImage16 = false + isDefaultNodeRunImage18 = true + } + return fmt.Sprintf(`{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "build_image": "build", + "run_image": "run", + "build_receipt_filename": "build-receipt.cyclonedx.json", + "run_receipt_filename": "run-receipt.cyclonedx.json", + "create_build_image": true, + "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" + }, + { + "name": "java-8", + "config_dir": "stack-java-8", + "output_dir": "build-java-8", + "build_image": "build-java-8", + "run_image": "run-java-8", + "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" + }, + { + "name": "java-11", + "config_dir": "stack-java-11", + "output_dir": "build-java-11", + "build_image": "build-java-11", + "run_image": "run-java-11", + "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }, + { + "name": "nodejs-16", + "is_default_run_image": %t, + "config_dir": "stack-nodejs-16", + "output_dir": "build-nodejs-16", + "build_image": "build-nodejs-16", + "run_image": "run-nodejs-16", + "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" + }, + { + "name": "nodejs-18", + "is_default_run_image": %t, + "config_dir": "stack-nodejs-18", + "output_dir": "build-nodejs-18", + "build_image": "build-nodejs-18", + "run_image": "run-nodejs-18", + "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" + } + ] + } +`, isDefaultNodeRunImage16, isDefaultNodeRunImage18) } From 406cafa56fd1b462ffd674c519bbf89e6844cd12 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Mon, 9 Sep 2024 22:17:49 +0300 Subject: [PATCH 11/19] using structs --- generate.go | 62 +++------------------------------- generate_test.go | 74 ++++++++++++++++------------------------- internal/utils/utils.go | 41 +++++++++++++++++++++++ run/main.go | 3 +- structs/structs.go | 15 +++++++++ 5 files changed, 90 insertions(+), 105 deletions(-) create mode 100644 structs/structs.go diff --git a/generate.go b/generate.go index 312917d..a916d20 100644 --- a/generate.go +++ b/generate.go @@ -4,12 +4,11 @@ import ( "bytes" _ "embed" "os" - "regexp" - "strconv" "strings" "text/template" "github.com/paketo-community/ubi-nodejs-extension/internal/utils" + "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/Masterminds/semver/v3" "github.com/paketo-buildpacks/libnodejs" @@ -24,26 +23,12 @@ const DEFAULT_USER_ID = 1002 const DEFAULT_GROUP_ID = 1000 const CONFIG_TOML_PATH = "/tmp/config.toml" -type DuringBuildPermissions struct { - CNB_USER_ID, CNB_GROUP_ID int -} - //go:embed templates/build.Dockerfile var buildDockerfileTemplate string -type BuildDockerfileProps struct { - NODEJS_VERSION uint64 - CNB_USER_ID, CNB_GROUP_ID int - CNB_STACK_ID, PACKAGES string -} - //go:embed templates/run.Dockerfile var runDockerfileTemplate string -type RunDockerfileProps struct { - Source string -} - //go:generate faux --interface DependencyManager --output fakes/dependency_manager.go type DependencyManager interface { Resolve(path, id, version, stack string) (postal.Dependency, error) @@ -51,7 +36,7 @@ type DependencyManager interface { GenerateBillOfMaterials(dependencies ...postal.Dependency) []packit.BOMEntry } -func Generate(dependencyManager DependencyManager, logger scribe.Emitter, duringBuildPermissions DuringBuildPermissions, imagesJsonPath string) packit.GenerateFunc { +func Generate(dependencyManager DependencyManager, logger scribe.Emitter, duringBuildPermissions structs.DuringBuildPermissions, imagesJsonPath string) packit.GenerateFunc { return func(context packit.GenerateContext) (packit.GenerateResult, error) { logger.Title("%s %s", context.Info.Name, context.Info.Version) @@ -118,7 +103,7 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Process("Selected Node Engine Major version %d", selectedNodeMajorVersion) // Generating build.Dockerfile - buildDockerfileContent, err := FillPropsToTemplate(BuildDockerfileProps{ + buildDockerfileContent, err := FillPropsToTemplate(structs.BuildDockerfileProps{ NODEJS_VERSION: selectedNodeMajorVersion, CNB_USER_ID: duringBuildPermissions.CNB_USER_ID, CNB_GROUP_ID: duringBuildPermissions.CNB_GROUP_ID, @@ -131,7 +116,7 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during } // Generating run.Dockerfile - runDockerfileContent, err := FillPropsToTemplate(RunDockerfileProps{ + runDockerfileContent, err := FillPropsToTemplate(structs.RunDockerfileProps{ Source: selectedNodeRunImage, }, runDockerfileTemplate) @@ -162,42 +147,3 @@ func FillPropsToTemplate(properties interface{}, templateString string) (result return buf.String(), nil } - -func GetDuringBuildPermissions(filepath string) DuringBuildPermissions { - - defaultPermissions := DuringBuildPermissions{ - CNB_USER_ID: DEFAULT_USER_ID, - CNB_GROUP_ID: DEFAULT_GROUP_ID, - } - re := regexp.MustCompile(`cnb:x:(\d+):(\d+)::`) - - etcPasswdFile, err := os.ReadFile(filepath) - - if err != nil { - return defaultPermissions - } - etcPasswdContent := string(etcPasswdFile) - - matches := re.FindStringSubmatch(etcPasswdContent) - - if len(matches) != 3 { - return defaultPermissions - } - - CNB_USER_ID, err := strconv.Atoi(matches[1]) - - if err != nil { - return defaultPermissions - } - - CNB_GROUP_ID, err := strconv.Atoi(matches[2]) - - if err != nil { - return defaultPermissions - } - - return DuringBuildPermissions{ - CNB_USER_ID: CNB_USER_ID, - CNB_GROUP_ID: CNB_GROUP_ID, - } -} diff --git a/generate_test.go b/generate_test.go index b606b1a..43ef13e 100644 --- a/generate_test.go +++ b/generate_test.go @@ -14,6 +14,8 @@ import ( "github.com/paketo-buildpacks/packit/cargo" "github.com/paketo-buildpacks/packit/v2" ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" + "github.com/paketo-community/ubi-nodejs-extension/internal/utils" + "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/sclevine/spec" "github.com/paketo-buildpacks/packit/v2/scribe" @@ -123,10 +125,10 @@ cnb:x:1234:2345::/home/cnb:/bin/bash nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin `), 0600)).To(Succeed()) - duringBuilderPermissions := ubinodejsextension.GetDuringBuildPermissions(path) + duringBuilderPermissions := utils.GetDuringBuildPermissions(path) Expect(duringBuilderPermissions).To(Equal( - ubinodejsextension.DuringBuildPermissions{ + structs.DuringBuildPermissions{ CNB_USER_ID: 1234, CNB_GROUP_ID: 2345, }, @@ -157,10 +159,10 @@ ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin `), 0600)).To(Succeed()) - duringBuilderPermissions := ubinodejsextension.GetDuringBuildPermissions(path) + duringBuilderPermissions := utils.GetDuringBuildPermissions(path) Expect(duringBuilderPermissions).To(Equal( - ubinodejsextension.DuringBuildPermissions{ + structs.DuringBuildPermissions{ CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, )) @@ -173,10 +175,10 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin tmpDir, err = os.MkdirTemp("", "") Expect(err).NotTo(HaveOccurred()) - duringBuilderPermissions := ubinodejsextension.GetDuringBuildPermissions(tmpDir) + duringBuilderPermissions := utils.GetDuringBuildPermissions(tmpDir) Expect(duringBuilderPermissions).To(Equal( - ubinodejsextension.DuringBuildPermissions{ + structs.DuringBuildPermissions{ CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, )) @@ -213,7 +215,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, "/path/to/images.json") err = toml.NewEncoder(buf).Encode(testBuildPlan) @@ -277,7 +279,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) @@ -354,12 +356,12 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerFileProps := ubinodejsextension.RunDockerfileProps{ + runDockerFileProps := structs.RunDockerfileProps{ Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), } runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) - buildDockerfileProps := ubinodejsextension.BuildDockerfileProps{ + buildDockerfileProps := structs.BuildDockerfileProps{ CNB_USER_ID: 1002, CNB_GROUP_ID: 1000, CNB_STACK_ID: "io.buildpacks.stacks.ubi8", @@ -389,7 +391,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) @@ -439,12 +441,12 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerFileProps := ubinodejsextension.RunDockerfileProps{ + runDockerFileProps := structs.RunDockerfileProps{ Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), } runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) - buildDockerfileProps := ubinodejsextension.BuildDockerfileProps{ + buildDockerfileProps := structs.BuildDockerfileProps{ CNB_USER_ID: 1002, CNB_GROUP_ID: 1000, CNB_STACK_ID: "io.buildpacks.stacks.ubi8", @@ -474,7 +476,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) @@ -514,12 +516,12 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerFileProps := ubinodejsextension.RunDockerfileProps{ + runDockerFileProps := structs.RunDockerfileProps{ Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), } runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) - buildDockerfileProps := ubinodejsextension.BuildDockerfileProps{ + buildDockerfileProps := structs.BuildDockerfileProps{ CNB_USER_ID: 1002, CNB_GROUP_ID: 1000, CNB_STACK_ID: "io.buildpacks.stacks.ubi8", @@ -548,7 +550,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) @@ -637,13 +639,13 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) entriesTests := []struct { Entries []packit.BuildpackPlanEntry - RunDockerfileProps ubinodejsextension.RunDockerfileProps + RunDockerfileProps structs.RunDockerfileProps }{ { Entries: []packit.BuildpackPlanEntry{ @@ -664,7 +666,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Metadata: map[string]interface{}{"version": "=16", "version-source": "BP_NODE_VERSION"}, }, }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ + RunDockerfileProps: structs.RunDockerfileProps{ Source: "paketocommunity/run-nodejs-16-ubi-base", }, }, @@ -683,7 +685,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Metadata: map[string]interface{}{"version": "=16", "version-source": "package.json"}, }, }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ + RunDockerfileProps: structs.RunDockerfileProps{ Source: "paketocommunity/run-nodejs-16-ubi-base", }, }, @@ -694,7 +696,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Metadata: map[string]interface{}{"version": "=16", "version-source": ".node-version"}, }, }, - RunDockerfileProps: ubinodejsextension.RunDockerfileProps{ + RunDockerfileProps: structs.RunDockerfileProps{ Source: "paketocommunity/run-nodejs-16-ubi-base", }, }, @@ -755,7 +757,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) @@ -788,7 +790,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - RunDockerfileProps := ubinodejsextension.RunDockerfileProps{ + RunDockerfileProps := structs.RunDockerfileProps{ Source: tt.BP_UBI_RUN_IMAGE_OVERRIDE, } @@ -810,7 +812,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { generate = ubinodejsextension.Generate( dependencyManager, logger, - ubinodejsextension.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, + structs.DuringBuildPermissions{CNB_USER_ID: 1002, CNB_GROUP_ID: 1000}, imagesJsonPath, ) @@ -845,7 +847,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - RunDockerfileProps := ubinodejsextension.RunDockerfileProps{ + RunDockerfileProps := structs.RunDockerfileProps{ Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.selectedNodeVersion), } @@ -889,26 +891,6 @@ func generateImagesJsonFile(defaultNodeVersion string) string { "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" }, - { - "name": "java-8", - "config_dir": "stack-java-8", - "output_dir": "build-java-8", - "build_image": "build-java-8", - "run_image": "run-java-8", - "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" - }, - { - "name": "java-11", - "config_dir": "stack-java-11", - "output_dir": "build-java-11", - "build_image": "build-java-11", - "run_image": "run-java-11", - "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" - }, { "name": "java-17", "config_dir": "stack-java-17", diff --git a/internal/utils/utils.go b/internal/utils/utils.go index d020704..eb0f5c6 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -10,6 +10,8 @@ import ( "strconv" "strings" + "github.com/paketo-community/ubi-nodejs-extension/structs" + "github.com/BurntSushi/toml" ) @@ -111,3 +113,42 @@ func ParseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { return imagesJsonData, nil } + +func GetDuringBuildPermissions(filepath string) structs.DuringBuildPermissions { + + defaultPermissions := structs.DuringBuildPermissions{ + CNB_USER_ID: 1002, + CNB_GROUP_ID: 1000, + } + re := regexp.MustCompile(`cnb:x:(\d+):(\d+)::`) + + etcPasswdFile, err := os.ReadFile(filepath) + + if err != nil { + return defaultPermissions + } + etcPasswdContent := string(etcPasswdFile) + + matches := re.FindStringSubmatch(etcPasswdContent) + + if len(matches) != 3 { + return defaultPermissions + } + + CNB_USER_ID, err := strconv.Atoi(matches[1]) + + if err != nil { + return defaultPermissions + } + + CNB_GROUP_ID, err := strconv.Atoi(matches[2]) + + if err != nil { + return defaultPermissions + } + + return structs.DuringBuildPermissions{ + CNB_USER_ID: CNB_USER_ID, + CNB_GROUP_ID: CNB_GROUP_ID, + } +} diff --git a/run/main.go b/run/main.go index fd097e0..b4afe1a 100644 --- a/run/main.go +++ b/run/main.go @@ -9,6 +9,7 @@ import ( "github.com/paketo-buildpacks/packit/v2/scribe" ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" + "github.com/paketo-community/ubi-nodejs-extension/internal/utils" ) const IMAGES_JSON_PATH = "/etc/buildpacks/images.json" @@ -16,7 +17,7 @@ const IMAGES_JSON_PATH = "/etc/buildpacks/images.json" func main() { dependencyManager := postal.NewService(cargo.NewTransport()) logEmitter := scribe.NewEmitter(os.Stdout).WithLevel(os.Getenv("BP_LOG_LEVEL")) - duringBuildPermissions := ubinodejsextension.GetDuringBuildPermissions("/etc/passwd") + duringBuildPermissions := utils.GetDuringBuildPermissions("/etc/passwd") packit.RunExtension( ubinodejsextension.Detect(), diff --git a/structs/structs.go b/structs/structs.go new file mode 100644 index 0000000..3bc5050 --- /dev/null +++ b/structs/structs.go @@ -0,0 +1,15 @@ +package structs + +type DuringBuildPermissions struct { + CNB_USER_ID, CNB_GROUP_ID int +} + +type BuildDockerfileProps struct { + NODEJS_VERSION uint64 + CNB_USER_ID, CNB_GROUP_ID int + CNB_STACK_ID, PACKAGES string +} + +type RunDockerfileProps struct { + Source string +} From 4b1645c9d53c6fb141de3e0fb69c162b0568020a Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Tue, 10 Sep 2024 11:28:11 +0300 Subject: [PATCH 12/19] refactor: moving rest of the utils under utils package --- generate.go | 33 +-- generate_test.go | 272 ++---------------- init_test.go | 2 - internal/utils/init_test.go | 3 + .../utils/templates}/build.Dockerfile | 0 .../utils/templates}/run.Dockerfile | 0 internal/utils/testdata/images.json.parsed.go | 45 --- internal/utils/testdata/images_corrupted.json | 71 ----- .../testdata/images_no_node_version.json | 91 ------ .../images_node_version_not_integer.json | 91 ------ internal/utils/testdata/images_sample.json | 91 ------ internal/utils/utils.go | 117 ++++++++ internal/utils/utils_test.go | 266 +++++++++++++++-- 13 files changed, 384 insertions(+), 698 deletions(-) rename {templates => internal/utils/templates}/build.Dockerfile (100%) rename {templates => internal/utils/templates}/run.Dockerfile (100%) delete mode 100644 internal/utils/testdata/images.json.parsed.go delete mode 100644 internal/utils/testdata/images_corrupted.json delete mode 100644 internal/utils/testdata/images_no_node_version.json delete mode 100644 internal/utils/testdata/images_node_version_not_integer.json delete mode 100644 internal/utils/testdata/images_sample.json diff --git a/generate.go b/generate.go index a916d20..7493c14 100644 --- a/generate.go +++ b/generate.go @@ -1,11 +1,8 @@ package ubinodejsextension import ( - "bytes" - _ "embed" "os" "strings" - "text/template" "github.com/paketo-community/ubi-nodejs-extension/internal/utils" "github.com/paketo-community/ubi-nodejs-extension/structs" @@ -23,12 +20,6 @@ const DEFAULT_USER_ID = 1002 const DEFAULT_GROUP_ID = 1000 const CONFIG_TOML_PATH = "/tmp/config.toml" -//go:embed templates/build.Dockerfile -var buildDockerfileTemplate string - -//go:embed templates/run.Dockerfile -var runDockerfileTemplate string - //go:generate faux --interface DependencyManager --output fakes/dependency_manager.go type DependencyManager interface { Resolve(path, id, version, stack string) (postal.Dependency, error) @@ -103,22 +94,22 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Process("Selected Node Engine Major version %d", selectedNodeMajorVersion) // Generating build.Dockerfile - buildDockerfileContent, err := FillPropsToTemplate(structs.BuildDockerfileProps{ + buildDockerfileContent, err := utils.GenerateBuildDockerfile(structs.BuildDockerfileProps{ NODEJS_VERSION: selectedNodeMajorVersion, CNB_USER_ID: duringBuildPermissions.CNB_USER_ID, CNB_GROUP_ID: duringBuildPermissions.CNB_GROUP_ID, CNB_STACK_ID: context.Stack, PACKAGES: PACKAGES, - }, buildDockerfileTemplate) + }) if err != nil { return packit.GenerateResult{}, err } // Generating run.Dockerfile - runDockerfileContent, err := FillPropsToTemplate(structs.RunDockerfileProps{ + runDockerfileContent, err := utils.GenerateRunDockerfile(structs.RunDockerfileProps{ Source: selectedNodeRunImage, - }, runDockerfileTemplate) + }) if err != nil { return packit.GenerateResult{}, err @@ -131,19 +122,3 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during }, nil } } - -func FillPropsToTemplate(properties interface{}, templateString string) (result string, Error error) { - - templ, err := template.New("template").Parse(templateString) - if err != nil { - return "", err - } - - var buf bytes.Buffer - err = templ.Execute(&buf, properties) - if err != nil { - panic(err) - } - - return buf.String(), nil -} diff --git a/generate_test.go b/generate_test.go index 43ef13e..1e71f4c 100644 --- a/generate_test.go +++ b/generate_test.go @@ -24,168 +24,6 @@ import ( postal "github.com/paketo-buildpacks/packit/v2/postal" ) -type RunDockerfileProps struct { - Source string -} - -//go:embed templates/run.Dockerfile -var runDockerfileTemplate string - -type BuildDockerfileProps struct { - NODEJS_VERSION uint64 - CNB_USER_ID, CNB_GROUP_ID int - CNB_STACK_ID, PACKAGES string -} - -//go:embed templates/build.Dockerfile -var buildDockerfileTemplate string - -func testFillPropsToTemplate(t *testing.T, context spec.G, it spec.S) { - - var ( - Expect = NewWithT(t).Expect - ) - - context("Adding props on templates with FillPropsToTemplate", func() { - - it("Should fill with properties the template/build.Dockerfile", func() { - - output, err := ubinodejsextension.FillPropsToTemplate(BuildDockerfileProps{ - NODEJS_VERSION: 16, - CNB_USER_ID: 1000, - CNB_GROUP_ID: 1000, - CNB_STACK_ID: "", - PACKAGES: ubinodejsextension.PACKAGES, - }, buildDockerfileTemplate) - - Expect(err).NotTo(HaveOccurred()) - Expect(output).To(Equal(fmt.Sprintf(`ARG base_image -FROM ${base_image} - -USER root - -ARG build_id=0 -RUN echo ${build_id} - -RUN microdnf -y module enable nodejs:16 -RUN microdnf --setopt=install_weak_deps=0 --setopt=tsflags=nodocs install -y %s && microdnf clean all - -RUN echo uid:gid "1000:1000" -USER 1000:1000 - -RUN echo "CNB_STACK_ID: "`, ubinodejsextension.PACKAGES))) - - }) - - it("Should fill with properties the template/run.Dockerfile", func() { - - RunDockerfileProps := RunDockerfileProps{ - Source: "paketocommunity/run-nodejs-18-ubi-base", - } - - output, err := ubinodejsextension.FillPropsToTemplate(RunDockerfileProps, runDockerfileTemplate) - - Expect(err).NotTo(HaveOccurred()) - Expect(output).To(Equal(`FROM paketocommunity/run-nodejs-18-ubi-base`)) - - }) - }) -} - -func testFetchingPermissionsFromEtcPasswdFile(t *testing.T, context spec.G, it spec.S) { - - var ( - Expect = NewWithT(t).Expect - tmpDir string - path string - err error - ) - - context("/etc/passwd exists and has the cnb user", func() { - - it("It should return the permissions specified for the cnb user", func() { - tmpDir, err = os.MkdirTemp("", "") - Expect(err).NotTo(HaveOccurred()) - - path = filepath.Join(tmpDir, "/passwd") - - Expect(os.WriteFile(path, []byte(`root:x:0:0:root:/root:/bin/bash -bin:x:1:1:bin:/bin:/sbin/nologin -daemon:x:2:2:daemon:/sbin:/sbin/nologin -adm:x:3:4:adm:/var/adm:/sbin/nologin -lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin -sync:x:5:0:sync:/sbin:/bin/sync -shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown -halt:x:7:0:halt:/sbin:/sbin/halt -mail:x:8:12:mail:/var/spool/mail:/sbin/nologin -operator:x:11:0:operator:/root:/sbin/nologin -games:x:12:100:games:/usr/games:/sbin/nologin -ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin -cnb:x:1234:2345::/home/cnb:/bin/bash -nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin -`), 0600)).To(Succeed()) - - duringBuilderPermissions := utils.GetDuringBuildPermissions(path) - - Expect(duringBuilderPermissions).To(Equal( - structs.DuringBuildPermissions{ - CNB_USER_ID: 1234, - CNB_GROUP_ID: 2345, - }, - )) - }) - }) - - context("/etc/passwd exists and does NOT have the cnb user", func() { - - it("It should return the default permissions", func() { - tmpDir, err = os.MkdirTemp("", "") - Expect(err).NotTo(HaveOccurred()) - - path = filepath.Join(tmpDir, "/passwd") - - Expect(os.WriteFile(path, []byte(`root:x:0:0:root:/root:/bin/bash -bin:x:1:1:bin:/bin:/sbin/nologin -daemon:x:2:2:daemon:/sbin:/sbin/nologin -adm:x:3:4:adm:/var/adm:/sbin/nologin -lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin -sync:x:5:0:sync:/sbin:/bin/sync -shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown -halt:x:7:0:halt:/sbin:/sbin/halt -mail:x:8:12:mail:/var/spool/mail:/sbin/nologin -operator:x:11:0:operator:/root:/sbin/nologin -games:x:12:100:games:/usr/games:/sbin/nologin -ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin -nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin -`), 0600)).To(Succeed()) - - duringBuilderPermissions := utils.GetDuringBuildPermissions(path) - - Expect(duringBuilderPermissions).To(Equal( - structs.DuringBuildPermissions{ - CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, - CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, - )) - }) - }) - - context("/etc/passwd does NOT exist", func() { - - it("It should return the default permissions", func() { - tmpDir, err = os.MkdirTemp("", "") - Expect(err).NotTo(HaveOccurred()) - - duringBuilderPermissions := utils.GetDuringBuildPermissions(tmpDir) - - Expect(duringBuilderPermissions).To(Equal( - structs.DuringBuildPermissions{ - CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, - CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, - )) - }) - }) -} - func testGenerate(t *testing.T, context spec.G, it spec.S) { var ( @@ -271,7 +109,9 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Specific version of node requested", func() { - imagesJsonContent := generateImagesJsonFile("18") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + hello := fmt.Sprintf(imagesJsonContent) + fmt.Println(hello) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -359,7 +199,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { runDockerFileProps := structs.RunDockerfileProps{ Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), } - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) + runDockerfileContent, _ := utils.GenerateRunDockerfile(runDockerFileProps) buildDockerfileProps := structs.BuildDockerfileProps{ CNB_USER_ID: 1002, @@ -369,7 +209,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { NODEJS_VERSION: uint64(tt.expectedNodeVersion), } - buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(buildDockerfileProps, buildDockerfileTemplate) + buildDockerfileContent, _ := utils.GenerateBuildDockerfile(buildDockerfileProps) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -383,7 +223,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("should return the default when node version has NOT been requested", func() { - imagesJsonContent := generateImagesJsonFile("16") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{true, false}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -445,7 +285,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), } - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) + runDockerfileContent, _ := utils.GenerateRunDockerfile(runDockerFileProps) buildDockerfileProps := structs.BuildDockerfileProps{ CNB_USER_ID: 1002, CNB_GROUP_ID: 1000, @@ -454,7 +294,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { NODEJS_VERSION: uint64(tt.expectedNodeVersion), } - buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(buildDockerfileProps, buildDockerfileTemplate) + buildDockerfileContent, _ := utils.GenerateBuildDockerfile(buildDockerfileProps) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -468,7 +308,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("should return the higher node version when it requests for >=nodeVersion", func() { - imagesJsonContent := generateImagesJsonFile("18") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -519,7 +359,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { runDockerFileProps := structs.RunDockerfileProps{ Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.expectedNodeVersion), } - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(runDockerFileProps, runDockerfileTemplate) + runDockerfileContent, _ := utils.GenerateRunDockerfile(runDockerFileProps) buildDockerfileProps := structs.BuildDockerfileProps{ CNB_USER_ID: 1002, @@ -529,7 +369,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { NODEJS_VERSION: uint64(tt.expectedNodeVersion), } - buildDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(buildDockerfileProps, buildDockerfileTemplate) + buildDockerfileContent, _ := utils.GenerateBuildDockerfile(buildDockerfileProps) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -542,7 +382,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should error on below cases of requested node", func() { - imagesJsonContent := generateImagesJsonFile("18") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -631,7 +471,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should respect the priorities and return the proper Node.js version", func() { - imagesJsonContent := generateImagesJsonFile("18") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -715,7 +555,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(generateResult).NotTo(Equal(nil)) - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(tt.RunDockerfileProps, runDockerfileTemplate) + runDockerfileContent, _ := utils.GenerateRunDockerfile(tt.RunDockerfileProps) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -749,7 +589,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should have the same value as the BP_UBI_RUN_IMAGE_OVERRIDE if is not empty string", func() { - imagesJsonContent := generateImagesJsonFile("18") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -794,7 +634,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Source: tt.BP_UBI_RUN_IMAGE_OVERRIDE, } - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(RunDockerfileProps, runDockerfileTemplate) + runDockerfileContent, _ := utils.GenerateRunDockerfile(RunDockerfileProps) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -804,7 +644,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should fallback to the run image which corresponds to the selected node version during build", func() { - imagesJsonContent := generateImagesJsonFile("18") + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -851,7 +691,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { Source: fmt.Sprintf("paketocommunity/run-nodejs-%d-ubi-base", tt.selectedNodeVersion), } - runDockerfileContent, _ := ubinodejsextension.FillPropsToTemplate(RunDockerfileProps, runDockerfileTemplate) + runDockerfileContent, _ := utils.GenerateRunDockerfile(RunDockerfileProps) buf := new(strings.Builder) _, _ = io.Copy(buf, generateResult.RunDockerfile) @@ -861,79 +701,3 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { }, spec.Sequential()) } - -func generateImagesJsonFile(defaultNodeVersion string) string { - - var isDefaultNodeRunImage16 bool - var isDefaultNodeRunImage18 bool - - if defaultNodeVersion == "16" { - isDefaultNodeRunImage16 = true - isDefaultNodeRunImage18 = false - } else if defaultNodeVersion == "18" { - isDefaultNodeRunImage16 = false - isDefaultNodeRunImage18 = true - } - return fmt.Sprintf(`{ - "support_usns": false, - "update_on_new_image": true, - "receipts_show_limit": 16, - "images": [ - { - "name": "default", - "config_dir": "stack", - "output_dir": "build", - "build_image": "build", - "run_image": "run", - "build_receipt_filename": "build-receipt.cyclonedx.json", - "run_receipt_filename": "run-receipt.cyclonedx.json", - "create_build_image": true, - "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" - }, - { - "name": "java-17", - "config_dir": "stack-java-17", - "output_dir": "build-java-17", - "build_image": "build-java-17", - "run_image": "run-java-17", - "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" - }, - { - "name": "java-21", - "config_dir": "stack-java-21", - "output_dir": "build-java-21", - "build_image": "build-java-21", - "run_image": "run-java-21", - "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" - }, - { - "name": "nodejs-16", - "is_default_run_image": %t, - "config_dir": "stack-nodejs-16", - "output_dir": "build-nodejs-16", - "build_image": "build-nodejs-16", - "run_image": "run-nodejs-16", - "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" - }, - { - "name": "nodejs-18", - "is_default_run_image": %t, - "config_dir": "stack-nodejs-18", - "output_dir": "build-nodejs-18", - "build_image": "build-nodejs-18", - "run_image": "run-nodejs-18", - "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" - } - ] - } -`, isDefaultNodeRunImage16, isDefaultNodeRunImage18) -} diff --git a/init_test.go b/init_test.go index 1b4736b..f843288 100644 --- a/init_test.go +++ b/init_test.go @@ -11,7 +11,5 @@ func TestUnitUbiNodejsExtension(t *testing.T) { suite := spec.New("ubi-nodejs-extension", spec.Report(report.Terminal{})) suite("Detect", testDetect) suite("Generate", testGenerate) - suite("Dockerfile Creation", testFillPropsToTemplate) - suite("Fetching during build permissions", testFetchingPermissionsFromEtcPasswdFile) suite.Run(t) } diff --git a/internal/utils/init_test.go b/internal/utils/init_test.go index 5e16ae0..ad7e769 100644 --- a/internal/utils/init_test.go +++ b/internal/utils/init_test.go @@ -13,5 +13,8 @@ func TestUnitUtils(t *testing.T) { suite("CreateConfigTomlFileContent", testCreateConfigTomlFileContent) suite("ParseImagesJsonFile", testParseImagesJsonFile) suite("GetNodejsStackImages", testGetNodejsStackImages) + suite("GetDuringBuildPermissions", testGetDuringBuildPermissions) + suite("testGenerateBuildDockerfile", testGenerateBuildDockerfile) + suite("testGenerateRunDockerfile", testGenerateRunDockerfile) suite.Run(t) } diff --git a/templates/build.Dockerfile b/internal/utils/templates/build.Dockerfile similarity index 100% rename from templates/build.Dockerfile rename to internal/utils/templates/build.Dockerfile diff --git a/templates/run.Dockerfile b/internal/utils/templates/run.Dockerfile similarity index 100% rename from templates/run.Dockerfile rename to internal/utils/templates/run.Dockerfile diff --git a/internal/utils/testdata/images.json.parsed.go b/internal/utils/testdata/images.json.parsed.go deleted file mode 100644 index 7df6484..0000000 --- a/internal/utils/testdata/images.json.parsed.go +++ /dev/null @@ -1,45 +0,0 @@ -package utils_testdata - -import "github.com/paketo-community/ubi-nodejs-extension/internal/utils" - -func GetParsedImages(filename string) utils.ImagesJson { - if filename == "images_sample.json" { - return utils.ImagesJson{ - StackImages: []utils.StackImages{ - { - Name: "default", - IsDefaultRunImage: false, - }, - { - Name: "java-8", - IsDefaultRunImage: false, - }, - { - Name: "java-11", - IsDefaultRunImage: false, - }, - { - Name: "java-17", - IsDefaultRunImage: false, - }, - { - Name: "java-21", - IsDefaultRunImage: false, - }, - { - Name: "nodejs-16", - IsDefaultRunImage: false, - }, - { - Name: "nodejs-18", - IsDefaultRunImage: false, - }, - { - Name: "nodejs-20", - IsDefaultRunImage: true, - }, - }, - } - } - return utils.ImagesJson{} -} diff --git a/internal/utils/testdata/images_corrupted.json b/internal/utils/testdata/images_corrupted.json deleted file mode 100644 index 0e8fe72..0000000 --- a/internal/utils/testdata/images_corrupted.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "support_usns": false, - "update_on_new_image": true, - "receipts_show_limit": 16, - "images": [ - { - "name": "default", - "config_dir": "stack", - "output_dir": "build", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" - }, - ge": "build-java-11", - "run_image": "run-java-11", - "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" - }, - { - "name": "java-17", - "config_dir": "stack-java-17", - "output_dir": "build-java-17", - "build_image": "build-java-17", - "run_image": "run-java-17", - "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" - }, - { - "name": "java-21", - "config_dir": "stack-java-21", - "output_dir": "build-java-21", - "build_image": "build-java-21", - "run_image": "run-java-21", - "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" - }, - { - "name": "nodejs-16", - "config_dir": "stack-nodejs-16", - "output_dir": "build-nodejs-16", - "build_image": "build-nodejs-16", - "run_image": "run-nodejs-16", - "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" - }, - { - "name": "nodejs-18", - "config_dir": "stack-nodejs-18", - "output_dir": "build-nodejs-18", - "build_image": "build-nodejs-18", - "run_image": "run-nodejs-18", - "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" - }, - { - "name": "nodejs-20", - "is_default_run_image": true, - "config_dir": "stack-nodejs-20", - "output_dir": "build-nodejs-20", - "build_image": "build-nodejs-20", - "run_image": "run-nodejs-20", - "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" - } - ] - } - \ No newline at end of file diff --git a/internal/utils/testdata/images_no_node_version.json b/internal/utils/testdata/images_no_node_version.json deleted file mode 100644 index 0e5263f..0000000 --- a/internal/utils/testdata/images_no_node_version.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "support_usns": false, - "update_on_new_image": true, - "receipts_show_limit": 16, - "images": [ - { - "name": "default", - "config_dir": "stack", - "output_dir": "build", - "build_image": "build", - "run_image": "run", - "build_receipt_filename": "build-receipt.cyclonedx.json", - "run_receipt_filename": "run-receipt.cyclonedx.json", - "create_build_image": true, - "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" - }, - { - "name": "java-8", - "config_dir": "stack-java-8", - "output_dir": "build-java-8", - "build_image": "build-java-8", - "run_image": "run-java-8", - "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" - }, - { - "name": "java-11", - "config_dir": "stack-java-11", - "output_dir": "build-java-11", - "build_image": "build-java-11", - "run_image": "run-java-11", - "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" - }, - { - "name": "java-17", - "config_dir": "stack-java-17", - "output_dir": "build-java-17", - "build_image": "build-java-17", - "run_image": "run-java-17", - "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" - }, - { - "name": "java-21", - "config_dir": "stack-java-21", - "output_dir": "build-java-21", - "build_image": "build-java-21", - "run_image": "run-java-21", - "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" - }, - { - "name": "nodejs-16", - "config_dir": "stack-nodejs-16", - "output_dir": "build-nodejs-16", - "build_image": "build-nodejs-16", - "run_image": "run-nodejs-16", - "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" - }, - { - "name": "nodejs-", - "config_dir": "stack-nodejs-18", - "output_dir": "build-nodejs-18", - "build_image": "build-nodejs-18", - "run_image": "run-nodejs-18", - "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" - }, - { - "name": "nodejs-20", - "is_default_run_image": true, - "config_dir": "stack-nodejs-20", - "output_dir": "build-nodejs-20", - "build_image": "build-nodejs-20", - "run_image": "run-nodejs-20", - "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" - } - ] - } - \ No newline at end of file diff --git a/internal/utils/testdata/images_node_version_not_integer.json b/internal/utils/testdata/images_node_version_not_integer.json deleted file mode 100644 index 81d4198..0000000 --- a/internal/utils/testdata/images_node_version_not_integer.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "support_usns": false, - "update_on_new_image": true, - "receipts_show_limit": 16, - "images": [ - { - "name": "default", - "config_dir": "stack", - "output_dir": "build", - "build_image": "build", - "run_image": "run", - "build_receipt_filename": "build-receipt.cyclonedx.json", - "run_receipt_filename": "run-receipt.cyclonedx.json", - "create_build_image": true, - "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" - }, - { - "name": "java-8", - "config_dir": "stack-java-8", - "output_dir": "build-java-8", - "build_image": "build-java-8", - "run_image": "run-java-8", - "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" - }, - { - "name": "java-11", - "config_dir": "stack-java-11", - "output_dir": "build-java-11", - "build_image": "build-java-11", - "run_image": "run-java-11", - "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" - }, - { - "name": "java-17", - "config_dir": "stack-java-17", - "output_dir": "build-java-17", - "build_image": "build-java-17", - "run_image": "run-java-17", - "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" - }, - { - "name": "java-21", - "config_dir": "stack-java-21", - "output_dir": "build-java-21", - "build_image": "build-java-21", - "run_image": "run-java-21", - "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" - }, - { - "name": "nodejs-16", - "config_dir": "stack-nodejs-16", - "output_dir": "build-nodejs-16", - "build_image": "build-nodejs-16", - "run_image": "run-nodejs-16", - "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" - }, - { - "name": "nodejs-18", - "config_dir": "stack-nodejs-18", - "output_dir": "build-nodejs-18", - "build_image": "build-nodejs-18", - "run_image": "run-nodejs-18", - "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" - }, - { - "name": "nodejs-hello", - "is_default_run_image": true, - "config_dir": "stack-nodejs-20", - "output_dir": "build-nodejs-20", - "build_image": "build-nodejs-20", - "run_image": "run-nodejs-20", - "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" - } - ] - } - \ No newline at end of file diff --git a/internal/utils/testdata/images_sample.json b/internal/utils/testdata/images_sample.json deleted file mode 100644 index ef663e1..0000000 --- a/internal/utils/testdata/images_sample.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "support_usns": false, - "update_on_new_image": true, - "receipts_show_limit": 16, - "images": [ - { - "name": "default", - "config_dir": "stack", - "output_dir": "build", - "build_image": "build", - "run_image": "run", - "build_receipt_filename": "build-receipt.cyclonedx.json", - "run_receipt_filename": "run-receipt.cyclonedx.json", - "create_build_image": true, - "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" - }, - { - "name": "java-8", - "config_dir": "stack-java-8", - "output_dir": "build-java-8", - "build_image": "build-java-8", - "run_image": "run-java-8", - "build_receipt_filename": "build-java-8-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-8-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-8-runtime" - }, - { - "name": "java-11", - "config_dir": "stack-java-11", - "output_dir": "build-java-11", - "build_image": "build-java-11", - "run_image": "run-java-11", - "build_receipt_filename": "build-java-11-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-11-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-11-runtime" - }, - { - "name": "java-17", - "config_dir": "stack-java-17", - "output_dir": "build-java-17", - "build_image": "build-java-17", - "run_image": "run-java-17", - "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" - }, - { - "name": "java-21", - "config_dir": "stack-java-21", - "output_dir": "build-java-21", - "build_image": "build-java-21", - "run_image": "run-java-21", - "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" - }, - { - "name": "nodejs-16", - "config_dir": "stack-nodejs-16", - "output_dir": "build-nodejs-16", - "build_image": "build-nodejs-16", - "run_image": "run-nodejs-16", - "build_receipt_filename": "build-nodejs-16-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-16-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-16-minimal" - }, - { - "name": "nodejs-18", - "config_dir": "stack-nodejs-18", - "output_dir": "build-nodejs-18", - "build_image": "build-nodejs-18", - "run_image": "run-nodejs-18", - "build_receipt_filename": "build-nodejs-18-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-18-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-18-minimal" - }, - { - "name": "nodejs-20", - "is_default_run_image": true, - "config_dir": "stack-nodejs-20", - "output_dir": "build-nodejs-20", - "build_image": "build-nodejs-20", - "run_image": "run-nodejs-20", - "build_receipt_filename": "build-nodejs-20-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-20-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-20-minimal" - } - ] - } - \ No newline at end of file diff --git a/internal/utils/utils.go b/internal/utils/utils.go index eb0f5c6..124fdab 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -1,6 +1,8 @@ package utils import ( + _ "embed" + "bytes" "encoding/json" "errors" @@ -9,12 +11,19 @@ import ( "regexp" "strconv" "strings" + "text/template" "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/BurntSushi/toml" ) +//go:embed templates/build.Dockerfile +var buildDockerfileTemplate string + +//go:embed templates/run.Dockerfile +var runDockerfileTemplate string + type StackImages struct { Name string `json:"name"` IsDefaultRunImage bool `json:"is_default_run_image,omitempty"` @@ -152,3 +161,111 @@ func GetDuringBuildPermissions(filepath string) structs.DuringBuildPermissions { CNB_GROUP_ID: CNB_GROUP_ID, } } + +func GenerateBuildDockerfile(buildProps structs.BuildDockerfileProps) (result string, Error error) { + + result, err := fillPropsToTemplate(buildProps, buildDockerfileTemplate) + + if err != nil { + return "", err + } + + return result, nil +} + +func GenerateRunDockerfile(runProps structs.RunDockerfileProps) (result string, Error error) { + + result, err := fillPropsToTemplate(runProps, runDockerfileTemplate) + + if err != nil { + return "", err + } + return result, nil +} + +func fillPropsToTemplate(properties interface{}, templateString string) (result string, Error error) { + + templ, err := template.New("template").Parse(templateString) + if err != nil { + return "", err + } + + var buf bytes.Buffer + err = templ.Execute(&buf, properties) + if err != nil { + panic(err) + } + + return buf.String(), nil +} + +func GenerateImagesJsonFile(nodeVersions []string, isDefault []bool, isCorrupted bool) string { + addStacks := "" + + for i, nodeVersion := range nodeVersions { + + addStacks += fmt.Sprintf(`, + { + "name": "nodejs-%s", + "is_default_run_image": %t, + "config_dir": "stack-nodejs-%s", + "output_dir": "build-nodejs-%s", + "build_image": "build-nodejs-%s", + "run_image": "run-nodejs-%s", + "build_receipt_filename": "build-nodejs-%s-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-%s-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-%s-runtime" + }`, nodeVersion, isDefault[i], nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion) + } + + if isCorrupted { + addStacks += `, + { + "name": "nodejs-18",} + not a valid json + }` + } + + stacks := fmt.Sprintf(`{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "build_image": "build", + "run_image": "run", + "build_receipt_filename": "build-receipt.cyclonedx.json", + "run_receipt_filename": "run-receipt.cyclonedx.json", + "create_build_image": true, + "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }%s + ] + } +`, addStacks) + + return stacks +} diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index cc317c9..159c7dc 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -2,13 +2,15 @@ package utils_test import ( _ "embed" + "fmt" "os" "path/filepath" "testing" . "github.com/onsi/gomega" + ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" "github.com/paketo-community/ubi-nodejs-extension/internal/utils" - utils_testdata "github.com/paketo-community/ubi-nodejs-extension/internal/utils/testdata" + "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/sclevine/spec" ) @@ -146,17 +148,43 @@ func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { }) it("successfully parses images.json file", func() { - cwd, err := os.Getwd() - if err != nil { - Expect(err).ToNot(HaveOccurred()) - } - imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(cwd, "/testdata/images_sample.json")) - Expect(err).ToNot(HaveOccurred()) + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, false) + imagesJsonTmpDir := t.TempDir() + imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) - imagesParsed := utils_testdata.GetParsedImages("images_sample.json") + imagesJsonData, err := utils.ParseImagesJsonFile(imagesJsonPath) + Expect(err).ToNot(HaveOccurred()) - Expect(imagesJsonData).To(Equal(imagesParsed)) + Expect(imagesJsonData).To(Equal(utils.ImagesJson{ + StackImages: []utils.StackImages{ + { + Name: "default", + IsDefaultRunImage: false, + }, + { + Name: "java-17", + IsDefaultRunImage: false, + }, + { + Name: "java-21", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-16", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-18", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-20", + IsDefaultRunImage: true, + }, + }, + })) }) it("erros when images.json file does not exist", func() { @@ -166,13 +194,15 @@ func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { Expect(imagesJsonData).To(Equal(utils.ImagesJson{})) }) - it("erros when images.json file is corrupted", func() { - cwd, err := os.Getwd() - if err != nil { - Expect(err).ToNot(HaveOccurred()) - } + it("erros when images.json file is not a valid json", func() { + + imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, true) + imagesJsonTmpDir := t.TempDir() + imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images_not_valid.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + + imagesJsonData, err := utils.ParseImagesJsonFile(imagesJsonPath) - imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(cwd, "/testdata/images_corrupted.json")) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid character")) Expect(imagesJsonData).To(Equal(utils.ImagesJson{})) @@ -188,8 +218,34 @@ func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { context("When passing the array with all the stacks", func() { it("should return only the nodejs stacks", func() { - allStacks := utils_testdata.GetParsedImages("images_sample.json") - nodejsStacks, err := utils.GetNodejsStackImages(allStacks) + nodejsStacks, err := utils.GetNodejsStackImages(utils.ImagesJson{ + StackImages: []utils.StackImages{ + { + Name: "default", + IsDefaultRunImage: false, + }, + { + Name: "java-17", + IsDefaultRunImage: false, + }, + { + Name: "java-21", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-16", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-18", + IsDefaultRunImage: false, + }, + { + Name: "nodejs-20", + IsDefaultRunImage: true, + }, + }, + }) Expect(err).ToNot(HaveOccurred()) Expect(nodejsStacks).To(Equal([]utils.StackImages{ @@ -215,10 +271,15 @@ func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { context("When node version is malformed or does not exist", func() { it("should error with a message", func() { - cwd, err := os.Getwd() - if err != nil { - Expect(err).ToNot(HaveOccurred()) - } + + imagesJsonTmpDir := t.TempDir() + imagesJsonNodeVersionNotIntegerContent := utils.GenerateImagesJsonFile([]string{"16", "18", "hello"}, []bool{false, false, true}, false) + imagesJsonNodeVersionNotIntegerPath := filepath.Join(imagesJsonTmpDir, "images_node_version_not_integer.json") + Expect(os.WriteFile(imagesJsonNodeVersionNotIntegerPath, []byte(imagesJsonNodeVersionNotIntegerContent), 0600)).To(Succeed()) + + imagesJsonNoNodeVersionContent := utils.GenerateImagesJsonFile([]string{"16", "", "20"}, []bool{false, false, true}, false) + imagesJsonNoNodeVersionPath := filepath.Join(imagesJsonTmpDir, "images_no_node_version.json") + Expect(os.WriteFile(imagesJsonNoNodeVersionPath, []byte(imagesJsonNoNodeVersionContent), 0600)).To(Succeed()) for _, tt := range []struct { errorMessage string @@ -226,14 +287,14 @@ func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { }{ { errorMessage: "extracted Node.js version [hello] for stack nodejs-hello is not an integer", - imagesJsonPath: "/testdata/images_node_version_not_integer.json", + imagesJsonPath: imagesJsonNodeVersionNotIntegerPath, }, { errorMessage: "extracted Node.js version [] for stack nodejs- is not an integer", - imagesJsonPath: "/testdata/images_no_node_version.json", + imagesJsonPath: imagesJsonNoNodeVersionPath, }, } { - imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(cwd, tt.imagesJsonPath)) + imagesJsonData, err := utils.ParseImagesJsonFile(filepath.Join(tt.imagesJsonPath)) Expect(err).ToNot(HaveOccurred()) nodejsStacks, err := utils.GetNodejsStackImages(imagesJsonData) @@ -244,3 +305,160 @@ func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { }) }) } + +func testGenerateBuildDockerfile(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + context("Adding props on build.dockerfile template", func() { + + it("Should fill with properties the template/build.Dockerfile", func() { + + output, err := utils.GenerateBuildDockerfile(structs.BuildDockerfileProps{ + NODEJS_VERSION: 16, + CNB_USER_ID: 1000, + CNB_GROUP_ID: 1000, + CNB_STACK_ID: "io.buildpacks.stacks.ubi8", + PACKAGES: ubinodejsextension.PACKAGES, + }) + + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(Equal(fmt.Sprintf(`ARG base_image +FROM ${base_image} + +USER root + +ARG build_id=0 +RUN echo ${build_id} + +RUN microdnf -y module enable nodejs:16 +RUN microdnf --setopt=install_weak_deps=0 --setopt=tsflags=nodocs install -y %s && microdnf clean all + +RUN echo uid:gid "1000:1000" +USER 1000:1000 + +RUN echo "CNB_STACK_ID: io.buildpacks.stacks.ubi8"`, ubinodejsextension.PACKAGES))) + + }) + + }) +} + +func testGenerateRunDockerfile(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + context("Adding props on build.dockerfile template", func() { + + it("Should fill with properties the template/run.Dockerfile", func() { + + RunDockerfileProps := structs.RunDockerfileProps{ + Source: "paketocommunity/run-nodejs-18-ubi-base", + } + + output, err := utils.GenerateRunDockerfile(RunDockerfileProps) + + Expect(err).NotTo(HaveOccurred()) + Expect(output).To(Equal(`FROM paketocommunity/run-nodejs-18-ubi-base`)) + + }) + }) +} + +func testGetDuringBuildPermissions(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + tmpDir string + path string + err error + ) + + context("/etc/passwd exists and has the cnb user", func() { + + it("It should return the permissions specified for the cnb user", func() { + tmpDir, err = os.MkdirTemp("", "") + Expect(err).NotTo(HaveOccurred()) + + path = filepath.Join(tmpDir, "/passwd") + + Expect(os.WriteFile(path, []byte(`root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +adm:x:3:4:adm:/var/adm:/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/sbin/nologin +operator:x:11:0:operator:/root:/sbin/nologin +games:x:12:100:games:/usr/games:/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin +cnb:x:1234:2345::/home/cnb:/bin/bash +nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin +`), 0600)).To(Succeed()) + + duringBuilderPermissions := utils.GetDuringBuildPermissions(path) + + Expect(duringBuilderPermissions).To(Equal( + structs.DuringBuildPermissions{ + CNB_USER_ID: 1234, + CNB_GROUP_ID: 2345, + }, + )) + }) + }) + + context("/etc/passwd exists and does NOT have the cnb user", func() { + + it("It should return the default permissions", func() { + tmpDir, err = os.MkdirTemp("", "") + Expect(err).NotTo(HaveOccurred()) + + path = filepath.Join(tmpDir, "/passwd") + + Expect(os.WriteFile(path, []byte(`root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +adm:x:3:4:adm:/var/adm:/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/sbin/nologin +operator:x:11:0:operator:/root:/sbin/nologin +games:x:12:100:games:/usr/games:/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin +nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin +`), 0600)).To(Succeed()) + + duringBuildPermissions := utils.GetDuringBuildPermissions(path) + + Expect(duringBuildPermissions).To(Equal( + structs.DuringBuildPermissions{ + CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, + CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, + )) + }) + }) + + context("/etc/passwd does NOT exist", func() { + + it("It should return the default permissions", func() { + tmpDir, err = os.MkdirTemp("", "") + Expect(err).NotTo(HaveOccurred()) + + duringBuilderPermissions := utils.GetDuringBuildPermissions(tmpDir) + + Expect(duringBuilderPermissions).To(Equal( + structs.DuringBuildPermissions{ + CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, + CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, + )) + }) + }) +} From d98d467fa13ae13c1ae3410dc388210d3bf87f00 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Tue, 10 Sep 2024 14:26:55 +0300 Subject: [PATCH 13/19] fixing integration tests to work with copied images.json --- integration/init_test.go | 16 ---------------- integration/provides_test.go | 5 ++--- integration/simple_app_test.go | 7 +++---- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/integration/init_test.go b/integration/init_test.go index 3172487..4285230 100644 --- a/integration/init_test.go +++ b/integration/init_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "os" "path/filepath" - "sort" "testing" "time" @@ -40,16 +39,6 @@ var settings struct { } Metadata struct { - DefaultVersions struct { - Node string `toml:"node"` - } `toml:"default-versions"` - Dependencies []struct { - ID string `toml:"id"` - Name string `toml:"name"` - Stacks []string `toml:"stacks"` - Source string `toml:"source"` - Version string `toml:"version"` - } `toml:"dependencies"` } `toml:"metadata"` Config struct { @@ -69,11 +58,6 @@ func TestIntegration(t *testing.T) { Expect(err).NotTo(HaveOccurred()) Expect(file.Close()).To(Succeed()) - // order by descending version - sort.Slice(settings.Metadata.Dependencies, func(i, j int) bool { - return settings.Metadata.Dependencies[i].Version > settings.Metadata.Dependencies[j].Version - }) - //reading the integration.json file file, err = os.Open("../integration.json") Expect(err).NotTo(HaveOccurred()) diff --git a/integration/provides_test.go b/integration/provides_test.go index c32db32..e759e11 100644 --- a/integration/provides_test.go +++ b/integration/provides_test.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "testing" "github.com/paketo-buildpacks/occam" @@ -70,12 +69,12 @@ func testProvides(t *testing.T, context spec.G, it spec.S) { " Candidate version sources (in priority order):", " -> \"\"")) - Expect(logs).To(ContainLines(fmt.Sprintf(" Selected Node Engine Major version %s", strings.Split(settings.Metadata.DefaultVersions.Node, ".")[0]))) + Expect(logs).To(ContainLines(MatchRegexp(` Selected Node Engine Major version \d+`))) Expect(logs).To(ContainLines("===> RESTORING")) Expect(logs).To(ContainLines("===> EXTENDING (BUILD)")) Expect(logs).To(ContainLines( "[extender (build)] Enabling module streams:", - fmt.Sprintf("[extender (build)] nodejs:%s", strings.Split(settings.Metadata.DefaultVersions.Node, ".")[0]))) + MatchRegexp(`\[extender \(build\)\] nodejs:\d+`))) // SBOM is not supported at the moment from UBI image // therefore there are no available logs to test/validate diff --git a/integration/simple_app_test.go b/integration/simple_app_test.go index 6b54ecc..e5b8a0b 100644 --- a/integration/simple_app_test.go +++ b/integration/simple_app_test.go @@ -6,7 +6,6 @@ import ( "net/http" "os" "path/filepath" - "strings" "testing" "github.com/paketo-buildpacks/occam" @@ -87,13 +86,13 @@ func testSimple(t *testing.T, context spec.G, it spec.S) { " Candidate version sources (in priority order):", " -> \"\"", )) - Expect(logs).To(ContainLines( - fmt.Sprintf(" Selected Node Engine Major version %s", strings.Split(settings.Metadata.DefaultVersions.Node, ".")[0]))) + + Expect(logs).To(ContainLines(MatchRegexp(` Selected Node Engine Major version \d+`))) Expect(logs).To(ContainLines("===> RESTORING")) Expect(logs).To(ContainLines("===> EXTENDING (BUILD)")) Expect(logs).To(ContainLines( "[extender (build)] Enabling module streams:", - fmt.Sprintf("[extender (build)] nodejs:%s", strings.Split(settings.Metadata.DefaultVersions.Node, ".")[0]))) + MatchRegexp(`\[extender \(build\)\] nodejs:\d+`))) // SBOM is not supported at the moment from UBI image // therefore there are no available logs to test/validate From 10318624ba6744a4c60d280fe91c1512179de9ed Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Wed, 11 Sep 2024 12:16:02 +0300 Subject: [PATCH 14/19] fix: adding validation in case there are no nodejs stacks --- generate_test.go | 2 -- internal/utils/utils.go | 11 +++++++++-- internal/utils/utils_test.go | 27 ++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/generate_test.go b/generate_test.go index 1e71f4c..0a6e22b 100644 --- a/generate_test.go +++ b/generate_test.go @@ -110,8 +110,6 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Specific version of node requested", func() { imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) - hello := fmt.Sprintf(imagesJsonContent) - fmt.Println(hello) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 124fdab..053ae71 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -18,6 +18,9 @@ import ( "github.com/BurntSushi/toml" ) +var DEFAULT_USER_ID = 1002 +var DEFAULT_GROUP_ID = 1000 + //go:embed templates/build.Dockerfile var buildDockerfileTemplate string @@ -103,6 +106,10 @@ func GetNodejsStackImages(imagesJsonData ImagesJson) ([]StackImages, error) { nodejsStacks = append(nodejsStacks, stack) } } + if len(nodejsStacks) == 0 { + return []StackImages{}, errors.New("no nodejs stacks found") + } + return nodejsStacks, nil } @@ -126,8 +133,8 @@ func ParseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { func GetDuringBuildPermissions(filepath string) structs.DuringBuildPermissions { defaultPermissions := structs.DuringBuildPermissions{ - CNB_USER_ID: 1002, - CNB_GROUP_ID: 1000, + CNB_USER_ID: DEFAULT_USER_ID, + CNB_GROUP_ID: DEFAULT_GROUP_ID, } re := regexp.MustCompile(`cnb:x:(\d+):(\d+)::`) diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 159c7dc..a852af9 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -43,7 +43,7 @@ func testGetDefaultNodeVersion(t *testing.T, context spec.G, it spec.S) { }) context("and there are no default run images", func() { - it("should error", func() { + it("should error with a message", func() { defaultNodeVersion, err := utils.GetDefaultNodeVersion([]utils.StackImages{ { Name: "nodejs-22", @@ -268,6 +268,31 @@ func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { }) }) + context("When passing a stack images array without any nodejs stacks in it", func() { + + it("should return an error with an appropriate message", func() { + nodejsStacks, err := utils.GetNodejsStackImages(utils.ImagesJson{ + StackImages: []utils.StackImages{ + { + Name: "default", + IsDefaultRunImage: false, + }, + { + Name: "java-17", + IsDefaultRunImage: false, + }, + { + Name: "java-21", + IsDefaultRunImage: false, + }, + }, + }) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("no nodejs stacks found")) + Expect(nodejsStacks).To(Equal([]utils.StackImages{})) + }) + }) + context("When node version is malformed or does not exist", func() { it("should error with a message", func() { From 64250c5b53419be4f15a87c82c0040d23e30abb6 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Thu, 12 Sep 2024 12:07:33 +0300 Subject: [PATCH 15/19] moving generateImagesJson testhelper function in a common place --- generate_test.go | 15 +++--- internal/testhelpers/testhelpers.go | 74 +++++++++++++++++++++++++++++ internal/utils/utils.go | 71 --------------------------- internal/utils/utils_test.go | 9 ++-- 4 files changed, 87 insertions(+), 82 deletions(-) create mode 100644 internal/testhelpers/testhelpers.go diff --git a/generate_test.go b/generate_test.go index 0a6e22b..72ac7e6 100644 --- a/generate_test.go +++ b/generate_test.go @@ -14,6 +14,7 @@ import ( "github.com/paketo-buildpacks/packit/cargo" "github.com/paketo-buildpacks/packit/v2" ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" + "github.com/paketo-community/ubi-nodejs-extension/internal/testhelpers" "github.com/paketo-community/ubi-nodejs-extension/internal/utils" "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/sclevine/spec" @@ -109,7 +110,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Specific version of node requested", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -221,7 +222,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("should return the default when node version has NOT been requested", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{true, false}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{true, false}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -306,7 +307,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("should return the higher node version when it requests for >=nodeVersion", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -380,7 +381,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should error on below cases of requested node", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -469,7 +470,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should respect the priorities and return the proper Node.js version", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -587,7 +588,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should have the same value as the BP_UBI_RUN_IMAGE_OVERRIDE if is not empty string", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -642,7 +643,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { it("Should fallback to the run image which corresponds to the selected node version during build", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) diff --git a/internal/testhelpers/testhelpers.go b/internal/testhelpers/testhelpers.go new file mode 100644 index 0000000..0d3d5db --- /dev/null +++ b/internal/testhelpers/testhelpers.go @@ -0,0 +1,74 @@ +package testhelpers + +import "fmt" + +func GenerateImagesJsonFile(nodeVersions []string, isDefault []bool, isCorrupted bool) string { + addStacks := "" + + for i, nodeVersion := range nodeVersions { + + addStacks += fmt.Sprintf(`, + { + "name": "nodejs-%s", + "is_default_run_image": %t, + "config_dir": "stack-nodejs-%s", + "output_dir": "build-nodejs-%s", + "build_image": "build-nodejs-%s", + "run_image": "run-nodejs-%s", + "build_receipt_filename": "build-nodejs-%s-receipt.cyclonedx.json", + "run_receipt_filename": "run-nodejs-%s-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-%s-runtime" + }`, nodeVersion, isDefault[i], nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion) + } + + if isCorrupted { + addStacks += `, + { + "name": "nodejs-18",} + not a valid json + }` + } + + stacks := fmt.Sprintf(`{ + "support_usns": false, + "update_on_new_image": true, + "receipts_show_limit": 16, + "images": [ + { + "name": "default", + "config_dir": "stack", + "output_dir": "build", + "build_image": "build", + "run_image": "run", + "build_receipt_filename": "build-receipt.cyclonedx.json", + "run_receipt_filename": "run-receipt.cyclonedx.json", + "create_build_image": true, + "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" + }, + { + "name": "java-17", + "config_dir": "stack-java-17", + "output_dir": "build-java-17", + "build_image": "build-java-17", + "run_image": "run-java-17", + "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" + }, + { + "name": "java-21", + "config_dir": "stack-java-21", + "output_dir": "build-java-21", + "build_image": "build-java-21", + "run_image": "run-java-21", + "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", + "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", + "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" + }%s + ] + } +`, addStacks) + + return stacks +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 053ae71..2947ac1 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -205,74 +205,3 @@ func fillPropsToTemplate(properties interface{}, templateString string) (result return buf.String(), nil } - -func GenerateImagesJsonFile(nodeVersions []string, isDefault []bool, isCorrupted bool) string { - addStacks := "" - - for i, nodeVersion := range nodeVersions { - - addStacks += fmt.Sprintf(`, - { - "name": "nodejs-%s", - "is_default_run_image": %t, - "config_dir": "stack-nodejs-%s", - "output_dir": "build-nodejs-%s", - "build_image": "build-nodejs-%s", - "run_image": "run-nodejs-%s", - "build_receipt_filename": "build-nodejs-%s-receipt.cyclonedx.json", - "run_receipt_filename": "run-nodejs-%s-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/nodejs-%s-runtime" - }`, nodeVersion, isDefault[i], nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion, nodeVersion) - } - - if isCorrupted { - addStacks += `, - { - "name": "nodejs-18",} - not a valid json - }` - } - - stacks := fmt.Sprintf(`{ - "support_usns": false, - "update_on_new_image": true, - "receipts_show_limit": 16, - "images": [ - { - "name": "default", - "config_dir": "stack", - "output_dir": "build", - "build_image": "build", - "run_image": "run", - "build_receipt_filename": "build-receipt.cyclonedx.json", - "run_receipt_filename": "run-receipt.cyclonedx.json", - "create_build_image": true, - "base_build_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/ubi-minimal" - }, - { - "name": "java-17", - "config_dir": "stack-java-17", - "output_dir": "build-java-17", - "build_image": "build-java-17", - "run_image": "run-java-17", - "build_receipt_filename": "build-java-17-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-17-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-17-runtime" - }, - { - "name": "java-21", - "config_dir": "stack-java-21", - "output_dir": "build-java-21", - "build_image": "build-java-21", - "run_image": "run-java-21", - "build_receipt_filename": "build-java-21-receipt.cyclonedx.json", - "run_receipt_filename": "run-java-21-receipt.cyclonedx.json", - "base_run_container_image": "docker://registry.access.redhat.com/ubi8/openjdk-21-runtime" - }%s - ] - } -`, addStacks) - - return stacks -} diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index a852af9..d13b623 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/gomega" ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" + testhelpers "github.com/paketo-community/ubi-nodejs-extension/internal/testhelpers" "github.com/paketo-community/ubi-nodejs-extension/internal/utils" "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/sclevine/spec" @@ -149,7 +150,7 @@ func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { it("successfully parses images.json file", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, false) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, false) imagesJsonTmpDir := t.TempDir() imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -196,7 +197,7 @@ func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { it("erros when images.json file is not a valid json", func() { - imagesJsonContent := utils.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, true) + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, true) imagesJsonTmpDir := t.TempDir() imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images_not_valid.json") Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) @@ -298,11 +299,11 @@ func testGetNodejsStackImages(t *testing.T, context spec.G, it spec.S) { it("should error with a message", func() { imagesJsonTmpDir := t.TempDir() - imagesJsonNodeVersionNotIntegerContent := utils.GenerateImagesJsonFile([]string{"16", "18", "hello"}, []bool{false, false, true}, false) + imagesJsonNodeVersionNotIntegerContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18", "hello"}, []bool{false, false, true}, false) imagesJsonNodeVersionNotIntegerPath := filepath.Join(imagesJsonTmpDir, "images_node_version_not_integer.json") Expect(os.WriteFile(imagesJsonNodeVersionNotIntegerPath, []byte(imagesJsonNodeVersionNotIntegerContent), 0600)).To(Succeed()) - imagesJsonNoNodeVersionContent := utils.GenerateImagesJsonFile([]string{"16", "", "20"}, []bool{false, false, true}, false) + imagesJsonNoNodeVersionContent := testhelpers.GenerateImagesJsonFile([]string{"16", "", "20"}, []bool{false, false, true}, false) imagesJsonNoNodeVersionPath := filepath.Join(imagesJsonTmpDir, "images_no_node_version.json") Expect(os.WriteFile(imagesJsonNoNodeVersionPath, []byte(imagesJsonNoNodeVersionContent), 0600)).To(Succeed()) From 276a7bc9679dd3aa929d54a8e9ad9862825876a5 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Thu, 12 Sep 2024 12:08:13 +0300 Subject: [PATCH 16/19] fix: fetch run image from env integration tests --- integration/fetch_run_image_from_env.go | 59 ++++--------------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/integration/fetch_run_image_from_env.go b/integration/fetch_run_image_from_env.go index fea1258..c874be4 100644 --- a/integration/fetch_run_image_from_env.go +++ b/integration/fetch_run_image_from_env.go @@ -2,13 +2,10 @@ package integration import ( "fmt" - "io" - "net/http" "os" "path/filepath" "testing" - "github.com/Masterminds/semver" "github.com/paketo-buildpacks/occam" "github.com/sclevine/spec" @@ -18,20 +15,13 @@ import ( func testFetchRunImageFromEnv(t *testing.T, context spec.G, it spec.S) { var ( - Expect = NewWithT(t).Expect - Eventually = NewWithT(t).Eventually - - docker occam.Docker + Expect = NewWithT(t).Expect pack occam.Pack - - image occam.Image - container occam.Container - name string - source string + name string + source string ) it.Before(func() { - docker = occam.NewDocker() pack = occam.NewPack() var err error @@ -40,9 +30,6 @@ func testFetchRunImageFromEnv(t *testing.T, context spec.G, it spec.S) { }) it.After(func() { - Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) - Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) - Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) Expect(os.RemoveAll(source)).To(Succeed()) }) @@ -52,18 +39,10 @@ func testFetchRunImageFromEnv(t *testing.T, context spec.G, it spec.S) { source, err = occam.Source(filepath.Join("testdata", "simple_app")) Expect(err).NotTo(HaveOccurred()) - nodeRunImage := settings.Metadata.Dependencies[0].Source - - runNodeVersion, err := semver.NewVersion(settings.Metadata.Dependencies[0].Version) - Expect(err).NotTo(HaveOccurred()) - runNodeMajorVersion := runNodeVersion.Major() - - buildNodeVersion, err := semver.NewVersion(settings.Metadata.Dependencies[len(settings.Metadata.Dependencies)-1].Version) - Expect(err).NotTo(HaveOccurred()) - buildNodeMajorVersion := buildNodeVersion.Major() + nodeRunImage := "this-is-a-run-image" var logs fmt.Stringer - image, logs, err = pack.WithNoColor().Build. + _, logs, err = pack.WithNoColor().Build. WithExtensions( settings.Buildpacks.NodeExtension.Online, ). @@ -71,38 +50,18 @@ func testFetchRunImageFromEnv(t *testing.T, context spec.G, it spec.S) { settings.Buildpacks.NodeEngine.Online, settings.Buildpacks.Processes.Online, ). - WithEnv(map[string]string{"BP_UBI_RUN_IMAGE_OVERRIDE": nodeRunImage, "BP_NODE_VERSION": fmt.Sprint(buildNodeMajorVersion)}). + WithEnv(map[string]string{"BP_UBI_RUN_IMAGE_OVERRIDE": nodeRunImage}). WithPullPolicy("always"). Execute(name, source) - Expect(err).NotTo(HaveOccurred(), logs.String()) + Expect(err).To(HaveOccurred()) Expect(logs).To(ContainLines(fmt.Sprintf("%s 1.2.3", settings.Extension.Name))) Expect(logs).To(ContainLines(" Resolving Node Engine version")) Expect(logs).To(ContainLines(" Candidate version sources (in priority order):")) - Expect(logs).To(ContainLines(fmt.Sprintf(" BP_NODE_VERSION -> \"%d\"", buildNodeMajorVersion))) - Expect(logs).To(ContainLines(" -> \"\"")) + Expect(logs).To(ContainLines(" -> \"\"")) Expect(logs).To(ContainLines(fmt.Sprintf(" Using run image specified by BP_UBI_RUN_IMAGE_OVERRIDE %s", nodeRunImage))) - - Expect(logs).To(ContainLines( - "[extender (build)] Enabling module streams:", - fmt.Sprintf("[extender (build)] nodejs:%d", buildNodeMajorVersion))) - - container, err = docker.Container.Run. - WithPublish("8080"). - Execute(image.ID) - Expect(err).NotTo(HaveOccurred()) - - Eventually(container).Should(BeAvailable()) - - response, err := http.Get(fmt.Sprintf("http://localhost:%s/version/major", container.HostPort("8080"))) - Expect(err).NotTo(HaveOccurred()) - Expect(response.StatusCode).To(Equal(http.StatusOK)) - - content, err := io.ReadAll(response.Body) - Expect(err).NotTo(HaveOccurred()) - Expect(string(content)).To(ContainSubstring(fmt.Sprint(runNodeMajorVersion))) - + Expect(logs).To(ContainLines(MatchRegexp(` Selected Node Engine Major version \d+`))) }) }) } From 7a429029473fee8bc813c4c51c59202aaf115532 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Thu, 12 Sep 2024 13:30:26 +0300 Subject: [PATCH 17/19] reafactor:adding a wrapper on create config content functions --- generate.go | 20 +--------- generate_test.go | 14 +++---- internal/utils/init_test.go | 1 + internal/utils/utils.go | 25 +++++++++++++ internal/utils/utils_test.go | 71 ++++++++++++++++++++++++++++++++++-- 5 files changed, 102 insertions(+), 29 deletions(-) diff --git a/generate.go b/generate.go index 7493c14..df64e39 100644 --- a/generate.go +++ b/generate.go @@ -42,29 +42,13 @@ func Generate(dependencyManager DependencyManager, logger scribe.Emitter, during logger.Candidates(allNodeVersionsInPriorityOrder) - imagesJsonData, err := utils.ParseImagesJsonFile(imagesJsonPath) - if err != nil { - return packit.GenerateResult{}, packit.Fail.WithMessage("Failed to parse images.json file: %s", err) - } - - nodejsStacks, err := utils.GetNodejsStackImages(imagesJsonData) - if err != nil { - return packit.GenerateResult{}, err - } - - defaultNodeVersion, err := utils.GetDefaultNodeVersion(nodejsStacks) - - if err != nil { - return packit.GenerateResult{}, err - } - - configTomlFileContent, err := utils.CreateConfigTomlFileContent(defaultNodeVersion, nodejsStacks, context.Stack) + configTomlFileContent, err := utils.GenerateConfigTomlContentFromImagesJson(imagesJsonPath, context.Stack) if err != nil { return packit.GenerateResult{}, err } //save config.toml file - err = os.WriteFile(CONFIG_TOML_PATH, configTomlFileContent.Bytes(), 0644) + err = os.WriteFile(CONFIG_TOML_PATH, configTomlFileContent, 0644) if err != nil { return packit.GenerateResult{}, err } diff --git a/generate_test.go b/generate_test.go index 72ac7e6..6e96db8 100644 --- a/generate_test.go +++ b/generate_test.go @@ -113,7 +113,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, @@ -225,7 +225,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{true, false}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, @@ -310,7 +310,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, @@ -384,7 +384,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, @@ -473,7 +473,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, @@ -591,7 +591,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, @@ -646,7 +646,7 @@ func testGenerate(t *testing.T, context spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18"}, []bool{false, true}, false) imagesJsonTmpDir = t.TempDir() imagesJsonPath = filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) generate = ubinodejsextension.Generate( dependencyManager, diff --git a/internal/utils/init_test.go b/internal/utils/init_test.go index ad7e769..da4aada 100644 --- a/internal/utils/init_test.go +++ b/internal/utils/init_test.go @@ -9,6 +9,7 @@ import ( func TestUnitUtils(t *testing.T) { suite := spec.New("utils-ubi-nodejs-extension", spec.Report(report.Terminal{})) + suite("GenerateConfigTomlContentFromImagesJson", testGenerateConfigTomlContentFromImagesJson) suite("GetDefaultNodeVersion", testGetDefaultNodeVersion) suite("CreateConfigTomlFileContent", testCreateConfigTomlFileContent) suite("ParseImagesJsonFile", testParseImagesJsonFile) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 2947ac1..99f4d63 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -37,6 +37,31 @@ type ImagesJson struct { StackImages []StackImages `json:"images"` } +func GenerateConfigTomlContentFromImagesJson(imagesJsonPath string, stackId string) ([]byte, error) { + imagesJsonData, err := ParseImagesJsonFile(imagesJsonPath) + if err != nil { + return []byte{}, err + } + + nodejsStacks, err := GetNodejsStackImages(imagesJsonData) + if err != nil { + return []byte{}, err + } + + defaultNodeVersion, err := GetDefaultNodeVersion(nodejsStacks) + if err != nil { + return []byte{}, err + } + + configTomlContent, err := CreateConfigTomlFileContent(defaultNodeVersion, nodejsStacks, stackId) + if err != nil { + return []byte{}, err + } + + configTomlContentString := configTomlContent.Bytes() + return configTomlContentString, nil +} + func GetDefaultNodeVersion(stacks []StackImages) (string, error) { var defaultNodeVersionsFound []string for _, stack := range stacks { diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index d13b623..77e7529 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -15,6 +15,68 @@ import ( "github.com/sclevine/spec" ) +func testGenerateConfigTomlContentFromImagesJson(t *testing.T, context spec.G, it spec.S) { + + var ( + Expect = NewWithT(t).Expect + ) + + var imagesJsonDir string + it.Before(func() { + imagesJsonDir = t.TempDir() + }) + + it.After(func() { + Expect(os.RemoveAll(imagesJsonDir)).To(Succeed()) + }) + context("When GenerateConfigTomlContentFromImagesJson is being called with a valid images.json file ", func() { + + it("successfully parses images.json file and returns the config.toml content", func() { + + imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, false) + imagesJsonTmpDir := t.TempDir() + imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images.json") + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) + + configTomlContent, err := utils.GenerateConfigTomlContentFromImagesJson(imagesJsonPath, "io.buildpacks.stacks.ubix") + + Expect(err).ToNot(HaveOccurred()) + Expect(string(configTomlContent)).To(ContainSubstring(`[metadata] + [metadata.default-versions] + node = "20.*.*" + + [[metadata.dependencies]] + id = "node" + source = "paketocommunity/run-nodejs-16-ubi-base" + stacks = ["io.buildpacks.stacks.ubix"] + version = "16.1000" + + [[metadata.dependencies]] + id = "node" + source = "paketocommunity/run-nodejs-18-ubi-base" + stacks = ["io.buildpacks.stacks.ubix"] + version = "18.1000" + + [[metadata.dependencies]] + id = "node" + source = "paketocommunity/run-nodejs-20-ubi-base" + stacks = ["io.buildpacks.stacks.ubix"] + version = "20.1000"`)) + }) + }) + + context("When GenerateConfigTomlContentFromImagesJson is being called with an invalide images.json file ", func() { + + it("It should throw an error with a message", func() { + + _, err := utils.GenerateConfigTomlContentFromImagesJson("/path/to/invalid/images.json", "io.buildpacks.stacks.ubix") + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("no such file or directory")) + }) + }) + +} func testGetDefaultNodeVersion(t *testing.T, context spec.G, it spec.S) { var ( @@ -110,6 +172,7 @@ func testCreateConfigTomlFileContent(t *testing.T, context spec.G, it spec.S) { { Name: "nodejs-20", IsDefaultRunImage: false, + NodeVersion: "20", }, }, "io.buildpacks.stacks.ubix") @@ -126,9 +189,9 @@ func testCreateConfigTomlFileContent(t *testing.T, context spec.G, it spec.S) { [[metadata.dependencies]] id = "node" - source = "paketocommunity/run-nodejs--ubi-base" + source = "paketocommunity/run-nodejs-20-ubi-base" stacks = ["io.buildpacks.stacks.ubix"] - version = ".1000"`)) + version = "20.1000"`)) }) }) } @@ -153,7 +216,7 @@ func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, false) imagesJsonTmpDir := t.TempDir() imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) imagesJsonData, err := utils.ParseImagesJsonFile(imagesJsonPath) Expect(err).ToNot(HaveOccurred()) @@ -200,7 +263,7 @@ func testParseImagesJsonFile(t *testing.T, _ spec.G, it spec.S) { imagesJsonContent := testhelpers.GenerateImagesJsonFile([]string{"16", "18", "20"}, []bool{false, false, true}, true) imagesJsonTmpDir := t.TempDir() imagesJsonPath := filepath.Join(imagesJsonTmpDir, "images_not_valid.json") - Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0600)).To(Succeed()) + Expect(os.WriteFile(imagesJsonPath, []byte(imagesJsonContent), 0644)).To(Succeed()) imagesJsonData, err := utils.ParseImagesJsonFile(imagesJsonPath) From 4ccc558a479cf127c007218719d300bcc58012d0 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Fri, 13 Sep 2024 10:40:53 +0300 Subject: [PATCH 18/19] fix: importing default values from extension --- constants/constants.go | 4 ++++ generate.go | 2 -- internal/utils/utils.go | 8 +++----- internal/utils/utils_test.go | 9 +++++---- 4 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 constants/constants.go diff --git a/constants/constants.go b/constants/constants.go new file mode 100644 index 0000000..8bb8d65 --- /dev/null +++ b/constants/constants.go @@ -0,0 +1,4 @@ +package constants + +const DEFAULT_USER_ID = 1002 +const DEFAULT_GROUP_ID = 1000 diff --git a/generate.go b/generate.go index df64e39..1120cb5 100644 --- a/generate.go +++ b/generate.go @@ -16,8 +16,6 @@ import ( ) const PACKAGES = "make gcc gcc-c++ libatomic_ops git openssl-devel nodejs npm nodejs-nodemon nss_wrapper which python3" -const DEFAULT_USER_ID = 1002 -const DEFAULT_GROUP_ID = 1000 const CONFIG_TOML_PATH = "/tmp/config.toml" //go:generate faux --interface DependencyManager --output fakes/dependency_manager.go diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 99f4d63..7b12359 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -13,14 +13,12 @@ import ( "strings" "text/template" + "github.com/paketo-community/ubi-nodejs-extension/constants" "github.com/paketo-community/ubi-nodejs-extension/structs" "github.com/BurntSushi/toml" ) -var DEFAULT_USER_ID = 1002 -var DEFAULT_GROUP_ID = 1000 - //go:embed templates/build.Dockerfile var buildDockerfileTemplate string @@ -158,8 +156,8 @@ func ParseImagesJsonFile(imagesJsonPath string) (ImagesJson, error) { func GetDuringBuildPermissions(filepath string) structs.DuringBuildPermissions { defaultPermissions := structs.DuringBuildPermissions{ - CNB_USER_ID: DEFAULT_USER_ID, - CNB_GROUP_ID: DEFAULT_GROUP_ID, + CNB_USER_ID: constants.DEFAULT_USER_ID, + CNB_GROUP_ID: constants.DEFAULT_GROUP_ID, } re := regexp.MustCompile(`cnb:x:(\d+):(\d+)::`) diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 77e7529..36a1f07 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/gomega" ubinodejsextension "github.com/paketo-community/ubi-nodejs-extension" + "github.com/paketo-community/ubi-nodejs-extension/constants" testhelpers "github.com/paketo-community/ubi-nodejs-extension/internal/testhelpers" "github.com/paketo-community/ubi-nodejs-extension/internal/utils" "github.com/paketo-community/ubi-nodejs-extension/structs" @@ -529,8 +530,8 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin Expect(duringBuildPermissions).To(Equal( structs.DuringBuildPermissions{ - CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, - CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, + CNB_USER_ID: constants.DEFAULT_USER_ID, + CNB_GROUP_ID: constants.DEFAULT_GROUP_ID}, )) }) }) @@ -545,8 +546,8 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin Expect(duringBuilderPermissions).To(Equal( structs.DuringBuildPermissions{ - CNB_USER_ID: ubinodejsextension.DEFAULT_USER_ID, - CNB_GROUP_ID: ubinodejsextension.DEFAULT_GROUP_ID}, + CNB_USER_ID: constants.DEFAULT_USER_ID, + CNB_GROUP_ID: constants.DEFAULT_GROUP_ID}, )) }) }) From 15c94001180126fd86b4c72f3becf9cf88a01a28 Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Fri, 13 Sep 2024 12:44:56 +0300 Subject: [PATCH 19/19] fix: remove tmp directory --- internal/utils/utils_test.go | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 36a1f07..bb4f262 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -461,21 +461,13 @@ func testGenerateRunDockerfile(t *testing.T, context spec.G, it spec.S) { func testGetDuringBuildPermissions(t *testing.T, context spec.G, it spec.S) { - var ( - Expect = NewWithT(t).Expect - tmpDir string - path string - err error - ) + var Expect = NewWithT(t).Expect context("/etc/passwd exists and has the cnb user", func() { it("It should return the permissions specified for the cnb user", func() { - tmpDir, err = os.MkdirTemp("", "") - Expect(err).NotTo(HaveOccurred()) - - path = filepath.Join(tmpDir, "/passwd") - + tmpDir := t.TempDir() + path := filepath.Join(tmpDir, "/passwd") Expect(os.WriteFile(path, []byte(`root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin @@ -506,10 +498,8 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin context("/etc/passwd exists and does NOT have the cnb user", func() { it("It should return the default permissions", func() { - tmpDir, err = os.MkdirTemp("", "") - Expect(err).NotTo(HaveOccurred()) - - path = filepath.Join(tmpDir, "/passwd") + tmpDir := t.TempDir() + path := filepath.Join(tmpDir, "/passwd") Expect(os.WriteFile(path, []byte(`root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin @@ -537,11 +527,8 @@ nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin }) context("/etc/passwd does NOT exist", func() { - it("It should return the default permissions", func() { - tmpDir, err = os.MkdirTemp("", "") - Expect(err).NotTo(HaveOccurred()) - + tmpDir := t.TempDir() duringBuilderPermissions := utils.GetDuringBuildPermissions(tmpDir) Expect(duringBuilderPermissions).To(Equal(