From 927fc5da33b75ecae6102887a5d9005758e74b49 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Fri, 3 Jan 2025 17:44:22 +0530 Subject: [PATCH 1/9] added git resource map --- .../appsmith/git/files/FileUtilsCEImpl.java | 7 ++ .../appsmith/external/git/FileInterface.java | 2 + .../git/ApplicationGitFileUtilsCEImpl.java | 10 ++ .../git/central/CentralGitServiceCEImpl.java | 3 +- .../server/git/fs/GitFSServiceCEImpl.java | 41 +++++---- .../helpers/ce/ArtifactGitFileUtilsCE.java | 4 + .../helpers/ce/CommonGitFileUtilsCE.java | 91 +++++++++++++++++++ .../migrations/JsonSchemaMigration.java | 1 + 8 files changed, 138 insertions(+), 21 deletions(-) diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java index b7f395022124..7d68aaf19e50 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java @@ -674,6 +674,13 @@ public Mono reconstructApplicationReferenceFromGitRepo( .subscribeOn(scheduler); } + @Override + public Mono constructGitResourceMapFromGitRepo(Path repositorySuffix, String refName) { + // TODO: check that we need to checkout to the ref + Path repositoryPath = Paths.get(gitServiceConfig.getGitRootPath()).resolve(repositorySuffix); + return Mono.fromCallable(() -> fetchGitResourceMap(repositoryPath)).subscribeOn(scheduler); + } + /** * This is used to initialize repo with Readme file when the application is connected to remote repo * diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java index d5422a24ef48..c655ef2bfbe8 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java @@ -50,6 +50,8 @@ Mono saveArtifactToGitRepo(Path baseRepoSuffix, GitResourceMap gitResource Mono reconstructApplicationReferenceFromGitRepo( String organisationId, String baseApplicationId, String repoName, String branchName); + Mono constructGitResourceMapFromGitRepo(Path repositorySuffix, String refName); + /** * This method just reconstructs the metdata of the json from git repo. * diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java index a5628db2df12..a9824225e07c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java @@ -29,6 +29,7 @@ import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; +import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import com.appsmith.server.helpers.CollectionUtils; import com.appsmith.server.helpers.ce.ArtifactGitFileUtilsCE; import com.appsmith.server.migrations.JsonSchemaMigration; @@ -471,6 +472,15 @@ public Mono reconstructArtifactExchangeJsonFromFilesInRepo }); } + @Override + public Mono performJsonMigration( + ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson) { + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String refName = jsonTransformationDTO.getRefName(); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + artifactExchangeJson, baseArtifactId, refName); + } + protected List getApplicationResource(Map resources, Type type) { List deserializedResources = new ArrayList<>(); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index bc6c38ebabad..877022465213 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -423,6 +423,7 @@ protected Mono checkoutReference( ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId()); + jsonTransformationDTO.setRefName(finalRefName); jsonTransformationDTO.setRefType(refType); jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); jsonTransformationDTO.setRepoName(baseGitMetadata.getRepoName()); @@ -689,7 +690,7 @@ protected Mono createReference( }) // after the branch is created, we need to reset the older branch to the // clean status, i.e. last commit - .doOnSuccess(newImportedArtifact -> discardChanges(sourceArtifact, gitType)); + .flatMap(newImportedArtifact -> discardChanges(sourceArtifact, gitType)); }) .flatMap(newImportedArtifact -> gitRedisUtils .releaseFileLock( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index eafd070e04fe..04457a460671 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -47,6 +47,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.jgit.api.errors.CannotDeleteCurrentBranchException; import org.eclipse.jgit.api.errors.EmptyCommitException; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -209,12 +210,8 @@ public void setRepositoryDetailsInGitArtifactMetadata( @Override public Mono reconstructArtifactJsonFromGitRepository( ArtifactJsonTransformationDTO artifactJsonTransformationDTO) { - return commonGitFileUtils.reconstructArtifactExchangeJsonFromGitRepoWithAnalytics( - artifactJsonTransformationDTO.getWorkspaceId(), - artifactJsonTransformationDTO.getBaseArtifactId(), - artifactJsonTransformationDTO.getRepoName(), - artifactJsonTransformationDTO.getRefName(), - artifactJsonTransformationDTO.getArtifactType()); + return commonGitFileUtils.constructArtifactExchangeJsonFromGitRepositoryWithAnalytics( + artifactJsonTransformationDTO); } @Override @@ -366,18 +363,23 @@ public Mono prepareChangesToBeCommitted( GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); - return commonGitFileUtils - .saveArtifactToLocalRepoWithAnalytics(repoSuffix, artifactExchangeJson, branchName) - .map(ignore -> Boolean.TRUE) - .onErrorResume(e -> { - log.error("Error in commit flow: ", e); - if (e instanceof RepositoryNotFoundException) { - return Mono.error(new AppsmithException(AppsmithError.REPOSITORY_NOT_FOUND, baseArtifactId)); - } else if (e instanceof AppsmithException) { - return Mono.error(e); - } - return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); - }); + try { + return commonGitFileUtils + .saveArtifactToLocalRepoNew(repoSuffix, artifactExchangeJson, branchName) + .map(ignore -> Boolean.TRUE) + .onErrorResume(e -> { + log.error("Error in commit flow: ", e); + if (e instanceof RepositoryNotFoundException) { + return Mono.error( + new AppsmithException(AppsmithError.REPOSITORY_NOT_FOUND, baseArtifactId)); + } else if (e instanceof AppsmithException) { + return Mono.error(e); + } + return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); + }); + } catch (IOException | GitAPIException e) { + return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); + } } @Override @@ -617,8 +619,7 @@ public Mono recreateArtifactJsonFromLastCommit( Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); return fsGitHandler.rebaseBranch(repoSuffix, refName).flatMap(rebaseStatus -> { - return commonGitFileUtils.reconstructArtifactExchangeJsonFromGitRepoWithAnalytics( - workspaceId, baseArtifactId, repoName, refName, artifactType); + return commonGitFileUtils.constructArtifactExchangeJsonFromGitRepository(jsonTransformationDTO); }); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java index f92820c047ac..f20fe5f878db 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java @@ -3,6 +3,7 @@ import com.appsmith.external.git.models.GitResourceMap; import com.appsmith.external.models.ArtifactGitReference; import com.appsmith.server.dtos.ArtifactExchangeJson; +import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import lombok.NonNull; import reactor.core.publisher.Mono; @@ -28,4 +29,7 @@ void addArtifactReferenceFromExportedJson( Path getRepoSuffixPath(String workspaceId, String artifactId, String repoName, @NonNull String... args); void setArtifactDependentPropertiesInJson(GitResourceMap gitResourceMap, ArtifactExchangeJson artifactExchangeJson); + + Mono performJsonMigration( + ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index 5349f788df6b..cad3822808bc 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -30,6 +30,7 @@ import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; +import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import com.appsmith.server.helpers.ArtifactGitFileUtils; import com.appsmith.server.migrations.JsonSchemaVersions; import com.appsmith.server.newactions.base.NewActionService; @@ -553,6 +554,96 @@ private void setDatasourcesInArtifactReference( artifactGitReference.setDatasources(resourceMap); } + public Mono constructArtifactExchangeJsonFromGitRepositoryWithAnalytics( + ArtifactJsonTransformationDTO jsonTransformationDTO) { + if (!isJsonTransformationDTOValid(jsonTransformationDTO)) { + return Mono.error(new AppsmithException( + AppsmithError.INVALID_GIT_CONFIGURATION, "ArtifactJSONTransformationDTO is invalid")); + } + + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + + ArtifactGitFileUtils artifactGitFileUtils = + getArtifactBasedFileHelper(jsonTransformationDTO.getArtifactType()); + Map constantsMap = artifactGitFileUtils.getConstantsMap(); + + return Mono.zip( + constructArtifactExchangeJsonFromGitRepository(jsonTransformationDTO), + sessionUserService.getCurrentUser()) + .flatMap(tuple -> { + final Map data = Map.of( + constantsMap.get(FieldName.ID), + baseArtifactId, + FieldName.WORKSPACE_ID, + workspaceId, + FieldName.FLOW_NAME, + AnalyticsEvents.GIT_DESERIALIZE_APP_RESOURCES_FROM_FILE.getEventName()); + + return analyticsService + .sendEvent( + AnalyticsEvents.UNIT_EXECUTION_TIME.getEventName(), + tuple.getT2().getUsername(), + data) + .thenReturn(tuple.getT1()); + }); + } + + /** + * Method to reconstruct the application from the local git repo + * @param jsonTransformationDTO : DTO which carries the parameter for transformation + * @return an instance of an object which extends artifact exchange json. + * i.e. Application Json, Package Json + */ + public Mono constructArtifactExchangeJsonFromGitRepository( + ArtifactJsonTransformationDTO jsonTransformationDTO) { + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + ArtifactGitFileUtils artifactGitFileUtils = getArtifactBasedFileHelper(artifactType); + + // Type is not required as checkout happens in similar fashion + String refName = jsonTransformationDTO.getRefName(); + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + Path repoSuffixPath = artifactGitFileUtils.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); + + Mono gitResourceMapMono = fileUtils.constructGitResourceMapFromGitRepo(repoSuffixPath, refName); + + return gitResourceMapMono.flatMap(gitResourceMap -> { + ArtifactExchangeJson artifactExchangeJson = createArtifactExchangeJson(gitResourceMap, artifactType); + copyMetadataToArtifactExchangeJson(gitResourceMap, artifactExchangeJson); + return artifactGitFileUtils.performJsonMigration(jsonTransformationDTO, artifactExchangeJson); + }); + } + + /** + * This method copies the metadata from git resource map to artifactExchangeJson + * @param gitResourceMap : git resource map generated from file system + * @param artifactExchangeJson : artifact json constructed from git resource map + */ + protected void copyMetadataToArtifactExchangeJson( + GitResourceMap gitResourceMap, ArtifactExchangeJson artifactExchangeJson) { + GitResourceIdentity metadataIdentity = + new GitResourceIdentity(GitResourceType.ROOT_CONFIG, METADATA + JSON_EXTENSION, ""); + Object metadata = gitResourceMap.getGitResourceMap().get(metadataIdentity); + + Gson gson = new Gson(); + JsonObject metadataJsonObject = gson.toJsonTree(metadata, Object.class).getAsJsonObject(); + + Integer serverSchemaVersion = getServerSchemaVersion(metadataJsonObject); + Integer clientSchemaVersion = getClientSchemaVersion(metadataJsonObject); + + artifactExchangeJson.setServerSchemaVersion(serverSchemaVersion); + artifactExchangeJson.setClientSchemaVersion(clientSchemaVersion); + } + + public boolean isJsonTransformationDTOValid(ArtifactJsonTransformationDTO jsonTransformationDTO) { + return jsonTransformationDTO.getArtifactType() != null + && hasText(jsonTransformationDTO.getWorkspaceId()) + && hasText(jsonTransformationDTO.getBaseArtifactId()) + && hasText(jsonTransformationDTO.getRefName()); + } + /** * Method to reconstruct the application from the local git repo * diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java index df6caf59bb10..adbd9b2c83f3 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java @@ -44,6 +44,7 @@ private Integer getCorrectSchemaVersion(Integer schemaVersion) { * @param branchName The branch name of the artifact being imported, * if it's a Git-connected application; otherwise, null. */ + // TODO: add refType support public Mono migrateArtifactExchangeJsonToLatestSchema( ArtifactExchangeJson artifactExchangeJson, String baseArtifactId, String branchName) { From 41f5faa8431ca98cac0be74d6abec16b92d3b708 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Fri, 3 Jan 2025 18:15:07 +0530 Subject: [PATCH 2/9] added reviewed comments --- .../server/git/fs/GitFSServiceCEImpl.java | 31 ++++++++----------- .../helpers/ce/CommonGitFileUtilsCE.java | 13 +++++--- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 04457a460671..598147b8f81b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -47,7 +47,6 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.jgit.api.errors.CannotDeleteCurrentBranchException; import org.eclipse.jgit.api.errors.EmptyCommitException; -import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -363,23 +362,19 @@ public Mono prepareChangesToBeCommitted( GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); - try { - return commonGitFileUtils - .saveArtifactToLocalRepoNew(repoSuffix, artifactExchangeJson, branchName) - .map(ignore -> Boolean.TRUE) - .onErrorResume(e -> { - log.error("Error in commit flow: ", e); - if (e instanceof RepositoryNotFoundException) { - return Mono.error( - new AppsmithException(AppsmithError.REPOSITORY_NOT_FOUND, baseArtifactId)); - } else if (e instanceof AppsmithException) { - return Mono.error(e); - } - return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); - }); - } catch (IOException | GitAPIException e) { - return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); - } + return commonGitFileUtils + .saveArtifactToLocalRepoNew(repoSuffix, artifactExchangeJson, branchName) + .map(ignore -> Boolean.TRUE) + .onErrorResume(e -> { + log.error("Error in commit flow: ", e); + if (e instanceof RepositoryNotFoundException) { + return Mono.error(new AppsmithException(AppsmithError.REPOSITORY_NOT_FOUND, baseArtifactId)); + } else if (e instanceof AppsmithException) { + return Mono.error(e); + } + + return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); + }); } @Override diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index cad3822808bc..4ce31654b06d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -160,16 +160,19 @@ public Mono saveArtifactToLocalRepo( } public Mono saveArtifactToLocalRepoNew( - Path baseRepoSuffix, ArtifactExchangeJson artifactExchangeJson, String branchName) - throws IOException, GitAPIException { + Path baseRepoSuffix, ArtifactExchangeJson artifactExchangeJson, String branchName) { // this should come from the specific files GitResourceMap gitResourceMap = createGitResourceMap(artifactExchangeJson); // Save application to git repo - return fileUtils - .saveArtifactToGitRepo(baseRepoSuffix, gitResourceMap, branchName) - .subscribeOn(Schedulers.boundedElastic()); + try { + return fileUtils + .saveArtifactToGitRepo(baseRepoSuffix, gitResourceMap, branchName) + .subscribeOn(Schedulers.boundedElastic()); + } catch (IOException | GitAPIException exception) { + return Mono.error(exception); + } } public Mono saveArtifactToLocalRepoWithAnalytics( From f464a95233547ea0a0734531d58ba5e0b2ba35e1 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Fri, 3 Jan 2025 18:54:34 +0530 Subject: [PATCH 3/9] added changes --- .../git/ApplicationGitFileUtilsCEImpl.java | 5 +- .../ApplicationImportServiceCEImpl.java | 8 +++- .../git/central/CentralGitServiceCE.java | 18 +++---- .../git/central/CentralGitServiceCEImpl.java | 48 +++++++++---------- .../GitApplicationControllerCE.java | 18 +++---- .../migrations/JsonSchemaMigration.java | 13 ++--- .../ce/CreateDBTablePageSolutionCEImpl.java | 2 +- .../server/git/CommonGitServiceCETest.java | 4 +- .../AutoCommitEventHandlerImplTest.java | 6 ++- .../git/autocommit/AutoCommitServiceTest.java | 7 +-- .../server/git/ops/GitCommitTests.java | 2 +- .../server/git/ops/GitConnectTests.java | 18 +++---- .../server/git/ops/GitDiscardTests.java | 4 +- .../ExchangeJsonConversionTests.java | 2 +- .../server/helpers/GitFileUtilsTest.java | 4 +- .../imports/internal/ImportServiceTests.java | 7 +-- .../migrations/JsonSchemaMigrationTest.java | 4 +- ...portApplicationTransactionServiceTest.java | 4 +- .../server/git/ArtifactBuilderExtension.java | 2 +- 19 files changed, 93 insertions(+), 83 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java index a9824225e07c..f4b2f7ee9afc 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java @@ -1,6 +1,7 @@ package com.appsmith.server.applications.git; import com.appsmith.external.git.FileInterface; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.git.models.GitResourceIdentity; import com.appsmith.external.git.models.GitResourceMap; import com.appsmith.external.git.models.GitResourceType; @@ -468,7 +469,7 @@ public Mono reconstructArtifactExchangeJsonFromFilesInRepo ApplicationJson applicationJson = getApplicationJsonFromGitReference(applicationReference); copyNestedNonNullProperties(metadata, applicationJson); return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( - applicationJson, baseArtifactId, branchName); + applicationJson, baseArtifactId, branchName, RefType.branch); }); } @@ -478,7 +479,7 @@ public Mono performJsonMigration( String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); String refName = jsonTransformationDTO.getRefName(); return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( - artifactExchangeJson, baseArtifactId, refName); + artifactExchangeJson, baseArtifactId, refName, null); } protected List getApplicationResource(Map resources, Type type) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java index 1ab22bc3d8f5..6d876dd96c38 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java @@ -1,5 +1,6 @@ package com.appsmith.server.applications.imports; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceStorageDTO; import com.appsmith.server.applications.base.ApplicationService; @@ -643,18 +644,21 @@ public Mono migrateArtifactExchangeJson( ApplicationJson applicationJson = (ApplicationJson) artifactExchangeJson; if (!hasText(branchedArtifactId)) { - return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null, null); } return applicationService.findById(branchedArtifactId).flatMap(application -> { String baseArtifactId = application.getBaseId(); String refName = null; + RefType refType = null; if (application.getGitArtifactMetadata() != null) { refName = application.getGitArtifactMetadata().getRefName(); + refType = application.getGitArtifactMetadata().getRefType(); } - return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, baseArtifactId, refName); + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( + applicationJson, baseArtifactId, refName, refType); }); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java index a9fc22f6a066..ccadec5b3c63 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java @@ -25,9 +25,9 @@ Mono importArtifactFromGit( Mono connectArtifactToGit( String baseArtifactId, + ArtifactType artifactType, GitConnectDTO gitConnectDTO, String originHeader, - ArtifactType artifactType, GitType gitType); Mono commitArtifact( @@ -36,44 +36,44 @@ Mono commitArtifact( Mono detachRemote(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono> listBranchForArtifact( - String branchedArtifactId, Boolean pruneBranches, ArtifactType artifactType, GitType gitType); + String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType); Mono fetchRemoteChanges( String referenceArtifactId, - boolean isFileLock, ArtifactType artifactType, + boolean isFileLock, GitType gitType, RefType refType); Mono discardChanges(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono getStatus( - String branchedArtifactId, boolean compareRemote, ArtifactType artifactType, GitType gitType); + String branchedArtifactId, ArtifactType artifactType, boolean compareRemote, GitType gitType); Mono pullArtifact(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono checkoutReference( String referenceArtifactId, + ArtifactType artifactType, GitRefDTO gitRefDTO, boolean addFileLock, - ArtifactType artifactType, GitType gitType); Mono createReference( - String referencedArtifactId, GitRefDTO refDTO, ArtifactType artifactType, GitType gitType); + String referencedArtifactId, ArtifactType artifactType, GitRefDTO refDTO, GitType gitType); Mono deleteGitReference( - String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType); + String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType); Mono> updateProtectedBranches( - String baseArtifactId, List branchNames, ArtifactType artifactType); + String baseArtifactId, ArtifactType artifactType, List branchNames); Mono> getProtectedBranches(String baseArtifactId, ArtifactType artifactType); Mono toggleAutoCommitEnabled(String baseArtifactId, ArtifactType artifactType); Mono getAutoCommitProgress( - String baseArtifactId, String branchName, ArtifactType artifactType); + String baseArtifactId, ArtifactType artifactType, String branchName); Mono generateSSHKey(String keyType); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index 877022465213..db895a42bb83 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -364,9 +364,9 @@ private boolean checkIsDatasourceNameConflict( @Override public Mono checkoutReference( String referenceArtifactId, + ArtifactType artifactType, GitRefDTO gitRefDTO, boolean addFileLock, - ArtifactType artifactType, GitType gitType) { if (gitRefDTO == null || !hasText(gitRefDTO.getRefName())) { @@ -475,7 +475,7 @@ protected Mono checkoutReference( } protected Mono checkoutRemoteReference( - String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType) { + String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType) { GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); @@ -560,7 +560,7 @@ private Mono checkoutRemoteReference( @Override public Mono createReference( - String referencedArtifactId, GitRefDTO refDTO, ArtifactType artifactType, GitType gitType) { + String referencedArtifactId, ArtifactType artifactType, GitRefDTO refDTO, GitType gitType) { /* 1. Check if the src artifact is available and user have sufficient permissions @@ -730,7 +730,7 @@ protected Mono isValidationForRefCreationComplete( @Override public Mono deleteGitReference( - String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType) { + String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType) { String refName = gitRefDTO.getRefName(); RefType refType = gitRefDTO.getRefType(); @@ -868,19 +868,19 @@ protected Mono deleteGitReference( * Each artifact is equal to a repo in the git(and each branch creates a new artifact with default artifact as parent) * * @param baseArtifactId : artifactId of the artifact which is getting connected to git - * @param gitConnectDTO artifactId - this is used to link the local git repo to an artifact - * remoteUrl - used for connecting to remote repo etc - * @param originHeader * @param artifactType + * @param gitConnectDTO artifactId - this is used to link the local git repo to an artifact + * remoteUrl - used for connecting to remote repo etc + * @param originHeader * @param gitType * @return an artifact with git metadata */ @Override public Mono connectArtifactToGit( String baseArtifactId, + ArtifactType artifactType, GitConnectDTO gitConnectDTO, String originHeader, - ArtifactType artifactType, GitType gitType) { /* * Connecting the artifact for the first time @@ -1474,31 +1474,31 @@ private boolean isBaseGitMetadataInvalid(GitArtifactMetadata gitArtifactMetadata } private Mono getStatusAfterComparingWithRemote( - String baseArtifactId, boolean isFileLock, ArtifactType artifactType, GitType gitType) { - return getStatus(baseArtifactId, isFileLock, true, artifactType, gitType); + String baseArtifactId, ArtifactType artifactType, boolean isFileLock, GitType gitType) { + return getStatus(baseArtifactId, artifactType, isFileLock, true, gitType); } @Override public Mono getStatus( - String branchedArtifactId, boolean compareRemote, ArtifactType artifactType, GitType gitType) { - return getStatus(branchedArtifactId, true, compareRemote, artifactType, gitType); + String branchedArtifactId, ArtifactType artifactType, boolean compareRemote, GitType gitType) { + return getStatus(branchedArtifactId, artifactType, true, compareRemote, gitType); } /** * Get the status of the artifact for given branched id * * @param branchedArtifactId branched id of the artifact + * @param artifactType Type of artifact in context * @param isFileLock if the locking is required, since the status API is used in the other flows of git * Only for the direct hits from the client the locking will be added - * @param artifactType Type of artifact in context * @param gitType Type of the service * @return Map of json file names which are added, modified, conflicting, removed and the working tree if this is clean */ private Mono getStatus( String branchedArtifactId, + ArtifactType artifactType, boolean isFileLock, boolean compareRemote, - ArtifactType artifactType, GitType gitType) { Mono> baseAndBranchedArtifacts = @@ -1868,14 +1868,14 @@ public Mono fetchRemoteChanges( * 1. Checkout (if required) to the branch to make sure we are comparing the right branch * 2. Run a git fetch command to fetch the latest changes from the remote * - * @param refArtifactId id of the reference - * @param isFileLock whether to add file lock or not + * @param refArtifactId id of the reference * @param artifactType + * @param isFileLock whether to add file lock or not * @return Mono of {@link BranchTrackingStatus} */ @Override public Mono fetchRemoteChanges( - String refArtifactId, boolean isFileLock, ArtifactType artifactType, GitType gitType, RefType refType) { + String refArtifactId, ArtifactType artifactType, boolean isFileLock, GitType gitType, RefType refType) { GitArtifactHelper artifactGitHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); AclPermission artifactEditPermission = artifactGitHelper.getArtifactEditPermission(); @@ -2067,15 +2067,15 @@ protected Mono discardChanges(Artifact branchedArtifact, Git } public Mono> listBranchForArtifact( - String branchedArtifactId, Boolean pruneBranches, ArtifactType artifactType, GitType gitType) { - return getBranchList(branchedArtifactId, pruneBranches, true, artifactType, gitType); + String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType) { + return getBranchList(branchedArtifactId, artifactType, pruneBranches, true, gitType); } protected Mono> getBranchList( String branchedArtifactId, + ArtifactType artifactType, Boolean pruneBranches, boolean syncDefaultBranchWithRemote, - ArtifactType artifactType, GitType gitType) { GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); @@ -2177,9 +2177,9 @@ private Mono syncDefaultBranchNameFromRemote( // default branch has been changed in remote return updateDefaultBranchName( metadata.getDefaultArtifactId(), + artifactType, defaultBranchNameInRemote, jsonTransformationDTO, - artifactType, gitType) .then() .thenReturn(defaultBranchNameInRemote); @@ -2192,9 +2192,9 @@ private Mono syncDefaultBranchNameFromRemote( private Flux updateDefaultBranchName( String baseArtifactId, + ArtifactType artifactType, String newDefaultBranchName, ArtifactJsonTransformationDTO jsonTransformationDTO, - ArtifactType artifactType, GitType gitType) { // Get the artifact from DB by new defaultBranchName GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); @@ -2392,7 +2392,7 @@ private Mono> getBranchListWithDefaultBranchName( @Override public Mono> updateProtectedBranches( - String baseArtifactId, List branchNames, ArtifactType artifactType) { + String baseArtifactId, ArtifactType artifactType, List branchNames) { GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); AclPermission artifactManageProtectedBranchPermission = @@ -2509,7 +2509,7 @@ public Mono toggleAutoCommitEnabled(String baseArtifactId, ArtifactType @Override public Mono getAutoCommitProgress( - String artifactId, String branchName, ArtifactType artifactType) { + String artifactId, ArtifactType artifactType, String branchName) { return gitAutoCommitHelper.getAutoCommitProgress(artifactId, branchName); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java index e08e5716fb3b..aefef9970fe6 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java @@ -68,7 +68,7 @@ public Mono> connectApplicationToRemoteRepo( @RequestBody GitConnectDTO gitConnectDTO, @RequestHeader("Origin") String originHeader) { return centralGitService - .connectArtifactToGit(applicationId, gitConnectDTO, originHeader, ARTIFACT_TYPE, GIT_TYPE) + .connectArtifactToGit(applicationId, ARTIFACT_TYPE, gitConnectDTO, originHeader, GIT_TYPE) .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); } @@ -95,7 +95,7 @@ public Mono> createReference( referencedApplicationId, srcBranch); return centralGitService - .createReference(referencedApplicationId, gitRefDTO, ArtifactType.APPLICATION, GIT_TYPE) + .createReference(referencedApplicationId, ArtifactType.APPLICATION, gitRefDTO, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); } @@ -104,7 +104,7 @@ public Mono> createReference( public Mono> checkoutReference( @PathVariable String referencedApplicationId, @RequestBody GitRefDTO gitRefDTO) { return centralGitService - .checkoutReference(referencedApplicationId, gitRefDTO, true, ARTIFACT_TYPE, GIT_TYPE) + .checkoutReference(referencedApplicationId, ARTIFACT_TYPE, gitRefDTO, true, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } @@ -133,7 +133,7 @@ public Mono> getStatus( @RequestParam(required = false, defaultValue = "true") Boolean compareRemote) { log.info("Going to get status for branchedApplicationId {}", branchedApplicationId); return centralGitService - .getStatus(branchedApplicationId, compareRemote, ARTIFACT_TYPE, GIT_TYPE) + .getStatus(branchedApplicationId, ARTIFACT_TYPE, compareRemote, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } @@ -144,7 +144,7 @@ public Mono> fetchRemoteChanges( @RequestHeader(required = false, defaultValue = "branch") RefType refType) { log.info("Going to compare with remote for default referencedApplicationId {}", referencedApplicationId); return centralGitService - .fetchRemoteChanges(referencedApplicationId, true, ARTIFACT_TYPE, GIT_TYPE, refType) + .fetchRemoteChanges(referencedApplicationId, ARTIFACT_TYPE, true, GIT_TYPE, refType) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } @@ -154,7 +154,7 @@ public Mono> deleteBranch( @PathVariable String baseArtifactId, @RequestBody GitRefDTO gitRefDTO) { log.info("Going to delete ref {} for baseApplicationId {}", gitRefDTO.getRefName(), baseArtifactId); return centralGitService - .deleteGitReference(baseArtifactId, gitRefDTO, ARTIFACT_TYPE, GIT_TYPE) + .deleteGitReference(baseArtifactId, ARTIFACT_TYPE, gitRefDTO, GIT_TYPE) .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); } @@ -173,7 +173,7 @@ public Mono>> updateProtectedBranches( @PathVariable String baseArtifactId, @RequestBody @Valid BranchProtectionRequestDTO branchProtectionRequestDTO) { return centralGitService - .updateProtectedBranches(baseArtifactId, branchProtectionRequestDTO.getBranchNames(), ARTIFACT_TYPE) + .updateProtectedBranches(baseArtifactId, ARTIFACT_TYPE, branchProtectionRequestDTO.getBranchNames()) .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); } @@ -199,7 +199,7 @@ public Mono> getAutoCommitProgress( @PathVariable String baseApplicationId, @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) { return centralGitService - .getAutoCommitProgress(baseApplicationId, branchName, ARTIFACT_TYPE) + .getAutoCommitProgress(baseApplicationId, ARTIFACT_TYPE, branchName) .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); } @@ -219,7 +219,7 @@ public Mono>> branch( log.debug("Going to get branch list for application {}", branchedApplicationId); return centralGitService .listBranchForArtifact( - branchedApplicationId, BooleanUtils.isTrue(pruneBranches), ARTIFACT_TYPE, GIT_TYPE) + branchedApplicationId, ARTIFACT_TYPE, BooleanUtils.isTrue(pruneBranches), GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java index adbd9b2c83f3..c5cb0f0843fa 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java @@ -1,5 +1,6 @@ package com.appsmith.server.migrations; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.dtos.ApplicationJson; import com.appsmith.server.dtos.ArtifactExchangeJson; @@ -41,23 +42,23 @@ private Integer getCorrectSchemaVersion(Integer schemaVersion) { * @param artifactExchangeJson The artifact to be imported. * @param baseArtifactId The base application ID to which it's being imported, * if it's a Git-connected artifact; otherwise, null. - * @param branchName The branch name of the artifact being imported, + * @param refName The ref name of the artifact being imported, * if it's a Git-connected application; otherwise, null. + * @param refType Type of the reference i.e. branch, tag. */ - // TODO: add refType support public Mono migrateArtifactExchangeJsonToLatestSchema( - ArtifactExchangeJson artifactExchangeJson, String baseArtifactId, String branchName) { + ArtifactExchangeJson artifactExchangeJson, String baseArtifactId, String refName, RefType refType) { if (ArtifactType.APPLICATION.equals(artifactExchangeJson.getArtifactJsonType())) { return migrateApplicationJsonToLatestSchema( - (ApplicationJson) artifactExchangeJson, baseArtifactId, branchName); + (ApplicationJson) artifactExchangeJson, baseArtifactId, refName, refType); } return Mono.fromCallable(() -> artifactExchangeJson); } public Mono migrateApplicationJsonToLatestSchema( - ApplicationJson applicationJson, String baseApplicationId, String branchName) { + ApplicationJson applicationJson, String baseApplicationId, String refName, RefType refType) { return Mono.fromCallable(() -> { setSchemaVersions(applicationJson); return applicationJson; @@ -67,7 +68,7 @@ public Mono migrateApplicationJsonToLatestSchema( return Mono.empty(); } - return migrateServerSchema(applicationJson, baseApplicationId, branchName); + return migrateServerSchema(applicationJson, baseApplicationId, refName); }) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON))); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java index da73e86a08bc..8f8bb0357f40 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java @@ -251,7 +251,7 @@ public Mono createPageFromDBTable( }) .subscribeOn(Schedulers.boundedElastic()) .flatMap(applicationJson -> - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null)); + jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null, null)); return datasourceStorageMono .zipWhen(datasourceStorage -> Mono.zip( diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java index 8963aba9e620..8ce36a1fc29c 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java @@ -292,8 +292,8 @@ private Mono createAppJson(String filePath) { return stringifiedFile .map(data -> gson.fromJson(data, ApplicationJson.class)) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java index 1afa9d79a013..c437281adc46 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java @@ -3,6 +3,7 @@ import com.appsmith.external.dtos.GitLogDTO; import com.appsmith.external.git.FileInterface; import com.appsmith.external.git.GitExecutor; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.external.models.ApplicationGitReference; import com.appsmith.server.configurations.ProjectProperties; @@ -435,7 +436,7 @@ public void autoCommitServerMigration_WhenServerHasNoChanges_NoCommitMade() thro doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - Mockito.eq(applicationJson), Mockito.anyString(), Mockito.anyString()); + Mockito.eq(applicationJson), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); doReturn(Mono.just("success")) .when(gitExecutor) @@ -514,7 +515,8 @@ public void autocommitServerMigration_WhenJsonSchemaMigrationPresent_CommitSucce doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) - .migrateApplicationJsonToLatestSchema(any(), Mockito.anyString(), Mockito.anyString()); + .migrateApplicationJsonToLatestSchema( + any(), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository(autoCommitEvent, applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java index 39a4287537c5..77bf3e4a0837 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java @@ -2,6 +2,7 @@ import com.appsmith.external.dtos.GitLogDTO; import com.appsmith.external.git.GitExecutor; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.applications.base.ApplicationService; @@ -255,7 +256,7 @@ public void testAutoCommit_whenOnlyServerIsEligibleForMigration_commitSuccess() doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); @@ -544,7 +545,7 @@ public void testAutoCommit_whenAutoCommitEligibleButPrerequisiteNotComplete_retu doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); @@ -618,7 +619,7 @@ public void testAutoCommit_whenServerIsRunningMigrationCallsAutocommitAgainOnDif doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java index 7b8b377c6428..6342eaf3b916 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java @@ -167,7 +167,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa gitConnectDTO.setGitProfile(gitProfile); return centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact) .block(); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java index 9d848250e358..541ef59eb6fa 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java @@ -84,7 +84,7 @@ public void connectArtifactToGit_withEmptyRemoteUrl_throwsInvalidParameterExcept gitConnectDTO.setRemoteUrl(null); gitConnectDTO.setGitProfile(new GitProfile()); Mono applicationMono = centralGitService - .connectArtifactToGit("testID", gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + .connectArtifactToGit("testID", ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -108,7 +108,7 @@ public void connectArtifactToGit_withEmptyOriginHeader_throwsInvalidParameterExc gitConnectDTO.setGitProfile(new GitProfile()); Mono applicationMono = centralGitService - .connectArtifactToGit("testID", gitConnectDTO, null, ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + .connectArtifactToGit("testID", ArtifactType.APPLICATION, gitConnectDTO, null, GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -151,7 +151,7 @@ public void connectArtifactToGit_whenConnectingMorePrivateReposThanSupported_thr gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -171,7 +171,7 @@ public void connectArtifactToGit_whenUserDoesNotHaveRequiredPermission_operation gitConnectDTO.setGitProfile(new GitProfile()); Mono applicationMono = centralGitService .connectArtifactToGit( - application.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -251,7 +251,7 @@ public void connectArtifactToGit_whenCloneOperationFails_throwsGitException() { Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -325,7 +325,7 @@ public void connectArtifactToGit_whenUsingGlobalProfile_completesSuccessfully() gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -375,7 +375,7 @@ public void connectArtifactToGit_whenUsingIncompleteLocalProfile_throwsAuthorNam gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -421,7 +421,7 @@ public void connectArtifactToGit_whenClonedRepoIsNotEmpty_throwsException() thro gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -470,7 +470,7 @@ public void connectArtifactToGit_whenDefaultCommitFails_throwsException() throws gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java index 7ca39f4bcb55..daa659593392 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java @@ -151,7 +151,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa gitConnectDTO.setGitProfile(gitProfile); return centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact) .block(); } @@ -167,7 +167,7 @@ private Mono createArtifactJson(String filePath) ArtifactExchangeJson artifactExchangeJson = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS).readValue(artifactJson, exchangeJsonType); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null, null); } @Test diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java index 56de587dcb81..9dfe3997401d 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java @@ -104,7 +104,7 @@ private Mono createArtifactJson(ExchangeJsonCont ArtifactExchangeJson artifactExchangeJson = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS).readValue(artifactJson, exchangeJsonType); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null, null); } @TestTemplate diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java index c9486d45314f..819d4e06de46 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java @@ -84,8 +84,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java index e6fe0159535b..37fd07110d3f 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java @@ -361,8 +361,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } @@ -2724,7 +2724,8 @@ public void applySchemaMigration_jsonFileWithFirstVersion_migratedToLatestVersio .flatMap(applicationJson -> { ApplicationJson applicationJson1 = new ApplicationJson(); AppsmithBeanUtils.copyNestedNonNullProperties(applicationJson, applicationJson1); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson1, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson1, null, null, null); }) .map(applicationJson -> (ApplicationJson) applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java index 1a08d854560a..ad9a79fd4b41 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java @@ -39,7 +39,7 @@ public void migrateArtifactToLatestSchema_whenFeatureFlagIsOn_returnsIncremented gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); ArtifactExchangeJson artifactExchangeJson = jsonSchemaMigration - .migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null) + .migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null, null) .block(); assertThat(artifactExchangeJson.getServerSchemaVersion()).isEqualTo(jsonSchemaVersions.getServerVersion()); assertThat(artifactExchangeJson.getClientSchemaVersion()).isEqualTo(jsonSchemaVersions.getClientVersion()); @@ -55,7 +55,7 @@ public void migrateApplicationJsonToLatestSchema_whenFeatureFlagIsOn_returnsIncr gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); Mono applicationJsonMono = - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); + jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null, null); StepVerifier.create(applicationJsonMono) .assertNext(appJson -> { assertThat(appJson.getServerSchemaVersion()).isEqualTo(jsonSchemaVersions.getServerVersion()); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java index f5d0c4835408..ffc8dabbe12f 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java @@ -130,8 +130,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java b/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java index 941265dbb432..123664de18e6 100644 --- a/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java +++ b/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java @@ -112,6 +112,6 @@ private Mono createArtifactJson(String filePath, ArtifactExchangeJson artifactExchangeJson = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS).readValue(artifactJson, exchangeJsonType); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null, null); } } From 7a3406e8b7d9b822d2b4db8ebd4f67dee6e8d788 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Fri, 3 Jan 2025 19:17:51 +0530 Subject: [PATCH 4/9] review comments --- .../applications/git/ApplicationGitFileUtilsCEImpl.java | 3 ++- .../server/solutions/ce/CreateDBTablePageSolutionCEImpl.java | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java index f4b2f7ee9afc..79aef2cb351c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java @@ -478,8 +478,9 @@ public Mono performJsonMigration( ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson) { String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); String refName = jsonTransformationDTO.getRefName(); + RefType refType = jsonTransformationDTO.getRefType(); return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( - artifactExchangeJson, baseArtifactId, refName, null); + artifactExchangeJson, baseArtifactId, refName, refType); } protected List getApplicationResource(Map resources, Type type) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java index 8f8bb0357f40..1b9d602f5d2f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java @@ -4,6 +4,7 @@ import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.converters.HttpMethodConverter; import com.appsmith.external.converters.ISOStringToInstantConverter; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; @@ -250,8 +251,8 @@ public Mono createPageFromDBTable( return applicationJson; }) .subscribeOn(Schedulers.boundedElastic()) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null, null)); + .flatMap(applicationJson -> jsonSchemaMigration.migrateApplicationJsonToLatestSchema( + applicationJson, null, null, RefType.branch)); return datasourceStorageMono .zipWhen(datasourceStorage -> Mono.zip( From 70ad2a103d2b316998e918eb09d2c9233c832be1 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Fri, 3 Jan 2025 20:09:40 +0530 Subject: [PATCH 5/9] modified mocking for test failures --- .../java/com/appsmith/server/git/ops/GitCommitTests.java | 6 +++--- .../java/com/appsmith/server/git/ops/GitDiscardTests.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java index 6342eaf3b916..39106cb937a7 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java @@ -87,7 +87,7 @@ public void commitArtifact_whenNoChangesInLocal_returnsWithEmptyCommitMessage() Mockito.doReturn(Mono.just(Paths.get(""))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.error(new EmptyCommitException("nothing to commit"))) .when(fsGitHandler) .commitArtifact( @@ -136,7 +136,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa .initializeReadme(any(Path.class), Mockito.anyString(), Mockito.anyString()); Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Application testApplication = new Application(); testApplication.setName(name); @@ -225,7 +225,7 @@ public void commitArtifact_whenLocalRepoNotAvailable_throwsRepoNotFoundException Mockito.doReturn(Mono.error(new RepositoryNotFoundException(AppsmithError.REPOSITORY_NOT_FOUND.getMessage()))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); StepVerifier.create(commitMono) .expectErrorMatches(throwable -> throwable instanceof AppsmithException diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java index daa659593392..30e0e35deda5 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java @@ -120,7 +120,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa .initializeReadme(any(Path.class), Mockito.anyString(), Mockito.anyString()); Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Application testApplication = new Application(); testApplication.setName(name); From 8877a5b92ae5bcb25b428ed50fe09a8d0b767e35 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Fri, 3 Jan 2025 20:39:58 +0530 Subject: [PATCH 6/9] more mocking --- .../java/com/appsmith/server/git/ops/GitConnectTests.java | 2 +- .../java/com/appsmith/server/git/ops/GitDiscardTests.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java index 541ef59eb6fa..21a2c17164e0 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java @@ -289,7 +289,7 @@ public void connectArtifactToGit_whenUsingGlobalProfile_completesSuccessfully() Mockito.anyString()); Mockito.doReturn(Mono.just(Paths.get(""))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.just(true)).when(commonGitFileUtils).checkIfDirectoryIsEmpty(any(Path.class)); Mockito.doReturn(Mono.just(Paths.get("textPath"))) .when(commonGitFileUtils) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java index 30e0e35deda5..d62ff5fc6a52 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java @@ -198,7 +198,7 @@ public void discardChanges_whenUpstreamChangesAvailable_discardsSuccessfully() t Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.just(artifactExchangeJson)) .when(gitHandlingService) .recreateArtifactJsonFromLastCommit(Mockito.any()); @@ -243,7 +243,7 @@ public void discardChanges_whenCancelledMidway_discardsSuccessfully() throws IOE Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.just(artifactExchangeJson)) .when(gitHandlingService) .recreateArtifactJsonFromLastCommit(Mockito.any()); From 1283574d1086c17bb3f8501d9e3a9e864848431a Mon Sep 17 00:00:00 2001 From: sondermanish Date: Sat, 4 Jan 2025 23:54:02 +0530 Subject: [PATCH 7/9] added merge --- .../git/handler/ce/FSGitHandlerCEImpl.java | 59 ++- .../external/git/handler/FSGitHandler.java | 4 +- .../git/central/CentralGitServiceCE.java | 8 + .../git/central/CentralGitServiceCEImpl.java | 456 +++++++++++++++++- .../git/central/GitHandlingServiceCE.java | 11 +- .../GitApplicationControllerCE.java | 30 ++ .../dtos/ArtifactJsonTransformationDTO.java | 10 + .../server/git/dtos/FetchRemoteDTO.java | 23 + .../server/git/fs/GitFSServiceCEImpl.java | 59 ++- 9 files changed, 605 insertions(+), 55 deletions(-) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java index 624dabcebab8..47f9630e72ed 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java @@ -33,7 +33,6 @@ import org.eclipse.jgit.api.ResetCommand; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.TransportConfigCallback; -import org.eclipse.jgit.api.errors.CheckoutConflictException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.BranchTrackingStatus; import org.eclipse.jgit.lib.PersonIdent; @@ -846,15 +845,14 @@ public Mono mergeBranch(Path repoSuffix, String sourceBranch, String des git -> Mono.fromCallable(() -> { Stopwatch processStopwatch = StopwatchHelpers.startStopwatch( repoSuffix, AnalyticsEvents.GIT_MERGE.getEventName()); - log.debug(Thread.currentThread().getName() + ": Merge branch " + sourceBranch - + " on " + destinationBranch); - try { - // checkout the branch on which the merge command is run - git.checkout() - .setName(destinationBranch) - .setCreateBranch(false) - .call(); + log.info( + "{}: Merge branch {} on {}", + Thread.currentThread().getName(), + sourceBranch, + destinationBranch); + + try { MergeResult mergeResult = git.merge() .include(git.getRepository().findRef(sourceBranch)) .setStrategy(MergeStrategy.RECURSIVE) @@ -934,7 +932,7 @@ public Mono fetchRemote( @Override public Mono fetchRemote( - Path repoSuffix, String publicKey, String privateKey, boolean isRepoPath, String... branchNames) { + Path repoSuffix, String publicKey, String privateKey, boolean isRepoPath, String... refNames) { Stopwatch processStopwatch = StopwatchHelpers.startStopwatch(repoSuffix, AnalyticsEvents.GIT_FETCH.getEventName()); Path repoPath = TRUE.equals(isRepoPath) ? repoSuffix : createRepoPath(repoSuffix); @@ -946,9 +944,9 @@ public Mono fetchRemote( String fetchMessages; List refSpecs = new ArrayList<>(); - for (String branchName : branchNames) { + for (String refName : refNames) { RefSpec ref = new RefSpec( - "refs/heads/" + branchName + ":refs/remotes/origin/" + branchName); + "refs/heads/" + refName + ":refs/remotes/origin/" + refName); refSpecs.add(ref); } @@ -980,30 +978,13 @@ public Mono isMergeBranch(Path repoSuffix, String sourceBranch, return Mono.using( () -> Git.open(createRepoPath(repoSuffix).toFile()), git -> Mono.fromCallable(() -> { - log.debug( - Thread.currentThread().getName() - + ": Check mergeability for repo {} with src: {}, dest: {}", + log.info( + "{}: Check mergeability for repo {} with src: {}, dest: {}", + Thread.currentThread().getName(), repoSuffix, sourceBranch, destinationBranch); - // checkout the branch on which the merge command is run - try { - git.checkout() - .setName(destinationBranch) - .setCreateBranch(false) - .call(); - } catch (GitAPIException e) { - if (e instanceof CheckoutConflictException) { - MergeStatusDTO mergeStatus = new MergeStatusDTO(); - mergeStatus.setMergeAble(false); - mergeStatus.setConflictingFiles( - ((CheckoutConflictException) e).getConflictingPaths()); - processStopwatch.stopAndLogTimeInMillis(); - return mergeStatus; - } - } - MergeResult mergeResult = git.merge() .include(git.getRepository().findRef(sourceBranch)) .setFastForward(MergeCommand.FastForwardMode.NO_FF) @@ -1054,6 +1035,20 @@ public Mono isMergeBranch(Path repoSuffix, String sourceBranch, return Mono.error(e); } }) + .onErrorResume(error -> { + try { + MergeStatusDTO mergeStatusDTO = new MergeStatusDTO(); + mergeStatusDTO.setMergeAble(false); + mergeStatusDTO.setMessage(error.getMessage()); + mergeStatusDTO.setReferenceDoc( + ErrorReferenceDocUrl.GIT_MERGE_CONFLICT.getDocUrl()); + return resetToLastCommit(repoSuffix, destinationBranch) + .thenReturn(mergeStatusDTO); + } catch (GitAPIException | IOException e) { + log.error("Error while hard resetting to latest commit {0}", e); + return Mono.error(e); + } + }) .timeout(Duration.ofMillis(Constraint.TIMEOUT_MILLIS)), Git::close) .subscribeOn(scheduler); diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java index b1eb6d68a303..b4dcdb549b5f 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java @@ -135,6 +135,8 @@ Mono pullApplication( Mono getStatus(Path repoPath, String branchName); /** + * This method merges source branch into destination branch for a git repository which is present on the partial + * path provided. This assumes that the branch on which the merge will happen is already checked out * @param repoSuffix suffixedPath used to generate the base repo path this includes orgId, defaultAppId, repoName * @param sourceBranch name of the branch whose commits will be referred amd merged to destinationBranch * @param destinationBranch Merge operation is performed on this branch @@ -158,7 +160,7 @@ Mono fetchRemote( boolean isFetchAll); Mono fetchRemote( - Path repoSuffix, String publicKey, String privateKey, boolean isRepoPath, String... branchNames); + Path repoSuffix, String publicKey, String privateKey, boolean isRepoPath, String... refNames); /** * diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java index ccadec5b3c63..752dced6f13b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java @@ -3,6 +3,7 @@ import com.appsmith.external.dtos.GitBranchDTO; import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitStatusDTO; +import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.git.dto.CommitDTO; import com.appsmith.server.constants.ArtifactType; @@ -13,6 +14,7 @@ import com.appsmith.server.dtos.AutoCommitResponseDTO; import com.appsmith.server.dtos.GitConnectDTO; import com.appsmith.server.dtos.GitDocsDTO; +import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.dtos.GitPullDTO; import reactor.core.publisher.Mono; @@ -45,6 +47,12 @@ Mono fetchRemoteChanges( GitType gitType, RefType refType); + Mono mergeBranch( + String branchedArtifactId, ArtifactType artifactType, GitMergeDTO gitMergeDTO, GitType gitType); + + Mono isBranchMergable( + String branchedArtifactId, ArtifactType artifactType, GitMergeDTO gitMergeDTO, GitType gitType); + Mono discardChanges(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono getStatus( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index db895a42bb83..8ddbfa7dd09f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -34,6 +34,7 @@ import com.appsmith.server.dtos.AutoCommitResponseDTO; import com.appsmith.server.dtos.GitConnectDTO; import com.appsmith.server.dtos.GitDocsDTO; +import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.dtos.GitPullDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; @@ -41,6 +42,7 @@ import com.appsmith.server.git.GitRedisUtils; import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; +import com.appsmith.server.git.dtos.FetchRemoteDTO; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.resolver.GitHandlingServiceResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; @@ -59,6 +61,7 @@ import io.micrometer.observation.ObservationRegistry; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.TransportException; @@ -519,8 +522,8 @@ private Mono checkoutRemoteReference( if (baseRefName.equals(finalRemoteRefName)) { /* in this case, user deleted the initial default branch and now wants to check out to that branch. - as we didn't delete the application object but only the branch from git repo, - we can just use this existing application without creating a new one. + as we didn't delete the artifact object but only the branch from git repo, + we can just use this existing artifact without creating a new one. */ artifactMono = Mono.just(baseArtifact); } else { @@ -529,7 +532,7 @@ private Mono checkoutRemoteReference( } Mono checkedOutRemoteArtifactMono = gitHandlingService - .fetchRemoteChanges(jsonTransformationDTO, baseGitMetadata.getGitAuth(), false) + .fetchRemoteReferences(jsonTransformationDTO, baseGitMetadata.getGitAuth(), false) .onErrorResume(error -> Mono.error( new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout branch", error.getMessage()))) .flatMap(ignoreRemoteChanges -> { @@ -624,7 +627,8 @@ protected Mono createReference( baseGitMetadata.getDefaultArtifactId(), GitConstants.GitCommandConstants.CREATE_BRANCH, FALSE); - Mono fetchRemoteMono = gitHandlingService.fetchRemoteChanges(jsonTransformationDTO, baseGitAuth, TRUE); + Mono fetchRemoteMono = + gitHandlingService.fetchRemoteReferences(jsonTransformationDTO, baseGitAuth, TRUE); Mono createBranchMono = acquireGitLockMono .flatMap(ignoreLockAcquisition -> fetchRemoteMono.onErrorResume( @@ -1139,10 +1143,10 @@ public Mono commitArtifact( GitType gitType, Boolean isFileLock) { /* - 1. Check if application exists and user have sufficient permissions + 1. Check if artifact exists and user have sufficient permissions 2. Check if branch name exists in git metadata - 3. Save application to the existing local repo - 4. Commit application : git add, git commit (Also check if git init required) + 3. Save artifact to the existing local repo + 4. Commit artifact : git add, git commit (Also check if git init required) */ String commitMessage = commitDTO.getMessage(); @@ -1390,7 +1394,7 @@ private Mono commitArtifact( /** * Method to remove all the git metadata for the artifact and connected resources. This will remove: * - local repo - * - all the branched applications present in DB except for default application + * - all the branched artifacts present in DB except for default artifact * * @param branchedArtifactId : id of any branched artifact for the given repo * @param artifactType : type of artifact @@ -1443,7 +1447,7 @@ public Mono detachRemote( jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); jsonTransformationDTO.setRefName(gitArtifactMetadata.getRefName()); - // Remove the parent application branch name from the list + // Remove the parent artifact branch name from the list Mono removeRepoMono = gitHandlingService.removeRepository(jsonTransformationDTO); Mono updatedArtifactMono = gitArtifactHelper.saveArtifact(baseArtifact); @@ -1583,7 +1587,7 @@ protected Mono getStatus( hence we don't need to do that manually */ log.error( - "Error to get status for application: {}, branch: {}", + "Error to get status for artifact: {}, branch: {}", baseArtifactId, finalBranchName, throwable); @@ -1693,11 +1697,11 @@ protected Mono pullArtifact(Artifact baseArtifact, Artifact branched } /** - * Method to pull the files from remote repo and rehydrate the application + * Method to pull the files from remote repo and rehydrate the artifact * * @param baseArtifact : base artifact * @param branchedArtifact : a branch created from branches of base artifact - * @return pull DTO with updated application + * @return pull DTO with updated artifact */ private Mono pullAndRehydrateArtifact( Artifact baseArtifact, Artifact branchedArtifact, GitType gitType) { @@ -1706,7 +1710,7 @@ private Mono pullAndRehydrateArtifact( 2. Do git pull after On Merge conflict - throw exception and ask user to resolve these conflicts on remote TODO create new branch and push the changes to remote and ask the user to resolve it on github/gitlab UI - 3. Rehydrate the application from filesystem so that the latest changes from remote are rendered to the application + 3. Rehydrate the artifact from filesystem so that the latest changes from remote are rendered to the artifact */ ArtifactType artifactType = baseArtifact.getArtifactType(); @@ -1821,7 +1825,7 @@ public Mono fetchRemoteChanges( // current user mono has been zipped just to run in parallel. Mono fetchRemoteMono = acquireGitLockMono - .then(Mono.defer(() -> gitHandlingService.fetchRemoteChanges( + .then(Mono.defer(() -> gitHandlingService.fetchRemoteReferences( jsonTransformationDTO, baseArtifactGitData.getGitAuth(), FALSE))) .flatMap(fetchedRemoteStatusString -> { return gitRedisUtils @@ -1834,7 +1838,7 @@ public Mono fetchRemoteChanges( hence we don't need to do that manually */ log.error( - "Error to fetch from remote for application: {}, branch: {}, git type {}", + "Error to fetch from remote for artifact: {}, ref: {}, git type {}", baseArtifactId, refArtifactGitData.getRefName(), gitType, @@ -1964,9 +1968,9 @@ private Mono updateArtifactWithGitMetadataGivenPermission( } artifact.setGitArtifactMetadata(gitMetadata); - // For default application we expect a GitAuth to be a part of gitMetadata. We are using save method to leverage + // For base artifact we expect a GitAuth to be a part of gitMetadata. We are using save method to leverage // @Encrypted annotation used for private SSH keys - // applicationService.save sets the transient fields so no need to set it again from this method + // saveArtifact method sets the transient fields so no need to set it again from this method return gitArtifactHelperResolver .getArtifactHelper(artifact.getArtifactType()) .saveArtifact(artifact); @@ -2245,8 +2249,8 @@ private Flux updateDefaultBranchName( private Mono> handleRepoNotFoundException( ArtifactJsonTransformationDTO jsonTransformationDTO, GitType gitType) { - // clone application to the local filesystem again and update the defaultBranch for the application - // list branch and compare with branch applications and checkout if not exists + // clone artifact to the local git system again and update the defaultBranch for the artifact + // list branch and compare with branch artifacts and checkout if not exists GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); GitArtifactHelper gitArtifactHelper = @@ -2356,7 +2360,7 @@ private Mono> getBranchListWithDefaultBranchName( if (TRUE.equals(pruneBranches)) { return gitHandlingService - .fetchRemoteChanges(jsonTransformationDTO, baseGitData.getGitAuth(), TRUE) + .fetchRemoteReferences(jsonTransformationDTO, baseGitData.getGitAuth(), TRUE) .then(listBranchesMono); } return listBranchesMono; @@ -2593,4 +2597,416 @@ public Mono> getGitDocUrls() { } return Mono.just(gitDocsDTOList); } + + @Override + public Mono mergeBranch( + String branchedArtifactId, ArtifactType artifactType, GitMergeDTO gitMergeDTO, GitType gitType) { + /* + * 1.Dehydrate the artifact from Mongodb so that the file system has the latest artifact data for both the source and destination branch artifact + * 2.Do git checkout destinationBranch ---> git merge sourceBranch after the rehydration + * On Merge conflict - create new branch and push the changes to remote and ask the user to resolve it on Github/Gitlab UI + * 3.Then rehydrate from the file system to mongodb so that the latest changes from remote are rendered to the artifact + * 4.Get the latest artifact mono from the mongodb and send it back to client + * */ + + final String sourceBranch = gitMergeDTO.getSourceBranch(); + final String destinationBranch = gitMergeDTO.getDestinationBranch(); + + if (!hasText(sourceBranch) || !hasText(destinationBranch)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); + } else if (sourceBranch.startsWith(ORIGIN)) { + return Mono.error( + new AppsmithException(AppsmithError.UNSUPPORTED_OPERATION_FOR_REMOTE_BRANCH, sourceBranch)); + } else if (destinationBranch.startsWith(ORIGIN)) { + return Mono.error( + new AppsmithException(AppsmithError.UNSUPPORTED_OPERATION_FOR_REMOTE_BRANCH, destinationBranch)); + } + + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); + + Mono> baseAndBranchedArtifactsMono = + getBaseAndBranchedArtifacts(branchedArtifactId, artifactType).cache(); + + Mono destinationArtifactMono = baseAndBranchedArtifactsMono.flatMap(artifactTuples -> { + Artifact baseArtifact = artifactTuples.getT1(); + if (destinationBranch.equals(baseArtifact.getGitArtifactMetadata().getRefName())) { + return Mono.just(baseArtifact); + } + + return gitArtifactHelper.getArtifactByBaseIdAndBranchName( + baseArtifact.getId(), destinationBranch, artifactEditPermission); + }); + + Mono mergeMono = baseAndBranchedArtifactsMono + .zipWith(destinationArtifactMono) + .flatMap(artifactTuples -> { + Artifact baseArtifact = artifactTuples.getT1().getT1(); + Artifact sourceArtifact = artifactTuples.getT1().getT2(); + Artifact destinationArtifact = artifactTuples.getT2(); + + GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); + if (isBaseGitMetadataInvalid(baseArtifact.getGitArtifactMetadata(), gitType)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_SSH_CONFIGURATION)); + } + + final String workspaceId = baseArtifact.getWorkspaceId(); + final String baseArtifactId = baseGitMetadata.getDefaultArtifactId(); + final String repoName = baseGitMetadata.getRepoName(); + + // 1. Hydrate from db to git system for both ref Artifacts + // Update function call + return Mono.usingWhen( + gitRedisUtils.acquireGitLock( + artifactType, baseArtifactId, GitConstants.GitCommandConstants.MERGE_BRANCH, TRUE), + ignoreLock -> { + ArtifactJsonTransformationDTO jsonTransformationDTO = + new ArtifactJsonTransformationDTO(workspaceId, baseArtifactId, repoName); + jsonTransformationDTO.setArtifactType(artifactType); + + FetchRemoteDTO fetchRemoteDTO = new FetchRemoteDTO(); + fetchRemoteDTO.setRefNames(List.of(sourceBranch, destinationBranch)); + + GitHandlingService gitHandlingService = + gitHandlingServiceResolver.getGitHandlingService(gitType); + + Mono> statusTupleMono = gitHandlingService + .fetchRemoteReferences( + jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth()) + .flatMap(remoteSpecs -> { + Mono sourceBranchStatusMono = Mono.defer(() -> getStatus( + baseArtifact, sourceArtifact, false, false, gitType) + .flatMap(srcBranchStatus -> { + if (srcBranchStatus.getIsClean()) { + return Mono.just(srcBranchStatus); + } + + AppsmithException statusFailureException; + + if (!Integer.valueOf(0) + .equals(srcBranchStatus.getBehindCount())) { + statusFailureException = new AppsmithException( + AppsmithError.GIT_MERGE_FAILED_REMOTE_CHANGES, + srcBranchStatus.getBehindCount(), + sourceBranch); + } else { + statusFailureException = new AppsmithException( + AppsmithError.GIT_MERGE_FAILED_LOCAL_CHANGES, + sourceBranch); + } + + return Mono.error(statusFailureException); + })); + + Mono destinationBranchStatusMono = Mono.defer(() -> getStatus( + baseArtifact, destinationArtifact, false, false, gitType) + .flatMap(destinationBranchStatus -> { + if (destinationBranchStatus.getIsClean()) { + Mono.just(destinationBranchStatus); + } + + AppsmithException statusFailureException; + + if (!Integer.valueOf(0) + .equals(destinationBranchStatus.getBehindCount())) { + statusFailureException = new AppsmithException( + AppsmithError.GIT_MERGE_FAILED_REMOTE_CHANGES, + destinationBranchStatus.getBehindCount(), + destinationBranch); + } else { + statusFailureException = new AppsmithException( + AppsmithError.GIT_MERGE_FAILED_LOCAL_CHANGES, + destinationBranch); + } + + return Mono.error(statusFailureException); + })); + + return sourceBranchStatusMono.zipWith(destinationBranchStatusMono); + }) + .onErrorResume(error -> { + log.error( + "Error in repo status check for artifact: {}, Details: {}", + branchedArtifactId, + error.getMessage()); + + if (error instanceof AppsmithException) { + Mono.error(error); + } + + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, "status", error)); + }); + + return statusTupleMono + .flatMap(statusTuples -> { + GitMergeDTO mergeDTO = new GitMergeDTO(); + mergeDTO.setSourceBranch(sourceBranch); + mergeDTO.setDestinationBranch(destinationBranch); + return gitHandlingService + .mergeBranches(jsonTransformationDTO, mergeDTO) + .onErrorResume(error -> gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE, + baseArtifact, + error.getClass() + .getName(), + error.getMessage(), + baseGitMetadata.getIsRepoPrivate()) + .flatMap(artifact -> { + if (error instanceof GitAPIException) { + return Mono.error(new AppsmithException( + AppsmithError.GIT_MERGE_CONFLICTS, + error.getMessage())); + } + + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, + "merge", + error.getMessage())); + })); + }) + .zipWhen(mergeStatus -> { + ArtifactJsonTransformationDTO constructJsonDTO = + new ArtifactJsonTransformationDTO( + workspaceId, baseArtifactId, repoName); + constructJsonDTO.setArtifactType(artifactType); + constructJsonDTO.setRefName(destinationBranch); + return Mono.defer( + () -> gitHandlingService.reconstructArtifactJsonFromGitRepository( + constructJsonDTO)); + }) + .flatMap(tuple2 -> { + ArtifactExchangeJson artifactExchangeJson = tuple2.getT2(); + MergeStatusDTO mergeStatusDTO = new MergeStatusDTO(); + mergeStatusDTO.setStatus(tuple2.getT1()); + mergeStatusDTO.setMergeAble(TRUE); + + // 4. Get the latest artifact mono with all the changes + return importService + .importArtifactInWorkspaceFromGit( + workspaceId, + destinationArtifact.getId(), + artifactExchangeJson, + destinationBranch.replaceFirst( + ORIGIN, REMOTE_NAME_REPLACEMENT)) + .flatMap(importedDestinationArtifact -> { + CommitDTO commitDTO = new CommitDTO(); + commitDTO.setMessage(DEFAULT_COMMIT_MESSAGE + + GitDefaultCommitMessage.SYNC_REMOTE_AFTER_MERGE + .getReason() + + sourceBranch); + + return commitArtifact( + commitDTO, + importedDestinationArtifact.getId(), + artifactType, + gitType) + .then(gitAnalyticsUtils.addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE, + importedDestinationArtifact, + importedDestinationArtifact + .getGitArtifactMetadata() + .getIsRepoPrivate())) + .thenReturn(mergeStatusDTO); + }); + }); + }, + ignoreLock -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, TRUE)); + }) + .name(GitSpan.OPS_MERGE_BRANCH) + .tap(Micrometer.observation(observationRegistry)); + + return Mono.create(sink -> mergeMono.subscribe(sink::success, sink::error, null, sink.currentContext())); + } + + @Override + public Mono isBranchMergable( + String branchedArtifactId, ArtifactType artifactType, GitMergeDTO gitMergeDTO, GitType gitType) { + + final String sourceBranch = gitMergeDTO.getSourceBranch(); + final String destinationBranch = gitMergeDTO.getDestinationBranch(); + + if (!hasText(sourceBranch) || !hasText(destinationBranch)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); + } else if (sourceBranch.startsWith(ORIGIN)) { + return Mono.error( + new AppsmithException(AppsmithError.UNSUPPORTED_OPERATION_FOR_REMOTE_BRANCH, sourceBranch)); + } else if (destinationBranch.startsWith(ORIGIN)) { + return Mono.error( + new AppsmithException(AppsmithError.UNSUPPORTED_OPERATION_FOR_REMOTE_BRANCH, destinationBranch)); + } + + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); + + Mono> baseAndBranchedArtifactsMono = + getBaseAndBranchedArtifacts(branchedArtifactId, artifactType).cache(); + + Mono destinationArtifactMono = baseAndBranchedArtifactsMono.flatMap(artifactTuples -> { + Artifact baseArtifact = artifactTuples.getT1(); + if (destinationBranch.equals(baseArtifact.getGitArtifactMetadata().getRefName())) { + return Mono.just(baseArtifact); + } + + return gitArtifactHelper.getArtifactByBaseIdAndBranchName( + baseArtifact.getId(), destinationBranch, artifactEditPermission); + }); + + Mono mergeableStatusMono = baseAndBranchedArtifactsMono + .zipWith(destinationArtifactMono) + .flatMap(artifactTuples -> { + Artifact baseArtifact = artifactTuples.getT1().getT1(); + Artifact sourceArtifact = artifactTuples.getT1().getT2(); + Artifact destinationArtifact = artifactTuples.getT2(); + + GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); + if (isBaseGitMetadataInvalid(baseArtifact.getGitArtifactMetadata(), gitType)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_SSH_CONFIGURATION)); + } + + final String workspaceId = baseArtifact.getWorkspaceId(); + final String baseArtifactId = baseGitMetadata.getDefaultArtifactId(); + final String repoName = baseGitMetadata.getRepoName(); + + // 1. Hydrate from db to git system for both ref Artifacts + // Update function call + return Mono.usingWhen( + gitRedisUtils.acquireGitLock( + artifactType, baseArtifactId, GitConstants.GitCommandConstants.MERGE_BRANCH, TRUE), + ignoreLock -> { + ArtifactJsonTransformationDTO jsonTransformationDTO = + new ArtifactJsonTransformationDTO(workspaceId, baseArtifactId, repoName); + jsonTransformationDTO.setArtifactType(artifactType); + + FetchRemoteDTO fetchRemoteDTO = new FetchRemoteDTO(); + fetchRemoteDTO.setRefNames(List.of(sourceBranch, destinationBranch)); + + GitHandlingService gitHandlingService = + gitHandlingServiceResolver.getGitHandlingService(gitType); + + Mono> statusTupleMono = gitHandlingService + .fetchRemoteReferences( + jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth()) + .flatMap(remoteSpecs -> { + Mono sourceBranchStatusMono = Mono.defer(() -> getStatus( + baseArtifact, sourceArtifact, false, false, gitType) + .flatMap(srcBranchStatus -> { + if (srcBranchStatus.getIsClean()) { + return Mono.just(srcBranchStatus); + } + + AppsmithError uncleanStatusError; + AppsmithException uncleanStatusException; + + if (!Integer.valueOf(0) + .equals(srcBranchStatus.getBehindCount())) { + uncleanStatusError = + AppsmithError.GIT_MERGE_FAILED_REMOTE_CHANGES; + uncleanStatusException = new AppsmithException( + uncleanStatusError, + srcBranchStatus.getBehindCount(), + sourceBranch); + } else { + uncleanStatusError = + AppsmithError.GIT_MERGE_FAILED_LOCAL_CHANGES; + uncleanStatusException = new AppsmithException( + uncleanStatusError, sourceBranch); + } + + return gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE_CHECK, + baseArtifact, + uncleanStatusError.name(), + uncleanStatusException.getMessage(), + baseGitMetadata.getIsRepoPrivate(), + false, + false) + .then(Mono.error(uncleanStatusException)); + })); + + Mono destinationBranchStatusMono = Mono.defer(() -> getStatus( + baseArtifact, destinationArtifact, false, false, gitType) + .flatMap(destinationBranchStatus -> { + if (destinationBranchStatus.getIsClean()) { + return Mono.just(destinationBranchStatus); + } + + AppsmithError uncleanStatusError; + AppsmithException uncleanStatusException; + + if (!Integer.valueOf(0) + .equals(destinationBranchStatus.getBehindCount())) { + uncleanStatusError = + AppsmithError.GIT_MERGE_FAILED_REMOTE_CHANGES; + uncleanStatusException = new AppsmithException( + uncleanStatusError, + destinationBranchStatus.getBehindCount(), + destinationBranch); + } else { + uncleanStatusError = + AppsmithError.GIT_MERGE_FAILED_LOCAL_CHANGES; + uncleanStatusException = new AppsmithException( + uncleanStatusError, destinationBranch); + } + + return gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE_CHECK, + baseArtifact, + uncleanStatusError.name(), + uncleanStatusException.getMessage(), + baseGitMetadata.getIsRepoPrivate(), + false, + false) + .then(Mono.error(uncleanStatusException)); + })); + + return sourceBranchStatusMono.zipWith(destinationBranchStatusMono); + }) + .onErrorResume(error -> { + log.error( + "Error in merge status check for baseArtifact {} ", + baseArtifactId, + error); + if (error instanceof AppsmithException) { + Mono.error(error); + } + + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, "status", error)); + }); + + return statusTupleMono.flatMap(statusTuple -> { + GitMergeDTO mergeDTO = new GitMergeDTO(); + mergeDTO.setSourceBranch(sourceBranch); + mergeDTO.setDestinationBranch(destinationBranch); + return gitHandlingService + .isBranchMergable(jsonTransformationDTO, mergeDTO) + .onErrorResume(error -> { + MergeStatusDTO mergeStatus = new MergeStatusDTO(); + mergeStatus.setMergeAble(false); + mergeStatus.setStatus("Merge check failed!"); + mergeStatus.setMessage(error.getMessage()); + + return gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE_CHECK, + baseArtifact, + error.getClass().getName(), + error.getMessage(), + baseGitMetadata.getIsRepoPrivate(), + false, + false) + .thenReturn(mergeStatus); + }); + }); + }, + ignoreLock -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, TRUE)); + }); + + return Mono.create( + sink -> mergeableStatusMono.subscribe(sink::success, sink::error, null, sink.currentContext())); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java index 43459bd9682a..0574667557b1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java @@ -9,7 +9,9 @@ import com.appsmith.server.domains.GitAuth; import com.appsmith.server.dtos.ArtifactExchangeJson; import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; +import com.appsmith.server.git.dtos.FetchRemoteDTO; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; @@ -70,9 +72,16 @@ Mono prepareChangesToBeCommitted( Mono> commitArtifact( Artifact branchedArtifact, CommitDTO commitDTO, ArtifactJsonTransformationDTO jsonTransformationDTO); - Mono fetchRemoteChanges( + Mono fetchRemoteReferences( ArtifactJsonTransformationDTO jsonTransformationDTO, GitAuth gitAuth, Boolean isFetchAll); + Mono fetchRemoteReferences( + ArtifactJsonTransformationDTO jsonTransformationDTO, FetchRemoteDTO fetchRemoteDTO, GitAuth gitAuth); + + Mono mergeBranches(ArtifactJsonTransformationDTO jsonTransformationDTO, GitMergeDTO gitMergeDTO); + + Mono isBranchMergable(ArtifactJsonTransformationDTO JsonTransformationDTO, GitMergeDTO gitMergeDTO); + Mono recreateArtifactJsonFromLastCommit( ArtifactJsonTransformationDTO jsonTransformationDTO); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java index aefef9970fe6..9adf691c24d8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java @@ -3,6 +3,7 @@ import com.appsmith.external.dtos.GitBranchDTO; import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitStatusDTO; +import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.views.Views; import com.appsmith.git.dto.CommitDTO; @@ -14,6 +15,7 @@ import com.appsmith.server.dtos.AutoCommitResponseDTO; import com.appsmith.server.dtos.BranchProtectionRequestDTO; import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.dtos.GitPullDTO; import com.appsmith.server.dtos.ResponseDTO; import com.appsmith.server.git.autocommit.AutoCommitService; @@ -148,6 +150,34 @@ public Mono> fetchRemoteChanges( .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } + @JsonView(Views.Public.class) + @PostMapping("/{branchedApplicationId}/merge") + public Mono> merge( + @PathVariable String branchedApplicationId, @RequestBody GitMergeDTO gitMergeDTO) { + log.debug( + "Going to merge branch {} with branch {} for application {}", + gitMergeDTO.getSourceBranch(), + gitMergeDTO.getDestinationBranch(), + branchedApplicationId); + return centralGitService + .mergeBranch(branchedApplicationId, ARTIFACT_TYPE, gitMergeDTO, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{branchedApplicationId}/merge/status") + public Mono> mergeStatus( + @PathVariable String branchedApplicationId, @RequestBody GitMergeDTO gitMergeDTO) { + log.info( + "Check if branch {} can be merged with branch {} for application {}", + gitMergeDTO.getSourceBranch(), + gitMergeDTO.getDestinationBranch(), + branchedApplicationId); + return centralGitService + .isBranchMergable(branchedApplicationId, ARTIFACT_TYPE, gitMergeDTO, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + @JsonView(Views.Public.class) @DeleteMapping("/{baseArtifactId}/ref") public Mono> deleteBranch( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/ArtifactJsonTransformationDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/ArtifactJsonTransformationDTO.java index f6d3d1ef5ace..a4a1470ffeae 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/ArtifactJsonTransformationDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/ArtifactJsonTransformationDTO.java @@ -2,7 +2,9 @@ import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.constants.ArtifactType; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; // TODO: Find a better name for this DTO @@ -11,6 +13,8 @@ * this is also responsible for traversing paths for fs ops */ @Data +@NoArgsConstructor +@AllArgsConstructor public class ArtifactJsonTransformationDTO { String workspaceId; @@ -24,4 +28,10 @@ public class ArtifactJsonTransformationDTO { ArtifactType artifactType; RefType refType; + + public ArtifactJsonTransformationDTO(String workspaceId, String baseArtifactId, String repoName) { + this.workspaceId = workspaceId; + this.baseArtifactId = baseArtifactId; + this.repoName = repoName; + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java new file mode 100644 index 000000000000..6495b6ef7243 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java @@ -0,0 +1,23 @@ +package com.appsmith.server.git.dtos; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FetchRemoteDTO { + + /** + * List of references which is to be fetched from remote. + */ + List refNames; + + /** + * fetch all the remotes + */ + Boolean isFetchAll; +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 598147b8f81b..59163eda3677 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -19,6 +19,7 @@ import com.appsmith.server.domains.GitDeployKeys; import com.appsmith.server.dtos.ArtifactExchangeJson; import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exports.internal.ExportService; @@ -26,9 +27,11 @@ import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.central.GitHandlingServiceCE; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; +import com.appsmith.server.git.dtos.FetchRemoteDTO; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; import com.appsmith.server.git.utils.GitProfileUtils; +import com.appsmith.server.helpers.CollectionUtils; import com.appsmith.server.helpers.CommonGitFileUtils; import com.appsmith.server.helpers.GitPrivateRepoHelper; import com.appsmith.server.helpers.GitUtils; @@ -60,6 +63,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -579,7 +583,7 @@ private Mono pushArtifactErrorRecovery(String pushResult, Artifact artif * @return : returns string for remote fetch */ @Override - public Mono fetchRemoteChanges( + public Mono fetchRemoteReferences( ArtifactJsonTransformationDTO jsonTransformationDTO, GitAuth gitAuth, Boolean isFetchAll) { String workspaceId = jsonTransformationDTO.getWorkspaceId(); @@ -600,6 +604,59 @@ public Mono fetchRemoteChanges( return fetchRemoteMono.flatMap(remoteFetched -> checkoutBranchMono.thenReturn(remoteFetched)); } + @Override + public Mono fetchRemoteReferences( + ArtifactJsonTransformationDTO jsonTransformationDTO, FetchRemoteDTO fetchRemoteDTO, GitAuth gitAuth) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); + + String publicKey = gitAuth.getPublicKey(); + String privateKey = gitAuth.getPrivateKey(); + + if (CollectionUtils.isNullOrEmpty(fetchRemoteDTO.getRefNames())) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION)); + } + + List remoteValues = new ArrayList<>(); + remoteValues.addAll(fetchRemoteDTO.getRefNames()); + return fsGitHandler.fetchRemote(repoSuffix, publicKey, privateKey, false, remoteValues.toArray(new String[0])); + } + + @Override + public Mono mergeBranches(ArtifactJsonTransformationDTO jsonTransformationDTO, GitMergeDTO gitMergeDTO) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); + + // At this point the assumption is that the repository has already checked out the destination branch + return fsGitHandler.mergeBranch(repoSuffix, gitMergeDTO.getSourceBranch(), gitMergeDTO.getDestinationBranch()); + } + + @Override + public Mono isBranchMergable( + ArtifactJsonTransformationDTO jsonTransformationDTO, GitMergeDTO gitMergeDTO) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); + + // At this point the assumption is that the repository has already checked out the destination branch + return fsGitHandler.isMergeBranch( + repoSuffix, gitMergeDTO.getSourceBranch(), gitMergeDTO.getDestinationBranch()); + } + @Override public Mono recreateArtifactJsonFromLastCommit( ArtifactJsonTransformationDTO jsonTransformationDTO) { From 9500e838a61ae9ef2a0ee6f183393c6325588751 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Wed, 8 Jan 2025 12:45:58 +0530 Subject: [PATCH 8/9] review comments --- .../git/handler/ce/FSGitHandlerCEImpl.java | 46 +++++--- .../external}/git/dtos/FetchRemoteDTO.java | 8 +- .../external/git/handler/FSGitHandler.java | 3 +- .../git/central/CentralGitServiceCEImpl.java | 106 +++++++++--------- .../git/central/GitHandlingServiceCE.java | 2 +- .../controllers/GitArtifactControllerCE.java | 3 +- .../server/git/fs/GitFSServiceCEImpl.java | 7 +- 7 files changed, 101 insertions(+), 74 deletions(-) rename app/server/{appsmith-server/src/main/java/com/appsmith/server => appsmith-interfaces/src/main/java/com/appsmith/external}/git/dtos/FetchRemoteDTO.java (64%) diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java index 47f9630e72ed..a1be0d583302 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java @@ -10,6 +10,7 @@ import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.git.constants.ce.RefType; +import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.external.git.handler.FSGitHandler; import com.appsmith.external.helpers.Stopwatch; import com.appsmith.git.configurations.GitServiceConfig; @@ -41,6 +42,7 @@ import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.TagOpt; import org.eclipse.jgit.util.StringUtils; import org.springframework.stereotype.Component; import org.springframework.util.FileSystemUtils; @@ -91,6 +93,11 @@ public class FSGitHandlerCEImpl implements FSGitHandler { private final Scheduler scheduler = Schedulers.boundedElastic(); + private static final String BRANCH_REF_REMOTE_SRC = "refs/heads/"; + private static final String BRANCH_REF_LOCAL_DST = "refs/remotes/origin/"; + private static final String SRC_DST_DELIMITER = ":"; + private static final String TAG_REF = "refs/tags/"; + private static final String SUCCESS_MERGE_STATUS = "This branch has no conflicts with the base branch."; /** @@ -932,9 +939,7 @@ public Mono fetchRemote( @Override public Mono fetchRemote( - Path repoSuffix, String publicKey, String privateKey, boolean isRepoPath, String... refNames) { - Stopwatch processStopwatch = - StopwatchHelpers.startStopwatch(repoSuffix, AnalyticsEvents.GIT_FETCH.getEventName()); + Path repoSuffix, boolean isRepoPath, FetchRemoteDTO fetchRemoteDTO, String publicKey, String privateKey) { Path repoPath = TRUE.equals(isRepoPath) ? repoSuffix : createRepoPath(repoSuffix); return Mono.using( () -> Git.open(repoPath.toFile()), @@ -943,21 +948,35 @@ public Mono fetchRemote( new SshTransportConfigCallback(privateKey, publicKey); String fetchMessages; + List refNames = fetchRemoteDTO.getRefNames(); + RefType refType = fetchRemoteDTO.getRefType(); + List refSpecs = new ArrayList<>(); - for (String refName : refNames) { - RefSpec ref = new RefSpec( - "refs/heads/" + refName + ":refs/remotes/origin/" + refName); - refSpecs.add(ref); + if (RefType.tag.equals(refType)) { + for (String tagName : refNames) { + RefSpec refSpec = new RefSpec(TAG_REF + tagName + ":" + TAG_REF + tagName); + refSpecs.add(refSpec); + } + } else { + for (String refName : refNames) { + RefSpec ref = new RefSpec(BRANCH_REF_REMOTE_SRC + + refName + + SRC_DST_DELIMITER + + BRANCH_REF_LOCAL_DST + + refName); + refSpecs.add(ref); + } } fetchMessages = git.fetch() .setRefSpecs(refSpecs.toArray(new RefSpec[0])) .setRemoveDeletedRefs(true) + .setTagOpt(TagOpt.NO_TAGS) // no tags would mean that tags are fetched + // explicitly .setTransportConfigCallback(config) .call() .getMessages(); - processStopwatch.stopAndLogTimeInMillis(); return fetchMessages; }) .onErrorResume(error -> { @@ -979,7 +998,7 @@ public Mono isMergeBranch(Path repoSuffix, String sourceBranch, () -> Git.open(createRepoPath(repoSuffix).toFile()), git -> Mono.fromCallable(() -> { log.info( - "{}: Check mergeability for repo {} with src: {}, dest: {}", + "{}: Check merge-ability for repo {} with source: {}, destination: {}", Thread.currentThread().getName(), repoSuffix, sourceBranch, @@ -1036,12 +1055,11 @@ public Mono isMergeBranch(Path repoSuffix, String sourceBranch, } }) .onErrorResume(error -> { + MergeStatusDTO mergeStatusDTO = new MergeStatusDTO(); + mergeStatusDTO.setMergeAble(false); + mergeStatusDTO.setMessage(error.getMessage()); + mergeStatusDTO.setReferenceDoc(ErrorReferenceDocUrl.GIT_MERGE_CONFLICT.getDocUrl()); try { - MergeStatusDTO mergeStatusDTO = new MergeStatusDTO(); - mergeStatusDTO.setMergeAble(false); - mergeStatusDTO.setMessage(error.getMessage()); - mergeStatusDTO.setReferenceDoc( - ErrorReferenceDocUrl.GIT_MERGE_CONFLICT.getDocUrl()); return resetToLastCommit(repoSuffix, destinationBranch) .thenReturn(mergeStatusDTO); } catch (GitAPIException | IOException e) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/dtos/FetchRemoteDTO.java similarity index 64% rename from app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java rename to app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/dtos/FetchRemoteDTO.java index 6495b6ef7243..eba9e1fe7c7b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/dtos/FetchRemoteDTO.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/dtos/FetchRemoteDTO.java @@ -1,5 +1,6 @@ -package com.appsmith.server.git.dtos; +package com.appsmith.external.git.dtos; +import com.appsmith.external.git.constants.ce.RefType; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -16,6 +17,11 @@ public class FetchRemoteDTO { */ List refNames; + /** + * Assumption is that we fetch only one type of refs at once. + */ + RefType refType; + /** * fetch all the remotes */ diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java index b4dcdb549b5f..8ff45d21cbad 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java @@ -5,6 +5,7 @@ import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO; +import com.appsmith.external.git.dtos.FetchRemoteDTO; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.BranchTrackingStatus; import reactor.core.publisher.Mono; @@ -160,7 +161,7 @@ Mono fetchRemote( boolean isFetchAll); Mono fetchRemote( - Path repoSuffix, String publicKey, String privateKey, boolean isRepoPath, String... refNames); + Path repoSuffix, boolean isRepoPath, FetchRemoteDTO fetchRemoteDTO, String publicKey, String privateKey); /** * diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index 8ddbfa7dd09f..a8471e978b27 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -9,6 +9,7 @@ import com.appsmith.external.git.constants.GitConstants; import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.git.constants.ce.RefType; +import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceStorage; import com.appsmith.git.dto.CommitDTO; @@ -42,7 +43,6 @@ import com.appsmith.server.git.GitRedisUtils; import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; -import com.appsmith.server.git.dtos.FetchRemoteDTO; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.resolver.GitHandlingServiceResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; @@ -2670,9 +2670,10 @@ public Mono mergeBranch( GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); - Mono> statusTupleMono = gitHandlingService - .fetchRemoteReferences( - jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth()) + Mono fetchingRemoteMono = gitHandlingService.fetchRemoteReferences( + jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth()); + + Mono> statusTupleMono = fetchingRemoteMono .flatMap(remoteSpecs -> { Mono sourceBranchStatusMono = Mono.defer(() -> getStatus( baseArtifact, sourceArtifact, false, false, gitType) @@ -2743,28 +2744,29 @@ public Mono mergeBranch( GitMergeDTO mergeDTO = new GitMergeDTO(); mergeDTO.setSourceBranch(sourceBranch); mergeDTO.setDestinationBranch(destinationBranch); - return gitHandlingService - .mergeBranches(jsonTransformationDTO, mergeDTO) - .onErrorResume(error -> gitAnalyticsUtils - .addAnalyticsForGitOperation( - AnalyticsEvents.GIT_MERGE, - baseArtifact, - error.getClass() - .getName(), - error.getMessage(), - baseGitMetadata.getIsRepoPrivate()) - .flatMap(artifact -> { - if (error instanceof GitAPIException) { - return Mono.error(new AppsmithException( - AppsmithError.GIT_MERGE_CONFLICTS, - error.getMessage())); - } - - return Mono.error(new AppsmithException( - AppsmithError.GIT_ACTION_FAILED, - "merge", - error.getMessage())); - })); + + Mono mergeBranchesMono = + gitHandlingService.mergeBranches(jsonTransformationDTO, mergeDTO); + + return mergeBranchesMono.onErrorResume(error -> gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE, + baseArtifact, + error.getClass().getName(), + error.getMessage(), + baseGitMetadata.getIsRepoPrivate()) + .flatMap(artifact -> { + if (error instanceof GitAPIException) { + return Mono.error(new AppsmithException( + AppsmithError.GIT_MERGE_CONFLICTS, + error.getMessage())); + } + + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, + "merge", + error.getMessage())); + })); }) .zipWhen(mergeStatus -> { ArtifactJsonTransformationDTO constructJsonDTO = @@ -2772,9 +2774,8 @@ public Mono mergeBranch( workspaceId, baseArtifactId, repoName); constructJsonDTO.setArtifactType(artifactType); constructJsonDTO.setRefName(destinationBranch); - return Mono.defer( - () -> gitHandlingService.reconstructArtifactJsonFromGitRepository( - constructJsonDTO)); + return gitHandlingService.reconstructArtifactJsonFromGitRepository( + constructJsonDTO); }) .flatMap(tuple2 -> { ArtifactExchangeJson artifactExchangeJson = tuple2.getT2(); @@ -2885,9 +2886,10 @@ public Mono isBranchMergable( GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); - Mono> statusTupleMono = gitHandlingService - .fetchRemoteReferences( - jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth()) + Mono fetchRemoteReferencesMono = gitHandlingService.fetchRemoteReferences( + jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth()); + + Mono> statusTupleMono = fetchRemoteReferencesMono .flatMap(remoteSpecs -> { Mono sourceBranchStatusMono = Mono.defer(() -> getStatus( baseArtifact, sourceArtifact, false, false, gitType) @@ -2982,25 +2984,27 @@ public Mono isBranchMergable( GitMergeDTO mergeDTO = new GitMergeDTO(); mergeDTO.setSourceBranch(sourceBranch); mergeDTO.setDestinationBranch(destinationBranch); - return gitHandlingService - .isBranchMergable(jsonTransformationDTO, mergeDTO) - .onErrorResume(error -> { - MergeStatusDTO mergeStatus = new MergeStatusDTO(); - mergeStatus.setMergeAble(false); - mergeStatus.setStatus("Merge check failed!"); - mergeStatus.setMessage(error.getMessage()); - - return gitAnalyticsUtils - .addAnalyticsForGitOperation( - AnalyticsEvents.GIT_MERGE_CHECK, - baseArtifact, - error.getClass().getName(), - error.getMessage(), - baseGitMetadata.getIsRepoPrivate(), - false, - false) - .thenReturn(mergeStatus); - }); + + Mono isBranchMergable = + gitHandlingService.isBranchMergable(jsonTransformationDTO, mergeDTO); + + return isBranchMergable.onErrorResume(error -> { + MergeStatusDTO mergeStatus = new MergeStatusDTO(); + mergeStatus.setMergeAble(false); + mergeStatus.setStatus("Merge check failed!"); + mergeStatus.setMessage(error.getMessage()); + + return gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_MERGE_CHECK, + baseArtifact, + error.getClass().getName(), + error.getMessage(), + baseGitMetadata.getIsRepoPrivate(), + false, + false) + .thenReturn(mergeStatus); + }); }); }, ignoreLock -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, TRUE)); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java index 0574667557b1..473d5f81ec36 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java @@ -3,6 +3,7 @@ import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO; +import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.git.dto.CommitDTO; import com.appsmith.server.domains.Artifact; import com.appsmith.server.domains.GitArtifactMetadata; @@ -11,7 +12,6 @@ import com.appsmith.server.dtos.GitConnectDTO; import com.appsmith.server.dtos.GitMergeDTO; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; -import com.appsmith.server.git.dtos.FetchRemoteDTO; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java index 71215783c16e..7293900367f6 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java @@ -5,6 +5,7 @@ import com.appsmith.server.constants.Url; import com.appsmith.server.domains.GitAuth; import com.appsmith.server.dtos.ApplicationImportDTO; +import com.appsmith.server.dtos.ArtifactImportDTO; import com.appsmith.server.dtos.GitConnectDTO; import com.appsmith.server.dtos.GitDeployKeyDTO; import com.appsmith.server.dtos.GitDocsDTO; @@ -38,7 +39,7 @@ public class GitArtifactControllerCE { @JsonView(Views.Public.class) @PostMapping("/import") - public Mono> importApplicationFromGit( + public Mono> importApplicationFromGit( @RequestParam String workspaceId, @RequestBody GitConnectDTO gitConnectDTO) { // TODO: remove artifact type from methods. diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 59163eda3677..541c57058ceb 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -8,6 +8,7 @@ import com.appsmith.external.git.constants.GitConstants; import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.git.constants.ce.RefType; +import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.external.git.handler.FSGitHandler; import com.appsmith.git.dto.CommitDTO; import com.appsmith.server.configurations.EmailConfig; @@ -27,7 +28,6 @@ import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper; import com.appsmith.server.git.central.GitHandlingServiceCE; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; -import com.appsmith.server.git.dtos.FetchRemoteDTO; import com.appsmith.server.git.resolver.GitArtifactHelperResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; import com.appsmith.server.git.utils.GitProfileUtils; @@ -63,7 +63,6 @@ import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -622,9 +621,7 @@ public Mono fetchRemoteReferences( return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION)); } - List remoteValues = new ArrayList<>(); - remoteValues.addAll(fetchRemoteDTO.getRefNames()); - return fsGitHandler.fetchRemote(repoSuffix, publicKey, privateKey, false, remoteValues.toArray(new String[0])); + return fsGitHandler.fetchRemote(repoSuffix, false, fetchRemoteDTO, publicKey, privateKey); } @Override From ab5e3363997d194c713b015d031fff27b7bf8404 Mon Sep 17 00:00:00 2001 From: sondermanish Date: Wed, 8 Jan 2025 12:59:43 +0530 Subject: [PATCH 9/9] further modification --- .../server/git/controllers/GitArtifactControllerCE.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java index 7293900367f6..d2fd03b8ad04 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java @@ -4,7 +4,6 @@ import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.constants.Url; import com.appsmith.server.domains.GitAuth; -import com.appsmith.server.dtos.ApplicationImportDTO; import com.appsmith.server.dtos.ArtifactImportDTO; import com.appsmith.server.dtos.GitConnectDTO; import com.appsmith.server.dtos.GitDeployKeyDTO; @@ -39,13 +38,12 @@ public class GitArtifactControllerCE { @JsonView(Views.Public.class) @PostMapping("/import") - public Mono> importApplicationFromGit( + public Mono> importArtifactFromGit( @RequestParam String workspaceId, @RequestBody GitConnectDTO gitConnectDTO) { // TODO: remove artifact type from methods. return centralGitService .importArtifactFromGit(workspaceId, gitConnectDTO, ArtifactType.APPLICATION, GIT_TYPE) - .map(artifactImportDTO -> (ApplicationImportDTO) artifactImportDTO) .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); }