chore: speeding up and verifying git apis (#38952)

## 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/13112635630>
> Commit: f85c2bbc5ffa6604c6e69a7b3e476538f6a61e14
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13112635630&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Git`
> Spec:
> <hr>Mon, 03 Feb 2025 12:27:57 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 a new way to pull remote changes without switching
branches, simplifying Git operations.
- Added endpoints for managing user Git configurations, including
default and repository-specific profiles.

- **Refactor**
- Streamlined Git branch and reference management with improved
parameter handling and updated URL structures.
- Enhanced error reporting and consistency in remote fetch and merge
operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Manish Kumar 2025-02-03 21:15:49 +05:30 committed by GitHub
parent a7d31b518e
commit 2e598068b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 434 additions and 288 deletions

View File

@ -465,6 +465,70 @@ public class FSGitHandlerCEImpl implements FSGitHandler {
.subscribeOn(scheduler); .subscribeOn(scheduler);
} }
@Override
public Mono<MergeStatusDTO> pullArtifactWithoutCheckout(
Path repoSuffix, String remoteUrl, String branchName, String privateKey, String publicKey)
throws IOException {
TransportConfigCallback transportConfigCallback = new SshTransportConfigCallback(privateKey, publicKey);
return Mono.using(
() -> Git.open(createRepoPath(repoSuffix).toFile()),
git -> Mono.fromCallable(() -> {
log.info(
"{} : Pull changes from remote {} for the branch {}.",
Thread.currentThread().getName(),
remoteUrl,
branchName);
MergeResult mergeResult;
try {
mergeResult = git.pull()
.setRemoteBranchName(branchName)
.setTransportConfigCallback(transportConfigCallback)
.setFastForward(MergeCommand.FastForwardMode.FF)
.call()
.getMergeResult();
} catch (GitAPIException e) {
throw e;
}
MergeStatusDTO mergeStatus = new MergeStatusDTO();
Long count = Arrays.stream(mergeResult.getMergedCommits())
.count();
if (mergeResult.getMergeStatus().isSuccessful()) {
mergeStatus.setMergeAble(true);
mergeStatus.setStatus(count + " commits merged from origin/" + branchName);
return mergeStatus;
} else {
// If there are conflicts add the conflicting file names to the response
// structure
mergeStatus.setMergeAble(false);
List<String> mergeConflictFiles = new ArrayList<>();
if (!Optional.ofNullable(mergeResult.getConflicts())
.isEmpty()) {
mergeConflictFiles.addAll(
mergeResult.getConflicts().keySet());
}
mergeStatus.setConflictingFiles(mergeConflictFiles);
try {
// On merge conflicts abort the merge => git merge --abort
git.getRepository().writeMergeCommitMsg(null);
git.getRepository().writeMergeHeads(null);
throw new org.eclipse.jgit.errors.CheckoutConflictException(
mergeConflictFiles.toString());
} catch (IOException e) {
log.debug("Encountered error while aborting merge", e);
throw new org.eclipse.jgit.errors.CheckoutConflictException(
mergeConflictFiles.toString());
}
}
})
.onErrorResume(error -> resetToLastCommit(git).flatMap(ignore -> Mono.error(error)))
.timeout(Duration.ofMillis(Constraint.TIMEOUT_MILLIS))
.name(GitSpan.FS_PULL)
.tap(Micrometer.observation(observationRegistry)),
Git::close)
.subscribeOn(scheduler);
}
@Override @Override
public Mono<MergeStatusDTO> pullApplication( public Mono<MergeStatusDTO> pullApplication(
Path repoSuffix, String remoteUrl, String branchName, String privateKey, String publicKey) Path repoSuffix, String remoteUrl, String branchName, String privateKey, String publicKey)
@ -951,7 +1015,14 @@ public class FSGitHandlerCEImpl implements FSGitHandler {
git -> Mono.fromCallable(() -> { git -> Mono.fromCallable(() -> {
TransportConfigCallback config = TransportConfigCallback config =
new SshTransportConfigCallback(privateKey, publicKey); new SshTransportConfigCallback(privateKey, publicKey);
String fetchMessages;
if (TRUE.equals(fetchRemoteDTO.getIsFetchAll())) {
return git.fetch()
.setRemoveDeletedRefs(true)
.setTransportConfigCallback(config)
.call()
.getMessages();
}
List<String> refNames = fetchRemoteDTO.getRefNames(); List<String> refNames = fetchRemoteDTO.getRefNames();
RefType refType = fetchRemoteDTO.getRefType(); RefType refType = fetchRemoteDTO.getRefType();
@ -973,7 +1044,7 @@ public class FSGitHandlerCEImpl implements FSGitHandler {
} }
} }
fetchMessages = git.fetch() return git.fetch()
.setRefSpecs(refSpecs.toArray(new RefSpec[0])) .setRefSpecs(refSpecs.toArray(new RefSpec[0]))
.setRemoveDeletedRefs(true) .setRemoveDeletedRefs(true)
.setTagOpt(TagOpt.NO_TAGS) // no tags would mean that tags are fetched .setTagOpt(TagOpt.NO_TAGS) // no tags would mean that tags are fetched
@ -981,8 +1052,6 @@ public class FSGitHandlerCEImpl implements FSGitHandler {
.setTransportConfigCallback(config) .setTransportConfigCallback(config)
.call() .call()
.getMessages(); .getMessages();
return fetchMessages;
}) })
.onErrorResume(error -> { .onErrorResume(error -> {
log.error(error.getMessage()); log.error(error.getMessage());

View File

@ -11,6 +11,7 @@ public class GitConstantsCE {
public static final String README_FILE_NAME = "README.md"; public static final String README_FILE_NAME = "README.md";
public static final String FIRST_COMMIT = "System added readme file";
public static final String DEFAULT_COMMIT_MESSAGE = "System generated commit, "; public static final String DEFAULT_COMMIT_MESSAGE = "System generated commit, ";
public static final String EMPTY_COMMIT_ERROR_MESSAGE = "On current branch nothing to commit, working tree clean"; public static final String EMPTY_COMMIT_ERROR_MESSAGE = "On current branch nothing to commit, working tree clean";
public static final String MERGE_CONFLICT_BRANCH_NAME = "_mergeConflict"; public static final String MERGE_CONFLICT_BRANCH_NAME = "_mergeConflict";
@ -45,7 +46,9 @@ public class GitConstantsCE {
public static final String FETCH_REMOTE = "fetchRemote"; public static final String FETCH_REMOTE = "fetchRemote";
public static final String COMMIT = "commit"; public static final String COMMIT = "commit";
public static final String CREATE_BRANCH = "createBranch"; public static final String CREATE_BRANCH = "createBranch";
public static final String CREATE_REF = "createRef";
public static final String CHECKOUT_BRANCH = "checkoutBranch"; public static final String CHECKOUT_BRANCH = "checkoutBranch";
public static final String CHECKOUT_REF = "checkoutRef";
public static final String SYNC_BRANCH = "syncBranch"; public static final String SYNC_BRANCH = "syncBranch";
public static final String LIST_BRANCH = "listBranch"; public static final String LIST_BRANCH = "listBranch";
public static final String MERGE_BRANCH = "mergeBranch"; public static final String MERGE_BRANCH = "mergeBranch";

View File

@ -102,6 +102,19 @@ public interface FSGitHandler {
*/ */
Mono<Boolean> checkoutToBranch(Path repoSuffix, String branchName); Mono<Boolean> checkoutToBranch(Path repoSuffix, String branchName);
/**
* Pull changes from remote branch and merge the changes
* @param repoSuffix suffixedPath used to generate the base repo path this includes workspaceId, defaultAppId, repoName
* @param remoteUrl ssh url of the git repo(we support cloning via ssh url only with deploy key)
* @param branchName remoteBranchName from which commits will be fetched and merged to the current branch
* @param privateKey generated by us and specific to the defaultApplication
* @param publicKey generated by us and specific to the defaultApplication
* @return success message
*/
Mono<MergeStatusDTO> pullArtifactWithoutCheckout(
Path repoSuffix, String remoteUrl, String branchName, String privateKey, String publicKey)
throws IOException;
/** /**
* Pull changes from remote branch and merge the changes * Pull changes from remote branch and merge the changes
* @param repoSuffix suffixedPath used to generate the base repo path this includes workspaceId, defaultAppId, repoName * @param repoSuffix suffixedPath used to generate the base repo path this includes workspaceId, defaultAppId, repoName

View File

@ -1,6 +1,5 @@
package com.appsmith.server.git.central; package com.appsmith.server.git.central;
import com.appsmith.external.dtos.GitBranchDTO;
import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitRefDTO;
import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.GitStatusDTO;
import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO;
@ -37,7 +36,7 @@ public interface CentralGitServiceCE {
Mono<? extends Artifact> detachRemote(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono<? extends Artifact> detachRemote(String branchedArtifactId, ArtifactType artifactType, GitType gitType);
Mono<List<GitBranchDTO>> listBranchForArtifact( Mono<List<GitRefDTO>> listBranchForArtifact(
String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType); String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType);
Mono<String> fetchRemoteChanges( Mono<String> fetchRemoteChanges(
@ -71,7 +70,7 @@ public interface CentralGitServiceCE {
String referencedArtifactId, ArtifactType artifactType, GitRefDTO refDTO, GitType gitType); String referencedArtifactId, ArtifactType artifactType, GitRefDTO refDTO, GitType gitType);
Mono<? extends Artifact> deleteGitReference( Mono<? extends Artifact> deleteGitReference(
String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType); String baseArtifactId, ArtifactType artifactType, String refName, RefType refType, GitType gitType);
Mono<List<String>> updateProtectedBranches( Mono<List<String>> updateProtectedBranches(
String baseArtifactId, ArtifactType artifactType, List<String> branchNames); String baseArtifactId, ArtifactType artifactType, List<String> branchNames);

View File

@ -7,8 +7,8 @@ import com.appsmith.external.dtos.GitRefDTO;
import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.GitStatusDTO;
import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO;
import com.appsmith.external.git.constants.GitConstants; import com.appsmith.external.git.constants.GitConstants;
import com.appsmith.external.git.constants.GitConstants.GitCommandConstants;
import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.git.constants.GitSpan;
import com.appsmith.external.git.constants.ce.GitConstantsCE;
import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.git.constants.ce.RefType;
import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.external.git.dtos.FetchRemoteDTO;
import com.appsmith.external.models.Datasource; import com.appsmith.external.models.Datasource;
@ -415,10 +415,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
Mono<Boolean> acquireFileLock = gitRedisUtils.acquireGitLock( Mono<Boolean> acquireFileLock = gitRedisUtils.acquireGitLock(
baseArtifact.getArtifactType(), baseArtifact.getArtifactType(), baseArtifactId, GitCommandConstants.CHECKOUT_REF, addFileLock);
baseArtifactId,
GitConstants.GitCommandConstants.CHECKOUT_BRANCH,
addFileLock);
Mono<? extends Artifact> checkedOutArtifactMono; Mono<? extends Artifact> checkedOutArtifactMono;
// If the user is trying to check out remote reference, create a new reference if it does not exist already // If the user is trying to check out remote reference, create a new reference if it does not exist already
@ -428,7 +425,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
jsonTransformationDTO.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId()); jsonTransformationDTO.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId());
jsonTransformationDTO.setRefName(finalRefName); jsonTransformationDTO.setRefName(finalRefName);
jsonTransformationDTO.setRefType(refType); jsonTransformationDTO.setRefType(refType);
jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); jsonTransformationDTO.setArtifactType(artifactType);
jsonTransformationDTO.setRepoName(baseGitMetadata.getRepoName()); jsonTransformationDTO.setRepoName(baseGitMetadata.getRepoName());
if (gitRefDTO.getRefName().startsWith(ORIGIN)) { if (gitRefDTO.getRefName().startsWith(ORIGIN)) {
@ -446,7 +443,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
return Mono.error(new AppsmithException( return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, AppsmithError.GIT_ACTION_FAILED,
"checkout", GitCommandConstants.CHECKOUT_REF,
gitRefDTO.getRefName() + " already exists in local - " + finalRefName)); gitRefDTO.getRefName() + " already exists in local - " + finalRefName));
}); });
} else { } else {
@ -632,17 +629,19 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
createRefTransformationDTO.setRefName(refDTO.getRefName()); createRefTransformationDTO.setRefName(refDTO.getRefName());
Mono<Boolean> acquireGitLockMono = gitRedisUtils.acquireGitLock( Mono<Boolean> acquireGitLockMono = gitRedisUtils.acquireGitLock(
artifactType, artifactType, baseGitMetadata.getDefaultArtifactId(), GitCommandConstants.CREATE_REF, FALSE);
baseGitMetadata.getDefaultArtifactId(),
GitConstants.GitCommandConstants.CREATE_BRANCH, FetchRemoteDTO fetchRemoteDTO = new FetchRemoteDTO();
FALSE); fetchRemoteDTO.setRefType(refType);
fetchRemoteDTO.setIsFetchAll(TRUE);
Mono<String> fetchRemoteMono = Mono<String> fetchRemoteMono =
gitHandlingService.fetchRemoteReferences(baseRefTransformationDTO, baseGitAuth, TRUE); gitHandlingService.fetchRemoteReferences(baseRefTransformationDTO, fetchRemoteDTO, baseGitAuth);
Mono<? extends Artifact> createBranchMono = acquireGitLockMono Mono<? extends Artifact> createBranchMono = acquireGitLockMono
.flatMap(ignoreLockAcquisition -> fetchRemoteMono.onErrorResume( .flatMap(ignoreLockAcquisition ->
error -> Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "fetch", error)))) fetchRemoteMono.onErrorResume(error -> Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, GitCommandConstants.FETCH_REMOTE, error))))
.flatMap(ignoreFetchString -> gitHandlingService .flatMap(ignoreFetchString -> gitHandlingService
.listReferences(createRefTransformationDTO, TRUE) .listReferences(createRefTransformationDTO, TRUE)
.flatMap(refList -> { .flatMap(refList -> {
@ -684,7 +683,8 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
Artifact newRefArtifact = tuple.getT1(); Artifact newRefArtifact = tuple.getT1();
Mono<String> refCreationMono = gitHandlingService Mono<String> refCreationMono = gitHandlingService
.createGitReference(createRefTransformationDTO, baseGitMetadata, refDTO) .createGitReference(
baseRefTransformationDTO, createRefTransformationDTO, baseGitMetadata, refDTO)
// TODO: this error could be shipped to handling layer as well? // TODO: this error could be shipped to handling layer as well?
.onErrorResume(error -> Mono.error(new AppsmithException( .onErrorResume(error -> Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, "ref creation preparation", error.getMessage()))); AppsmithError.GIT_ACTION_FAILED, "ref creation preparation", error.getMessage())));
@ -701,7 +701,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
return gitArtifactHelper.publishArtifactPostRefCreation( return gitArtifactHelper.publishArtifactPostRefCreation(
importedArtifact, refType, TRUE); importedArtifact, refType, TRUE);
}) })
// after the branch is created, we need to reset the older branch to the // after the ref is created, the older ref should be reset to a
// clean status, i.e. last commit // clean status, i.e. last commit
.flatMap(newImportedArtifact -> .flatMap(newImportedArtifact ->
discardChanges(sourceArtifact, gitType).thenReturn(newImportedArtifact)); discardChanges(sourceArtifact, gitType).thenReturn(newImportedArtifact));
@ -716,7 +716,10 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
log.error("An error occurred while creating reference. error {}", error.getMessage()); log.error("An error occurred while creating reference. error {}", error.getMessage());
return gitRedisUtils return gitRedisUtils
.releaseFileLock(artifactType, baseArtifactId, TRUE) .releaseFileLock(artifactType, baseArtifactId, TRUE)
.then(Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout"))); .then(Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED,
GitCommandConstants.CREATE_REF,
error.getMessage())));
}) })
.name(GitSpan.OPS_CREATE_BRANCH) .name(GitSpan.OPS_CREATE_BRANCH)
.tap(Micrometer.observation(observationRegistry)); .tap(Micrometer.observation(observationRegistry));
@ -741,10 +744,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
@Override @Override
public Mono<? extends Artifact> deleteGitReference( public Mono<? extends Artifact> deleteGitReference(
String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType) { String baseArtifactId, ArtifactType artifactType, String refName, RefType refType, GitType gitType) {
String refName = gitRefDTO.getRefName();
RefType refType = gitRefDTO.getRefType();
if (refType == null) { if (refType == null) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, REF_TYPE)); return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, REF_TYPE));
@ -1073,14 +1073,13 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
jsonTransformationDTO.setArtifactType(artifactType); jsonTransformationDTO.setArtifactType(artifactType);
jsonTransformationDTO.setRepoName(repoName); jsonTransformationDTO.setRepoName(repoName);
final String README_FILE_NAME = GitConstantsCE.README_FILE_NAME; final String README_FILE_NAME = GitConstants.README_FILE_NAME;
Mono<Boolean> readMeIntialisationMono = gitHandlingService.initialiseReadMe( Mono<Boolean> readMeIntialisationMono = gitHandlingService.initialiseReadMe(
jsonTransformationDTO, artifact, README_FILE_NAME, originHeader); jsonTransformationDTO, artifact, README_FILE_NAME, originHeader);
return Mono.zip(readMeIntialisationMono, gitUserMono) return Mono.zip(readMeIntialisationMono, gitUserMono)
.flatMap(tuple2 -> { .flatMap(tuple2 -> {
String commitMessage = String commitMessage = GitConstants.FIRST_COMMIT;
DEFAULT_COMMIT_MESSAGE + GitDefaultCommitMessage.CONNECT_FLOW.getReason();
GitUser author = tuple2.getT2(); GitUser author = tuple2.getT2();
CommitDTO commitDTO = new CommitDTO(); CommitDTO commitDTO = new CommitDTO();
commitDTO.setAuthor(author); commitDTO.setAuthor(author);
@ -1533,64 +1532,65 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
boolean compareRemote, boolean compareRemote,
GitType gitType) { GitType gitType) {
ArtifactType artifactType = baseArtifact.getArtifactType();
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata();
final String baseArtifactId = baseGitMetadata.getDefaultArtifactId();
GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata();
branchedGitMetadata.setGitAuth(baseGitMetadata.getGitAuth()); branchedGitMetadata.setGitAuth(baseGitMetadata.getGitAuth());
final String finalBranchName = branchedGitMetadata.getRefName(); final String finalBranchName = branchedGitMetadata.getRefName();
RefType refType = branchedGitMetadata.getRefType();
if (!StringUtils.hasText(finalBranchName)) { if (!StringUtils.hasText(finalBranchName)) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME));
} }
Mono<? extends ArtifactExchangeJson> exportedArtifactJsonMono = ArtifactType artifactType = baseArtifact.getArtifactType();
exportService.exportByArtifactId(branchedArtifact.getId(), VERSION_CONTROL, artifactType); final String baseArtifactId = baseGitMetadata.getDefaultArtifactId();
String workspaceId = baseArtifact.getWorkspaceId();
String repoName = baseGitMetadata.getRepoName();
Mono<GitStatusDTO> statusMono = exportedArtifactJsonMono ArtifactJsonTransformationDTO jsonTransformationDTO =
.flatMap(artifactExchangeJson -> { new ArtifactJsonTransformationDTO(workspaceId, baseArtifactId, repoName, artifactType);
return gitRedisUtils
.acquireGitLock(
artifactType, 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); jsonTransformationDTO.setRefName(finalBranchName);
jsonTransformationDTO.setRefType(refType);
FetchRemoteDTO fetchRemoteDTO = new FetchRemoteDTO();
fetchRemoteDTO.setRefNames(List.of(finalBranchName));
fetchRemoteDTO.setRefType(refType);
fetchRemoteDTO.setIsFetchAll(false);
Mono<? extends ArtifactExchangeJson> exportedArtifactJsonMono = exportService
.exportByArtifactId(branchedArtifact.getId(), VERSION_CONTROL, artifactType)
.zipWhen(exportedArtifactJson -> gitRedisUtils.acquireGitLock(
artifactType, baseArtifactId, GitCommandConstants.STATUS, isFileLock))
.map(Tuple2::getT1);
// This block only enters when a redis lock is acquired
Mono<GitStatusDTO> lockHandledStatusMono = Mono.usingWhen(
exportedArtifactJsonMono,
artifactExchangeJson -> {
Mono<Boolean> prepareForStatus = Mono<Boolean> prepareForStatus =
gitHandlingService.prepareChangesToBeCommitted(jsonTransformationDTO, artifactExchangeJson); gitHandlingService.prepareChangesToBeCommitted(jsonTransformationDTO, artifactExchangeJson);
Mono<String> fetchRemoteMono;
Mono<String> fetchRemoteMono = Mono.just("ignored");
if (compareRemote) { if (compareRemote) {
fetchRemoteMono = Mono.defer( if (isBaseGitMetadataInvalid(baseGitMetadata, gitType)) {
() -> fetchRemoteChanges(baseArtifact, branchedArtifact, FALSE, gitType, RefType.branch) return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION));
.onErrorResume(error -> Mono.error(new AppsmithException(
AppsmithError.GIT_GENERIC_ERROR, error.getMessage()))));
} else {
fetchRemoteMono = Mono.just("ignored");
} }
return Mono.zip(prepareForStatus, fetchRemoteMono).flatMap(tuple2 -> { fetchRemoteMono = Mono.defer(() -> gitHandlingService
return gitHandlingService .fetchRemoteReferences(
.getStatus(jsonTransformationDTO) jsonTransformationDTO, fetchRemoteDTO, baseGitMetadata.getGitAuth())
.flatMap(gitStatusDTO -> { .onErrorResume(error -> Mono.error(new AppsmithException(
return gitRedisUtils AppsmithError.GIT_ACTION_FAILED,
.releaseFileLock(artifactType, baseArtifactId, isFileLock) GitCommandConstants.FETCH_REMOTE,
.thenReturn(gitStatusDTO); error.getMessage()))));
}); }
});
}) return Mono.zip(prepareForStatus, fetchRemoteMono)
.then(Mono.defer(() -> gitHandlingService.getStatus(jsonTransformationDTO)))
.onErrorResume(throwable -> { .onErrorResume(throwable -> {
/* /*
in case of any error, the global exception handler will release the lock in case of any error, the global exception handler will release the lock
@ -1601,10 +1601,19 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
baseArtifactId, baseArtifactId,
finalBranchName, finalBranchName,
throwable); throwable);
return Mono.error(new AppsmithException(AppsmithError.GIT_GENERIC_ERROR, throwable.getMessage())); if (throwable instanceof AppsmithException) {
}); return Mono.error(throwable);
}
return Mono.zip(statusMono, sessionUserService.getCurrentUser()) return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED,
GitCommandConstants.STATUS,
throwable.getMessage()));
});
},
artifactExchangeJson -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, isFileLock));
return Mono.zip(lockHandledStatusMono, sessionUserService.getCurrentUser())
.elapsed() .elapsed()
.flatMap(objects -> { .flatMap(objects -> {
Long elapsedTime = objects.getT1(); Long elapsedTime = objects.getT1();
@ -1661,49 +1670,44 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
protected Mono<GitPullDTO> pullArtifact(Artifact baseArtifact, Artifact branchedArtifact, GitType gitType) { protected Mono<GitPullDTO> pullArtifact(Artifact baseArtifact, Artifact branchedArtifact, GitType gitType) {
GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata();
Mono<GitStatusDTO> statusMono = getStatus(baseArtifact, branchedArtifact, false, true, gitType);
ArtifactType artifactType = baseArtifact.getArtifactType(); ArtifactType artifactType = baseArtifact.getArtifactType();
String baseArtifactId = branchedGitMetadata.getDefaultArtifactId();
Mono<GitPullDTO> pullDTOMono = gitRedisUtils Mono<GitPullDTO> lockHandledpullDTOMono = Mono.usingWhen(
.acquireGitLock( gitRedisUtils.acquireGitLock(artifactType, baseArtifactId, GitCommandConstants.PULL, TRUE),
artifactType, ignoreLock -> {
branchedGitMetadata.getDefaultArtifactId(), // TODO: verifying why remote needs to be fetched for status, when only modified is checked
GitConstants.GitCommandConstants.PULL, Mono<GitStatusDTO> statusMono =
TRUE) getStatus(baseArtifact, branchedArtifact, false, false, gitType);
.then(Mono.defer(() -> statusMono))
.flatMap(status -> { return statusMono.flatMap(gitStatusDTO -> {
// Check if the repo is clean // Check if the repo is clean
if (!CollectionUtils.isEmpty(status.getModified())) { if (!CollectionUtils.isEmpty(gitStatusDTO.getModified())) {
return gitRedisUtils return Mono.error(
.releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE)
.then(
Mono.error(
new AppsmithException( new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, AppsmithError.GIT_ACTION_FAILED,
"pull", GitCommandConstants.PULL,
"There are uncommitted changes present in your local. Please commit them first and then try git pull"))); "There are uncommitted changes present in your local. Please commit them first and then try git pull"));
}
return pullAndRehydrateArtifact(baseArtifact, branchedArtifact, gitType)
.onErrorResume(exception -> {
if (exception instanceof AppsmithException) {
return Mono.error(exception);
} }
return pullAndRehydrateArtifact(baseArtifact, branchedArtifact, gitType) return Mono.error(new AppsmithException(
// Release file lock after the pull operation AppsmithError.GIT_ACTION_FAILED,
.flatMap(gitPullDTO -> gitRedisUtils GitCommandConstants.PULL,
.releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) exception.getMessage()));
.then(Mono.just(gitPullDTO))); });
}) });
.onErrorResume(error -> { },
log.error( ignoreLock -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, TRUE))
"An error occurred while trying to pull the artifact with base id: {} and branchName: {}",
branchedGitMetadata.getDefaultArtifactId(),
branchedGitMetadata.getRefName());
return gitRedisUtils
.releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE)
.then(Mono.error(error));
})
.name(GitSpan.OPS_PULL) .name(GitSpan.OPS_PULL)
.tap(Micrometer.observation(observationRegistry)); .tap(Micrometer.observation(observationRegistry));
return Mono.create(sink -> pullDTOMono.subscribe(sink::success, sink::error, null, sink.currentContext())); return Mono.create(
sink -> lockHandledpullDTOMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
} }
/** /**
@ -1740,13 +1744,11 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
final String repoName = branchedGitMetadata.getRepoName(); final String repoName = branchedGitMetadata.getRepoName();
final String branchName = branchedGitMetadata.getRefName(); final String branchName = branchedGitMetadata.getRefName();
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(
jsonTransformationDTO.setRepoName(repoName); workspaceId, baseArtifactId, repoName, baseArtifact.getArtifactType());
jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setRefType(RefType.branch);
jsonTransformationDTO.setRefName(branchName); jsonTransformationDTO.setRefName(branchName);
jsonTransformationDTO.setWorkspaceId(workspaceId);
jsonTransformationDTO.setBaseArtifactId(baseArtifactId);
jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType());
return Mono.defer(() -> { return Mono.defer(() -> {
// Rehydrate the artifact from git system // Rehydrate the artifact from git system
@ -2013,80 +2015,79 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
protected Mono<? extends Artifact> discardChanges(Artifact branchedArtifact, GitType gitType) { protected Mono<? extends Artifact> discardChanges(Artifact branchedArtifact, GitType gitType) {
ArtifactType artifactType = branchedArtifact.getArtifactType(); ArtifactType artifactType = branchedArtifact.getArtifactType();
GitArtifactHelper<?> gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata(); GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata();
if (branchedGitData == null || !hasText(branchedGitData.getDefaultArtifactId())) { if (branchedGitData == null || !hasText(branchedGitData.getDefaultArtifactId())) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR));
} }
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); GitArtifactHelper<?> gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
jsonTransformationDTO.setArtifactType(branchedArtifact.getArtifactType()); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
final String workspaceId = branchedArtifact.getWorkspaceId();
final String baseArtifactId = branchedGitData.getDefaultArtifactId();
final String repoName = branchedGitData.getRepoName();
final String branchName = branchedGitData.getRefName();
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(
workspaceId, baseArtifactId, repoName, branchedArtifact.getArtifactType());
// Because this operation is only valid for branches // Because this operation is only valid for branches
jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setRefType(RefType.branch);
jsonTransformationDTO.setWorkspaceId(branchedArtifact.getWorkspaceId()); jsonTransformationDTO.setRefName(branchName);
jsonTransformationDTO.setBaseArtifactId(branchedGitData.getDefaultArtifactId());
jsonTransformationDTO.setRefName(branchedGitData.getRefName());
jsonTransformationDTO.setRepoName(branchedGitData.getRepoName());
Mono<? extends Artifact> recreatedArtifactFromLastCommit = gitRedisUtils Mono<? extends Artifact> artifactFromLastCommitMono = Mono.usingWhen(
.acquireGitLock( gitRedisUtils.acquireGitLock(artifactType, baseArtifactId, GitCommandConstants.DISCARD, TRUE),
artifactType, ignoreLockAcquisition -> {
branchedGitData.getDefaultArtifactId(), Mono<? extends ArtifactExchangeJson> artifactJsonFromLastCommitMono = gitHandlingService
GitConstants.GitCommandConstants.DISCARD,
TRUE)
.then(gitHandlingService
.recreateArtifactJsonFromLastCommit(jsonTransformationDTO) .recreateArtifactJsonFromLastCommit(jsonTransformationDTO)
.onErrorResume(throwable -> { .onErrorResume(exception -> {
log.error("Git recreate ArtifactJsonFailed : {}", throwable.getMessage()); log.error("Git recreate Artifact Json Failed : {}", exception.getMessage());
return gitRedisUtils
.releaseFileLock(artifactType, branchedGitData.getDefaultArtifactId(), TRUE) return Mono.error(
.then(
Mono.error(
new AppsmithException( new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, AppsmithError.GIT_ACTION_FAILED,
"discard changes", GitCommandConstants.DISCARD,
"Please create a new branch and resolve conflicts in the remote repository before proceeding."))); "Please create a new branch and resolve conflicts in the remote repository before proceeding."));
})) });
return artifactJsonFromLastCommitMono
.flatMap(artifactExchangeJson -> importService.importArtifactInWorkspaceFromGit( .flatMap(artifactExchangeJson -> importService.importArtifactInWorkspaceFromGit(
branchedArtifact.getWorkspaceId(), workspaceId, branchedArtifact.getId(), artifactExchangeJson, branchName))
branchedArtifact.getId(), .flatMap(artifactFromLastCommit ->
artifactExchangeJson, gitArtifactHelper.publishArtifact(artifactFromLastCommit, true))
branchedGitData.getRefName())) .flatMap(publishedArtifact -> gitAnalyticsUtils.addAnalyticsForGitOperation(
// Update the last deployed status after the rebase AnalyticsEvents.GIT_DISCARD_CHANGES, publishedArtifact, null))
.flatMap(importedArtifact -> gitArtifactHelper.publishArtifact(importedArtifact, true)) .onErrorResume(exception -> {
.flatMap(publishedArtifact -> {
return gitRedisUtils
.releaseFileLock(
artifactType,
publishedArtifact.getGitArtifactMetadata().getDefaultArtifactId(),
TRUE)
.then(gitAnalyticsUtils.addAnalyticsForGitOperation(
AnalyticsEvents.GIT_DISCARD_CHANGES, publishedArtifact, null));
})
.onErrorResume(error -> {
log.error( log.error(
"An error occurred while discarding branch with artifact id {}. error {}", "An error occurred while discarding branched artifact id {}. error {}",
branchedGitData.getDefaultArtifactId(), branchedArtifact.getId(),
error.getMessage()); exception.getMessage());
return gitRedisUtils
.releaseFileLock(artifactType, branchedGitData.getDefaultArtifactId(), TRUE) if (exception instanceof AppsmithException) {
.then(Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout"))); return Mono.error(exception);
}) }
return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED,
GitCommandConstants.DISCARD,
exception.getMessage()));
});
},
ignoreLockAcquisition -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, TRUE))
.name(GitSpan.OPS_DISCARD_CHANGES) .name(GitSpan.OPS_DISCARD_CHANGES)
.tap(Micrometer.observation(observationRegistry)); .tap(Micrometer.observation(observationRegistry));
return Mono.create(sink -> return Mono.create(
recreatedArtifactFromLastCommit.subscribe(sink::success, sink::error, null, sink.currentContext())); sink -> artifactFromLastCommitMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
} }
public Mono<List<GitBranchDTO>> listBranchForArtifact( public Mono<List<GitRefDTO>> listBranchForArtifact(
String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType) { String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType) {
return getBranchList(branchedArtifactId, artifactType, pruneBranches, true, gitType); return getBranchList(branchedArtifactId, artifactType, pruneBranches, true, gitType);
} }
protected Mono<List<GitBranchDTO>> getBranchList( protected Mono<List<GitRefDTO>> getBranchList(
String branchedArtifactId, String branchedArtifactId,
ArtifactType artifactType, ArtifactType artifactType,
Boolean pruneBranches, Boolean pruneBranches,
@ -2109,7 +2110,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
}); });
} }
protected Mono<List<GitBranchDTO>> getBranchList( protected Mono<List<GitRefDTO>> getBranchList(
Artifact baseArtifact, Artifact baseArtifact,
Artifact branchedArtifact, Artifact branchedArtifact,
Boolean pruneBranches, Boolean pruneBranches,
@ -2128,15 +2129,6 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
final String repoName = baseGitData.getRepoName(); final String repoName = baseGitData.getRepoName();
final String currentBranch = branchedGitData.getRefName(); final String currentBranch = branchedGitData.getRefName();
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO();
jsonTransformationDTO.setRepoName(repoName);
jsonTransformationDTO.setWorkspaceId(workspaceId);
jsonTransformationDTO.setBaseArtifactId(baseArtifactId);
jsonTransformationDTO.setRefName(currentBranch);
// not that it matters
jsonTransformationDTO.setRefType(branchedGitData.getRefType());
jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType());
if (!hasText(baseArtifactId) || !hasText(repoName) || !hasText(currentBranch)) { if (!hasText(baseArtifactId) || !hasText(repoName) || !hasText(currentBranch)) {
log.error( log.error(
"Git config is not present for artifact {} of type {}", "Git config is not present for artifact {} of type {}",
@ -2145,6 +2137,12 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR));
} }
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(
workspaceId, baseArtifactId, repoName, baseArtifact.getArtifactType());
jsonTransformationDTO.setRefName(currentBranch);
jsonTransformationDTO.setRefType(branchedGitData.getRefType());
Mono<String> baseBranchMono; Mono<String> baseBranchMono;
if (TRUE.equals(pruneBranches) && syncDefaultBranchWithRemote) { if (TRUE.equals(pruneBranches) && syncDefaultBranchWithRemote) {
baseBranchMono = syncDefaultBranchNameFromRemote(baseGitData, jsonTransformationDTO, gitType); baseBranchMono = syncDefaultBranchNameFromRemote(baseGitData, jsonTransformationDTO, gitType);
@ -2152,7 +2150,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
baseBranchMono = Mono.just(GitUtils.getDefaultBranchName(baseGitData)); baseBranchMono = Mono.just(GitUtils.getDefaultBranchName(baseGitData));
} }
Mono<List<GitBranchDTO>> branchMono = baseBranchMono Mono<List<GitRefDTO>> branchMono = baseBranchMono
.flatMap(baseBranchName -> { .flatMap(baseBranchName -> {
return getBranchListWithDefaultBranchName( return getBranchListWithDefaultBranchName(
baseArtifact, baseBranchName, currentBranch, pruneBranches, gitType); baseArtifact, baseBranchName, currentBranch, pruneBranches, gitType);
@ -2258,7 +2256,7 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
}); });
} }
private Mono<List<GitBranchDTO>> handleRepoNotFoundException( private Mono<List<GitRefDTO>> handleRepoNotFoundException(
ArtifactJsonTransformationDTO jsonTransformationDTO, GitType gitType) { ArtifactJsonTransformationDTO jsonTransformationDTO, GitType gitType) {
// clone artifact to the local git system again and update the defaultBranch for the artifact // 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 // list branch and compare with branch artifacts and checkout if not exists
@ -2283,13 +2281,14 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
.flatMap(defaultBranch -> gitHandlingService.listReferences(jsonTransformationDTO, true)) .flatMap(defaultBranch -> gitHandlingService.listReferences(jsonTransformationDTO, true))
.flatMap(branches -> { .flatMap(branches -> {
List<String> branchesToCheckout = new ArrayList<>(); List<String> branchesToCheckout = new ArrayList<>();
List<GitBranchDTO> gitBranchDTOList = new ArrayList<>();
List<GitRefDTO> gitRefDTOs = new ArrayList<>();
for (String branch : branches) { for (String branch : branches) {
GitBranchDTO gitBranchDTO = new GitBranchDTO(); GitBranchDTO gitBranchDTO = new GitBranchDTO();
gitBranchDTO.setBranchName(branch); gitBranchDTO.setBranchName(branch);
if (branch.startsWith(ORIGIN)) { if (branch.startsWith(ORIGIN)) {
// remove origin/ prefix from the remote branch name // remove `origin/` prefix from the remote branch name
String branchName = branch.replace(ORIGIN, REMOTE_NAME_REPLACEMENT); String branchName = branch.replace(ORIGIN, REMOTE_NAME_REPLACEMENT);
// The root defaultArtifact is always there, no need to check out it again // The root defaultArtifact is always there, no need to check out it again
if (!branchName.equals(gitArtifactMetadata.getBranchName())) { if (!branchName.equals(gitArtifactMetadata.getBranchName())) {
@ -2319,90 +2318,102 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
// checkout the branch locally // checkout the branch locally
.flatMap(artifact -> { .flatMap(artifact -> {
// Add the locally checked out branch to the branchList // Add the locally checked out branch to the branchList
GitBranchDTO gitBranchDTO = new GitBranchDTO(); GitRefDTO gitRefDTO = new GitRefDTO();
gitBranchDTO.setBranchName(branchName); gitRefDTO.setRefName(branchName);
// set the default branch flag if there's a match. // set the default branch flag if there's a match.
// This can happen when user has changed the default branch other // This can happen when user has changed the default branch other
// than // than remote
// remote gitRefDTO.setDefault(gitArtifactMetadata
gitBranchDTO.setDefault(gitArtifactMetadata
.getDefaultBranchName() .getDefaultBranchName()
.equals(branchName)); .equals(branchName));
gitBranchDTOList.add(gitBranchDTO);
gitRefDTOs.add(gitRefDTO);
branchCheckoutDTO.setRefName(branchName); branchCheckoutDTO.setRefName(branchName);
return gitHandlingService.checkoutRemoteReference(branchCheckoutDTO); return gitHandlingService.checkoutRemoteReference(branchCheckoutDTO);
}) })
// Return empty mono when the branched defaultArtifact is not in db // Return empty mono when the branched defaultArtifact is not in db
.onErrorResume(throwable -> Mono.empty())) .onErrorResume(throwable -> Mono.empty()))
.then(Mono.just(gitBranchDTOList)); .then(Mono.just(gitRefDTOs));
}); });
}); });
} }
private Mono<List<GitBranchDTO>> getBranchListWithDefaultBranchName( private Mono<List<GitRefDTO>> getBranchListWithDefaultBranchName(
Artifact baseArtifact, Artifact baseArtifact,
String defaultBranchName, String defaultBranchName,
String currentBranch, String currentBranch,
boolean pruneBranches, boolean pruneBranches,
GitType gitType) { GitType gitType) {
ArtifactType artifactType = baseArtifact.getArtifactType();
GitArtifactMetadata baseGitData = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata baseGitData = baseArtifact.getGitArtifactMetadata();
String workspaceId = baseArtifact.getWorkspaceId();
String baseArtifactId = baseGitData.getDefaultArtifactId();
String repoName = baseGitData.getRepoName();
RefType refType = RefType.branch; // baseGitData.getRefType();
ArtifactType artifactType = baseArtifact.getArtifactType();
return Mono.usingWhen(
gitRedisUtils.acquireGitLock(
artifactType, baseArtifactId, GitConstants.GitCommandConstants.LIST_BRANCH, TRUE),
ignoreLock -> {
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
ArtifactJsonTransformationDTO jsonTransformationDTO =
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); new ArtifactJsonTransformationDTO(workspaceId, baseArtifactId, repoName, artifactType);
jsonTransformationDTO.setRepoName(baseGitData.getRepoName());
jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId());
jsonTransformationDTO.setBaseArtifactId(baseGitData.getDefaultArtifactId());
jsonTransformationDTO.setRefName(currentBranch); jsonTransformationDTO.setRefName(currentBranch);
jsonTransformationDTO.setRefType(baseGitData.getRefType()); jsonTransformationDTO.setRefType(refType);
jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType());
Mono<String> fetchRemoteMono = Mono.just("");
if (TRUE.equals(pruneBranches)) {
fetchRemoteMono = gitHandlingService.fetchRemoteReferences(
jsonTransformationDTO, baseGitData.getGitAuth(), TRUE);
}
return gitRedisUtils
.acquireGitLock(
artifactType,
baseGitData.getDefaultArtifactId(),
GitConstants.GitCommandConstants.LIST_BRANCH,
TRUE)
.flatMap(ignoredLock -> {
Mono<List<String>> listBranchesMono = Mono<List<String>> listBranchesMono =
Mono.defer(() -> gitHandlingService.listReferences(jsonTransformationDTO, true)); Mono.defer(() -> gitHandlingService.listReferences(jsonTransformationDTO, true));
if (TRUE.equals(pruneBranches)) { return fetchRemoteMono
return gitHandlingService .then(listBranchesMono)
.fetchRemoteReferences(jsonTransformationDTO, baseGitData.getGitAuth(), TRUE) .onErrorResume(Mono::error)
.then(listBranchesMono); .map(branches -> {
} List<GitRefDTO> gitRefDTOs = new ArrayList<>();
return listBranchesMono; List<GitBranchDTO> gitBranchDTOs = new ArrayList<>();
})
.onErrorResume(error -> { branches.forEach(branch -> {
return gitRedisUtils
.releaseFileLock(artifactType, baseGitData.getDefaultArtifactId(), TRUE)
.then(Mono.error(error));
})
.flatMap(branches -> {
return gitRedisUtils
.releaseFileLock(artifactType, baseGitData.getDefaultArtifactId(), TRUE)
.thenReturn(branches.stream()
.map(branchName -> {
GitBranchDTO gitBranchDTO = new GitBranchDTO(); GitBranchDTO gitBranchDTO = new GitBranchDTO();
gitBranchDTO.setBranchName(branchName); gitBranchDTO.setBranchName(branch);
if (branchName.equalsIgnoreCase(defaultBranchName)) { gitBranchDTO.setDefault(branch.equalsIgnoreCase(defaultBranchName));
gitBranchDTO.setDefault(true); gitBranchDTOs.add(gitBranchDTO);
});
branches.forEach(branch -> {
GitRefDTO gitRefDTO = new GitRefDTO();
gitRefDTO.setRefName(branch);
gitRefDTO.setRefType(jsonTransformationDTO.getRefType());
gitRefDTO.setDefault(branch.equalsIgnoreCase(defaultBranchName));
gitRefDTOs.add(gitRefDTO);
});
return gitRefDTOs;
})
.flatMap(gitRefDTOs -> {
if (!TRUE.equals(pruneBranches)) {
return Mono.just(gitRefDTOs);
} }
return gitBranchDTO;
}) return gitAnalyticsUtils
.toList());
})
.flatMap(gitBranchDTOList -> FALSE.equals(pruneBranches)
? Mono.just(gitBranchDTOList)
: gitAnalyticsUtils
.addAnalyticsForGitOperation( .addAnalyticsForGitOperation(
AnalyticsEvents.GIT_PRUNE, AnalyticsEvents.GIT_PRUNE,
baseArtifact, baseArtifact,
baseArtifact.getGitArtifactMetadata().getIsRepoPrivate()) baseArtifact
.thenReturn(gitBranchDTOList)); .getGitArtifactMetadata()
.getIsRepoPrivate())
.thenReturn(gitRefDTOs);
});
},
ignoreLock -> gitRedisUtils.releaseFileLock(artifactType, baseArtifactId, TRUE));
} }
@Override @Override

View File

@ -65,7 +65,6 @@ public interface GitHandlingServiceCE {
Mono<String> createFirstCommit(ArtifactJsonTransformationDTO jsonTransformationDTO, CommitDTO commitDTO); Mono<String> createFirstCommit(ArtifactJsonTransformationDTO jsonTransformationDTO, CommitDTO commitDTO);
// TODO: provide a proper name
Mono<Boolean> prepareChangesToBeCommitted( Mono<Boolean> prepareChangesToBeCommitted(
ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson); ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson);
@ -88,6 +87,7 @@ public interface GitHandlingServiceCE {
Mono<GitStatusDTO> getStatus(ArtifactJsonTransformationDTO jsonTransformationDTO); Mono<GitStatusDTO> getStatus(ArtifactJsonTransformationDTO jsonTransformationDTO);
Mono<String> createGitReference( Mono<String> createGitReference(
ArtifactJsonTransformationDTO baseRefJsonTransformationDTO,
ArtifactJsonTransformationDTO artifactJsonTransformationDTO, ArtifactJsonTransformationDTO artifactJsonTransformationDTO,
GitArtifactMetadata baseGitData, GitArtifactMetadata baseGitData,
GitRefDTO gitRefDTO); GitRefDTO gitRefDTO);

View File

@ -1,6 +1,5 @@
package com.appsmith.server.git.controllers; package com.appsmith.server.git.controllers;
import com.appsmith.external.dtos.GitBranchDTO;
import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitRefDTO;
import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.GitStatusDTO;
import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO;
@ -181,10 +180,12 @@ public class GitApplicationControllerCE {
@JsonView(Views.Public.class) @JsonView(Views.Public.class)
@DeleteMapping("/{baseArtifactId}/ref") @DeleteMapping("/{baseArtifactId}/ref")
public Mono<ResponseDTO<? extends Artifact>> deleteBranch( public Mono<ResponseDTO<? extends Artifact>> deleteBranch(
@PathVariable String baseArtifactId, @RequestBody GitRefDTO gitRefDTO) { @PathVariable String baseArtifactId,
log.info("Going to delete ref {} for baseApplicationId {}", gitRefDTO.getRefName(), baseArtifactId); @RequestParam String refName,
@RequestParam(required = false, defaultValue = "branch") RefType refType) {
log.info("Going to delete ref {} for baseApplicationId {}", refName, baseArtifactId);
return centralGitService return centralGitService
.deleteGitReference(baseArtifactId, ARTIFACT_TYPE, gitRefDTO, GIT_TYPE) .deleteGitReference(baseArtifactId, ARTIFACT_TYPE, refName, refType, GIT_TYPE)
.map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null));
} }
@ -198,7 +199,7 @@ public class GitApplicationControllerCE {
} }
@JsonView(Views.Public.class) @JsonView(Views.Public.class)
@PostMapping("/{baseArtifactId}/branch/protected") @PostMapping("/{baseArtifactId}/protected-branches")
public Mono<ResponseDTO<List<String>>> updateProtectedBranches( public Mono<ResponseDTO<List<String>>> updateProtectedBranches(
@PathVariable String baseArtifactId, @PathVariable String baseArtifactId,
@RequestBody @Valid BranchProtectionRequestDTO branchProtectionRequestDTO) { @RequestBody @Valid BranchProtectionRequestDTO branchProtectionRequestDTO) {
@ -208,7 +209,7 @@ public class GitApplicationControllerCE {
} }
@JsonView(Views.Public.class) @JsonView(Views.Public.class)
@GetMapping("/{baseArtifactId}/branch/protected") @GetMapping("/{baseArtifactId}/protected-branches")
public Mono<ResponseDTO<List<String>>> getProtectedBranches(@PathVariable String baseArtifactId) { public Mono<ResponseDTO<List<String>>> getProtectedBranches(@PathVariable String baseArtifactId) {
return centralGitService return centralGitService
.getProtectedBranches(baseArtifactId, ARTIFACT_TYPE) .getProtectedBranches(baseArtifactId, ARTIFACT_TYPE)
@ -242,9 +243,10 @@ public class GitApplicationControllerCE {
} }
@JsonView(Views.Public.class) @JsonView(Views.Public.class)
@GetMapping("/{branchedApplicationId}/branches") @GetMapping("/{branchedApplicationId}/refs")
public Mono<ResponseDTO<List<GitBranchDTO>>> branch( public Mono<ResponseDTO<List<GitRefDTO>>> getReferences(
@PathVariable String branchedApplicationId, @PathVariable String branchedApplicationId,
@RequestParam(required = false, defaultValue = "branch") RefType refType,
@RequestParam(required = false, defaultValue = "false") Boolean pruneBranches) { @RequestParam(required = false, defaultValue = "false") Boolean pruneBranches) {
log.debug("Going to get branch list for application {}", branchedApplicationId); log.debug("Going to get branch list for application {}", branchedApplicationId);
return centralGitService return centralGitService

View File

@ -4,6 +4,7 @@ import com.appsmith.external.views.Views;
import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.constants.ArtifactType;
import com.appsmith.server.constants.Url; import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.GitAuth; import com.appsmith.server.domains.GitAuth;
import com.appsmith.server.domains.GitProfile;
import com.appsmith.server.dtos.ArtifactImportDTO; import com.appsmith.server.dtos.ArtifactImportDTO;
import com.appsmith.server.dtos.GitConnectDTO; import com.appsmith.server.dtos.GitConnectDTO;
import com.appsmith.server.dtos.GitDeployKeyDTO; import com.appsmith.server.dtos.GitDeployKeyDTO;
@ -18,13 +19,16 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.List; import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
@RequestMapping(Url.GIT_ARTIFACT_URL) @RequestMapping(Url.GIT_ARTIFACT_URL)
@ -36,6 +40,47 @@ public class GitArtifactControllerCE {
protected static final GitType GIT_TYPE = GitType.FILE_SYSTEM; protected static final GitType GIT_TYPE = GitType.FILE_SYSTEM;
/**
* artifact id is the base artifact id
* For every git connected artifact, the master branch artifact id is used as base application Id
* This is stored in gitArtifactId
* Note : The master branch here refers to the artifact that was created even before connecting to git
*/
@JsonView(Views.Public.class)
@PostMapping("/profile/default")
public Mono<ResponseDTO<Map<String, GitProfile>>> saveGitProfile(@RequestBody GitProfile gitProfile) {
log.debug("Going to add default git profile for user");
return gitProfileUtils
.updateOrCreateGitProfileForCurrentUser(gitProfile)
.map(response -> new ResponseDTO<>(HttpStatus.OK.value(), response, null));
}
@JsonView(Views.Public.class)
@GetMapping("/profile/default")
public Mono<ResponseDTO<GitProfile>> getDefaultGitConfigForUser() {
return gitProfileUtils
.getDefaultGitProfileOrCreateIfEmpty()
.map(gitConfigResponse -> new ResponseDTO<>(HttpStatus.OK.value(), gitConfigResponse, null));
}
@JsonView(Views.Public.class)
@PutMapping("/{baseApplicationId}/profile")
public Mono<ResponseDTO<Map<String, GitProfile>>> saveGitProfile(
@PathVariable String baseApplicationId, @RequestBody GitProfile gitProfile) {
log.debug("Going to add repo specific git profile for application: {}", baseApplicationId);
return gitProfileUtils
.updateOrCreateGitProfileForCurrentUser(gitProfile, baseApplicationId)
.map(response -> new ResponseDTO<>(HttpStatus.ACCEPTED.value(), response, null));
}
@JsonView(Views.Public.class)
@GetMapping("/{baseArtifactId}/profile")
public Mono<ResponseDTO<GitProfile>> getGitConfigForUser(@PathVariable String baseArtifactId) {
return gitProfileUtils
.getGitProfileForUser(baseArtifactId)
.map(gitConfigResponse -> new ResponseDTO<>(HttpStatus.OK.value(), gitConfigResponse, null));
}
@JsonView(Views.Public.class) @JsonView(Views.Public.class)
@PostMapping("/import") @PostMapping("/import")
public Mono<ResponseDTO<? extends ArtifactImportDTO>> importArtifactFromGit( public Mono<ResponseDTO<? extends ArtifactImportDTO>> importArtifactFromGit(

View File

@ -6,6 +6,7 @@ import com.appsmith.external.dtos.GitRefDTO;
import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.GitStatusDTO;
import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO;
import com.appsmith.external.git.constants.GitConstants; import com.appsmith.external.git.constants.GitConstants;
import com.appsmith.external.git.constants.GitConstants.GitCommandConstants;
import com.appsmith.external.git.constants.GitSpan; import com.appsmith.external.git.constants.GitSpan;
import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.git.constants.ce.RefType;
import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.external.git.dtos.FetchRemoteDTO;
@ -70,6 +71,7 @@ import java.util.concurrent.TimeoutException;
import static com.appsmith.external.git.constants.ce.GitConstantsCE.EMPTY_COMMIT_ERROR_MESSAGE; import static com.appsmith.external.git.constants.ce.GitConstantsCE.EMPTY_COMMIT_ERROR_MESSAGE;
import static com.appsmith.external.git.constants.ce.GitConstantsCE.GIT_CONFIG_ERROR; import static com.appsmith.external.git.constants.ce.GitConstantsCE.GIT_CONFIG_ERROR;
import static java.lang.Boolean.TRUE;
@Slf4j @Slf4j
@Service @Service
@ -252,8 +254,8 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
.listBranches(repoSuffix) .listBranches(repoSuffix)
.flatMapMany(Flux::fromIterable) .flatMapMany(Flux::fromIterable)
.filter(gitBranchDTO -> { .filter(gitBranchDTO -> {
boolean branchToBeListed = !gitBranchDTO.getBranchName().startsWith("origin") boolean branchToBeListed =
|| Boolean.TRUE.equals(listRemoteBranches); !gitBranchDTO.getBranchName().startsWith("origin") || TRUE.equals(listRemoteBranches);
return StringUtils.hasText(gitBranchDTO.getBranchName()) && branchToBeListed; return StringUtils.hasText(gitBranchDTO.getBranchName()) && branchToBeListed;
}) })
@ -326,7 +328,7 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
try { try {
return gitArtifactHelper return gitArtifactHelper
.intialiseReadMe(artifact, readmePath, originHeader) .intialiseReadMe(artifact, readmePath, originHeader)
.map(path -> Boolean.TRUE); .map(path -> TRUE);
} catch (IOException ioException) { } catch (IOException ioException) {
log.error("Error while creating readme file in the repository, {}", ioException.getMessage()); log.error("Error while creating readme file in the repository, {}", ioException.getMessage());
return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, ioException.getMessage())); return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, ioException.getMessage()));
@ -368,7 +370,7 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
return commonGitFileUtils return commonGitFileUtils
.saveArtifactToLocalRepoNew(repoSuffix, artifactExchangeJson, branchName) .saveArtifactToLocalRepoNew(repoSuffix, artifactExchangeJson, branchName)
.map(ignore -> Boolean.TRUE) .map(ignore -> TRUE)
.onErrorResume(e -> { .onErrorResume(e -> {
log.error("Error in commit flow: ", e); log.error("Error in commit flow: ", e);
if (e instanceof RepositoryNotFoundException) { if (e instanceof RepositoryNotFoundException) {
@ -513,8 +515,8 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
.flatMap(tuple2 -> { .flatMap(tuple2 -> {
String pushStatus = tuple2.getT1(); String pushStatus = tuple2.getT1();
Artifact artifact = tuple2.getT2(); Artifact artifact = tuple2.getT2();
Mono<Boolean> fileLockReleasedMono = Mono.just(Boolean.TRUE).flatMap(flag -> { Mono<Boolean> fileLockReleasedMono = Mono.just(TRUE).flatMap(flag -> {
if (!Boolean.TRUE.equals(isFileLock)) { if (!TRUE.equals(isFileLock)) {
return Mono.just(flag); return Mono.just(flag);
} }
return Mono.defer(() -> gitRedisUtils.releaseFileLock( return Mono.defer(() -> gitRedisUtils.releaseFileLock(
@ -618,7 +620,8 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
String publicKey = gitAuth.getPublicKey(); String publicKey = gitAuth.getPublicKey();
String privateKey = gitAuth.getPrivateKey(); String privateKey = gitAuth.getPrivateKey();
if (CollectionUtils.isNullOrEmpty(fetchRemoteDTO.getRefNames())) { if (CollectionUtils.isNullOrEmpty(fetchRemoteDTO.getRefNames())
&& !TRUE.equals(fetchRemoteDTO.getIsFetchAll())) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION)); return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION));
} }
@ -690,10 +693,15 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
@Override @Override
public Mono<String> createGitReference( public Mono<String> createGitReference(
ArtifactJsonTransformationDTO jsonTransformationDTO, GitArtifactMetadata baseGitData, GitRefDTO gitRefDTO) { ArtifactJsonTransformationDTO baseRefJsonTransformationDTO,
ArtifactJsonTransformationDTO jsonTransformationDTO,
GitArtifactMetadata baseGitData,
GitRefDTO gitRefDTO) {
GitArtifactHelper<?> gitArtifactHelper = GitArtifactHelper<?> gitArtifactHelper =
gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType()); gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType());
String baseRefName = baseRefJsonTransformationDTO.getRefName();
String remoteUrl = baseGitData.getRemoteUrl(); String remoteUrl = baseGitData.getRemoteUrl();
String publicKey = baseGitData.getGitAuth().getPublicKey(); String publicKey = baseGitData.getGitAuth().getPublicKey();
String privateKey = baseGitData.getGitAuth().getPrivateKey(); String privateKey = baseGitData.getGitAuth().getPrivateKey();
@ -704,10 +712,10 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
jsonTransformationDTO.getRepoName()); jsonTransformationDTO.getRepoName());
// TODO: add the checkout to the current branch as well. // TODO: add the checkout to the current branch as well.
return fsGitHandler return fsGitHandler.checkoutToBranch(repoSuffix, baseRefName).flatMap(isCheckedOut -> fsGitHandler
.createAndCheckoutReference(repoSuffix, gitRefDTO) .createAndCheckoutReference(repoSuffix, gitRefDTO)
.then(fsGitHandler.pushApplication( .flatMap(newRef -> fsGitHandler.pushApplication(
repoSuffix, remoteUrl, publicKey, privateKey, gitRefDTO.getRefName())); repoSuffix, remoteUrl, publicKey, privateKey, gitRefDTO.getRefName())));
} }
@Override @Override
@ -739,7 +747,7 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
log.error("Delete branch failed {}", throwable.getMessage()); log.error("Delete branch failed {}", throwable.getMessage());
Mono<Boolean> releaseLockMono = gitRedisUtils.releaseFileLock( Mono<Boolean> releaseLockMono = gitRedisUtils.releaseFileLock(
artifactType, jsonTransformationDTO.getBaseArtifactId(), Boolean.TRUE); artifactType, jsonTransformationDTO.getBaseArtifactId(), TRUE);
if (throwable instanceof CannotDeleteCurrentBranchException) { if (throwable instanceof CannotDeleteCurrentBranchException) {
return releaseLockMono.then(Mono.error(new AppsmithException( return releaseLockMono.then(Mono.error(new AppsmithException(
@ -780,16 +788,15 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
String branchName = jsonTransformationDTO.getRefName(); String branchName = jsonTransformationDTO.getRefName();
// git checkout and pull origin branchName // pull remote branchName
try { try {
return fsGitHandler return fsGitHandler
.checkoutToBranch(repoSuffix, jsonTransformationDTO.getRefName()) .pullArtifactWithoutCheckout(
.then(fsGitHandler.pullApplication(
repoSuffix, repoSuffix,
baseMetadata.getRemoteUrl(), baseMetadata.getRemoteUrl(),
branchName, branchName,
baseMetadata.getGitAuth().getPrivateKey(), baseMetadata.getGitAuth().getPrivateKey(),
baseMetadata.getGitAuth().getPublicKey())) baseMetadata.getGitAuth().getPublicKey())
.onErrorResume(error -> { .onErrorResume(error -> {
if (error.getMessage().contains("conflict")) { if (error.getMessage().contains("conflict")) {
return Mono.error( return Mono.error(
@ -800,8 +807,9 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
mergeStatus.setMergeAble(true); mergeStatus.setMergeAble(true);
return Mono.just(mergeStatus); return Mono.just(mergeStatus);
} }
return Mono.error(
new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "pull", error.getMessage())); return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, GitCommandConstants.PULL, error.getMessage()));
}); });
} catch (IOException e) { } catch (IOException e) {
return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage()));

View File

@ -1,6 +1,5 @@
package com.appsmith.server.git; package com.appsmith.server.git;
import com.appsmith.external.dtos.GitBranchDTO;
import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitRefDTO;
import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.GitStatusDTO;
import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO;
@ -437,7 +436,7 @@ public class GitBranchesITWithCentralService {
// Delete foo locally and re-populate from remote // Delete foo locally and re-populate from remote
List<String> branchList = centralGitService.listBranchForArtifact(artifactId, artifactType, false, GitType.FILE_SYSTEM) List<String> branchList = centralGitService.listBranchForArtifact(artifactId, artifactType, false, GitType.FILE_SYSTEM)
.flatMapMany(Flux::fromIterable) .flatMapMany(Flux::fromIterable)
.map(GitBranchDTO::getBranchName) .map(GitRefDTO::getRefName)
.collectList() .collectList()
.block(); .block();
assertThat(branchList).containsExactlyInAnyOrder( assertThat(branchList).containsExactlyInAnyOrder(
@ -448,7 +447,7 @@ public class GitBranchesITWithCentralService {
barMetadata.getRefName(), barMetadata.getRefName(),
"origin/" + barMetadata.getRefName()); "origin/" + barMetadata.getRefName());
Mono<? extends Artifact> deleteBranchAttemptMono = centralGitService.deleteGitReference(artifactId, artifactType, gitRefDTO, GitType.FILE_SYSTEM); Mono<? extends Artifact> deleteBranchAttemptMono = centralGitService.deleteGitReference(artifactId, artifactType, gitRefDTO.getRefName(), gitRefDTO.getRefType(), GitType.FILE_SYSTEM);
StepVerifier StepVerifier
.create(deleteBranchAttemptMono) .create(deleteBranchAttemptMono)
.expectErrorSatisfies(e -> assertThat(e.getMessage()).contains("Cannot delete current checked out branch")) .expectErrorSatisfies(e -> assertThat(e.getMessage()).contains("Cannot delete current checked out branch"))
@ -461,14 +460,11 @@ public class GitBranchesITWithCentralService {
git.checkout().setName("bar").call(); git.checkout().setName("bar").call();
} }
GitRefDTO deleteFooDTO = new GitRefDTO(); centralGitService.deleteGitReference(artifactId, artifactType, "foo", RefType.branch, GitType.FILE_SYSTEM).block();
deleteFooDTO.setRefType(RefType.branch);
deleteFooDTO.setRefName("foo");
centralGitService.deleteGitReference(artifactId, artifactType, deleteFooDTO, GitType.FILE_SYSTEM).block();
List<String> branchList2 = centralGitService.listBranchForArtifact(artifactId, artifactType, false, GitType.FILE_SYSTEM) List<String> branchList2 = centralGitService.listBranchForArtifact(artifactId, artifactType, false, GitType.FILE_SYSTEM)
.flatMapMany(Flux::fromIterable) .flatMapMany(Flux::fromIterable)
.map(GitBranchDTO::getBranchName) .map(GitRefDTO::getRefName)
.collectList() .collectList()
.block(); .block();
assertThat(branchList2).containsExactlyInAnyOrder( assertThat(branchList2).containsExactlyInAnyOrder(
@ -486,7 +482,7 @@ public class GitBranchesITWithCentralService {
assertThat(checkedOutFooArtifact).isNotNull(); assertThat(checkedOutFooArtifact).isNotNull();
List<String> branchList3 = centralGitService.listBranchForArtifact(artifactId, artifactType, false, GitType.FILE_SYSTEM) List<String> branchList3 = centralGitService.listBranchForArtifact(artifactId, artifactType, false, GitType.FILE_SYSTEM)
.flatMapMany(Flux::fromIterable) .flatMapMany(Flux::fromIterable)
.map(GitBranchDTO::getBranchName) .map(GitRefDTO::getRefName)
.collectList() .collectList()
.block(); .block();
assertThat(branchList3).containsExactlyInAnyOrder( assertThat(branchList3).containsExactlyInAnyOrder(