Skip to content

Commit dea1c03

Browse files
author
Diljit
authored
chore: in memory git status (#40891)
## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Git" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/15607977360> > Commit: b50460f > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=15607977360&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Git` > Spec: > <hr>Thu, 12 Jun 2025 11:13:06 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced detailed Git status computation showing added, modified, and removed files. - Added branch tracking status retrieval for repositories. - **Improvements** - Enhanced integration of Git status and branch tracking features across interfaces and services. - Improved status reporting by enriching Git status with branch tracking details. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 126f557 commit dea1c03

File tree

10 files changed

+152
-11
lines changed

10 files changed

+152
-11
lines changed

app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.appsmith.git.files;
22

3+
import com.appsmith.external.dtos.GitStatusDTO;
34
import com.appsmith.external.dtos.ModifiedResources;
45
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
56
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
@@ -19,6 +20,7 @@
1920
import com.appsmith.git.constants.CommonConstants;
2021
import com.appsmith.git.helpers.DSLTransformerHelper;
2122
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import io.micrometer.observation.ObservationRegistry;
2224
import io.micrometer.tracing.Span;
2325
import lombok.Getter;
2426
import lombok.extern.slf4j.Slf4j;
@@ -31,6 +33,7 @@
3133
import org.springframework.stereotype.Component;
3234
import org.springframework.util.FileSystemUtils;
3335
import org.springframework.util.StringUtils;
36+
import reactor.core.observability.micrometer.Micrometer;
3437
import reactor.core.publisher.Mono;
3538
import reactor.core.scheduler.Scheduler;
3639
import reactor.core.scheduler.Schedulers;
@@ -90,7 +93,7 @@ public class FileUtilsCEImpl implements FileInterface {
9093
protected final FileOperations fileOperations;
9194
private final ObservationHelper observationHelper;
9295
protected final ObjectMapper objectMapper;
93-
96+
private final ObservationRegistry observationRegistry;
9497
private static final String EDIT_MODE_URL_TEMPLATE = "{{editModeUrl}}";
9598

9699
private static final String VIEW_MODE_URL_TEMPLATE = "{{viewModeUrl}}";
@@ -108,13 +111,15 @@ public FileUtilsCEImpl(
108111
GitExecutor gitExecutor,
109112
FileOperations fileOperations,
110113
ObservationHelper observationHelper,
111-
ObjectMapper objectMapper) {
114+
ObjectMapper objectMapper,
115+
ObservationRegistry observationRegistry) {
112116
this.gitServiceConfig = gitServiceConfig;
113117
this.fsGitHandler = fsGitHandler;
114118
this.gitExecutor = gitExecutor;
115119
this.fileOperations = fileOperations;
116120
this.observationHelper = observationHelper;
117121
this.objectMapper = objectMapper;
122+
this.observationRegistry = observationRegistry;
118123
}
119124

120125
protected Map<GitResourceType, GitResourceType> getModifiedResourcesTypes() {
@@ -290,6 +295,66 @@ public Mono<Path> saveArtifactToGitRepo(
290295
.subscribeOn(scheduler);
291296
}
292297

298+
public Mono<GitStatusDTO> computeGitStatus(
299+
Path baseRepoSuffix, GitResourceMap gitResourceMapFromDB, String branchName, boolean keepWorkingDirChanges)
300+
throws GitAPIException, IOException {
301+
return fsGitHandler
302+
.resetToLastCommit(baseRepoSuffix, branchName, keepWorkingDirChanges)
303+
.flatMap(__ -> constructGitResourceMapFromGitRepo(baseRepoSuffix, branchName))
304+
.flatMap(gitResourceMapFromFS -> {
305+
Map<GitResourceIdentity, Object> resourceMapFromDB = gitResourceMapFromDB.getGitResourceMap();
306+
Map<GitResourceIdentity, Object> resourceMapFromFS = gitResourceMapFromFS.getGitResourceMap();
307+
308+
Map<String, Object> filePathObjectsMapFromFS = resourceMapFromFS.entrySet().parallelStream()
309+
.collect(
310+
Collectors.toMap(entry -> entry.getKey().getFilePath(), entry -> entry.getValue()));
311+
312+
Map<String, Object> filePathToObjectsFromDB = resourceMapFromDB.entrySet().parallelStream()
313+
.collect(
314+
Collectors.toMap(entry -> entry.getKey().getFilePath(), entry -> entry.getValue()));
315+
316+
Set<String> filePathsInDb = new HashSet<>(filePathToObjectsFromDB.keySet());
317+
Set<String> filePathsInFS = new HashSet<>(filePathObjectsMapFromFS.keySet());
318+
319+
// added files
320+
Set<String> addedFiles = new HashSet<>(filePathsInDb);
321+
addedFiles.removeAll(filePathsInFS);
322+
323+
// removed files
324+
Set<String> removedFiles = new HashSet<>(filePathsInFS);
325+
removedFiles.removeAll(filePathsInDb);
326+
removedFiles.remove(README_FILE_NAME);
327+
328+
// common files
329+
Set<String> commonFiles = new HashSet<>(filePathsInDb);
330+
commonFiles.retainAll(filePathsInFS);
331+
332+
// modified files
333+
Set<String> modifiedFiles = commonFiles.stream()
334+
.filter(filePath -> {
335+
Object fileInDB = filePathToObjectsFromDB.get(filePath);
336+
Object fileInFS = filePathObjectsMapFromFS.get(filePath);
337+
try {
338+
return fileOperations.hasFileChanged(fileInDB, fileInFS);
339+
} catch (IOException e) {
340+
log.error("Error while checking if file has changed", e);
341+
return false;
342+
}
343+
})
344+
.collect(Collectors.toSet());
345+
346+
GitStatusDTO localRepoStatus = new GitStatusDTO();
347+
localRepoStatus.setAdded(addedFiles);
348+
localRepoStatus.setModified(modifiedFiles);
349+
localRepoStatus.setRemoved(removedFiles);
350+
boolean isClean = addedFiles.isEmpty() && modifiedFiles.isEmpty() && removedFiles.isEmpty();
351+
localRepoStatus.setIsClean(isClean);
352+
353+
fsGitHandler.populateModifiedEntities(localRepoStatus);
354+
return Mono.just(localRepoStatus);
355+
});
356+
}
357+
293358
protected Set<String> getWhitelistedPaths() {
294359
String pages = PAGE_DIRECTORY + DELIMITER_PATH;
295360
String datasources = DATASOURCE_DIRECTORY + DELIMITER_PATH;
@@ -802,7 +867,10 @@ public Mono<ApplicationGitReference> reconstructApplicationReferenceFromGitRepo(
802867
@Override
803868
public Mono<GitResourceMap> constructGitResourceMapFromGitRepo(Path repositorySuffix, String refName) {
804869
Path repositoryPath = Paths.get(gitServiceConfig.getGitRootPath()).resolve(repositorySuffix);
805-
return Mono.fromCallable(() -> fetchGitResourceMap(repositoryPath)).subscribeOn(scheduler);
870+
return Mono.fromCallable(() -> fetchGitResourceMap(repositoryPath))
871+
.subscribeOn(scheduler)
872+
.name("construct-git-resource-map")
873+
.tap(Micrometer.observation(observationRegistry));
806874
}
807875

808876
/**

app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsImpl.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.appsmith.external.helpers.ObservationHelper;
88
import com.appsmith.git.configurations.GitServiceConfig;
99
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import io.micrometer.observation.ObservationRegistry;
1011
import lombok.Getter;
1112
import lombok.extern.slf4j.Slf4j;
1213
import org.springframework.context.annotation.Import;
@@ -26,7 +27,15 @@ public FileUtilsImpl(
2627
GitExecutor gitExecutor,
2728
FileOperations fileOperations,
2829
ObservationHelper observationHelper,
29-
ObjectMapper objectMapper) {
30-
super(gitServiceConfig, fsGitHandler, gitExecutor, fileOperations, observationHelper, objectMapper);
30+
ObjectMapper objectMapper,
31+
ObservationRegistry observationRegistry) {
32+
super(
33+
gitServiceConfig,
34+
fsGitHandler,
35+
gitExecutor,
36+
fileOperations,
37+
observationHelper,
38+
objectMapper,
39+
observationRegistry);
3140
}
3241
}

app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,8 @@ public Mono<GitStatusDTO> getStatus(Path repoPath, String branchName, boolean ke
935935
.subscribeOn(scheduler);
936936
}
937937

938-
protected void populateModifiedEntities(GitStatusDTO response) {
938+
@Override
939+
public void populateModifiedEntities(GitStatusDTO response) {
939940
populatePageChanges(response);
940941
populateQueryChanges(response);
941942
populateJsObjectChanges(response);

app/server/appsmith-git/src/test/java/com/appsmith/git/helpers/FileUtilsImplTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.appsmith.git.files.operations.FileOperationsImpl;
1010
import com.appsmith.git.service.GitExecutorImpl;
1111
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import io.micrometer.observation.ObservationRegistry;
1213
import org.apache.commons.io.FileUtils;
1314
import org.eclipse.jgit.api.errors.GitAPIException;
1415
import org.junit.jupiter.api.AfterEach;
@@ -51,7 +52,8 @@ public void setUp() {
5152
gitExecutor,
5253
fileOperations,
5354
ObservationHelper.NOOP,
54-
new ObjectMapper());
55+
new ObjectMapper(),
56+
ObservationRegistry.NOOP);
5557
}
5658

5759
@AfterEach

app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.appsmith.external.git;
22

3+
import com.appsmith.external.dtos.GitStatusDTO;
34
import com.appsmith.external.git.models.GitResourceMap;
45
import com.appsmith.external.models.ApplicationGitReference;
56
import com.appsmith.external.models.ArtifactGitReference;
@@ -42,6 +43,10 @@ Mono<Path> saveArtifactToGitRepo(
4243
Path baseRepoSuffix, GitResourceMap gitResourceMap, String branchName, boolean keepWorkingDirChanges)
4344
throws GitAPIException, IOException;
4445

46+
Mono<GitStatusDTO> computeGitStatus(
47+
Path baseRepoSuffix, GitResourceMap gitResourceMap, String branchName, boolean keepWorkingDirChanges)
48+
throws GitAPIException, IOException;
49+
4550
/**
4651
* This method will reconstruct the application from the repo
4752
*

app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/handler/FSGitHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ Mono<MergeStatusDTO> pullApplication(
160160
*/
161161
Mono<GitStatusDTO> getStatus(Path repoPath, String branchName, boolean keepWorkingDirChanges);
162162

163+
void populateModifiedEntities(GitStatusDTO response);
164+
163165
/**
164166
* This method merges source branch into destination branch for a git repository which is present on the partial
165167
* path provided. <B> This assumes that the branch on which the merge will happen is already checked out </B>

app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,8 +1675,10 @@ protected Mono<GitStatusDTO> getStatus(
16751675
Mono<GitStatusDTO> lockHandledStatusMono = Mono.usingWhen(
16761676
exportedArtifactJsonMono,
16771677
artifactExchangeJson -> {
1678-
Mono<Boolean> prepareForStatus =
1679-
gitHandlingService.prepareChangesToBeCommitted(jsonTransformationDTO, artifactExchangeJson);
1678+
Mono<GitStatusDTO> statusMono = gitHandlingService
1679+
.computeGitStatus(jsonTransformationDTO, artifactExchangeJson)
1680+
.name("in-memory-status-computation")
1681+
.tap(Micrometer.observation(observationRegistry));
16801682

16811683
Mono<String> fetchRemoteMono = Mono.just("ignored");
16821684

@@ -1694,8 +1696,31 @@ protected Mono<GitStatusDTO> getStatus(
16941696
error.getMessage()))));
16951697
}
16961698

1697-
return Mono.zip(prepareForStatus, fetchRemoteMono)
1698-
.then(Mono.defer(() -> gitHandlingService.getStatus(jsonTransformationDTO)))
1699+
return Mono.zip(statusMono, fetchRemoteMono)
1700+
.flatMap(tuple -> {
1701+
return gitHandlingService
1702+
.getBranchTrackingStatus(jsonTransformationDTO)
1703+
.map(branchTrackingStatus -> {
1704+
GitStatusDTO status = tuple.getT1();
1705+
1706+
if (branchTrackingStatus != null) {
1707+
status.setAheadCount(branchTrackingStatus.getAheadCount());
1708+
status.setBehindCount(branchTrackingStatus.getBehindCount());
1709+
status.setRemoteBranch(branchTrackingStatus.getRemoteTrackingBranch());
1710+
1711+
} else {
1712+
log.debug(
1713+
"Remote tracking details not present for branch: {}, repo: {}",
1714+
finalBranchName,
1715+
repoName);
1716+
status.setAheadCount(0);
1717+
status.setBehindCount(0);
1718+
status.setRemoteBranch("untracked");
1719+
}
1720+
1721+
return status;
1722+
});
1723+
})
16991724
.onErrorResume(throwable -> {
17001725
/*
17011726
in case of any error, the global exception handler will release the lock

app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ Mono<Boolean> initialiseReadMe(
8686
Mono<Boolean> prepareChangesToBeCommitted(
8787
ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson);
8888

89+
Mono<GitStatusDTO> computeGitStatus(
90+
ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson);
91+
8992
Mono<Tuple2<? extends Artifact, String>> commitArtifact(
9093
Artifact branchedArtifact, CommitDTO commitDTO, ArtifactJsonTransformationDTO jsonTransformationDTO);
9194

app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,19 @@ public Mono<GitStatusDTO> getStatus(ArtifactJsonTransformationDTO jsonTransforma
764764
keepWorkingDirChanges -> fsGitHandler.getStatus(repoPath, refName, keepWorkingDirChanges));
765765
}
766766

767+
public Mono<GitStatusDTO> computeGitStatus(
768+
ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson) {
769+
String workspaceId = jsonTransformationDTO.getWorkspaceId();
770+
String baseArtifactId = jsonTransformationDTO.getBaseArtifactId();
771+
String repoName = jsonTransformationDTO.getRepoName();
772+
String branchName = jsonTransformationDTO.getRefName();
773+
774+
ArtifactType artifactType = jsonTransformationDTO.getArtifactType();
775+
GitArtifactHelper<?> gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
776+
Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName);
777+
return commonGitFileUtils.computeGitStatus(repoSuffix, artifactExchangeJson, branchName);
778+
}
779+
767780
@Override
768781
public Mono<String> createGitReference(
769782
ArtifactJsonTransformationDTO baseRefJsonTransformationDTO,

app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.appsmith.server.helpers.ce;
22

33
import com.appsmith.external.constants.AnalyticsEvents;
4+
import com.appsmith.external.dtos.GitStatusDTO;
45
import com.appsmith.external.enums.FeatureFlagEnum;
56
import com.appsmith.external.git.FileInterface;
67
import com.appsmith.external.git.models.GitResourceIdentity;
@@ -195,6 +196,18 @@ public Mono<Path> saveArtifactToLocalRepoNew(
195196
});
196197
}
197198

199+
public Mono<GitStatusDTO> computeGitStatus(
200+
Path baseRepoSuffix, ArtifactExchangeJson artifactExchangeJson, String branchName) {
201+
GitResourceMap gitResourceMapFromDB = createGitResourceMap(artifactExchangeJson);
202+
try {
203+
return fileUtils
204+
.computeGitStatus(baseRepoSuffix, gitResourceMapFromDB, branchName, true)
205+
.subscribeOn(Schedulers.boundedElastic());
206+
} catch (IOException | GitAPIException exception) {
207+
return Mono.error(exception);
208+
}
209+
}
210+
198211
public Mono<Path> saveArtifactToLocalRepoWithAnalytics(
199212
Path baseRepoSuffix, ArtifactExchangeJson artifactExchangeJson, String branchName) {
200213

0 commit comments

Comments
 (0)