chore: added interface changes to the server (#38258)
## Description - interface layer changes for Git executor Fixes # > [!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/12481281011> > Commit: e510ca6c5f34e5dd201d040d4fc866ca4c0628d8 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12481281011&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Git` > Spec: > <hr>Tue, 24 Dec 2024 16:05:39 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 ## Summary by CodeRabbit - **New Features** - Introduced methods for creating and checking out branches and tags in Git. - Added functionality for validating reference creation based on artifact status. - Enhanced artifact publishing with new methods related to reference creation. - Added a method for checking out artifacts based on provided details. - **Bug Fixes** - Improved error handling for Git operations, providing more specific error messages. - **Documentation** - Updated method signatures to reflect new parameters and functionalities. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
c0d393a8f7
commit
a8cb8aac44
|
|
@ -5,9 +5,11 @@ import com.appsmith.external.constants.AnalyticsEvents;
|
|||
import com.appsmith.external.constants.ErrorReferenceDocUrl;
|
||||
import com.appsmith.external.dtos.GitBranchDTO;
|
||||
import com.appsmith.external.dtos.GitLogDTO;
|
||||
import com.appsmith.external.dtos.GitRefDTO;
|
||||
import com.appsmith.external.dtos.GitStatusDTO;
|
||||
import com.appsmith.external.dtos.MergeStatusDTO;
|
||||
import com.appsmith.external.git.constants.GitSpan;
|
||||
import com.appsmith.external.git.constants.ce.RefType;
|
||||
import com.appsmith.external.git.handler.FSGitHandler;
|
||||
import com.appsmith.external.helpers.Stopwatch;
|
||||
import com.appsmith.git.configurations.GitServiceConfig;
|
||||
|
|
@ -344,6 +346,52 @@ public class FSGitHandlerCEImpl implements FSGitHandler {
|
|||
.subscribeOn(scheduler);
|
||||
}
|
||||
|
||||
private String createAndCheckoutBranch(Git git, GitRefDTO gitRefDTO) throws GitAPIException, IOException {
|
||||
String branchName = gitRefDTO.getRefName();
|
||||
git.checkout()
|
||||
.setCreateBranch(TRUE)
|
||||
.setName(branchName)
|
||||
.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
|
||||
.call();
|
||||
|
||||
repositoryHelper.updateRemoteBranchTrackingConfig(branchName, git);
|
||||
return git.getRepository().getBranch();
|
||||
}
|
||||
|
||||
private String createTag(Git git, GitRefDTO gitRefDTO) throws GitAPIException {
|
||||
String tagName = gitRefDTO.getRefName();
|
||||
String message = gitRefDTO.getMessage();
|
||||
return git.tag().setName(tagName).setMessage(message).call().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> createAndCheckoutReference(Path repoSuffix, GitRefDTO gitRefDTO) {
|
||||
RefType refType = gitRefDTO.getRefType();
|
||||
String refName = gitRefDTO.getRefName();
|
||||
|
||||
return Mono.using(
|
||||
() -> Git.open(createRepoPath(repoSuffix).toFile()),
|
||||
git -> Mono.fromCallable(() -> {
|
||||
log.info(
|
||||
"{} : Creating reference of type {} and name {} for the repo {}",
|
||||
Thread.currentThread().getName(),
|
||||
refType.name(),
|
||||
refName,
|
||||
repoSuffix);
|
||||
|
||||
if (RefType.TAG.equals(refType)) {
|
||||
return createTag(git, gitRefDTO);
|
||||
}
|
||||
|
||||
return createAndCheckoutBranch(git, gitRefDTO);
|
||||
})
|
||||
.timeout(Duration.ofMillis(Constraint.TIMEOUT_MILLIS))
|
||||
.name(GitSpan.FS_CREATE_BRANCH)
|
||||
.tap(Micrometer.observation(observationRegistry)),
|
||||
Git::close)
|
||||
.subscribeOn(scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> deleteBranch(Path repoSuffix, String branchName) {
|
||||
// We can safely assume that repo has been already initialised either in commit or clone flow and can directly
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ public class GitRefDTO {
|
|||
|
||||
RefType refType;
|
||||
|
||||
/**
|
||||
* for tags, while tagging we require messages.
|
||||
*/
|
||||
String message;
|
||||
|
||||
boolean isDefault;
|
||||
|
||||
boolean createdFromLocal;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.appsmith.external.git.handler;
|
|||
|
||||
import com.appsmith.external.dtos.GitBranchDTO;
|
||||
import com.appsmith.external.dtos.GitLogDTO;
|
||||
import com.appsmith.external.dtos.GitRefDTO;
|
||||
import com.appsmith.external.dtos.GitStatusDTO;
|
||||
import com.appsmith.external.dtos.MergeStatusDTO;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
|
|
@ -80,6 +81,8 @@ public interface FSGitHandler {
|
|||
*/
|
||||
Mono<String> createAndCheckoutToBranch(Path repoSuffix, String branchName);
|
||||
|
||||
Mono<String> createAndCheckoutReference(Path repoSuffix, GitRefDTO gitRefDTO);
|
||||
|
||||
/**
|
||||
* Delete a branch in the local repo
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.appsmith.server.applications.git;
|
||||
|
||||
import com.appsmith.external.git.constants.ce.RefType;
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
import com.appsmith.server.actioncollections.base.ActionCollectionService;
|
||||
import com.appsmith.server.applications.base.ApplicationService;
|
||||
|
|
@ -327,4 +328,16 @@ public class GitApplicationHelperCEImpl implements GitArtifactHelperCE<Applicati
|
|||
public Mono<? extends Artifact> validateAndPublishArtifact(Artifact artifact, boolean publish) {
|
||||
return publishArtifact(artifact, publish);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Application> publishArtifactPostRefCreation(
|
||||
Artifact artifact, RefType refType, Boolean isPublishedManually) {
|
||||
// TODO: create publish for ref type creation.
|
||||
Application application = (Application) artifact;
|
||||
if (RefType.TAG.equals(refType)) {
|
||||
return Mono.just(application);
|
||||
}
|
||||
|
||||
return Mono.just(application);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -419,21 +419,30 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
});
|
||||
} else {
|
||||
// TODO refactor method to account for RefName as well
|
||||
checkedOutArtifactMono = Mono.defer(() -> gitArtifactHelper
|
||||
.getArtifactByBaseIdAndBranchName(
|
||||
baseArtifactId, finalRefName, gitArtifactHelper.getArtifactReadPermission())
|
||||
checkedOutArtifactMono = gitHandlingService
|
||||
.checkoutArtifact(jsonTransformationDTO)
|
||||
.flatMap(isCheckedOut -> gitArtifactHelper.getArtifactByBaseIdAndBranchName(
|
||||
baseArtifactId, finalRefName, gitArtifactHelper.getArtifactReadPermission()))
|
||||
.flatMap(artifact -> gitAnalyticsUtils.addAnalyticsForGitOperation(
|
||||
AnalyticsEvents.GIT_CHECKOUT_BRANCH,
|
||||
artifact,
|
||||
artifact.getGitArtifactMetadata().getIsRepoPrivate())));
|
||||
artifact.getGitArtifactMetadata().getIsRepoPrivate()));
|
||||
}
|
||||
|
||||
return checkedOutArtifactMono
|
||||
.doFinally(signalType -> gitRedisUtils.releaseFileLock(baseArtifactId, addFileLock))
|
||||
return acquireFileLock
|
||||
.then(checkedOutArtifactMono)
|
||||
.flatMap(checkedOutArtifact -> gitRedisUtils
|
||||
.releaseFileLock(baseArtifactId, addFileLock)
|
||||
.thenReturn(checkedOutArtifact))
|
||||
.onErrorResume(error -> {
|
||||
log.error("An error occurred while checking out the reference. error {}", error.getMessage());
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(baseArtifactId, addFileLock)
|
||||
.then(Mono.error(error));
|
||||
})
|
||||
.tag(GitConstants.GitMetricConstants.CHECKOUT_REMOTE, FALSE.toString())
|
||||
.name(GitSpan.OPS_CHECKOUT_BRANCH)
|
||||
.tap(Micrometer.observation(observationRegistry))
|
||||
.onErrorResume(Mono::error);
|
||||
.tap(Micrometer.observation(observationRegistry));
|
||||
}
|
||||
|
||||
// TODO @Manish: add checkout Remote Branch
|
||||
|
|
@ -451,8 +460,6 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
3. Rehydrate the artifact from source artifact reference
|
||||
*/
|
||||
|
||||
RefType refType = refDTO.getRefType();
|
||||
|
||||
if (refDTO.getRefType() == null) {
|
||||
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, REF_TYPE));
|
||||
}
|
||||
|
|
@ -462,116 +469,152 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
}
|
||||
|
||||
GitArtifactHelper<?> gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
|
||||
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
|
||||
AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission();
|
||||
|
||||
Mono<Tuple2<? extends Artifact, ? extends Artifact>> baseAndBranchedArtifactMono =
|
||||
getBaseAndBranchedArtifacts(referencedArtifactId, artifactType, artifactEditPermission);
|
||||
|
||||
Mono<? extends Artifact> createBranchMono = baseAndBranchedArtifactMono
|
||||
.flatMap(artifactTuples -> {
|
||||
Artifact baseArtifact = artifactTuples.getT1();
|
||||
Artifact parentArtifact = artifactTuples.getT2();
|
||||
return baseAndBranchedArtifactMono.flatMap(artifactTuples -> {
|
||||
Artifact baseArtifact = artifactTuples.getT1();
|
||||
Artifact parentArtifact = artifactTuples.getT2();
|
||||
|
||||
GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata();
|
||||
GitAuth baseGitAuth = baseGitMetadata.getGitAuth();
|
||||
GitArtifactMetadata parentGitMetadata = parentArtifact.getGitArtifactMetadata();
|
||||
return createReference(baseArtifact, parentArtifact, refDTO, gitType);
|
||||
});
|
||||
}
|
||||
|
||||
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO();
|
||||
jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId());
|
||||
jsonTransformationDTO.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId());
|
||||
jsonTransformationDTO.setRepoName(baseGitMetadata.getRepoName());
|
||||
jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType());
|
||||
jsonTransformationDTO.setRefType(refType);
|
||||
jsonTransformationDTO.setRefName(refDTO.getRefName());
|
||||
protected Mono<? extends Artifact> createReference(
|
||||
Artifact baseArtifact, Artifact sourceArtifact, GitRefDTO refDTO, GitType gitType) {
|
||||
|
||||
if (parentGitMetadata == null
|
||||
|| !hasText(parentGitMetadata.getDefaultArtifactId())
|
||||
|| !hasText(parentGitMetadata.getRepoName())) {
|
||||
// TODO: add refType in error
|
||||
return Mono.error(
|
||||
new AppsmithException(
|
||||
AppsmithError.INVALID_GIT_CONFIGURATION,
|
||||
"Unable to find the parent reference. Please create a reference from other available references"));
|
||||
}
|
||||
RefType refType = refDTO.getRefType();
|
||||
GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata();
|
||||
GitAuth baseGitAuth = baseGitMetadata.getGitAuth();
|
||||
GitArtifactMetadata sourceGitMetadata = sourceArtifact.getGitArtifactMetadata();
|
||||
|
||||
Mono<Boolean> acquireGitLockMono = gitRedisUtils.acquireGitLock(
|
||||
baseGitMetadata.getDefaultArtifactId(),
|
||||
GitConstants.GitCommandConstants.CREATE_BRANCH,
|
||||
FALSE);
|
||||
Mono<String> fetchRemoteMono =
|
||||
gitHandlingService.fetchRemoteChanges(jsonTransformationDTO, baseGitAuth, TRUE);
|
||||
GitArtifactHelper<?> gitArtifactHelper =
|
||||
gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType());
|
||||
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
|
||||
|
||||
return acquireGitLockMono
|
||||
.flatMap(ignoreLockAcquisition -> fetchRemoteMono.onErrorResume(error ->
|
||||
Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "fetch", error))))
|
||||
.flatMap(ignoreFetchString -> gitHandlingService
|
||||
.listReferences(jsonTransformationDTO, TRUE, refType)
|
||||
.flatMap(refList -> {
|
||||
boolean isDuplicateName = refList.stream()
|
||||
// We are only supporting origin as the remote name so this is safe
|
||||
// but needs to be altered if we start supporting user defined remote
|
||||
// names
|
||||
.anyMatch(ref -> ref.replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT)
|
||||
.equals(refDTO.getRefName()));
|
||||
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO();
|
||||
jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId());
|
||||
jsonTransformationDTO.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId());
|
||||
jsonTransformationDTO.setRepoName(baseGitMetadata.getRepoName());
|
||||
jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType());
|
||||
jsonTransformationDTO.setRefType(refType);
|
||||
jsonTransformationDTO.setRefName(refDTO.getRefName());
|
||||
|
||||
if (isDuplicateName) {
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.DUPLICATE_KEY_USER_ERROR,
|
||||
"remotes/origin/" + refDTO.getRefName(),
|
||||
FieldName.BRANCH_NAME));
|
||||
}
|
||||
if (sourceGitMetadata == null
|
||||
|| !hasText(sourceGitMetadata.getDefaultArtifactId())
|
||||
|| !hasText(sourceGitMetadata.getRepoName())) {
|
||||
// TODO: add refType in error
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.INVALID_GIT_CONFIGURATION,
|
||||
"Unable to find the parent reference. Please create a reference from other available references"));
|
||||
}
|
||||
|
||||
Mono<? extends ArtifactExchangeJson> artifactExchangeJsonMono =
|
||||
exportService.exportByArtifactId(
|
||||
parentArtifact.getId(), VERSION_CONTROL, artifactType);
|
||||
Mono<Boolean> acquireGitLockMono = gitRedisUtils.acquireGitLock(
|
||||
baseGitMetadata.getDefaultArtifactId(), GitConstants.GitCommandConstants.CREATE_BRANCH, FALSE);
|
||||
Mono<String> fetchRemoteMono = gitHandlingService.fetchRemoteChanges(jsonTransformationDTO, baseGitAuth, TRUE);
|
||||
|
||||
Mono<? extends Artifact> newArtifactFromSourceMono =
|
||||
// TODO: add refType support over here
|
||||
gitArtifactHelper.createNewArtifactForCheckout(
|
||||
parentArtifact, refDTO.getRefName());
|
||||
Mono<? extends Artifact> createBranchMono = acquireGitLockMono
|
||||
.flatMap(ignoreLockAcquisition -> fetchRemoteMono.onErrorResume(
|
||||
error -> Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "fetch", error))))
|
||||
.flatMap(ignoreFetchString -> gitHandlingService
|
||||
.listReferences(jsonTransformationDTO, TRUE, refType)
|
||||
.flatMap(refList -> {
|
||||
boolean isDuplicateName = refList.stream()
|
||||
// We are only supporting origin as the remote name so this is safe
|
||||
// but needs to be altered if we start supporting user defined remote
|
||||
// names
|
||||
.anyMatch(ref -> ref.replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT)
|
||||
.equals(refDTO.getRefName()));
|
||||
|
||||
return Mono.zip(newArtifactFromSourceMono, artifactExchangeJsonMono);
|
||||
}))
|
||||
.flatMap(tuple -> {
|
||||
ArtifactExchangeJson exportedJson = tuple.getT2();
|
||||
Artifact newRefArtifact = tuple.getT1();
|
||||
if (isDuplicateName) {
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.DUPLICATE_KEY_USER_ERROR,
|
||||
"remotes/origin/" + refDTO.getRefName(),
|
||||
FieldName.BRANCH_NAME));
|
||||
}
|
||||
|
||||
Mono<String> refCreationMono = gitHandlingService
|
||||
.createGitReference(jsonTransformationDTO)
|
||||
// TODO: ths error could be shipped to handling layer as well?
|
||||
.onErrorResume(error -> Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED,
|
||||
"ref creation preparation",
|
||||
error.getMessage())));
|
||||
Mono<Boolean> refCreationValidationMono =
|
||||
isValidationForRefCreationComplete(baseArtifact, sourceArtifact, gitType, refType);
|
||||
|
||||
return refCreationMono
|
||||
.flatMap(ignoredString -> {
|
||||
return importService.importArtifactInWorkspaceFromGit(
|
||||
newRefArtifact.getWorkspaceId(),
|
||||
newRefArtifact.getId(),
|
||||
exportedJson,
|
||||
refDTO.getRefName());
|
||||
})
|
||||
// after the branch is created, we need to reset the older branch to initial
|
||||
// commit
|
||||
.doOnSuccess(newImportedArtifact ->
|
||||
discardChanges(parentArtifact.getId(), artifactType, gitType));
|
||||
Mono<? extends ArtifactExchangeJson> artifactExchangeJsonMono =
|
||||
exportService.exportByArtifactId(
|
||||
sourceArtifact.getId(), VERSION_CONTROL, baseArtifact.getArtifactType());
|
||||
|
||||
Mono<? extends Artifact> newArtifactFromSourceMono =
|
||||
// TODO: add refType support over here
|
||||
gitArtifactHelper.createNewArtifactForCheckout(sourceArtifact, refDTO.getRefName());
|
||||
|
||||
return refCreationValidationMono.flatMap(isOkayToProceed -> {
|
||||
if (!TRUE.equals(isOkayToProceed)) {
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED, "ref creation", "status unclean"));
|
||||
}
|
||||
|
||||
return Mono.zip(newArtifactFromSourceMono, artifactExchangeJsonMono);
|
||||
});
|
||||
}))
|
||||
.flatMap(tuple -> {
|
||||
ArtifactExchangeJson exportedJson = tuple.getT2();
|
||||
Artifact newRefArtifact = tuple.getT1();
|
||||
|
||||
Mono<String> refCreationMono = gitHandlingService
|
||||
.createGitReference(jsonTransformationDTO, refDTO)
|
||||
// TODO: this error could be shipped to handling layer as well?
|
||||
.onErrorResume(error -> Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED, "ref creation preparation", error.getMessage())));
|
||||
|
||||
return refCreationMono
|
||||
.flatMap(ignoredString -> {
|
||||
return importService.importArtifactInWorkspaceFromGit(
|
||||
newRefArtifact.getWorkspaceId(),
|
||||
newRefArtifact.getId(),
|
||||
exportedJson,
|
||||
refDTO.getRefName());
|
||||
})
|
||||
.flatMap(importedArtifact -> {
|
||||
return gitArtifactHelper.publishArtifactPostRefCreation(
|
||||
importedArtifact, refType, TRUE);
|
||||
})
|
||||
// after the branch is created, we need to reset the older branch to the
|
||||
// clean status, i.e. last commit
|
||||
.doOnSuccess(newImportedArtifact -> discardChanges(sourceArtifact, gitType));
|
||||
})
|
||||
.flatMap(newImportedArtifact -> gitAnalyticsUtils
|
||||
.addAnalyticsForGitOperation(
|
||||
.flatMap(newImportedArtifact -> gitRedisUtils
|
||||
.releaseFileLock(
|
||||
newImportedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), TRUE)
|
||||
.then(gitAnalyticsUtils.addAnalyticsForGitOperation(
|
||||
AnalyticsEvents.GIT_CREATE_BRANCH,
|
||||
newImportedArtifact,
|
||||
newImportedArtifact.getGitArtifactMetadata().getIsRepoPrivate())
|
||||
.doFinally(signalType -> gitRedisUtils.releaseFileLock(
|
||||
newImportedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), TRUE)))
|
||||
newImportedArtifact.getGitArtifactMetadata().getIsRepoPrivate())))
|
||||
.onErrorResume(error -> {
|
||||
log.error("An error occurred while creating reference. error {}", error.getMessage());
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(baseGitMetadata.getDefaultArtifactId(), TRUE)
|
||||
.then(Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout")));
|
||||
})
|
||||
.name(GitSpan.OPS_CREATE_BRANCH)
|
||||
.tap(Micrometer.observation(observationRegistry));
|
||||
|
||||
return Mono.create(sink -> createBranchMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
|
||||
}
|
||||
|
||||
protected Mono<Boolean> isValidationForRefCreationComplete(
|
||||
Artifact baseArtifact, Artifact parentArtifact, GitType gitType, RefType refType) {
|
||||
if (RefType.BRANCH.equals(refType)) {
|
||||
return Mono.just(TRUE);
|
||||
}
|
||||
|
||||
return getStatus(baseArtifact, parentArtifact, false, true, gitType).map(gitStatusDTO -> {
|
||||
if (!Boolean.TRUE.equals(gitStatusDTO.getIsClean())) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<? extends Artifact> deleteGitReference(
|
||||
String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType) {
|
||||
|
|
@ -650,7 +693,9 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
|
||||
return gitHandlingService
|
||||
.deleteGitReference(jsonTransformationDTO)
|
||||
.doFinally(signalType -> gitRedisUtils.releaseFileLock(baseArtifactId, TRUE))
|
||||
.flatMap(isReferenceDeleted -> gitRedisUtils
|
||||
.releaseFileLock(baseArtifactId, TRUE)
|
||||
.thenReturn(isReferenceDeleted))
|
||||
.flatMap(isReferenceDeleted -> {
|
||||
if (FALSE.equals(isReferenceDeleted)) {
|
||||
return Mono.error(new AppsmithException(
|
||||
|
|
@ -686,6 +731,14 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
AnalyticsEvents.GIT_DELETE_BRANCH,
|
||||
deletedArtifact,
|
||||
deletedArtifact.getGitArtifactMetadata().getIsRepoPrivate()))
|
||||
.onErrorResume(error -> {
|
||||
log.error(
|
||||
"An error occurred while deleting the git reference : {}, with base id {}",
|
||||
referenceArtifactMetadata.getRefName(),
|
||||
baseArtifactId);
|
||||
|
||||
return gitRedisUtils.releaseFileLock(baseArtifactId, TRUE).then(Mono.error(error));
|
||||
})
|
||||
.name(GitSpan.OPS_DELETE_BRANCH)
|
||||
.tap(Micrometer.observation(observationRegistry));
|
||||
|
||||
|
|
@ -1163,13 +1216,14 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
return gitHandlingService
|
||||
.commitArtifact(updatedBranchedArtifact, commitDTO, jsonTransformationDTO)
|
||||
.onErrorResume(error -> {
|
||||
return gitAnalyticsUtils
|
||||
.addAnalyticsForGitOperation(
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(baseArtifact.getId(), TRUE)
|
||||
.then(gitAnalyticsUtils.addAnalyticsForGitOperation(
|
||||
AnalyticsEvents.GIT_COMMIT,
|
||||
updatedBranchedArtifact,
|
||||
error.getClass().getName(),
|
||||
error.getMessage(),
|
||||
gitArtifactMetadata.getIsRepoPrivate())
|
||||
gitArtifactMetadata.getIsRepoPrivate()))
|
||||
.then(Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED, "commit", error.getMessage())));
|
||||
});
|
||||
|
|
@ -1198,6 +1252,16 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
.thenReturn(status)
|
||||
.name(OPS_COMMIT)
|
||||
.tap(Micrometer.observation(observationRegistry));
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
log.error(
|
||||
"An error occurred while committing changes to artifact with base id: {} and branch: {}",
|
||||
branchedGitMetadata.getDefaultArtifactId(),
|
||||
branchedGitMetadata.getBranchName());
|
||||
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(branchedGitMetadata.getDefaultArtifactId(), TRUE)
|
||||
.then(Mono.error(error));
|
||||
});
|
||||
|
||||
return Mono.create(sink -> {
|
||||
|
|
@ -1384,10 +1448,16 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
fetchRemoteMono = Mono.just("ignored");
|
||||
}
|
||||
|
||||
return Mono.zip(prepareForStatus, fetchRemoteMono)
|
||||
.then(gitHandlingService.getStatus(jsonTransformationDTO));
|
||||
return Mono.zip(prepareForStatus, fetchRemoteMono).flatMap(tuple2 -> {
|
||||
return gitHandlingService
|
||||
.getStatus(jsonTransformationDTO)
|
||||
.flatMap(gitStatusDTO -> {
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(baseArtifactId, isFileLock)
|
||||
.thenReturn(gitStatusDTO);
|
||||
});
|
||||
});
|
||||
})
|
||||
.doFinally(signalType -> gitRedisUtils.releaseFileLock(baseArtifactId, isFileLock))
|
||||
.onErrorResume(throwable -> {
|
||||
/*
|
||||
in case of any error, the global exception handler will release the lock
|
||||
|
|
@ -1626,61 +1696,69 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
|
|||
GitArtifactHelper<?> gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
|
||||
AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission();
|
||||
|
||||
Mono<? extends Artifact> branchedArtifactMonoCached =
|
||||
gitArtifactHelper.getArtifactById(branchedArtifactId, artifactEditPermission);
|
||||
return gitArtifactHelper
|
||||
.getArtifactById(branchedArtifactId, artifactEditPermission)
|
||||
.flatMap(branchedArtifact -> discardChanges(branchedArtifact, gitType));
|
||||
}
|
||||
|
||||
Mono<? extends Artifact> recreatedArtifactFromLastCommit;
|
||||
protected Mono<? extends Artifact> discardChanges(Artifact branchedArtifact, GitType gitType) {
|
||||
|
||||
// Rehydrate the artifact from local file system
|
||||
recreatedArtifactFromLastCommit = branchedArtifactMonoCached
|
||||
.flatMap(branchedArtifact -> {
|
||||
GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata();
|
||||
if (branchedGitData == null || !hasText(branchedGitData.getDefaultArtifactId())) {
|
||||
return Mono.error(
|
||||
new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR));
|
||||
}
|
||||
GitArtifactHelper<?> gitArtifactHelper =
|
||||
gitArtifactHelperResolver.getArtifactHelper(branchedArtifact.getArtifactType());
|
||||
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
|
||||
|
||||
return Mono.just(branchedArtifact)
|
||||
.doFinally(signalType -> gitRedisUtils.acquireGitLock(
|
||||
branchedGitData.getDefaultArtifactId(),
|
||||
GitConstants.GitCommandConstants.DISCARD,
|
||||
TRUE));
|
||||
GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata();
|
||||
if (branchedGitData == null || !hasText(branchedGitData.getDefaultArtifactId())) {
|
||||
return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR));
|
||||
}
|
||||
|
||||
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO();
|
||||
jsonTransformationDTO.setArtifactType(branchedArtifact.getArtifactType());
|
||||
// Because this operation is only valid for branches
|
||||
jsonTransformationDTO.setRefType(RefType.BRANCH);
|
||||
jsonTransformationDTO.setWorkspaceId(branchedArtifact.getWorkspaceId());
|
||||
jsonTransformationDTO.setBaseArtifactId(branchedGitData.getDefaultArtifactId());
|
||||
jsonTransformationDTO.setRefName(branchedGitData.getRefName());
|
||||
jsonTransformationDTO.setRepoName(branchedGitData.getRepoName());
|
||||
|
||||
Mono<? extends Artifact> recreatedArtifactFromLastCommit = gitRedisUtils
|
||||
.acquireGitLock(branchedGitData.getDefaultArtifactId(), GitConstants.GitCommandConstants.DISCARD, TRUE)
|
||||
.then(gitHandlingService
|
||||
.recreateArtifactJsonFromLastCommit(jsonTransformationDTO)
|
||||
.onErrorResume(throwable -> {
|
||||
log.error("Git recreate ArtifactJsonFailed : {}", throwable.getMessage());
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(branchedGitData.getDefaultArtifactId(), TRUE)
|
||||
.then(
|
||||
Mono.error(
|
||||
new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED,
|
||||
"discard changes",
|
||||
"Please create a new branch and resolve conflicts in the remote repository before proceeding.")));
|
||||
}))
|
||||
.flatMap(artifactExchangeJson -> importService.importArtifactInWorkspaceFromGit(
|
||||
branchedArtifact.getWorkspaceId(),
|
||||
branchedArtifact.getId(),
|
||||
artifactExchangeJson,
|
||||
branchedGitData.getBranchName()))
|
||||
// Update the last deployed status after the rebase
|
||||
.flatMap(importedArtifact -> gitArtifactHelper.publishArtifact(importedArtifact, true))
|
||||
.flatMap(publishedArtifact -> {
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(
|
||||
publishedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), TRUE)
|
||||
.then(gitAnalyticsUtils.addAnalyticsForGitOperation(
|
||||
AnalyticsEvents.GIT_DISCARD_CHANGES, publishedArtifact, null));
|
||||
})
|
||||
.flatMap(branchedArtifact -> {
|
||||
GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata();
|
||||
ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO();
|
||||
// Because this operation is only valid for branches
|
||||
jsonTransformationDTO.setArtifactType(artifactType);
|
||||
jsonTransformationDTO.setRefType(RefType.BRANCH);
|
||||
jsonTransformationDTO.setWorkspaceId(branchedArtifact.getWorkspaceId());
|
||||
jsonTransformationDTO.setBaseArtifactId(branchedGitData.getDefaultArtifactId());
|
||||
jsonTransformationDTO.setRefName(branchedGitData.getRefName());
|
||||
jsonTransformationDTO.setRepoName(branchedGitData.getRepoName());
|
||||
|
||||
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
|
||||
|
||||
return gitHandlingService
|
||||
.recreateArtifactJsonFromLastCommit(jsonTransformationDTO)
|
||||
.onErrorResume(throwable -> {
|
||||
log.error("Git recreate ArtifactJsonFailed : {}", throwable.getMessage());
|
||||
return Mono.error(
|
||||
new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED,
|
||||
"discard changes",
|
||||
"Please create a new branch and resolve conflicts in the remote repository before proceeding."));
|
||||
})
|
||||
.flatMap(artifactExchangeJson -> importService.importArtifactInWorkspaceFromGit(
|
||||
branchedArtifact.getWorkspaceId(),
|
||||
branchedArtifact.getId(),
|
||||
artifactExchangeJson,
|
||||
branchedGitData.getBranchName()))
|
||||
// Update the last deployed status after the rebase
|
||||
.flatMap(importedArtifact -> gitArtifactHelper.publishArtifact(importedArtifact, true));
|
||||
.onErrorResume(error -> {
|
||||
log.error(
|
||||
"An error occurred while discarding branch with artifact id {}. error {}",
|
||||
branchedGitData.getDefaultArtifactId(),
|
||||
error.getMessage());
|
||||
return gitRedisUtils
|
||||
.releaseFileLock(branchedGitData.getDefaultArtifactId(), TRUE)
|
||||
.then(Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout")));
|
||||
})
|
||||
.flatMap(branchedArtifact -> gitAnalyticsUtils
|
||||
.addAnalyticsForGitOperation(AnalyticsEvents.GIT_DISCARD_CHANGES, branchedArtifact, null)
|
||||
.doFinally(signalType -> gitRedisUtils.releaseFileLock(
|
||||
branchedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), TRUE)))
|
||||
.name(GitSpan.OPS_DISCARD_CHANGES)
|
||||
.tap(Micrometer.observation(observationRegistry));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.appsmith.server.git.central;
|
||||
|
||||
import com.appsmith.external.dtos.GitRefDTO;
|
||||
import com.appsmith.external.dtos.GitStatusDTO;
|
||||
import com.appsmith.external.git.constants.ce.RefType;
|
||||
import com.appsmith.git.dto.CommitDTO;
|
||||
|
|
@ -76,7 +77,9 @@ public interface GitHandlingServiceCE {
|
|||
|
||||
Mono<GitStatusDTO> getStatus(ArtifactJsonTransformationDTO jsonTransformationDTO);
|
||||
|
||||
Mono<String> createGitReference(ArtifactJsonTransformationDTO artifactJsonTransformationDTO);
|
||||
Mono<String> createGitReference(ArtifactJsonTransformationDTO artifactJsonTransformationDTO, GitRefDTO gitRefDTO);
|
||||
|
||||
Mono<Boolean> deleteGitReference(ArtifactJsonTransformationDTO jsonTransformationDTO);
|
||||
|
||||
Mono<Boolean> checkoutArtifact(ArtifactJsonTransformationDTO jsonTransformationDTO);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.appsmith.server.git.fs;
|
|||
|
||||
import com.appsmith.external.constants.AnalyticsEvents;
|
||||
import com.appsmith.external.dtos.GitBranchDTO;
|
||||
import com.appsmith.external.dtos.GitRefDTO;
|
||||
import com.appsmith.external.dtos.GitStatusDTO;
|
||||
import com.appsmith.external.git.constants.GitConstants;
|
||||
import com.appsmith.external.git.constants.GitSpan;
|
||||
|
|
@ -662,7 +663,7 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> createGitReference(ArtifactJsonTransformationDTO jsonTransformationDTO) {
|
||||
public Mono<String> createGitReference(ArtifactJsonTransformationDTO jsonTransformationDTO, GitRefDTO gitRefDTO) {
|
||||
GitArtifactHelper<?> gitArtifactHelper =
|
||||
gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType());
|
||||
|
||||
|
|
@ -671,7 +672,7 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
|
|||
jsonTransformationDTO.getBaseArtifactId(),
|
||||
jsonTransformationDTO.getRepoName());
|
||||
|
||||
return fsGitHandler.createAndCheckoutToBranch(repoSuffix, jsonTransformationDTO.getRefName());
|
||||
return fsGitHandler.createAndCheckoutReference(repoSuffix, gitRefDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -688,14 +689,34 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
|
|||
.deleteBranch(repoSuffix, jsonTransformationDTO.getRefName())
|
||||
.onErrorResume(throwable -> {
|
||||
log.error("Delete branch failed {}", throwable.getMessage());
|
||||
|
||||
Mono<Boolean> releaseLockMono =
|
||||
gitRedisUtils.releaseFileLock(jsonTransformationDTO.getBaseArtifactId(), Boolean.TRUE);
|
||||
|
||||
if (throwable instanceof CannotDeleteCurrentBranchException) {
|
||||
return Mono.error(new AppsmithException(
|
||||
return releaseLockMono.then(Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED,
|
||||
"delete branch",
|
||||
"Cannot delete current checked out branch"));
|
||||
"Cannot delete current checked out branch")));
|
||||
}
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED, "delete branch", throwable.getMessage()));
|
||||
|
||||
return releaseLockMono.then(Mono.error(new AppsmithException(
|
||||
AppsmithError.GIT_ACTION_FAILED, "delete branch", throwable.getMessage())));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> checkoutArtifact(ArtifactJsonTransformationDTO jsonTransformationDTO) {
|
||||
|
||||
GitArtifactHelper<?> gitArtifactHelper =
|
||||
gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType());
|
||||
|
||||
Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(
|
||||
jsonTransformationDTO.getWorkspaceId(),
|
||||
jsonTransformationDTO.getBaseArtifactId(),
|
||||
jsonTransformationDTO.getRepoName());
|
||||
|
||||
// Tags and branch checkout with the same mechanism.
|
||||
return fsGitHandler.checkoutToBranch(repoSuffix, jsonTransformationDTO.getRefName());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.appsmith.server.services.ce;
|
||||
|
||||
import com.appsmith.external.git.constants.ce.RefType;
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
import com.appsmith.server.domains.Artifact;
|
||||
import com.appsmith.server.dtos.ArtifactExchangeJson;
|
||||
|
|
@ -70,4 +71,6 @@ public interface GitArtifactHelperCE<T extends Artifact> {
|
|||
Mono<T> publishArtifactPostCommit(Artifact committedArtifact);
|
||||
|
||||
Mono<? extends Artifact> validateAndPublishArtifact(Artifact artifact, boolean publish);
|
||||
|
||||
Mono<T> publishArtifactPostRefCreation(Artifact artifact, RefType refType, Boolean isPublishedManually);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user