diff --git a/controllers/componentdetectionquery_controller.go b/controllers/componentdetectionquery_controller.go index 5103ea9d8..4e7da7e9f 100644 --- a/controllers/componentdetectionquery_controller.go +++ b/controllers/componentdetectionquery_controller.go @@ -284,7 +284,7 @@ func (r *ComponentDetectionQueryReconciler) Reconcile(ctx context.Context, req c if isMultiComponent { log.Info(fmt.Sprintf("Since this is a multi-component, attempt will be made to read only level 1 dir for devfiles... %v", req.NamespacedName)) - devfilesMap, devfilesURLMap, dockerfileContextMap, componentPortsMap, err = devfile.ScanRepo(log, r.AlizerClient, componentPath, r.DevfileRegistryURL, source) + devfilesMap, devfilesURLMap, dockerfileContextMap, componentPortsMap, err = devfile.ScanRepoWithContext(log, r.AlizerClient, source.Context, componentPath, r.DevfileRegistryURL, source) if err != nil { if _, ok := err.(*devfile.NoDevfileFound); !ok { log.Error(err, fmt.Sprintf("Unable to find devfile(s) in repo %s due to an error %s, exiting reconcile loop %v", source.URL, err.Error(), req.NamespacedName)) diff --git a/pkg/devfile/detect.go b/pkg/devfile/detect.go index d665d5318..665331a63 100644 --- a/pkg/devfile/detect.go +++ b/pkg/devfile/detect.go @@ -46,7 +46,7 @@ type AlizerClient struct { // Map 2 returns a context to the matched devfileURL from the github repository. If no devfile was present, then a link to a matching devfile in the devfile registry will be used instead. // Map 3 returns a context to the Dockerfile uri or a matched DockerfileURL from the devfile registry if no Dockerfile is present in the context // Map 4 returns a context to the list of ports that were detected by alizer in the source code, at that given context -func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL string, source appstudiov1alpha1.GitSource) (map[string][]byte, map[string]string, map[string]string, map[string][]int, error) { +func search(log logr.Logger, a Alizer, originalContext string, localpath string, devfileRegistryURL string, source appstudiov1alpha1.GitSource) (map[string][]byte, map[string]string, map[string]string, map[string][]int, error) { devfileMapFromRepo := make(map[string][]byte) devfilesURLMapFromRepo := make(map[string]string) @@ -63,7 +63,8 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri isDevfilePresent := false isDockerfilePresent := false curPath := path.Join(localpath, f.Name()) - context := f.Name() + dirName := f.Name() + contextKey := originalContext + f.Name() files, err := ioutil.ReadDir(curPath) if err != nil { return nil, nil, nil, nil, err @@ -74,7 +75,7 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri /* #nosec G304 -- false positive, filename is not based on user input*/ devfilePath := path.Join(curPath, f.Name()) // Set the proper devfile URL for the detected devfile - updatedLink, err := UpdateGitLink(source.URL, source.Revision, path.Join(source.Context, path.Join(context, f.Name()))) + updatedLink, err := UpdateGitLink(source.URL, source.Revision, path.Join(source.Context, path.Join(dirName, f.Name()))) if err != nil { return nil, nil, nil, nil, err } @@ -85,8 +86,8 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri if shouldIgnoreDevfile { isDevfilePresent = false } else { - devfileMapFromRepo[context] = devfileBytes - devfilesURLMapFromRepo[context] = updatedLink + devfileMapFromRepo[contextKey] = devfileBytes + devfilesURLMapFromRepo[contextKey] = updatedLink isDevfilePresent = true } } else if f.IsDir() && f.Name() == HiddenDevfileDir { @@ -105,7 +106,7 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri devfilePath := path.Join(hiddenDirPath, f.Name()) // Set the proper devfile URL for the detected devfile - updatedLink, err := UpdateGitLink(source.URL, source.Revision, path.Join(source.Context, path.Join(context, HiddenDevfileDir, f.Name()))) + updatedLink, err := UpdateGitLink(source.URL, source.Revision, path.Join(source.Context, path.Join(dirName, HiddenDevfileDir, f.Name()))) if err != nil { return nil, nil, nil, nil, err } @@ -117,8 +118,8 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri if shouldIgnoreDevfile { isDevfilePresent = false } else { - devfileMapFromRepo[context] = devfileBytes - devfilesURLMapFromRepo[context] = updatedLink + devfileMapFromRepo[contextKey] = devfileBytes + devfilesURLMapFromRepo[contextKey] = updatedLink isDevfilePresent = true } @@ -131,11 +132,11 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri // we will read the devfile to ensure a Dockerfile has been referenced. // However, if a Dockerfile is named differently and not referenced in the devfile // it will go undetected - dockerfileContextMapFromRepo[context] = DockerfileName + dockerfileContextMapFromRepo[contextKey] = DockerfileName isDockerfilePresent = true } else if f.Name() == ContainerfileName { // Check for Containerfile - dockerfileContextMapFromRepo[context] = ContainerfileName + dockerfileContextMapFromRepo[contextKey] = ContainerfileName isDockerfilePresent = true } else if f.IsDir() && (f.Name() == DockerDir || f.Name() == HiddenDockerDir || f.Name() == BuildDir) { // Check for docker/Dockerfile, .docker/Dockerfile and build/Dockerfile @@ -148,7 +149,7 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri } for _, f := range files { if f.Name() == DockerfileName || f.Name() == ContainerfileName { - dockerfileContextMapFromRepo[context] = path.Join(dirName, f.Name()) + dockerfileContextMapFromRepo[contextKey] = path.Join(dirName, f.Name()) isDockerfilePresent = true } } @@ -158,12 +159,12 @@ func search(log logr.Logger, a Alizer, localpath string, devfileRegistryURL stri // at this stage, we need to ensure the Dockerfile has been referenced // in the devfile image component even if we detect both devfile and Dockerfile if isDevfilePresent && isDockerfilePresent { - delete(dockerfileContextMapFromRepo, context) + delete(dockerfileContextMapFromRepo, contextKey) isDockerfilePresent = false } if (!isDevfilePresent && !isDockerfilePresent) || (isDevfilePresent && !isDockerfilePresent) { - err := AnalyzePath(log, a, curPath, context, devfileRegistryURL, devfileMapFromRepo, devfilesURLMapFromRepo, dockerfileContextMapFromRepo, componentPortsMapFromRepo, isDevfilePresent, isDockerfilePresent) + err := AnalyzePath(log, a, curPath, contextKey, devfileRegistryURL, devfileMapFromRepo, devfilesURLMapFromRepo, dockerfileContextMapFromRepo, componentPortsMapFromRepo, isDevfilePresent, isDockerfilePresent) if err != nil { return nil, nil, nil, nil, err } diff --git a/pkg/devfile/devfile.go b/pkg/devfile/devfile.go index 8e56e8160..7a84439b6 100644 --- a/pkg/devfile/devfile.go +++ b/pkg/devfile/devfile.go @@ -851,7 +851,28 @@ func DownloadDevfileAndDockerfile(url string) ([]byte, string, []byte, string) { // Map 3 returns a context to the Dockerfile uri or a matched DockerfileURL from the devfile registry if no Dockerfile/Containerfile is present in the context // Map 4 returns a context to the list of ports that were detected by alizer in the source code, at that given context func ScanRepo(log logr.Logger, a Alizer, localpath string, devfileRegistryURL string, source appstudiov1alpha1.GitSource) (map[string][]byte, map[string]string, map[string]string, map[string][]int, error) { - return search(log, a, localpath, devfileRegistryURL, source) + return search(log, a, "", localpath, devfileRegistryURL, source) +} + +// ScanRepoWithContext attempts to read and return devfiles and Dockerfiles/Containerfiles from the local path upto the specified depth +// it also takes an originalContext parameter that represents the context path in the git repo +// this will be appended to the keys of all the returned maps +// Iterate through each sub-folder under first level, and scan for component. (devfile, Dockerfile/Containerfile, then Alizer) +// If no devfile(s) or Dockerfile(s)/Containerfile(s) are found in sub-folders of the root directory, then the Alizer tool is used to detect and match a devfile/Dockerfile from the devfile registry +// ScanRepo returns 3 maps and an error: +// Map 1 returns a context to the devfile bytes if present. +// Map 2 returns a context to the matched devfileURL from the devfile registry if no devfile is present in the context. +// Map 3 returns a context to the Dockerfile uri or a matched DockerfileURL from the devfile registry if no Dockerfile/Containerfile is present in the context +// Map 4 returns a context to the list of ports that were detected by alizer in the source code, at that given context +func ScanRepoWithContext(log logr.Logger, a Alizer, originalContext string, localpath string, devfileRegistryURL string, source appstudiov1alpha1.GitSource) (map[string][]byte, map[string]string, map[string]string, map[string][]int, error) { + if originalContext != "" { + if originalContext == "./" { + originalContext = "" + } else if !strings.HasSuffix(originalContext, "/") { + originalContext += "/" + } + } + return search(log, a, originalContext, localpath, devfileRegistryURL, source) } // UpdateLocalDockerfileURItoAbsolute takes in a Devfile, and a DockefileURL, and returns back a Devfile with any local URIs to the Dockerfile updates to be absolute