diff --git a/docs/public/alizer-spec.md b/docs/public/alizer-spec.md index 57a6851d..3e52311e 100644 --- a/docs/public/alizer-spec.md +++ b/docs/public/alizer-spec.md @@ -156,6 +156,7 @@ Component detection is only enabled for a subset of programming languages - Python - Rust - PHP +- Dockerfile To perform component detection Alizer splits the languages in two sets: `languages with a configuration file` (like Java which can have a pom.xml or a build.gradle) and `languages without a configuration file` (such as Python which does not have a diff --git a/pkg/apis/enricher/docker_enricher.go b/pkg/apis/enricher/docker_enricher.go new file mode 100644 index 00000000..8a14364a --- /dev/null +++ b/pkg/apis/enricher/docker_enricher.go @@ -0,0 +1,52 @@ +// +// Copyright 2023 Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package enricher + +import ( + "context" + "github.com/devfile/alizer/pkg/apis/model" +) + +type DockerEnricher struct{} + +type DockerFrameworkDetector interface { + DoPortsDetection(component *model.Component, ctx *context.Context) +} + +func (d DockerEnricher) GetSupportedLanguages() []string { + return []string{"dockerfile"} +} + +func (d DockerEnricher) DoEnrichLanguage(language *model.Language, _ *[]string) { + // The Dockerfile language does not contain frameworks + return +} + +func (d DockerEnricher) DoEnrichComponent(component *model.Component, _ model.DetectionSettings, _ *context.Context) { + projectName := GetDefaultProjectName(component.Path) + component.Name = projectName + + var ports []int + ports = GetPortsFromDockerFile(component.Path) + if len(ports) > 0 { + component.Ports = ports + } + return +} + +func (d DockerEnricher) IsConfigValidForComponentDetection(language string, config string) bool { + return IsConfigurationValidForLanguage(language, config) +} diff --git a/pkg/apis/enricher/enricher.go b/pkg/apis/enricher/enricher.go index 1ab28e7e..67303a85 100644 --- a/pkg/apis/enricher/enricher.go +++ b/pkg/apis/enricher/enricher.go @@ -93,6 +93,7 @@ func getEnrichers() []Enricher { &DotNetEnricher{}, &GoEnricher{}, &PHPEnricher{}, + &DockerEnricher{}, } } diff --git a/pkg/apis/model/model.go b/pkg/apis/model/model.go index 21ca1a07..b0cc66e8 100644 --- a/pkg/apis/model/model.go +++ b/pkg/apis/model/model.go @@ -27,12 +27,13 @@ type DetectionSettings struct { } type Language struct { - Name string - Aliases []string - Weight float64 - Frameworks []string - Tools []string - CanBeComponent bool + Name string + Aliases []string + Weight float64 + Frameworks []string + Tools []string + CanBeComponent bool + CanBeContainerComponent bool } type Component struct { diff --git a/pkg/apis/recognizer/component_recognizer.go b/pkg/apis/recognizer/component_recognizer.go index 57af9a01..9502ccc8 100644 --- a/pkg/apis/recognizer/component_recognizer.go +++ b/pkg/apis/recognizer/component_recognizer.go @@ -182,6 +182,17 @@ func isAnyComponentInPath(path string, components []model.Component) bool { return false } +// isAnyComponentInDirectPath checks if a component is present in the exact path. +// Search starts from path and will return true if a component is found. +func isAnyComponentInDirectPath(path string, components []model.Component) bool { + for _, component := range components { + if strings.Contains(path, component.Path) { + return true + } + } + return false +} + // isFirstPathParentOfSecond check if first path is parent (direct or not) of second path. func isFirstPathParentOfSecond(firstPath string, secondPath string) bool { return strings.Contains(secondPath, firstPath) @@ -194,6 +205,7 @@ func DetectComponentsFromFilesList(files []string, settings model.DetectionSetti alizerLogger.V(0).Info(fmt.Sprintf("Detecting components for %d fetched file paths", len(files))) configurationPerLanguage := langfiles.Get().GetConfigurationPerLanguageMapping() var components []model.Component + var containerComponents []model.Component for _, file := range files { alizerLogger.V(1).Info(fmt.Sprintf("Accessing %s", file)) languages, err := getLanguagesByConfigurationFile(configurationPerLanguage, file) @@ -210,8 +222,20 @@ func DetectComponentsFromFilesList(files []string, settings model.DetectionSetti alizerLogger.V(1).Info(err.Error()) continue } - alizerLogger.V(0).Info(fmt.Sprintf("Component %s found", component.Name)) - components = appendIfMissing(components, component) + if component.Languages[0].CanBeComponent { + alizerLogger.V(0).Info(fmt.Sprintf("Component %s found", component.Name)) + components = appendIfMissing(components, component) + } + if component.Languages[0].CanBeContainerComponent { + alizerLogger.V(0).Info(fmt.Sprintf("Container component %s found", component.Name)) + containerComponents = appendIfMissing(containerComponents, component) + } + } + + for _, component := range containerComponents { + if !isAnyComponentInDirectPath(component.Path, components) { + components = appendIfMissing(components, component) + } } return components } @@ -226,8 +250,9 @@ func appendIfMissing(components []model.Component, component model.Component) [] } func getLanguagesByConfigurationFile(configurationPerLanguage map[string][]string, file string) ([]string, error) { + filename := filepath.Base(file) for regex, languages := range configurationPerLanguage { - if match, _ := regexp.MatchString(regex, file); match { + if match, _ := regexp.MatchString(regex, filename); match { return languages, nil } } diff --git a/pkg/apis/recognizer/component_recognizer_test.go b/pkg/apis/recognizer/component_recognizer_test.go new file mode 100644 index 00000000..cb4967e9 --- /dev/null +++ b/pkg/apis/recognizer/component_recognizer_test.go @@ -0,0 +1,59 @@ +package recognizer + +import ( + "github.com/devfile/alizer/pkg/apis/model" + "reflect" + "testing" +) + +func Test_isAnyComponentInDirectPath(t *testing.T) { + tests := []struct { + name string + path string + components []model.Component + want bool + }{ + { + name: "Case 1: path should match", + path: "/alizer/resources/projects/ocparcade/arkanoid/", + components: []model.Component{{ + Name: "", + Path: "/alizer/resources/projects/ocparcade/arkanoid/", + Languages: nil, + Ports: nil, + }}, + want: true, + }, + { + name: "Case 2: path should match", + path: "/alizer/resources/projects/ocparcade/arkanoid/arkanoid/", + components: []model.Component{{ + Name: "", + Path: "/alizer/resources/projects/ocparcade/arkanoid/arkanoid/", + Languages: nil, + Ports: nil, + }}, + want: true, + }, + { + name: "Case 3: path should not match", + path: "/alizer/resources/projects/ocparcade/arkanoid/", + components: []model.Component{{ + Name: "", + Path: "/alizer/resources/projects/ocparcade/arkanoid/arkanoid/", + Languages: nil, + Ports: nil, + }}, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isAnyComponentInDirectPath(tt.path, tt.components) + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("Got: %t, want: %t", result, tt.want) + } + }) + } +} diff --git a/pkg/apis/recognizer/language_recognizer.go b/pkg/apis/recognizer/language_recognizer.go index c6b868dc..6474b906 100644 --- a/pkg/apis/recognizer/language_recognizer.go +++ b/pkg/apis/recognizer/language_recognizer.go @@ -127,12 +127,14 @@ func AnalyzeFile(configFile string, targetLanguage string) (model.Language, erro return model.Language{}, err } tmpLanguage := model.Language{ - Name: lang.Name, - Aliases: lang.Aliases, - Frameworks: []string{}, - Tools: []string{}, - Weight: 100, - CanBeComponent: true} + Name: lang.Name, + Aliases: lang.Aliases, + Frameworks: []string{}, + Tools: []string{}, + Weight: 100, + CanBeComponent: lang.Component, + CanBeContainerComponent: lang.ContainerComponent, + } langEnricher := enricher.GetEnricherByLanguage(targetLanguage) if langEnricher != nil { langEnricher.DoEnrichLanguage(&tmpLanguage, &[]string{configFile}) diff --git a/pkg/schema/languages.go b/pkg/schema/languages.go index 295e2dea..d9a04505 100644 --- a/pkg/schema/languages.go +++ b/pkg/schema/languages.go @@ -29,6 +29,7 @@ type LanguagesProperties map[string]LanguageProperties type LanguageCustomization struct { ConfigurationFiles []string `yaml:"configuration_files"` Component bool `yaml:"component"` + ContainerComponent bool `yaml:"container_component"` ExcludeFolders []string `yaml:"exclude_folders,omitempty"` Aliases []string `yaml:"aliases"` Disabled bool `default:"false" yaml:"disable_detection"` diff --git a/pkg/utils/langfiles/languages_file_handler.go b/pkg/utils/langfiles/languages_file_handler.go index e36d7ebc..9237e990 100644 --- a/pkg/utils/langfiles/languages_file_handler.go +++ b/pkg/utils/langfiles/languages_file_handler.go @@ -28,6 +28,7 @@ type LanguageItem struct { ConfigurationFiles []string ExcludeFolders []string Component bool + ContainerComponent bool disabled bool } @@ -87,6 +88,7 @@ func customizeLanguage(languageItem *LanguageItem) { (*languageItem).ConfigurationFiles = customization.ConfigurationFiles (*languageItem).ExcludeFolders = customization.ExcludeFolders (*languageItem).Component = customization.Component + (*languageItem).ContainerComponent = customization.ContainerComponent (*languageItem).Aliases = appendSlice((*languageItem).Aliases, customization.Aliases) (*languageItem).disabled = customization.Disabled } diff --git a/pkg/utils/langfiles/languages_file_handler_test.go b/pkg/utils/langfiles/languages_file_handler_test.go index a34bcbcb..19a98961 100644 --- a/pkg/utils/langfiles/languages_file_handler_test.go +++ b/pkg/utils/langfiles/languages_file_handler_test.go @@ -118,7 +118,7 @@ func TestGetLanguageByName(t *testing.T) { }, { name: "JavaScript", - expectedItem: LanguageItem{Name: "JavaScript", Aliases: []string{"js", "node", "nodejs", "TypeScript"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"[^-]package.json"}, ExcludeFolders: []string{"node_modules"}, Component: true, disabled: false}, + expectedItem: LanguageItem{Name: "JavaScript", Aliases: []string{"js", "node", "nodejs", "TypeScript"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"package.json"}, ExcludeFolders: []string{"node_modules"}, Component: true, disabled: false}, expectedErr: nil, }, { @@ -133,7 +133,12 @@ func TestGetLanguageByName(t *testing.T) { }, { name: "PHP", - expectedItem: LanguageItem{Name: "PHP", Aliases: []string{"inc"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"composer.json", "[^-]package.json"}, ExcludeFolders: []string(nil), Component: true, disabled: false}, + expectedItem: LanguageItem{Name: "PHP", Aliases: []string{"inc"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"composer.json", "package.json"}, ExcludeFolders: []string(nil), Component: true, disabled: false}, + expectedErr: nil, + }, + { + name: "Dockerfile", + expectedItem: LanguageItem{Name: "Dockerfile", Aliases: []string{"Containerfile"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"[Dd]ockerfile(\\.\\w+)?$", "[Cc]ontainerfile(\\.\\w+)?$"}, ExcludeFolders: []string(nil), Component: false, ContainerComponent: true, disabled: false}, expectedErr: nil, }, } @@ -194,7 +199,7 @@ func TestGetLanguageByAlias(t *testing.T) { { name: "JavaScript", alias: "TypeScript", - expectedItem: LanguageItem{Name: "JavaScript", Aliases: []string{"js", "node", "nodejs", "TypeScript"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"[^-]package.json"}, ExcludeFolders: []string{"node_modules"}, Component: true, disabled: false}, + expectedItem: LanguageItem{Name: "JavaScript", Aliases: []string{"js", "node", "nodejs", "TypeScript"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"package.json"}, ExcludeFolders: []string{"node_modules"}, Component: true, disabled: false}, expectedErr: nil, }, { @@ -206,7 +211,13 @@ func TestGetLanguageByAlias(t *testing.T) { { name: "PHP", alias: "inc", - expectedItem: LanguageItem{Name: "PHP", Aliases: []string{"inc"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"composer.json", "[^-]package.json"}, ExcludeFolders: []string(nil), Component: true, disabled: false}, + expectedItem: LanguageItem{Name: "PHP", Aliases: []string{"inc"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"composer.json", "package.json"}, ExcludeFolders: []string(nil), Component: true, disabled: false}, + expectedErr: nil, + }, + { + name: "Dockerfile", + alias: "Containerfile", + expectedItem: LanguageItem{Name: "Dockerfile", Aliases: []string{"Containerfile"}, Kind: "programming", Group: "", ConfigurationFiles: []string{"[Dd]ockerfile(\\.\\w+)?$", "[Cc]ontainerfile(\\.\\w+)?$"}, ExcludeFolders: []string(nil), Component: false, ContainerComponent: true, disabled: false}, expectedErr: nil, }, } diff --git a/pkg/utils/langfiles/resources/languages-customization.yml b/pkg/utils/langfiles/resources/languages-customization.yml index 1f1105b2..162b69b1 100644 --- a/pkg/utils/langfiles/resources/languages-customization.yml +++ b/pkg/utils/langfiles/resources/languages-customization.yml @@ -6,6 +6,13 @@ C#: - ".*\\.\\w+proj" - "appsettings.json" component: true +Dockerfile: + aliases: + - "Containerfile" + configuration_files: + - "[Dd]ockerfile(\\.\\w+)?$" + - "[Cc]ontainerfile(\\.\\w+)?$" + container_component: true F#: aliases: - "dotnet" @@ -33,12 +40,12 @@ JavaScript: exclude_folders: - "node_modules" configuration_files: - - "[^-]package.json" + - "package.json" component: true PHP: configuration_files: - "composer.json" - - "[^-]package.json" + - "package.json" component: true Python: configuration_files: @@ -55,7 +62,7 @@ TypeScript: exclude_folders: - "node_modules" configuration_files: - - "[^-]package.json" + - "package.json" component: true Visual Basic .NET: aliases: diff --git a/resources/projects/containerfile-orphan/Containerfile b/resources/projects/containerfile-orphan/Containerfile new file mode 100644 index 00000000..eb341b0a --- /dev/null +++ b/resources/projects/containerfile-orphan/Containerfile @@ -0,0 +1,16 @@ +FROM node:16 + +# Create app directory +WORKDIR /usr/src/app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package*.json ./ + +RUN npm install + +# Bundle app source +COPY . . + +EXPOSE 8090 +CMD [ "node", "server.js" ] diff --git a/resources/projects/dockerfile-double-components/Dockerfile b/resources/projects/dockerfile-double-components/Dockerfile new file mode 100644 index 00000000..e49e9a23 --- /dev/null +++ b/resources/projects/dockerfile-double-components/Dockerfile @@ -0,0 +1,16 @@ +FROM node:16 + +# Create app directory +WORKDIR /usr/src/app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package*.json ./ + +RUN npm install + +# Bundle app source +COPY .. . + +EXPOSE 8085 +CMD [ "node", "server.js" ] diff --git a/resources/projects/dockerfile-double-components/python/manage.py b/resources/projects/dockerfile-double-components/python/manage.py new file mode 100644 index 00000000..4eb04477 --- /dev/null +++ b/resources/projects/dockerfile-double-components/python/manage.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) + from django.core.management.commands.runserver import Command as runserver + runserver.default_port = "3543" \ No newline at end of file diff --git a/resources/projects/dockerfile-double-components/python/project/__init__.py b/resources/projects/dockerfile-double-components/python/project/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/resources/projects/dockerfile-double-components/python/project/database.py b/resources/projects/dockerfile-double-components/python/project/database.py new file mode 100644 index 00000000..f2a2f184 --- /dev/null +++ b/resources/projects/dockerfile-double-components/python/project/database.py @@ -0,0 +1,29 @@ +import os + +from django.conf import settings + + +engines = { + 'sqlite': 'django.db.backends.sqlite3', + 'postgresql': 'django.db.backends.postgresql_psycopg2', + 'mysql': 'django.db.backends.mysql', +} + + +def config(): + service_name = os.getenv('DATABASE_SERVICE_NAME', '').upper().replace('-', '_') + if service_name: + engine = engines.get(os.getenv('DATABASE_ENGINE'), engines['sqlite']) + else: + engine = engines['sqlite'] + name = os.getenv('DATABASE_NAME') + if not name and engine == engines['sqlite']: + name = os.path.join(settings.BASE_DIR, 'db.sqlite3') + return { + 'ENGINE': engine, + 'NAME': name, + 'USER': os.getenv('DATABASE_USER'), + 'PASSWORD': os.getenv('DATABASE_PASSWORD'), + 'HOST': os.getenv('{}_SERVICE_HOST'.format(service_name)), + 'PORT': os.getenv('{}_SERVICE_PORT'.format(service_name)), + } diff --git a/resources/projects/dockerfile-double-components/python/project/settings.py b/resources/projects/dockerfile-double-components/python/project/settings.py new file mode 100644 index 00000000..8855547e --- /dev/null +++ b/resources/projects/dockerfile-double-components/python/project/settings.py @@ -0,0 +1,133 @@ +""" +Django settings for this project. + +Generated by 'django-admin startproject' using Django 1.11.6. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +# The SECRET_KEY is provided via an environment variable in OpenShift +SECRET_KEY = os.getenv( + 'DJANGO_SECRET_KEY', + # safe value used for development when DJANGO_SECRET_KEY might not be set + '9e4@&tw46$l31)zrqe3wi+-slqm(ruvz&se0^%9#6(_w3ui!c0' +) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'debug_toolbar', + 'welcome', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', + 'debug_toolbar.middleware.DebugToolbarMiddleware', +] + +ROOT_URLCONF = 'project.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +from . import database + +DATABASES = { + 'default': database.config() +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') + +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' + +INTERNAL_IPS = ['127.0.0.1'] diff --git a/resources/projects/dockerfile-double-components/python/project/urls.py b/resources/projects/dockerfile-double-components/python/project/urls.py new file mode 100644 index 00000000..5c6a8e36 --- /dev/null +++ b/resources/projects/dockerfile-double-components/python/project/urls.py @@ -0,0 +1,21 @@ +from django.conf import settings +from django.conf.urls import include, url +from django.contrib import admin + +from welcome.views import index, health + +urlpatterns = [ + # Examples: + # url(r'^$', 'project.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), + + url(r'^$', index), + url(r'^health$', health), + url(r'^admin/', include(admin.site.urls)), +] + +if settings.DEBUG: + import debug_toolbar + urlpatterns = [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + urlpatterns diff --git a/resources/projects/dockerfile-double-components/python/requirements.txt b/resources/projects/dockerfile-double-components/python/requirements.txt new file mode 100644 index 00000000..0d8440df --- /dev/null +++ b/resources/projects/dockerfile-double-components/python/requirements.txt @@ -0,0 +1,5 @@ +django>=3.2.14,<1.12 +django-debug-toolbar==1.8 +gunicorn==19.5.0 +psycopg2-binary==2.8.5 +whitenoise==3.3.1 diff --git a/resources/projects/dockerfile-double-components/python/wsgi.py b/resources/projects/dockerfile-double-components/python/wsgi.py new file mode 100644 index 00000000..2ef9a16d --- /dev/null +++ b/resources/projects/dockerfile-double-components/python/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for project project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") + +application = get_wsgi_application() diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/Dockerfile b/resources/projects/dockerfile-nested-inner-double-components/docker/Dockerfile new file mode 100644 index 00000000..d56dbd48 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/Dockerfile @@ -0,0 +1,16 @@ +FROM node:16 + +# Create app directory +WORKDIR /usr/src/app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package*.json ./ + +RUN npm install + +# Bundle app source +COPY . . + +EXPOSE 8085 +CMD [ "node", "server.js" ] diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/manage.py b/resources/projects/dockerfile-nested-inner-double-components/docker/python/manage.py new file mode 100644 index 00000000..4eb04477 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/python/manage.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) + from django.core.management.commands.runserver import Command as runserver + runserver.default_port = "3543" \ No newline at end of file diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/__init__.py b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/database.py b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/database.py new file mode 100644 index 00000000..f2a2f184 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/database.py @@ -0,0 +1,29 @@ +import os + +from django.conf import settings + + +engines = { + 'sqlite': 'django.db.backends.sqlite3', + 'postgresql': 'django.db.backends.postgresql_psycopg2', + 'mysql': 'django.db.backends.mysql', +} + + +def config(): + service_name = os.getenv('DATABASE_SERVICE_NAME', '').upper().replace('-', '_') + if service_name: + engine = engines.get(os.getenv('DATABASE_ENGINE'), engines['sqlite']) + else: + engine = engines['sqlite'] + name = os.getenv('DATABASE_NAME') + if not name and engine == engines['sqlite']: + name = os.path.join(settings.BASE_DIR, 'db.sqlite3') + return { + 'ENGINE': engine, + 'NAME': name, + 'USER': os.getenv('DATABASE_USER'), + 'PASSWORD': os.getenv('DATABASE_PASSWORD'), + 'HOST': os.getenv('{}_SERVICE_HOST'.format(service_name)), + 'PORT': os.getenv('{}_SERVICE_PORT'.format(service_name)), + } diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/settings.py b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/settings.py new file mode 100644 index 00000000..8855547e --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/settings.py @@ -0,0 +1,133 @@ +""" +Django settings for this project. + +Generated by 'django-admin startproject' using Django 1.11.6. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +# The SECRET_KEY is provided via an environment variable in OpenShift +SECRET_KEY = os.getenv( + 'DJANGO_SECRET_KEY', + # safe value used for development when DJANGO_SECRET_KEY might not be set + '9e4@&tw46$l31)zrqe3wi+-slqm(ruvz&se0^%9#6(_w3ui!c0' +) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'debug_toolbar', + 'welcome', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', + 'debug_toolbar.middleware.DebugToolbarMiddleware', +] + +ROOT_URLCONF = 'project.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +from . import database + +DATABASES = { + 'default': database.config() +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') + +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' + +INTERNAL_IPS = ['127.0.0.1'] diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/urls.py b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/urls.py new file mode 100644 index 00000000..5c6a8e36 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/python/project/urls.py @@ -0,0 +1,21 @@ +from django.conf import settings +from django.conf.urls import include, url +from django.contrib import admin + +from welcome.views import index, health + +urlpatterns = [ + # Examples: + # url(r'^$', 'project.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), + + url(r'^$', index), + url(r'^health$', health), + url(r'^admin/', include(admin.site.urls)), +] + +if settings.DEBUG: + import debug_toolbar + urlpatterns = [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + urlpatterns diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/requirements.txt b/resources/projects/dockerfile-nested-inner-double-components/docker/python/requirements.txt new file mode 100644 index 00000000..0d8440df --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/python/requirements.txt @@ -0,0 +1,5 @@ +django>=3.2.14,<1.12 +django-debug-toolbar==1.8 +gunicorn==19.5.0 +psycopg2-binary==2.8.5 +whitenoise==3.3.1 diff --git a/resources/projects/dockerfile-nested-inner-double-components/docker/python/wsgi.py b/resources/projects/dockerfile-nested-inner-double-components/docker/python/wsgi.py new file mode 100644 index 00000000..2ef9a16d --- /dev/null +++ b/resources/projects/dockerfile-nested-inner-double-components/docker/python/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for project project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") + +application = get_wsgi_application() diff --git a/resources/projects/dockerfile-nested-inner/python/Dockerfile b/resources/projects/dockerfile-nested-inner/python/Dockerfile new file mode 100644 index 00000000..a9f43736 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/Dockerfile @@ -0,0 +1,16 @@ +FROM node:16 + +# Create app directory +WORKDIR /usr/src/app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package*.json ./ + +RUN npm install + +# Bundle app source +COPY docker . + +EXPOSE 8085 +CMD [ "node", "server.js" ] diff --git a/resources/projects/dockerfile-nested-inner/python/manage.py b/resources/projects/dockerfile-nested-inner/python/manage.py new file mode 100644 index 00000000..4eb04477 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/manage.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) + from django.core.management.commands.runserver import Command as runserver + runserver.default_port = "3543" \ No newline at end of file diff --git a/resources/projects/dockerfile-nested-inner/python/project/__init__.py b/resources/projects/dockerfile-nested-inner/python/project/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/resources/projects/dockerfile-nested-inner/python/project/database.py b/resources/projects/dockerfile-nested-inner/python/project/database.py new file mode 100644 index 00000000..f2a2f184 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/project/database.py @@ -0,0 +1,29 @@ +import os + +from django.conf import settings + + +engines = { + 'sqlite': 'django.db.backends.sqlite3', + 'postgresql': 'django.db.backends.postgresql_psycopg2', + 'mysql': 'django.db.backends.mysql', +} + + +def config(): + service_name = os.getenv('DATABASE_SERVICE_NAME', '').upper().replace('-', '_') + if service_name: + engine = engines.get(os.getenv('DATABASE_ENGINE'), engines['sqlite']) + else: + engine = engines['sqlite'] + name = os.getenv('DATABASE_NAME') + if not name and engine == engines['sqlite']: + name = os.path.join(settings.BASE_DIR, 'db.sqlite3') + return { + 'ENGINE': engine, + 'NAME': name, + 'USER': os.getenv('DATABASE_USER'), + 'PASSWORD': os.getenv('DATABASE_PASSWORD'), + 'HOST': os.getenv('{}_SERVICE_HOST'.format(service_name)), + 'PORT': os.getenv('{}_SERVICE_PORT'.format(service_name)), + } diff --git a/resources/projects/dockerfile-nested-inner/python/project/settings.py b/resources/projects/dockerfile-nested-inner/python/project/settings.py new file mode 100644 index 00000000..8855547e --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/project/settings.py @@ -0,0 +1,133 @@ +""" +Django settings for this project. + +Generated by 'django-admin startproject' using Django 1.11.6. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +# The SECRET_KEY is provided via an environment variable in OpenShift +SECRET_KEY = os.getenv( + 'DJANGO_SECRET_KEY', + # safe value used for development when DJANGO_SECRET_KEY might not be set + '9e4@&tw46$l31)zrqe3wi+-slqm(ruvz&se0^%9#6(_w3ui!c0' +) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'debug_toolbar', + 'welcome', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', + 'debug_toolbar.middleware.DebugToolbarMiddleware', +] + +ROOT_URLCONF = 'project.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +from . import database + +DATABASES = { + 'default': database.config() +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') + +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' + +INTERNAL_IPS = ['127.0.0.1'] diff --git a/resources/projects/dockerfile-nested-inner/python/project/urls.py b/resources/projects/dockerfile-nested-inner/python/project/urls.py new file mode 100644 index 00000000..5c6a8e36 --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/project/urls.py @@ -0,0 +1,21 @@ +from django.conf import settings +from django.conf.urls import include, url +from django.contrib import admin + +from welcome.views import index, health + +urlpatterns = [ + # Examples: + # url(r'^$', 'project.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), + + url(r'^$', index), + url(r'^health$', health), + url(r'^admin/', include(admin.site.urls)), +] + +if settings.DEBUG: + import debug_toolbar + urlpatterns = [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + urlpatterns diff --git a/resources/projects/dockerfile-nested-inner/python/requirements.txt b/resources/projects/dockerfile-nested-inner/python/requirements.txt new file mode 100644 index 00000000..0d8440df --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/requirements.txt @@ -0,0 +1,5 @@ +django>=3.2.14,<1.12 +django-debug-toolbar==1.8 +gunicorn==19.5.0 +psycopg2-binary==2.8.5 +whitenoise==3.3.1 diff --git a/resources/projects/dockerfile-nested-inner/python/wsgi.py b/resources/projects/dockerfile-nested-inner/python/wsgi.py new file mode 100644 index 00000000..2ef9a16d --- /dev/null +++ b/resources/projects/dockerfile-nested-inner/python/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for project project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") + +application = get_wsgi_application() diff --git a/resources/projects/dockerfile-orphan/Dockerfile b/resources/projects/dockerfile-orphan/Dockerfile new file mode 100644 index 00000000..e49e9a23 --- /dev/null +++ b/resources/projects/dockerfile-orphan/Dockerfile @@ -0,0 +1,16 @@ +FROM node:16 + +# Create app directory +WORKDIR /usr/src/app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package*.json ./ + +RUN npm install + +# Bundle app source +COPY .. . + +EXPOSE 8085 +CMD [ "node", "server.js" ] diff --git a/test/apis/component_recognizer_test.go b/test/apis/component_recognizer_test.go index 5c2f6374..4fc88fd1 100644 --- a/test/apis/component_recognizer_test.go +++ b/test/apis/component_recognizer_test.go @@ -297,8 +297,20 @@ func TestComponentDetectionOnDoubleComponents(t *testing.T) { isComponentsInProject(t, "double-components", 2, "javascript", "") } +func TestComponentDetectionWithDoubleComponentsDockerFile(t *testing.T) { + isComponentsInProject(t, "dockerfile-double-components", 2, "python", "") +} + +func TestComponentDetectionWithNestedComponents(t *testing.T) { + isComponentsInProject(t, "dockerfile-nested-inner-double-components", 2, "python", "") +} + +func TestComponentDetectionWithNestedComponents2(t *testing.T) { + isComponentsInProject(t, "dockerfile-nested-inner", 1, "python", "") +} + func TestComponentDetectionWithGitIgnoreRule(t *testing.T) { - testingProjectPath := GetTestProjectPath("component-wrapped-in-folder") + testingProjectPath := getTestProjectPath("component-wrapped-in-folder") settings := model.DetectionSettings{ BasePath: testingProjectPath, } @@ -335,7 +347,7 @@ func TestComponentDetectionWithGitIgnoreRule(t *testing.T) { func TestComponentDetectionMultiProjects(t *testing.T) { components := getComponentsFromTestProject(t, "") - nComps := 50 + nComps := 54 if len(components) != nComps { t.Errorf("Expected " + strconv.Itoa(nComps) + " components but found " + strconv.Itoa(len(components))) } @@ -362,6 +374,14 @@ func TestPortDetectionWithContainerFile(t *testing.T) { testPortDetectionInProject(t, "containerfile", []int{8085}) } +func TestPortDetectionWithOrphanContainerFile(t *testing.T) { + testPortDetectionInProject(t, "containerfile-orphan", []int{8090}) +} + +func TestPortDetectionWithOrphanDockerFile(t *testing.T) { + testPortDetectionInProject(t, "dockerfile-orphan", []int{8085}) +} + func TestPortDetectionWithSecondLevelDockerFile(t *testing.T) { testPortDetectionInProject(t, "dockerfile-nested", []int{8085}) } diff --git a/test/apis/devfile_recognizer_test.go b/test/apis/devfile_recognizer_test.go index d2430a2e..25826361 100644 --- a/test/apis/devfile_recognizer_test.go +++ b/test/apis/devfile_recognizer_test.go @@ -231,7 +231,7 @@ func getExceptedVersionsUrl(url, minSchemaVersion, maxSchemaVersion string, err func detectDevFiles(t *testing.T, projectName string, devFilesName []string) { detectDevFilesFunc := func(devFileTypes []model.DevFileType) ([]int, error) { - testingProjectPath := GetTestProjectPath(projectName) + testingProjectPath := getTestProjectPath(projectName) return recognizer.SelectDevFilesFromTypes(testingProjectPath, devFileTypes) } detectDevFilesInner(t, devFilesName, detectDevFilesFunc) @@ -239,7 +239,7 @@ func detectDevFiles(t *testing.T, projectName string, devFilesName []string) { func detectDevFile(t *testing.T, projectName string, devFilesName []string) { detectDevFilesFunc := func(devFileTypes []model.DevFileType) ([]int, error) { - testingProjectPath := GetTestProjectPath(projectName) + testingProjectPath := getTestProjectPath(projectName) devfileIndex, err := recognizer.SelectDevFileFromTypes(testingProjectPath, devFileTypes) return []int{devfileIndex}, err } @@ -248,7 +248,7 @@ func detectDevFile(t *testing.T, projectName string, devFilesName []string) { func detectDevFilesUsingLanguages(t *testing.T, projectName string, languages []model.Language, devFileName []string) { if projectName != "" { - testingProjectPath := GetTestProjectPath(projectName) + testingProjectPath := getTestProjectPath(projectName) var err error languages, err = recognizer.Analyze(testingProjectPath) if err != nil { diff --git a/test/apis/git_recognizer_test.go b/test/apis/git_recognizer_test.go index 1c2ae289..d5f00889 100644 --- a/test/apis/git_recognizer_test.go +++ b/test/apis/git_recognizer_test.go @@ -2,7 +2,7 @@ package recognizer import ( "encoding/json" - "io/ioutil" + "os" "path/filepath" "sort" "strconv" @@ -18,17 +18,17 @@ import ( const ( repoUrl = "https://github.com/devfile-resources/alizer-test-resources.git" - repoCommit = "2f37ba079800f2d6a33237f09153f5699614f9be" + repoCommit = "28a60a19f9368c28b57b4645ae2a43d11f1cb6be" ) func TestExternalRepos(t *testing.T) { // read git test file to retrieve all test resources and their expected properties - jsonFile, err := ioutil.ReadFile("../git_test.json") + jsonFile, err := os.ReadFile("../git_test.json") if err != nil { t.Fatal("Unable to fetch git repositories file to run tests to") } var data []test.GitTestProperties - err = json.Unmarshal([]byte(jsonFile), &data) + err = json.Unmarshal(jsonFile, &data) if err != nil { t.Fatal("Unable to fetch git repositories file to run tests to") } diff --git a/test/apis/language_recognizer_test.go b/test/apis/language_recognizer_test.go index e6bf2146..cf4bedca 100644 --- a/test/apis/language_recognizer_test.go +++ b/test/apis/language_recognizer_test.go @@ -11,8 +11,6 @@ package recognizer import ( - "path/filepath" - "runtime" "strings" "testing" @@ -53,7 +51,7 @@ func TestAnalyzeOnGoGin(t *testing.T) { } func isLanguageInProject(t *testing.T, project string, wantedLanguage string, wantedTools []string, wantedFrameworks []string) { - testingProjectPath := GetTestProjectPath(project) + testingProjectPath := getTestProjectPath(project) languages, err := recognizer.Analyze(testingProjectPath) if err != nil { @@ -109,9 +107,3 @@ func hasWantedTool(language model.Language, wantedTool string) bool { } return false } - -func GetTestProjectPath(folder string) string { - _, b, _, _ := runtime.Caller(0) - basepath := filepath.Dir(b) - return filepath.Join(basepath, "..", "..", "resources/projects", folder) -} diff --git a/test/apis/utils.go b/test/apis/utils.go index 33a6c0ad..ff3b844c 100644 --- a/test/apis/utils.go +++ b/test/apis/utils.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "os" + "path/filepath" + "runtime" "strconv" "strings" "testing" @@ -30,8 +32,7 @@ func updateContent(filePath string, data []byte) error { } func getComponentsFromTestProject(t *testing.T, project string) []model.Component { - testingProjectPath := GetTestProjectPath(project) - + testingProjectPath := getTestProjectPath(project) return getComponentsFromProjectInner(t, testingProjectPath) } @@ -97,3 +98,9 @@ func testPortDetectionInProject(t *testing.T, project string, ports []int) { found = false } } + +func getTestProjectPath(folder string) string { + _, b, _, _ := runtime.Caller(0) + basepath := filepath.Dir(b) + return filepath.Join(basepath, "..", "..", "resources/projects", folder) +} diff --git a/test/git_test.json b/test/git_test.json index b63ac4b8..ff423721 100644 --- a/test/git_test.json +++ b/test/git_test.json @@ -10,7 +10,7 @@ "tools": [ "NodeJs" ] - } + } ], "name": "event-handler" }, @@ -23,7 +23,7 @@ "tools": [ "1.14" ] - } + } ] } ] @@ -42,7 +42,7 @@ "tools": [ "1.14" ] - } + } ] } ] @@ -192,7 +192,7 @@ "Ports": null } ] - }, + }, { "directory": "jhipster-sample-app-micronaut", "components": [ @@ -917,7 +917,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Svelte" ], "tools": [ @@ -932,7 +932,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -950,7 +950,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Vue" ], "tools": [ @@ -965,7 +965,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -988,7 +988,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1008,7 +1008,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1023,7 +1023,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1043,7 +1043,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1058,7 +1058,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1091,7 +1091,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1111,7 +1111,7 @@ "languages": [ { "name": "Java", - "frameworks": [ + "frameworks": [ "Quarkus" ], "tools": [ @@ -1125,7 +1125,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Vue" ], "tools": [ @@ -1145,7 +1145,7 @@ "languages": [ { "name": "Java", - "frameworks": [ + "frameworks": [ "Micronaut" ], "tools": [ @@ -1159,7 +1159,7 @@ "languages": [ { "name": "Java", - "frameworks": [ + "frameworks": [ "Quarkus" ], "tools": [ @@ -1173,7 +1173,7 @@ "languages": [ { "name": "Java", - "frameworks": [ + "frameworks": [ "Spring" ], "tools": [ @@ -1192,7 +1192,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1204,6 +1204,63 @@ } ] }, + { + "directory": "ocparcade", + "components": [ + { + "name": "js-dos-template", + "languages": [ + { + "name": "JavaScript", + "frameworks": [], + "tools": [ + "NodeJs", + "Node.js" + ] + } + ] + }, + { + "name": "js-dos-template", + "languages": [ + { + "name": "JavaScript", + "frameworks": [], + "tools": [ + "NodeJs", + "Node.js" + ] + } + ] + }, + { + "name": "arkanoid", + "languages": [ + { + "name": "Dockerfile", + "frameworks": [], + "tools": [] + } + ], + "ports": [ + 8080 + ] + }, + { + "name": "epicpinball", + "languages": [ + { + "name": "Dockerfile", + "frameworks": [], + "tools": [] + } + ], + "ports": [ + 8081 + ] + } + ] + }, { "directory": "nodejs-messaging-work-queue", "components": [ @@ -1212,7 +1269,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1227,7 +1284,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1247,7 +1304,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [ @@ -1262,7 +1319,7 @@ "languages": [ { "name": "JavaScript", - "frameworks": [ + "frameworks": [ "Express" ], "tools": [