From 0098c4f51896e81d44e3cfdc5a0ea610bf29ffed Mon Sep 17 00:00:00 2001 From: kartik-579 <84493919+kartik-579@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:09:00 +0530 Subject: [PATCH] feat: Description for cluster and apps (#4154) * wip * updated description provision in app update api used for labels * added api for getting app meta info for helm app * updated app meta info api for helm app chart used data support * corrected api method * fixed validation for cluster description update api * added icon * refactored query for better viewing * enhanced env listing query for app overview to support new required data at FE * review comments * updated sql script no * added code source info * fixed ea wiring * updated params in other-env api * updated api for fetching other env data * fixed import * fix * wip * wip * wip * added pipeline deleted condition - fetch other env * updated sql script no. --- api/appStore/AppStoreRouter.go | 3 +- api/appStore/InstalledAppRestHandler.go | 44 +++++++++- api/bean/AppView.go | 4 + api/cluster/ClusterRestHandler.go | 40 +++++++++ api/cluster/ClusterRouter.go | 6 +- api/restHandler/AppRestHandler.go | 6 +- api/restHandler/CoreAppRestHandler.go | 6 +- api/router/AppRouter.go | 4 +- cmd/external-app/wire.go | 2 + cmd/external-app/wire_gen.go | 3 +- .../sql/repository/AppListingRepository.go | 28 ++++-- internal/sql/repository/app/AppRepository.go | 9 ++ internal/util/ArgoUtil/ArgoClient.go | 2 +- internal/util/GitService.go | 2 +- pkg/app/AppCrudOperationService.go | 88 +++++++++++++++++-- pkg/appClone/AppCloneService.go | 4 +- pkg/bean/app.go | 23 ++++- pkg/chartRepo/ChartRepositoryService.go | 2 +- pkg/cluster/ClusterDescriptionService.go | 6 +- pkg/cluster/ClusterService.go | 16 ++++ .../ClusterDescriptionRepository.go | 17 ++-- pkg/cluster/repository/ClusterRepository.go | 10 +++ .../tests/GenericNoteService_test.go | 2 +- pkg/gitops/GitOpsConfigService.go | 2 +- pkg/pipeline/BuildPipelineConfigService.go | 6 +- pkg/pipeline/CiCdPipelineOrchestrator.go | 23 ++--- pkg/pipeline/GitRegistryConfig.go | 8 +- pkg/plugin/GlobalPluginService.go | 2 +- pkg/resourceGroup/ResourceGroupService.go | 10 +-- ...185_alter_cluster_add_description.down.sql | 2 + .../185_alter_cluster_add_description.up.sql | 2 + wire_gen.go | 6 +- 32 files changed, 313 insertions(+), 75 deletions(-) create mode 100644 scripts/sql/185_alter_cluster_add_description.down.sql create mode 100644 scripts/sql/185_alter_cluster_add_description.up.sql diff --git a/api/appStore/AppStoreRouter.go b/api/appStore/AppStoreRouter.go index 624bbaec35e..1d8adf1d376 100644 --- a/api/appStore/AppStoreRouter.go +++ b/api/appStore/AppStoreRouter.go @@ -78,7 +78,8 @@ func (router AppStoreRouterImpl) Init(configRouter *mux.Router) { chartProviderSubRouter := configRouter.PathPrefix("/chart-provider").Subrouter() router.chartProviderRouter.Init(chartProviderSubRouter) // chart provider router ends - + configRouter.Path("/overview").Queries("installedAppId", "{installedAppId}"). + HandlerFunc(router.deployRestHandler.FetchAppOverview).Methods("GET") configRouter.Path("/application/exists"). HandlerFunc(router.deployRestHandler.CheckAppExists).Methods("POST") configRouter.Path("/group/install"). diff --git a/api/appStore/InstalledAppRestHandler.go b/api/appStore/InstalledAppRestHandler.go index d253bec64ab..ee41925beda 100644 --- a/api/appStore/InstalledAppRestHandler.go +++ b/api/appStore/InstalledAppRestHandler.go @@ -31,6 +31,7 @@ import ( "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/middleware" util2 "github.com/devtron-labs/devtron/internal/util" + app2 "github.com/devtron-labs/devtron/pkg/app" appStoreBean "github.com/devtron-labs/devtron/pkg/appStore/bean" "github.com/devtron-labs/devtron/pkg/appStore/deployment/repository" "github.com/devtron-labs/devtron/pkg/appStore/deployment/service" @@ -53,6 +54,7 @@ import ( ) type InstalledAppRestHandler interface { + FetchAppOverview(w http.ResponseWriter, r *http.Request) GetAllInstalledApp(w http.ResponseWriter, r *http.Request) DeployBulk(w http.ResponseWriter, r *http.Request) CheckAppExists(w http.ResponseWriter, r *http.Request) @@ -82,6 +84,7 @@ type InstalledAppRestHandlerImpl struct { cdApplicationStatusUpdateHandler cron.CdApplicationStatusUpdateHandler installedAppRepository repository.InstalledAppRepository K8sApplicationService application2.K8sApplicationService + appCrudOperationService app2.AppCrudOperationService } func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService user.UserService, @@ -91,7 +94,7 @@ func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService u argoUserService argo.ArgoUserService, cdApplicationStatusUpdateHandler cron.CdApplicationStatusUpdateHandler, installedAppRepository repository.InstalledAppRepository, -) *InstalledAppRestHandlerImpl { + appCrudOperationService app2.AppCrudOperationService) *InstalledAppRestHandlerImpl { return &InstalledAppRestHandlerImpl{ Logger: Logger, userAuthService: userAuthService, @@ -108,8 +111,47 @@ func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService u argoUserService: argoUserService, cdApplicationStatusUpdateHandler: cdApplicationStatusUpdateHandler, installedAppRepository: installedAppRepository, + appCrudOperationService: appCrudOperationService, } } +func (handler *InstalledAppRestHandlerImpl) FetchAppOverview(w http.ResponseWriter, r *http.Request) { + userId, err := handler.userAuthService.GetLoggedInUser(r) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, nil, http.StatusUnauthorized) + return + } + + vars := mux.Vars(r) + installedAppId, err := strconv.Atoi(vars["installedAppId"]) + if err != nil { + handler.Logger.Errorw("request err, FetchAppOverview", "err", err, "installedAppId", installedAppId) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + token := r.Header.Get("token") + handler.Logger.Infow("request payload, FindAppOverview", "installedAppId", installedAppId) + installedApp, err := handler.installedAppService.CheckAppExistsByInstalledAppId(installedAppId) + appOverview, err := handler.appCrudOperationService.GetAppMetaInfo(installedApp.AppId, installedAppId, installedApp.EnvironmentId) + if err != nil { + handler.Logger.Errorw("service err, FetchAppOverview", "err", err, "appId", installedApp.AppId, "installedAppId", installedAppId) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + + //rbac block starts from here + object, object2 := handler.enforcerUtil.GetHelmObject(appOverview.AppId, installedApp.EnvironmentId) + var ok bool + if object2 == "" { + ok = handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object) + } else { + ok = handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object) || handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object2) + } + if !ok { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) + return + } + common.WriteJsonResp(w, nil, appOverview, http.StatusOK) +} func (handler InstalledAppRestHandlerImpl) GetAllInstalledApp(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) diff --git a/api/bean/AppView.go b/api/bean/AppView.go index d57dd848cb1..3a12db54a77 100644 --- a/api/bean/AppView.go +++ b/api/bean/AppView.go @@ -198,10 +198,14 @@ type Environment struct { Prod bool `json:"prod"` ChartRefId int `json:"chartRefId"` LastDeployed string `json:"lastDeployed"` + LastDeployedBy string `json:"lastDeployedBy"` + LastDeployedImage string `json:"lastDeployedImage"` DeploymentAppDeleteRequest bool `json:"deploymentAppDeleteRequest"` Description string `json:"description" validate:"max=40"` IsVirtualEnvironment bool `json:"isVirtualEnvironment"` ClusterId int `json:"clusterId"` + PipelineId int `json:"pipelineId"` + LatestCdWorkflowRunnerId int `json:"latestCdWorkflowRunnerId,omitempty"` } type InstanceDetail struct { diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 4ef72f5b75b..3f733a57c8e 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -51,6 +51,7 @@ type ClusterRestHandler interface { FindById(w http.ResponseWriter, r *http.Request) FindNoteByClusterId(w http.ResponseWriter, r *http.Request) Update(w http.ResponseWriter, r *http.Request) + UpdateClusterDescription(w http.ResponseWriter, r *http.Request) UpdateClusterNote(w http.ResponseWriter, r *http.Request) FindAllForAutoComplete(w http.ResponseWriter, r *http.Request) DeleteCluster(w http.ResponseWriter, r *http.Request) @@ -453,6 +454,45 @@ func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request common.WriteJsonResp(w, err, bean, http.StatusOK) } +func (impl ClusterRestHandlerImpl) UpdateClusterDescription(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("token") + decoder := json.NewDecoder(r.Body) + userId, err := impl.userService.GetLoggedInUser(r) + if userId == 0 || err != nil { + impl.logger.Errorw("service err, Update", "error", err, "userId", userId) + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } + var bean cluster.ClusterBean + err = decoder.Decode(&bean) + if err != nil { + impl.logger.Errorw("request err, UpdateClusterDescription", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + impl.logger.Infow("request payload, UpdateClusterDescription", "payload", bean) + //TODO: add apt validation + clusterDescription, err := impl.clusterDescriptionService.FindByClusterIdWithClusterDetails(bean.Id) + if err != nil { + impl.logger.Errorw("service err, FindById", "err", err, "clusterId", bean.Id) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + // RBAC enforcer applying + if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, strings.ToLower(clusterDescription.ClusterName)); !ok { + common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) + return + } + // RBAC enforcer ends + err = impl.clusterService.UpdateClusterDescription(&bean, userId) + if err != nil { + impl.logger.Errorw("service err, UpdateClusterDescription", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, err, "Cluster description updated successfully", http.StatusOK) +} + func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("token") decoder := json.NewDecoder(r.Body) diff --git a/api/cluster/ClusterRouter.go b/api/cluster/ClusterRouter.go index 7a61bc1be53..c27137aa328 100644 --- a/api/cluster/ClusterRouter.go +++ b/api/cluster/ClusterRouter.go @@ -66,7 +66,7 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) { Methods("PUT"). HandlerFunc(impl.clusterRestHandler.Update) - clusterRouter.Path("/description"). + clusterRouter.Path("/note"). Methods("PUT"). HandlerFunc(impl.clusterRestHandler.UpdateClusterNote) @@ -89,4 +89,8 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) { clusterRouter.Path("/auth-list"). Methods("GET"). HandlerFunc(impl.clusterRestHandler.FindAllForClusterPermission) + + clusterRouter.Path("/description"). + Methods("PUT"). + HandlerFunc(impl.clusterRestHandler.UpdateClusterDescription) } diff --git a/api/restHandler/AppRestHandler.go b/api/restHandler/AppRestHandler.go index b8bde79a717..de0a3ac16fc 100644 --- a/api/restHandler/AppRestHandler.go +++ b/api/restHandler/AppRestHandler.go @@ -43,7 +43,7 @@ type AppRestHandler interface { UpdateApp(w http.ResponseWriter, r *http.Request) UpdateProjectForApps(w http.ResponseWriter, r *http.Request) GetAppListByTeamIds(w http.ResponseWriter, r *http.Request) - UpdateAppDescription(w http.ResponseWriter, r *http.Request) + UpdateAppNote(w http.ResponseWriter, r *http.Request) } type AppRestHandlerImpl struct { @@ -123,7 +123,7 @@ func (handler AppRestHandlerImpl) GetAppMetaInfo(w http.ResponseWriter, r *http. } //rback implementation ends here - res, err := handler.appService.GetAppMetaInfo(appId) + res, err := handler.appService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID) if err != nil { handler.logger.Errorw("service err, GetAppMetaInfo", "err", err) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) @@ -343,7 +343,7 @@ func (handler AppRestHandlerImpl) GetAppListByTeamIds(w http.ResponseWriter, r * common.WriteJsonResp(w, err, projectWiseApps, http.StatusOK) } -func (handler AppRestHandlerImpl) UpdateAppDescription(w http.ResponseWriter, r *http.Request) { +func (handler AppRestHandlerImpl) UpdateAppNote(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("token") decoder := json.NewDecoder(r.Body) userId, err := handler.userAuthService.GetLoggedInUser(r) diff --git a/api/restHandler/CoreAppRestHandler.go b/api/restHandler/CoreAppRestHandler.go index 188dc85536f..71282cd0220 100644 --- a/api/restHandler/CoreAppRestHandler.go +++ b/api/restHandler/CoreAppRestHandler.go @@ -440,7 +440,7 @@ func (handler CoreAppRestHandlerImpl) CreateApp(w http.ResponseWriter, r *http.R func (handler CoreAppRestHandlerImpl) buildAppMetadata(appId int) (*appBean.AppMetadata, error, int) { handler.logger.Debugw("Getting app detail - meta data", "appId", appId) - appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId) + appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID) if err != nil { handler.logger.Errorw("service err, GetAppMetaInfo in GetAppAllDetail", "err", err, "appId", appId) return nil, err, http.StatusInternalServerError @@ -2328,7 +2328,7 @@ func (handler CoreAppRestHandlerImpl) GetAppWorkflow(w http.ResponseWriter, r *h token := r.Header.Get("token") // get app metadata for appId - appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId) + appMetaInfo, err := handler.appCrudOperationService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID) if err != nil { handler.logger.Errorw("service err, GetAppMetaInfo in GetAppWorkflow", "appId", appId, "err", err) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) @@ -2379,7 +2379,7 @@ func (handler CoreAppRestHandlerImpl) GetAppWorkflowAndOverridesSample(w http.Re common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - app, err := handler.appCrudOperationService.GetAppMetaInfo(appId) + app, err := handler.appCrudOperationService.GetAppMetaInfo(appId, app.ZERO_INSTALLED_APP_ID, app.ZERO_ENVIRONMENT_ID) if err != nil { handler.logger.Errorw("service err, GetAppMetaInfo in GetAppAllDetail", "err", err) common.WriteJsonResp(w, err, nil, http.StatusBadRequest) diff --git a/api/router/AppRouter.go b/api/router/AppRouter.go index ec7c83ff7b5..2f6f146ea49 100644 --- a/api/router/AppRouter.go +++ b/api/router/AppRouter.go @@ -56,7 +56,7 @@ func (router AppRouterImpl) InitAppRouter(appRouter *mux.Router) { appRouter.Path("/min").HandlerFunc(router.handler.GetAppListByTeamIds).Methods("GET") - appRouter.Path("/description"). + appRouter.Path("/note"). Methods("PUT"). - HandlerFunc(router.handler.UpdateAppDescription) + HandlerFunc(router.handler.UpdateAppNote) } diff --git a/cmd/external-app/wire.go b/cmd/external-app/wire.go index f31eda91986..93df07ba35b 100644 --- a/cmd/external-app/wire.go +++ b/cmd/external-app/wire.go @@ -92,6 +92,8 @@ func InitializeApp() (*App, error) { telemetry.NewPosthogClient, delete2.NewDeleteServiceImpl, + pipelineConfig.NewMaterialRepositoryImpl, + wire.Bind(new(pipelineConfig.MaterialRepository), new(*pipelineConfig.MaterialRepositoryImpl)), //appStatus appStatus.NewAppStatusRepositoryImpl, wire.Bind(new(appStatus.AppStatusRepository), new(*appStatus.AppStatusRepositoryImpl)), diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index 319e9ebb01d..3f896b05300 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -368,7 +368,8 @@ func InitializeApp() (*App, error) { attributesRestHandlerImpl := restHandler.NewAttributesRestHandlerImpl(sugaredLogger, enforcerImpl, userServiceImpl, attributesServiceImpl) attributesRouterImpl := router.NewAttributesRouterImpl(attributesRestHandlerImpl) appLabelRepositoryImpl := pipelineConfig.NewAppLabelRepositoryImpl(db) - appCrudOperationServiceImpl := app2.NewAppCrudOperationServiceImpl(appLabelRepositoryImpl, sugaredLogger, appRepositoryImpl, userRepositoryImpl, installedAppRepositoryImpl, genericNoteServiceImpl) + materialRepositoryImpl := pipelineConfig.NewMaterialRepositoryImpl(db) + appCrudOperationServiceImpl := app2.NewAppCrudOperationServiceImpl(appLabelRepositoryImpl, sugaredLogger, appRepositoryImpl, userRepositoryImpl, installedAppRepositoryImpl, genericNoteServiceImpl, materialRepositoryImpl) appRestHandlerImpl := restHandler.NewAppRestHandlerImpl(sugaredLogger, appCrudOperationServiceImpl, userServiceImpl, validate, enforcerUtilImpl, enforcerImpl, helmAppServiceImpl, enforcerUtilHelmImpl, genericNoteServiceImpl) appRouterImpl := router.NewAppRouterImpl(sugaredLogger, appRestHandlerImpl) rbacRoleServiceImpl := user.NewRbacRoleServiceImpl(sugaredLogger, rbacRoleDataRepositoryImpl) diff --git a/internal/sql/repository/AppListingRepository.go b/internal/sql/repository/AppListingRepository.go index 5ac8a186656..fc18a3ddc47 100644 --- a/internal/sql/repository/AppListingRepository.go +++ b/internal/sql/repository/AppListingRepository.go @@ -632,19 +632,29 @@ func (impl AppListingRepositoryImpl) makeAppStageStatus(stage int, stageName str } func (impl AppListingRepositoryImpl) FetchOtherEnvironment(appId int) ([]*bean.Environment, error) { - impl.Logger.Debug("reached at FetchOtherEnvironment:") - // other environment tab - //TODO : create new optimised query and need to use explain analyse for both queries var otherEnvironments []*bean.Environment - query := "select OE.*,B.status as app_status " + - "FROM " + - "(SELECT p.environment_id,env.environment_name,env.description, p.last_deployed, env_app_m.app_metrics, env.default as prod, env_app_m.infra_metrics, p.deployment_app_delete_request from ( SELECT pl.id,pl.app_id,pl.environment_id,pl.deleted, pl.deployment_app_delete_request,MAX(pco.created_on) as last_deployed from pipeline pl LEFT JOIN pipeline_config_override pco on pco.pipeline_id = pl.id WHERE pl.app_id = ? and pl.deleted = FALSE GROUP BY pl.id) p INNER JOIN environment env on env.id=p.environment_id LEFT JOIN env_level_app_metrics env_app_m on env.id=env_app_m.env_id and p.app_id = env_app_m.app_id where p.app_id=? and p.deleted = FALSE AND env.active = TRUE GROUP BY 1,2,3,4,5,6,7,8) OE " + - " LEFT JOIN app_status B ON OE.environment_id = B.env_id AND B.app_id = ? ;" - impl.Logger.Debugw("other env query:", query) - _, err := impl.dbConnection.Query(&otherEnvironments, query, appId, appId, appId) + query := `select pcwr.pipeline_id, pcwr.last_deployed, pcwr.latest_cd_workflow_runner_id, pcwr.environment_id, pcwr.deployment_app_delete_request, + e.cluster_id, e.environment_name, e.default as prod, e.description, ca.image as last_deployed_image, + u.email_id as last_deployed_by, elam.app_metrics, elam.infra_metrics, ap.status as app_status + from (select * + from (select p.id as pipeline_id, p.app_id, cwr.started_on as last_deployed, cwr.triggered_by, cwr.id as latest_cd_workflow_runner_id, + cw.ci_artifact_id, p.environment_id, p.deployment_app_delete_request, + row_number() over (partition by p.id order by cwr.started_on desc) as max_started_on_rank + from (select * from pipeline where app_id = ? and deleted=?) as p + left join cd_workflow cw on cw.pipeline_id = p.id + left join cd_workflow_runner cwr on cwr.cd_workflow_id = cw.id + where cwr.workflow_type = ? or cwr.workflow_type is null) pcwrraw + where max_started_on_rank = 1) pcwr + INNER JOIN environment e on e.id = pcwr.environment_id + LEFT JOIN ci_artifact ca on ca.id = pcwr.ci_artifact_id + LEFT JOIN users u on u.id = pcwr.triggered_by + LEFT JOIN env_level_app_metrics elam on pcwr.environment_id = elam.env_id and pcwr.app_id = elam.app_id + LEFT JOIN app_status ap ON pcwr.environment_id = ap.env_id and pcwr.app_id=ap.app_id;` + _, err := impl.dbConnection.Query(&otherEnvironments, query, appId, false, "DEPLOY") if err != nil { impl.Logger.Error("error in fetching other environment", "error", err) + return nil, err } return otherEnvironments, nil } diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 96853d76676..650980ecb1c 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -24,6 +24,7 @@ import ( "github.com/devtron-labs/devtron/pkg/team" "github.com/go-pg/pg" "go.uber.org/zap" + "time" ) type App struct { @@ -45,6 +46,7 @@ type AppRepository interface { SaveWithTxn(pipelineGroup *App, tx *pg.Tx) error Update(app *App) error UpdateWithTxn(app *App, tx *pg.Tx) error + SetDescription(id int, description string, userId int32) error FindActiveByName(appName string) (pipelineGroup *App, err error) FindJobByDisplayName(appName string) (pipelineGroup *App, err error) FindActiveListByName(appName string) ([]*App, error) @@ -116,6 +118,13 @@ func (repo AppRepositoryImpl) UpdateWithTxn(app *App, tx *pg.Tx) error { return err } +func (repo AppRepositoryImpl) SetDescription(id int, description string, userId int32) error { + _, err := repo.dbConnection.Model((*App)(nil)). + Set("description = ?", description).Set("updated_by = ?", userId).Set("updated_on = ?", time.Now()). + Where("id = ?", id).Update() + return err +} + func (repo AppRepositoryImpl) FindActiveByName(appName string) (*App, error) { pipelineGroup := &App{} err := repo.dbConnection. diff --git a/internal/util/ArgoUtil/ArgoClient.go b/internal/util/ArgoUtil/ArgoClient.go index 26de17389c0..d6d3af4cc13 100644 --- a/internal/util/ArgoUtil/ArgoClient.go +++ b/internal/util/ArgoUtil/ArgoClient.go @@ -109,7 +109,7 @@ func (session *ArgoSession) DoRequest(clientRequest *ClientRequest) (resBody []b func NewArgoSession(config *ArgoConfig, logger *zap.SugaredLogger) (session *ArgoSession, err error) { /*location := "/api/v1/session" - baseUrl, err := url.Parse(config.Url) + baseUrl, err := url.Parse(config.RedirectionUrl) if err != nil { return nil, err } diff --git a/internal/util/GitService.go b/internal/util/GitService.go index 6acd00b734c..882772e523a 100644 --- a/internal/util/GitService.go +++ b/internal/util/GitService.go @@ -38,7 +38,7 @@ import ( const ( GIT_WORKING_DIR = "/tmp/gitops/" - GetRepoUrlStage = "Get Repo Url" + GetRepoUrlStage = "Get Repo RedirectionUrl" CreateRepoStage = "Create Repo" CloneHttpStage = "Clone Http" CreateReadmeStage = "Create Readme" diff --git a/pkg/app/AppCrudOperationService.go b/pkg/app/AppCrudOperationService.go index 9a3bb90b3db..e46536fc140 100644 --- a/pkg/app/AppCrudOperationService.go +++ b/pkg/app/AppCrudOperationService.go @@ -30,16 +30,22 @@ import ( "github.com/devtron-labs/devtron/pkg/user/repository" "github.com/go-pg/pg" "go.uber.org/zap" + "regexp" "strconv" "strings" "time" ) +const ( + ZERO_INSTALLED_APP_ID = 0 + ZERO_ENVIRONMENT_ID = 0 +) + type AppCrudOperationService interface { Create(request *bean.AppLabelDto, tx *pg.Tx) (*bean.AppLabelDto, error) FindById(id int) (*bean.AppLabelDto, error) FindAll() ([]*bean.AppLabelDto, error) - GetAppMetaInfo(appId int) (*bean.AppMetaInfoDto, error) + GetAppMetaInfo(appId int, installedAppId int, envId int) (*bean.AppMetaInfoDto, error) GetHelmAppMetaInfo(appId string) (*bean.AppMetaInfoDto, error) GetLabelsByAppIdForDeployment(appId int) ([]byte, error) GetLabelsByAppId(appId int) (map[string]string, error) @@ -48,6 +54,7 @@ type AppCrudOperationService interface { GetAppMetaInfoByAppName(appName string) (*bean.AppMetaInfoDto, error) GetAppListByTeamIds(teamIds []int, appType string) ([]*TeamAppBean, error) } + type AppCrudOperationServiceImpl struct { logger *zap.SugaredLogger appLabelRepository pipelineConfig.AppLabelRepository @@ -55,12 +62,14 @@ type AppCrudOperationServiceImpl struct { userRepository repository.UserRepository installedAppRepository repository2.InstalledAppRepository genericNoteService genericNotes.GenericNoteService + gitMaterialRepository pipelineConfig.MaterialRepository } func NewAppCrudOperationServiceImpl(appLabelRepository pipelineConfig.AppLabelRepository, logger *zap.SugaredLogger, appRepository appRepository.AppRepository, userRepository repository.UserRepository, installedAppRepository repository2.InstalledAppRepository, - genericNoteService genericNotes.GenericNoteService) *AppCrudOperationServiceImpl { + genericNoteService genericNotes.GenericNoteService, + gitMaterialRepository pipelineConfig.MaterialRepository) *AppCrudOperationServiceImpl { return &AppCrudOperationServiceImpl{ appLabelRepository: appLabelRepository, logger: logger, @@ -68,6 +77,7 @@ func NewAppCrudOperationServiceImpl(appLabelRepository pipelineConfig.AppLabelRe userRepository: userRepository, installedAppRepository: installedAppRepository, genericNoteService: genericNoteService, + gitMaterialRepository: gitMaterialRepository, } } @@ -125,6 +135,13 @@ func (impl AppCrudOperationServiceImpl) UpdateApp(request *bean.CreateAppDTO) (* return nil, err } + //updating description + err = impl.appRepository.SetDescription(app.Id, request.Description, request.UserId) + if err != nil { + impl.logger.Errorw("error in setting app description", "err", err, "appId", app.Id) + return nil, err + } + err = tx.Commit() if err != nil { impl.logger.Errorw("error in commit db transaction", "error", err) @@ -284,7 +301,8 @@ func (impl AppCrudOperationServiceImpl) FindAll() ([]*bean.AppLabelDto, error) { return results, nil } -func (impl AppCrudOperationServiceImpl) GetAppMetaInfo(appId int) (*bean.AppMetaInfoDto, error) { +// GetAppMetaInfo here envId is for installedApp +func (impl AppCrudOperationServiceImpl) GetAppMetaInfo(appId int, installedAppId int, envId int) (*bean.AppMetaInfoDto, error) { app, err := impl.appRepository.FindAppAndProjectByAppId(appId) if err != nil { impl.logger.Errorw("error in fetching GetAppMetaInfo", "error", err) @@ -326,25 +344,85 @@ func (impl AppCrudOperationServiceImpl) GetAppMetaInfo(appId int) (*bean.AppMeta if app.AppType == helper.Job { appName = app.DisplayName } - descriptionResp, err := impl.genericNoteService.GetGenericNotesForAppIds([]int{app.Id}) + noteResp, err := impl.genericNoteService.GetGenericNotesForAppIds([]int{app.Id}) if err != nil { impl.logger.Errorw("error in fetching description", "err", err, "appId", app.Id) return nil, err } + info := &bean.AppMetaInfoDto{ AppId: app.Id, AppName: appName, + Description: app.Description, ProjectId: app.TeamId, ProjectName: app.Team.Name, CreatedBy: userEmailId, CreatedOn: app.CreatedOn, Labels: labels, Active: app.Active, - Description: descriptionResp[app.Id], + Note: noteResp[app.Id], + } + if installedAppId > 0 { + installedAppVersion, err := impl.installedAppRepository.GetInstalledAppVersionByInstalledAppIdAndEnvId(installedAppId, envId) + if err != nil { + impl.logger.Error(err) + return nil, err + } + var chartName string + if installedAppVersion != nil { + info.ChartUsed = &bean.ChartUsedDto{ + AppStoreAppName: installedAppVersion.AppStoreApplicationVersion.Name, + AppStoreAppVersion: installedAppVersion.AppStoreApplicationVersion.Version, + ChartAvatar: installedAppVersion.AppStoreApplicationVersion.Icon, + } + if installedAppVersion.AppStoreApplicationVersion.AppStore != nil { + appStore := installedAppVersion.AppStoreApplicationVersion.AppStore + if appStore.ChartRepoId != 0 && appStore.ChartRepo != nil { + chartName = appStore.ChartRepo.Name + } else if appStore.DockerArtifactStore != nil { + chartName = appStore.DockerArtifactStore.Id + } + + info.ChartUsed.AppStoreChartId = appStore.Id + info.ChartUsed.AppStoreChartName = chartName + } + } + } else { + //app type not helm type, getting gitMaterials + gitMaterials, err := impl.gitMaterialRepository.FindByAppId(appId) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in getting gitMaterials by appId", "err", err, "appId", appId) + return nil, err + } + gitMaterialMetaDtos := make([]*bean.GitMaterialMetaDto, 0, len(gitMaterials)) + for _, gitMaterial := range gitMaterials { + gitMaterialMetaDtos = append(gitMaterialMetaDtos, &bean.GitMaterialMetaDto{ + DisplayName: gitMaterial.Name[strings.Index(gitMaterial.Name, "-")+1:], + OriginalUrl: gitMaterial.Url, + RedirectionUrl: convertUrlToHttpsIfSshType(gitMaterial.Url), + }) + } + info.GitMaterials = gitMaterialMetaDtos } return info, nil } +func convertUrlToHttpsIfSshType(url string) string { + // Regular expression to match SSH URL patterns + sshPattern := `^(git@|ssh:\/\/)([^:]+):(.+)$` + + // Compile the regular expression + re := regexp.MustCompile(sshPattern) + + // Check if the input URL matches the SSH pattern, if not already a https one + if !re.MatchString(url) { + return url + } + // Replace the SSH parts with HTTPS parts + httpsURL := re.ReplaceAllString(url, "https://$2/$3") + return httpsURL +} + func (impl AppCrudOperationServiceImpl) GetHelmAppMetaInfo(appId string) (*bean.AppMetaInfoDto, error) { // adding separate function for helm apps because for CLI helm apps, apps can be of form "1|clusterName|releaseName" diff --git a/pkg/appClone/AppCloneService.go b/pkg/appClone/AppCloneService.go index 73b8996f61c..18394b9fd37 100644 --- a/pkg/appClone/AppCloneService.go +++ b/pkg/appClone/AppCloneService.go @@ -131,7 +131,7 @@ func (impl *AppCloneServiceImpl) CloneApp(createReq *bean.CreateAppDTO, context ProjectId: createReq.TeamId, AppLabels: createReq.AppLabels, AppType: createReq.AppType, - Description: createReq.Description, + Description: createReq.GenericNote, } userId := createReq.UserId appStatus, err := impl.appListingService.FetchAppStageStatus(cloneReq.RefAppId, int(cloneReq.AppType)) @@ -238,7 +238,7 @@ func (impl *AppCloneServiceImpl) CreateApp(cloneReq *CloneRequest, userId int32) TeamId: cloneReq.ProjectId, AppLabels: cloneReq.AppLabels, AppType: cloneReq.AppType, - Description: cloneReq.Description, + GenericNote: cloneReq.Description, } createRes, err := impl.pipelineBuilder.CreateApp(createAppReq) return createRes, err diff --git a/pkg/bean/app.go b/pkg/bean/app.go index 2c4c1dcae36..be2619f9193 100644 --- a/pkg/bean/app.go +++ b/pkg/bean/app.go @@ -43,12 +43,13 @@ type SourceTypeConfig struct { type CreateAppDTO struct { Id int `json:"id,omitempty" validate:"number"` AppName string `json:"appName" validate:"name-component,max=100"` + Description string `json:"description"` UserId int32 `json:"-"` //not exposed to UI Material []*GitMaterial `json:"material" validate:"dive,min=1"` TeamId int `json:"teamId,omitempty" validate:"number,required"` TemplateId int `json:"templateId"` AppLabels []*Label `json:"labels,omitempty" validate:"dive"` - Description *bean2.GenericNoteResponseBean `json:"description,omitempty"` + GenericNote *bean2.GenericNoteResponseBean `json:"genericNote,omitempty"` AppType helper.AppType `json:"appType" validate:"gt=-1,lt=3"` //TODO: Change Validation if new AppType is introduced } @@ -764,14 +765,32 @@ type Label struct { type AppMetaInfoDto struct { AppId int `json:"appId"` AppName string `json:"appName"` + Description string `json:"description"` ProjectId int `json:"projectId"` ProjectName string `json:"projectName"` CreatedBy string `json:"createdBy"` CreatedOn time.Time `json:"createdOn"` Active bool `json:"active,notnull"` Labels []*Label `json:"labels"` - Description *bean2.GenericNoteResponseBean `json:"description"` + Note *bean2.GenericNoteResponseBean `json:"note"` UserId int32 `json:"-"` + //below field is only valid for helm apps + ChartUsed *ChartUsedDto `json:"chartUsed,omitempty"` + GitMaterials []*GitMaterialMetaDto `json:"gitMaterials,omitempty"` +} + +type GitMaterialMetaDto struct { + DisplayName string `json:"displayName"` + RedirectionUrl string `json:"redirectionUrl"` // here we are converting ssh urls to https for redirection at FE + OriginalUrl string `json:"originalUrl"` +} + +type ChartUsedDto struct { + AppStoreChartName string `json:"appStoreChartName,omitempty"` + AppStoreChartId int `json:"appStoreChartId,omitempty"` + AppStoreAppName string `json:"appStoreAppName,omitempty"` + AppStoreAppVersion string `json:"appStoreAppVersion,omitempty"` + ChartAvatar string `json:"chartAvatar,omitempty"` } type AppLabelsJsonForDeployment struct { diff --git a/pkg/chartRepo/ChartRepositoryService.go b/pkg/chartRepo/ChartRepositoryService.go index 3b87ea0027f..3d4ca9f7d53 100644 --- a/pkg/chartRepo/ChartRepositoryService.go +++ b/pkg/chartRepo/ChartRepositoryService.go @@ -434,7 +434,7 @@ func (impl *ChartRepositoryServiceImpl) DeleteChartRepo(request *ChartRepoDto) e } updateSuccess := false retryCount := 0 - //request.Url = "" + //request.RedirectionUrl = "" for !updateSuccess && retryCount < 3 { retryCount = retryCount + 1 diff --git a/pkg/cluster/ClusterDescriptionService.go b/pkg/cluster/ClusterDescriptionService.go index 1c4ac4b7608..1fe503dcf27 100644 --- a/pkg/cluster/ClusterDescriptionService.go +++ b/pkg/cluster/ClusterDescriptionService.go @@ -29,6 +29,8 @@ import ( type ClusterDescriptionBean struct { ClusterId int `json:"clusterId" validate:"number"` ClusterName string `json:"clusterName" validate:"required"` + Description string `json:"description"` + ServerUrl string `json:"serverUrl"` ClusterCreatedBy string `json:"clusterCreatedBy" validate:"number"` ClusterCreatedOn time.Time `json:"clusterCreatedOn" validate:"required"` ClusterNote *apiBean.GenericNoteResponseBean `json:"clusterNote,omitempty"` @@ -71,13 +73,15 @@ func (impl *ClusterDescriptionServiceImpl) FindByClusterIdWithClusterDetails(clu bean := &ClusterDescriptionBean{ ClusterId: model.ClusterId, ClusterName: model.ClusterName, + Description: model.ClusterDescription, + ServerUrl: model.ServerUrl, ClusterCreatedBy: clusterCreatedByUser.EmailId, ClusterCreatedOn: model.ClusterCreatedOn, } if model.NoteId > 0 { clusterNote := &apiBean.GenericNoteResponseBean{ Id: model.NoteId, - Description: model.Description, + Description: model.Note, UpdatedBy: noteUpdatedByUser.EmailId, UpdatedOn: model.UpdatedOn, } diff --git a/pkg/cluster/ClusterService.go b/pkg/cluster/ClusterService.go index 992b377518f..5b45a3b52de 100644 --- a/pkg/cluster/ClusterService.go +++ b/pkg/cluster/ClusterService.go @@ -71,6 +71,7 @@ type PrometheusAuth struct { type ClusterBean struct { Id int `json:"id" validate:"number"` ClusterName string `json:"cluster_name,omitempty" validate:"required"` + Description string `json:"description"` ServerUrl string `json:"server_url,omitempty" validate:"url,required"` PrometheusUrl string `json:"prometheus_url,omitempty" validate:"validate-non-empty-url"` Active bool `json:"active"` @@ -93,6 +94,7 @@ func GetClusterBean(model repository.Cluster) ClusterBean { bean := ClusterBean{} bean.Id = model.Id bean.ClusterName = model.ClusterName + //bean.Note = model.Note bean.ServerUrl = model.ServerUrl bean.PrometheusUrl = model.PrometheusEndpoint bean.AgentInstallationStage = model.AgentInstallationStage @@ -155,6 +157,7 @@ type DefaultClusterComponent struct { type ClusterService interface { Save(parent context.Context, bean *ClusterBean, userId int32) (*ClusterBean, error) + UpdateClusterDescription(bean *ClusterBean, userId int32) error ValidateKubeconfig(kubeConfig string) (map[string]*ValidateClusterBean, error) FindOne(clusterName string) (*ClusterBean, error) FindOneActive(clusterName string) (*ClusterBean, error) @@ -221,6 +224,7 @@ func (impl *ClusterServiceImpl) ConvertClusterBeanToCluster(clusterBean *Cluster model := &repository.Cluster{} model.ClusterName = clusterBean.ClusterName + //model.Note = clusterBean.Note model.Active = true model.ServerUrl = clusterBean.ServerUrl model.Config = clusterBean.Config @@ -317,6 +321,18 @@ func (impl *ClusterServiceImpl) Save(parent context.Context, bean *ClusterBean, return bean, err } +// UpdateClusterDescription is new api service logic to only update description, this should be done in cluster update operation only +// but not supported currently as per product +func (impl *ClusterServiceImpl) UpdateClusterDescription(bean *ClusterBean, userId int32) error { + //updating description as other fields are not supported yet + err := impl.clusterRepository.SetDescription(bean.Id, bean.Description, userId) + if err != nil { + impl.logger.Errorw("error in setting cluster description", "err", err, "clusterId", bean.Id) + return err + } + return nil +} + func (impl *ClusterServiceImpl) FindOne(clusterName string) (*ClusterBean, error) { model, err := impl.clusterRepository.FindOne(clusterName) if err != nil { diff --git a/pkg/cluster/repository/ClusterDescriptionRepository.go b/pkg/cluster/repository/ClusterDescriptionRepository.go index c4ab627ffa4..5b1b58f9232 100644 --- a/pkg/cluster/repository/ClusterDescriptionRepository.go +++ b/pkg/cluster/repository/ClusterDescriptionRepository.go @@ -25,13 +25,16 @@ import ( "time" ) +// TODO: remove this whole repository, nothing different which cannot be included in cluster repository type ClusterDescription struct { - ClusterId int `sql:"cluster_id"` - ClusterName string `sql:"cluster_name"` - ClusterCreatedOn time.Time `sql:"cluster_created_on"` - ClusterCreatedBy int32 `sql:"cluster_created_by"` - NoteId int `sql:"note_id,pk"` - Description string `sql:"description"` + ClusterId int `sql:"cluster_id"` + ClusterName string `sql:"cluster_name"` + ClusterDescription string `sql:"cluster_description"` + ServerUrl string `sql:"server_url"` + ClusterCreatedOn time.Time `sql:"cluster_created_on"` + ClusterCreatedBy int32 `sql:"cluster_created_by"` + NoteId int `sql:"note_id,pk"` + Note string `sql:"note"` sql.AuditLog } @@ -53,7 +56,7 @@ type ClusterDescriptionRepositoryImpl struct { func (impl ClusterDescriptionRepositoryImpl) FindByClusterIdWithClusterDetails(clusterId int) (*ClusterDescription, error) { clusterDescription := &ClusterDescription{} - query := "SELECT cl.id AS cluster_id, cl.cluster_name AS cluster_name, cl.created_on AS cluster_created_on, cl.created_by AS cluster_created_by, gn.id AS note_id, gn.description, gn.created_by, gn.created_on, gn.updated_by, gn.updated_on FROM" + + query := "SELECT cl.id AS cluster_id, cl.cluster_name AS cluster_name, cl.description AS cluster_description, cl.server_url, cl.created_on AS cluster_created_on, cl.created_by AS cluster_created_by, gn.id AS note_id, gn.description AS note, gn.created_by, gn.created_on, gn.updated_by, gn.updated_on FROM" + " cluster cl LEFT JOIN" + " generic_note gn " + " ON cl.id=gn.identifier AND (gn.identifier_type = %d OR gn.identifier_type IS NULL)" + diff --git a/pkg/cluster/repository/ClusterRepository.go b/pkg/cluster/repository/ClusterRepository.go index 5fe9941e93e..44597b69aa2 100644 --- a/pkg/cluster/repository/ClusterRepository.go +++ b/pkg/cluster/repository/ClusterRepository.go @@ -21,12 +21,14 @@ import ( "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" "go.uber.org/zap" + "time" ) type Cluster struct { tableName struct{} `sql:"cluster" pg:",discard_unknown_columns"` Id int `sql:"id,pk"` ClusterName string `sql:"cluster_name"` + Description string `sql:"description"` ServerUrl string `sql:"server_url"` PrometheusEndpoint string `sql:"prometheus_endpoint"` Active bool `sql:"active,notnull"` @@ -54,6 +56,7 @@ type ClusterRepository interface { FindById(id int) (*Cluster, error) FindByIds(id []int) ([]Cluster, error) Update(model *Cluster) error + SetDescription(id int, description string, userId int32) error Delete(model *Cluster) error MarkClusterDeleted(model *Cluster) error UpdateClusterConnectionStatus(clusterId int, errorInConnecting string) error @@ -172,6 +175,13 @@ func (impl ClusterRepositoryImpl) Update(model *Cluster) error { return impl.dbConnection.Update(model) } +func (impl ClusterRepositoryImpl) SetDescription(id int, description string, userId int32) error { + _, err := impl.dbConnection.Model((*Cluster)(nil)). + Set("description = ?", description).Set("updated_by = ?", userId).Set("updated_on = ?", time.Now()). + Where("id = ?", id).Update() + return err +} + func (impl ClusterRepositoryImpl) Delete(model *Cluster) error { return impl.dbConnection.Delete(model) } diff --git a/pkg/genericNotes/tests/GenericNoteService_test.go b/pkg/genericNotes/tests/GenericNoteService_test.go index 70b19914cdf..198ca1c4ec4 100644 --- a/pkg/genericNotes/tests/GenericNoteService_test.go +++ b/pkg/genericNotes/tests/GenericNoteService_test.go @@ -310,7 +310,7 @@ func TestGetGenericNotesForAppIds(t *testing.T) { }) - t.Run("Test Success, Get Newly edited/created Description and old descriptions", func(tt *testing.T) { + t.Run("Test Success, Get Newly edited/created GenericNote and old descriptions", func(tt *testing.T) { genericNoteSvc, mockedNoteRepo, _, mockedUserRepo := initGenericNoteService(t) mockedNoteRepo.On("GetGenericNotesForAppIds", mock.AnythingOfType("[]int")).Return(getGenericNotesForAppIdsResp, nil) diff --git a/pkg/gitops/GitOpsConfigService.go b/pkg/gitops/GitOpsConfigService.go index 2054fd9e0cb..fe2e70ec0f1 100644 --- a/pkg/gitops/GitOpsConfigService.go +++ b/pkg/gitops/GitOpsConfigService.go @@ -69,7 +69,7 @@ const ( CommitOnRestStage = "Commit On Rest" PushStage = "Push" CloneStage = "Clone" - GetRepoUrlStage = "Get Repo Url" + GetRepoUrlStage = "Get Repo RedirectionUrl" CreateRepoStage = "Create Repo" CloneHttp = "Clone Http" CreateReadmeStage = "Create Readme" diff --git a/pkg/pipeline/BuildPipelineConfigService.go b/pkg/pipeline/BuildPipelineConfigService.go index d467b9f4c71..933e20dc464 100644 --- a/pkg/pipeline/BuildPipelineConfigService.go +++ b/pkg/pipeline/BuildPipelineConfigService.go @@ -440,13 +440,11 @@ func (impl *CiPipelineConfigServiceImpl) buildPayloadOption() []bean.PayloadOpti func (impl *CiPipelineConfigServiceImpl) buildExternalCiWebhookSchema() map[string]interface{} { schema := make(map[string]interface{}) - schema["dockerImage"] = &bean.SchemaObject{Description: "docker image created for your application (Eg. quay.io/devtron/test:da3ba325-161-467)", DataType: "String", Example: "test-docker-repo/test:b150cc81-5-20", Optional: false} - //schema["digest"] = &bean.SchemaObject{Description: "docker image sha1 digest", DataType: "String", Example: "sha256:94180dead8336237430e848ef8145f060b51", Optional: true} - //schema["materialType"] = &bean.SchemaObject{Description: "git", DataType: "String", Example: "git", Optional: true} + schema["dockerImage"] = &bean.SchemaObject{Description: "docker image created for your application (Eg. docker/test:latest)", DataType: "String", Example: "test-docker-repo/test:b150cc81-5-20", Optional: false} ciProjectDetails := make([]map[string]interface{}, 0) ciProjectDetail := make(map[string]interface{}) - ciProjectDetail["commitHash"] = &bean.SchemaObject{Description: "Hash of git commit used to build the image (Eg. 4bd84gba5ebdd6b1937ffd6c0734c2ad52ede782)", DataType: "String", Example: "dg46f67559dbsdfdfdfdsfba47901caf47f8b7e", Optional: true} + ciProjectDetail["commitHash"] = &bean.SchemaObject{Description: "Hash of git commit used to build the image (Eg. 4bd84gba5ebdd6b2ad52ede782)", DataType: "String", Example: "dg46f67559dbsdfdfdfdsfba47901caf47f8b7e", Optional: true} ciProjectDetail["commitTime"] = &bean.SchemaObject{Description: "Time at which the code was committed to git (Eg. 2022-11-12T12:12:00)", DataType: "String", Example: "2022-11-12T12:12:00", Optional: true} ciProjectDetail["message"] = &bean.SchemaObject{Description: "Message provided during code commit (Eg. This is a sample commit message)", DataType: "String", Example: "commit message", Optional: true} ciProjectDetail["author"] = &bean.SchemaObject{Description: "Name or email id of the user who has done git commit (Eg. John Doe, johndoe@company.com)", DataType: "String", Example: "Devtron User", Optional: true} diff --git a/pkg/pipeline/CiCdPipelineOrchestrator.go b/pkg/pipeline/CiCdPipelineOrchestrator.go index f9c16a0518f..4aaf825d026 100644 --- a/pkg/pipeline/CiCdPipelineOrchestrator.go +++ b/pkg/pipeline/CiCdPipelineOrchestrator.go @@ -1054,13 +1054,13 @@ func (impl CiCdPipelineOrchestratorImpl) CreateApp(createRequest *bean.CreateApp } // Rollback tx on error. defer tx.Rollback() - app, err := impl.createAppGroup(createRequest.AppName, createRequest.UserId, createRequest.TeamId, createRequest.AppType, tx) + app, err := impl.createAppGroup(createRequest.AppName, createRequest.Description, createRequest.UserId, createRequest.TeamId, createRequest.AppType, tx) if err != nil { return nil, err } - err = impl.storeDescription(tx, createRequest, app.Id) + err = impl.storeGenericNote(tx, createRequest, app.Id) if err != nil { - impl.logger.Errorw("error in saving description", "err", err, "descriptionObj", createRequest.Description, "userId", createRequest.UserId) + impl.logger.Errorw("error in saving generic note", "err", err, "genericNoteObj", createRequest.GenericNote, "userId", createRequest.UserId) return nil, err } // create labels and tags with app @@ -1097,19 +1097,19 @@ func (impl CiCdPipelineOrchestratorImpl) CreateApp(createRequest *bean.CreateApp return createRequest, nil } -func (impl CiCdPipelineOrchestratorImpl) storeDescription(tx *pg.Tx, createRequest *bean.CreateAppDTO, appId int) error { - if createRequest.Description != nil && createRequest.Description.Description != "" { - descriptionObj := repository3.GenericNote{ - Description: createRequest.Description.Description, +func (impl CiCdPipelineOrchestratorImpl) storeGenericNote(tx *pg.Tx, createRequest *bean.CreateAppDTO, appId int) error { + if createRequest.GenericNote != nil && createRequest.GenericNote.Description != "" { + genericNoteObj := repository3.GenericNote{ + Description: createRequest.GenericNote.Description, IdentifierType: repository3.AppType, Identifier: appId, } - note, err := impl.genericNoteService.Save(tx, &descriptionObj, createRequest.UserId) + note, err := impl.genericNoteService.Save(tx, &genericNoteObj, createRequest.UserId) if err != nil { - impl.logger.Errorw("error in saving description", "err", err, "descriptionObj", descriptionObj, "userId", createRequest.UserId) + impl.logger.Errorw("error in saving description", "err", err, "genericNoteObj", genericNoteObj, "userId", createRequest.UserId) return err } - createRequest.Description = note + createRequest.GenericNote = note } return nil } @@ -1266,7 +1266,7 @@ func (impl CiCdPipelineOrchestratorImpl) addRepositoryToGitSensor(materials []*b } // FIXME: not thread safe -func (impl CiCdPipelineOrchestratorImpl) createAppGroup(name string, userId int32, teamId int, appType helper.AppType, tx *pg.Tx) (*app2.App, error) { +func (impl CiCdPipelineOrchestratorImpl) createAppGroup(name, description string, userId int32, teamId int, appType helper.AppType, tx *pg.Tx) (*app2.App, error) { app, err := impl.appRepository.FindActiveByName(name) if err != nil && err != pg.ErrNoRows { return nil, err @@ -1306,6 +1306,7 @@ func (impl CiCdPipelineOrchestratorImpl) createAppGroup(name string, userId int3 Active: true, AppName: appName, DisplayName: displayName, + Description: description, TeamId: teamId, AppType: appType, AuditLog: sql.AuditLog{UpdatedBy: userId, CreatedBy: userId, UpdatedOn: time.Now(), CreatedOn: time.Now()}, diff --git a/pkg/pipeline/GitRegistryConfig.go b/pkg/pipeline/GitRegistryConfig.go index 93b2140be7b..5fa9c132e7d 100644 --- a/pkg/pipeline/GitRegistryConfig.go +++ b/pkg/pipeline/GitRegistryConfig.go @@ -192,14 +192,14 @@ func (impl GitRegistryConfigImpl) Update(request *types.GitRegistry) (*types.Git impl.logger.Debugw("get repo create request", "req", request) /* - exist, err := impl.gitProviderRepo.ProviderExists(request.Url) + exist, err := impl.gitProviderRepo.ProviderExists(request.RedirectionUrl) if err != nil { - impl.logger.Errorw("error in fetch ", "url", request.Url, "err", err) + impl.logger.Errorw("error in fetch ", "url", request.RedirectionUrl, "err", err) return nil, err } if exist { - impl.logger.Infow("repo already exists", "url", request.Url) - return nil, errors.NewAlreadyExists(err, request.Url) + impl.logger.Infow("repo already exists", "url", request.RedirectionUrl) + return nil, errors.NewAlreadyExists(err, request.RedirectionUrl) } */ diff --git a/pkg/plugin/GlobalPluginService.go b/pkg/plugin/GlobalPluginService.go index 857f6f86c32..191dc65008e 100644 --- a/pkg/plugin/GlobalPluginService.go +++ b/pkg/plugin/GlobalPluginService.go @@ -56,7 +56,7 @@ func (impl *GlobalPluginServiceImpl) GetAllGlobalVariables() ([]*GlobalVariable, { Name: "DOCKER_REGISTRY_URL", Format: string(repository.PLUGIN_VARIABLE_FORMAT_TYPE_STRING), - Description: "Url of the container registry used for this pipeline.", + Description: "RedirectionUrl of the container registry used for this pipeline.", Type: "ci", }, { diff --git a/pkg/resourceGroup/ResourceGroupService.go b/pkg/resourceGroup/ResourceGroupService.go index 306b1a68bb1..5f5c106e503 100644 --- a/pkg/resourceGroup/ResourceGroupService.go +++ b/pkg/resourceGroup/ResourceGroupService.go @@ -127,14 +127,6 @@ type ResourceGroupDto struct { EnvironmentId int `json:"environmentId,omitempty"` } -//type ApplicationDto struct { -// ResourceGroupId int `json:"appGroupId,omitempty"` -// AppId int `json:"appId,omitempty"` -// AppName string `json:"appName,omitempty"` -// EnvironmentId int `json:"environmentId,omitempty"` -// Description string `json:"description,omitempty"` -//} - func (impl *ResourceGroupServiceImpl) CreateResourceGroup(request *ResourceGroupDto) (*ResourceGroupDto, error) { resourceKeyToId := impl.devtronResourceService.GetAllSearchableKeyNameIdMap() @@ -350,7 +342,7 @@ func (impl *ResourceGroupServiceImpl) GetActiveResourceGroupList(emailId string, // for _, appGroup := range appGroups { // appGroupDto := &ApplicationDto{ // AppId: appGroup.ResourceId, -// Description: appGroup.ResourceGroup.Description, +// GenericNote: appGroup.ResourceGroup.GenericNote, // } // applications = append(applications, appGroupDto) // } diff --git a/scripts/sql/185_alter_cluster_add_description.down.sql b/scripts/sql/185_alter_cluster_add_description.down.sql new file mode 100644 index 00000000000..b384410e283 --- /dev/null +++ b/scripts/sql/185_alter_cluster_add_description.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE cluster + DROP COLUMN IF EXISTS description; \ No newline at end of file diff --git a/scripts/sql/185_alter_cluster_add_description.up.sql b/scripts/sql/185_alter_cluster_add_description.up.sql new file mode 100644 index 00000000000..c6b5c630a01 --- /dev/null +++ b/scripts/sql/185_alter_cluster_add_description.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE cluster + ADD COLUMN description TEXT; \ No newline at end of file diff --git a/wire_gen.go b/wire_gen.go index 408abc38e56..dd1873e4d4a 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -389,7 +389,8 @@ func InitializeApp() (*App, error) { genericNoteHistoryRepositoryImpl := repository10.NewGenericNoteHistoryRepositoryImpl(db) genericNoteHistoryServiceImpl := genericNotes.NewGenericNoteHistoryServiceImpl(genericNoteHistoryRepositoryImpl, sugaredLogger) genericNoteServiceImpl := genericNotes.NewGenericNoteServiceImpl(genericNoteRepositoryImpl, genericNoteHistoryServiceImpl, userRepositoryImpl, sugaredLogger) - appCrudOperationServiceImpl := app2.NewAppCrudOperationServiceImpl(appLabelRepositoryImpl, sugaredLogger, appRepositoryImpl, userRepositoryImpl, installedAppRepositoryImpl, genericNoteServiceImpl) + materialRepositoryImpl := pipelineConfig.NewMaterialRepositoryImpl(db) + appCrudOperationServiceImpl := app2.NewAppCrudOperationServiceImpl(appLabelRepositoryImpl, sugaredLogger, appRepositoryImpl, userRepositoryImpl, installedAppRepositoryImpl, genericNoteServiceImpl, materialRepositoryImpl) dockerRegistryIpsConfigRepositoryImpl := repository5.NewDockerRegistryIpsConfigRepositoryImpl(db) ciTemplateOverrideRepositoryImpl := pipelineConfig.NewCiTemplateOverrideRepositoryImpl(db, sugaredLogger) dockerRegistryIpsConfigServiceImpl := dockerRegistry.NewDockerRegistryIpsConfigServiceImpl(sugaredLogger, dockerRegistryIpsConfigRepositoryImpl, k8sUtil, clusterServiceImplExtended, ciPipelineRepositoryImpl, dockerArtifactStoreRepositoryImpl, ciTemplateOverrideRepositoryImpl) @@ -438,7 +439,6 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - materialRepositoryImpl := pipelineConfig.NewMaterialRepositoryImpl(db) deploymentGroupRepositoryImpl := repository.NewDeploymentGroupRepositoryImpl(sugaredLogger, db) cvePolicyRepositoryImpl := security.NewPolicyRepositoryImpl(db) imageScanResultRepositoryImpl := security.NewImageScanResultRepositoryImpl(db, sugaredLogger) @@ -641,7 +641,7 @@ func InitializeApp() (*App, error) { chartRefRouterImpl := router.NewChartRefRouterImpl(chartRefRestHandlerImpl) configMapRestHandlerImpl := restHandler.NewConfigMapRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, chartServiceImpl, userServiceImpl, teamServiceImpl, enforcerImpl, pipelineRepositoryImpl, enforcerUtilImpl, configMapServiceImpl) configMapRouterImpl := router.NewConfigMapRouterImpl(configMapRestHandlerImpl) - installedAppRestHandlerImpl := appStore.NewInstalledAppRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, installedAppServiceImpl, validate, clusterServiceImplExtended, applicationServiceClientImpl, appStoreDeploymentServiceImpl, helmAppClientImpl, helmAppServiceImpl, argoUserServiceImpl, cdApplicationStatusUpdateHandlerImpl, installedAppRepositoryImpl) + installedAppRestHandlerImpl := appStore.NewInstalledAppRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, installedAppServiceImpl, validate, clusterServiceImplExtended, applicationServiceClientImpl, appStoreDeploymentServiceImpl, helmAppClientImpl, helmAppServiceImpl, argoUserServiceImpl, cdApplicationStatusUpdateHandlerImpl, installedAppRepositoryImpl, appCrudOperationServiceImpl) appStoreValuesRestHandlerImpl := appStoreValues.NewAppStoreValuesRestHandlerImpl(sugaredLogger, userServiceImpl, appStoreValuesServiceImpl) appStoreValuesRouterImpl := appStoreValues.NewAppStoreValuesRouterImpl(appStoreValuesRestHandlerImpl) appStoreServiceImpl := service3.NewAppStoreServiceImpl(sugaredLogger, appStoreApplicationVersionRepositoryImpl)