diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ce/GitStatusCE_DTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ce/GitStatusCE_DTO.java index ed4e074f2417..0c1666a517b7 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ce/GitStatusCE_DTO.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ce/GitStatusCE_DTO.java @@ -8,6 +8,7 @@ /** * DTO to convey the status local git repo */ +// TODO: @Manish modify git status DTO accordingly @Data public class GitStatusCE_DTO { 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 4254b5d4dd2a..40b65564d7e3 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 @@ -1,5 +1,6 @@ package com.appsmith.server.git.central; +import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.git.dto.CommitDTO; import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.constants.ce.RefType; @@ -33,4 +34,7 @@ Mono fetchRemoteChanges( RefType refType); Mono discardChanges(String branchedArtifactId, ArtifactType artifactType, GitType gitType); + + Mono getStatus( + String branchedArtifactId, boolean compareRemote, ArtifactType artifactType, GitType gitType); } 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 55e1692b816e..9d244ab846fd 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 @@ -1,6 +1,7 @@ package com.appsmith.server.git.central; import com.appsmith.external.constants.AnalyticsEvents; +import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.git.constants.GitConstants; import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.models.Datasource; @@ -67,6 +68,7 @@ import static com.appsmith.external.git.constants.ce.GitConstantsCE.GIT_CONFIG_ERROR; import static com.appsmith.external.git.constants.ce.GitConstantsCE.GIT_PROFILE_ERROR; import static com.appsmith.external.git.constants.ce.GitSpanCE.OPS_COMMIT; +import static com.appsmith.external.git.constants.ce.GitSpanCE.OPS_STATUS; import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties; import static com.appsmith.server.constants.FieldName.BRANCH_NAME; import static com.appsmith.server.constants.FieldName.DEFAULT; @@ -929,6 +931,137 @@ private boolean isBaseGitMetadataInvalid(GitArtifactMetadata gitArtifactMetadata .isGitAuthInvalid(gitArtifactMetadata.getGitAuth()); } + private Mono getStatusAfterComparingWithRemote( + String baseArtifactId, boolean isFileLock, ArtifactType artifactType, GitType gitType) { + return getStatus(baseArtifactId, isFileLock, true, artifactType, gitType); + } + + @Override + public Mono getStatus( + String branchedArtifactId, boolean compareRemote, ArtifactType artifactType, GitType gitType) { + return getStatus(branchedArtifactId, true, compareRemote, artifactType, gitType); + } + + /** + * Get the status of the artifact for given branched id + * + * @param branchedArtifactId branched id of the artifact + * @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, + boolean isFileLock, + boolean compareRemote, + ArtifactType artifactType, + GitType gitType) { + + Mono> baseAndBranchedArtifacts = + getBaseAndBranchedArtifacts(branchedArtifactId, artifactType); + + return baseAndBranchedArtifacts.flatMap(artifactTuple -> { + Artifact baseArtifact = artifactTuple.getT1(); + Artifact branchedArtifact = artifactTuple.getT2(); + return getStatus(baseArtifact, branchedArtifact, isFileLock, compareRemote, gitType); + }); + } + + protected Mono getStatus( + Artifact baseArtifact, + Artifact branchedArtifact, + boolean isFileLock, + boolean compareRemote, + GitType gitType) { + + ArtifactType artifactType = baseArtifact.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); + + GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); + final String baseArtifactId = baseGitMetadata.getDefaultArtifactId(); + + GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); + branchedGitMetadata.setGitAuth(baseGitMetadata.getGitAuth()); + + final String finalBranchName = branchedGitMetadata.getBranchName(); + + if (!StringUtils.hasText(finalBranchName)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); + } + + Mono exportedArtifactJsonMono = + exportService.exportByArtifactId(branchedArtifact.getId(), VERSION_CONTROL, artifactType); + + Mono statusMono = exportedArtifactJsonMono + .flatMap(artifactExchangeJson -> { + return gitRedisUtils + .acquireGitLock(baseArtifactId, GitConstants.GitCommandConstants.STATUS, isFileLock) + .thenReturn(artifactExchangeJson); + }) + .flatMap(artifactExchangeJson -> { + ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); + jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); + jsonTransformationDTO.setBaseArtifactId(baseArtifact.getId()); + jsonTransformationDTO.setRepoName( + branchedArtifact.getGitArtifactMetadata().getRepoName()); + jsonTransformationDTO.setArtifactType(artifactExchangeJson.getArtifactJsonType()); + jsonTransformationDTO.setRefName(finalBranchName); + + Mono prepareForStatus = + gitHandlingService.prepareChangesToBeCommitted(jsonTransformationDTO, artifactExchangeJson); + Mono fetchRemoteMono; + + if (compareRemote) { + fetchRemoteMono = Mono.defer( + () -> fetchRemoteChanges(baseArtifact, branchedArtifact, FALSE, gitType, RefType.BRANCH) + .onErrorResume(error -> Mono.error(new AppsmithException( + AppsmithError.GIT_GENERIC_ERROR, error.getMessage())))); + } else { + fetchRemoteMono = Mono.just("ignored"); + } + + return Mono.zip(prepareForStatus, fetchRemoteMono) + .then(gitHandlingService.getStatus(jsonTransformationDTO)); + }) + .doFinally(signalType -> gitRedisUtils.releaseFileLock(baseArtifactId, isFileLock)) + .onErrorResume(throwable -> { + /* + in case of any error, the global exception handler will release the lock + hence we don't need to do that manually + */ + log.error( + "Error to get status for application: {}, branch: {}", + baseArtifactId, + finalBranchName, + throwable); + return Mono.error(new AppsmithException(AppsmithError.GIT_GENERIC_ERROR, throwable.getMessage())); + }); + + return Mono.zip(statusMono, sessionUserService.getCurrentUser()) + .elapsed() + .flatMap(objects -> { + Long elapsedTime = objects.getT1(); + GitStatusDTO gitStatusDTO = objects.getT2().getT1(); + User currentUser = objects.getT2().getT2(); + String flowName; + if (compareRemote) { + flowName = AnalyticsEvents.GIT_STATUS.getEventName(); + } else { + flowName = AnalyticsEvents.GIT_STATUS_WITHOUT_FETCH.getEventName(); + } + + return gitAnalyticsUtils + .sendUnitExecutionTimeAnalyticsEvent(flowName, elapsedTime, currentUser, branchedArtifact) + .thenReturn(gitStatusDTO); + }) + .name(OPS_STATUS) + .tap(Micrometer.observation(observationRegistry)); + } + public Mono fetchRemoteChanges( Artifact baseArtifact, Artifact refArtifact, boolean isFileLock, GitType gitType, RefType refType) { @@ -967,7 +1100,9 @@ public Mono fetchRemoteChanges( .then(Mono.defer(() -> gitHandlingService.fetchRemoteChanges(jsonTransformationDTO, baseArtifactGitData.getGitAuth()))) .flatMap(fetchedRemoteStatusString -> { - return gitRedisUtils.releaseFileLock(baseArtifactId).thenReturn(fetchedRemoteStatusString); + return gitRedisUtils + .releaseFileLock(baseArtifactId, isFileLock) + .thenReturn(fetchedRemoteStatusString); }) .onErrorResume(throwable -> { /* 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 de387a9e75ee..57a2847af58c 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 @@ -1,5 +1,6 @@ package com.appsmith.server.git.central; +import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.git.dto.CommitDTO; import com.appsmith.server.domains.Artifact; import com.appsmith.server.domains.GitArtifactMetadata; @@ -51,6 +52,7 @@ Mono initialiseReadMe( Mono createFirstCommit(ArtifactJsonTransformationDTO jsonTransformationDTO, CommitDTO commitDTO); + // TODO: provide a proper name Mono prepareChangesToBeCommitted( ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson); @@ -61,4 +63,6 @@ Mono> commitArtifact( Mono recreateArtifactJsonFromLastCommit( ArtifactJsonTransformationDTO jsonTransformationDTO); + + Mono getStatus(ArtifactJsonTransformationDTO jsonTransformationDTO); } 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 27dc09fde456..6b6f412c1e1e 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 @@ -2,6 +2,7 @@ import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.dtos.GitBranchDTO; +import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.git.constants.GitConstants; import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.git.handler.FSGitHandler; @@ -617,4 +618,19 @@ public Mono recreateArtifactJsonFromLastCommit( workspaceId, baseArtifactId, repoName, refName, artifactType); }); } + + @Override + public Mono getStatus(ArtifactJsonTransformationDTO jsonTransformationDTO) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + String refName = jsonTransformationDTO.getRefName(); + + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); + + Path repoPath = fsGitHandler.createRepoPath(repoSuffix); + return fsGitHandler.getStatus(repoPath, refName); + } }