chore: implementation of artifact type agnostic import (#39237)

## Description
 - Added implementation for ArtifactType agnostic git import

Fixes #`Issue Number`  

## Automation

/ok-to-test tags="@tag.All"

### 🔍 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/13305383592>
> Commit: bdb5b6515ad365b611831082ee20af327b940687
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13305383592&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Thu, 13 Feb 2025 11:38:58 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**
- Streamlined Git artifact import with a simplified interface for easier
repository integration.
- Enhanced metadata reconstruction and remote repository management to
improve artifact handling.
- Advanced Git analytics and error tracking for improved operational
insights.
- Expanded application lookup via Git integration, offering more robust
identification.
- New methods for moving artifacts and retrieving artifact types from
repositories.
  - Added support for handling artifact JSON types in Git repositories.

- **Refactor**
  - Updated theme property management for improved internal consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Manish Kumar 2025-02-13 18:42:28 +05:30 committed by GitHub
parent ec4ea27d7d
commit 7764d3df87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 409 additions and 13 deletions

View File

@ -1200,6 +1200,16 @@ public class FileUtilsCEImpl implements FileInterface {
return metadataMono.subscribeOn(scheduler);
}
@Override
public Mono<Object> reconstructMetadataFromGitRepository(Path repoSuffix) {
Mono<Object> metadataMono = Mono.fromCallable(() -> {
Path baseRepoPath = Paths.get(gitServiceConfig.getGitRootPath()).resolve(repoSuffix);
return fileOperations.readFile(baseRepoPath.resolve(CommonConstants.METADATA + JSON_EXTENSION));
});
return metadataMono.subscribeOn(scheduler);
}
@Override
public Mono<Object> reconstructPageFromGitRepo(
String pageName, String branchName, Path baseRepoSuffixPath, Boolean resetToLastCommitRequired) {

View File

@ -71,6 +71,8 @@ public interface FileInterface {
Path repoSuffixPath,
Boolean isResetToLastCommitRequired);
Mono<Object> reconstructMetadataFromGitRepository(Path repoSuffix);
Mono<Object> reconstructPageFromGitRepo(
String pageName, String branchName, Path repoSuffixPath, Boolean checkoutRequired);

View File

@ -10,6 +10,7 @@ public class GitConstantsCE {
public static final String ACTION_COLLECTION_LIST = "actionCollectionList";
public static final String README_FILE_NAME = "README.md";
public static final String ARTIFACT_JSON_TYPE = "artifactJsonType";
public static final String FIRST_COMMIT = "System added readme file";
public static final String DEFAULT_COMMIT_MESSAGE = "System generated commit, ";

View File

@ -71,6 +71,7 @@ public class FieldNameCE {
public static final String ACTIONS = "actions";
public static final String ASSET = "asset";
public static final String APPLICATION = "application";
public static final String ARTIFACT = "artifact";
public static final String SOURCE_APPLICATION = "sourceApplication";
public static final String COMMENT = "comment";
public static final String COMMENT_THREAD = "commentThread";

View File

@ -49,7 +49,8 @@ public class Theme extends BaseDomain {
@JsonProperty("isSystemTheme") // manually setting property name to make sure it's compatible with Gson
@JsonView({Views.Public.class, Git.class})
private boolean isSystemTheme = false; // should be false by default
// The primitive is changed to wrapper because of serialization - deserialization issues
private Boolean isSystemTheme = false; // should be false by default
@Data
@AllArgsConstructor
@ -59,6 +60,21 @@ public class Theme extends BaseDomain {
private String backgroundColor;
}
public void setSystemTheme(boolean isSystemTheme) {
this.isSystemTheme = isSystemTheme;
}
@JsonView({Views.Internal.class})
public Boolean getSystemTheme() {
return this.isSystemTheme;
}
// To be deleted in later on refactors
@JsonView({Views.Internal.class})
public Boolean isSystemTheme() {
return this.isSystemTheme;
}
@Override
public void sanitiseToExportDBObject() {
this.setId(null);

View File

@ -24,6 +24,9 @@ public interface CentralGitServiceCE {
Mono<? extends ArtifactImportDTO> importArtifactFromGit(
String workspaceId, GitConnectDTO gitConnectDTO, ArtifactType artifactType, GitType gitType);
Mono<? extends ArtifactImportDTO> importArtifactFromGit(
String workspaceId, GitConnectDTO gitConnectDTO, GitType gitType);
Mono<? extends Artifact> connectArtifactToGit(
String baseArtifactId,
ArtifactType artifactType,

View File

@ -85,6 +85,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
import static com.appsmith.external.git.constants.ce.GitConstantsCE.DEFAULT_COMMIT_MESSAGE;
@ -143,6 +144,204 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE {
return gitPrivateRepoHelper.isRepoLimitReached(workspaceId, true);
}
@Override
public Mono<? extends ArtifactImportDTO> importArtifactFromGit(
String workspaceId, GitConnectDTO gitConnectDTO, GitType gitType) {
if (!StringUtils.hasText(workspaceId)) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID));
}
GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType);
Set<String> errors = gitHandlingService.validateGitConnectDTO(gitConnectDTO);
if (!CollectionUtils.isEmpty(errors)) {
return Mono.error(new AppsmithException(
AppsmithError.INVALID_PARAMETER, errors.stream().findAny().get()));
}
final String repoName = gitHandlingService.getRepoName(gitConnectDTO);
// since at this point in the import flow, there is no context about the artifact type
// it needs to be retrieved from the fetched repository itself. however, in order to retrieve
// the artifact type from repository, the repository needs to be saved.
// for saving the repo an identifier is required (which usually is the artifact id);
// however, the artifact could only be generated after the artifact type is known.
// hence this is a temporary placeholder to hold the repository and it's components
String placeholder = "temp" + UUID.randomUUID();
ArtifactJsonTransformationDTO tempJsonTransformationDTO =
new ArtifactJsonTransformationDTO(workspaceId, placeholder, repoName);
ArtifactJsonTransformationDTO jsonDTOPostRefCreation =
new ArtifactJsonTransformationDTO(workspaceId, placeholder, repoName);
Mono<Boolean> isRepositoryPrivateMonoCached =
gitHandlingService.isRepoPrivate(gitConnectDTO).cache();
Mono<Boolean> isRepositoryLimitReachedForWorkspaceMono = isRepositoryPrivateMonoCached.flatMap(
isRepositoryPrivate -> isRepositoryLimitReachedForWorkspace(workspaceId, isRepositoryPrivate));
Mono<GitAuth> gitAuthMonoCached = gitHandlingService.getGitAuthForUser().cache();
Mono<? extends Artifact> blankArtifactForImportMono = isRepositoryLimitReachedForWorkspaceMono
.flatMap(isLimitReachedForPrivateRepositories -> {
if (!TRUE.equals(isLimitReachedForPrivateRepositories)) {
return gitAuthMonoCached;
}
return gitAnalyticsUtils
.addAnalyticsForGitOperation(
AnalyticsEvents.GIT_IMPORT,
workspaceId,
AppsmithError.GIT_APPLICATION_LIMIT_ERROR.getErrorType(),
AppsmithError.GIT_APPLICATION_LIMIT_ERROR.getMessage(),
true,
false)
.then(Mono.error(new AppsmithException(AppsmithError.GIT_APPLICATION_LIMIT_ERROR)));
})
.flatMap(gitAuth -> {
return gitHandlingService
.fetchRemoteRepository(gitConnectDTO, gitAuth, tempJsonTransformationDTO)
.flatMap(defaultBranch -> {
return Mono.zip(
Mono.just(defaultBranch),
gitHandlingService.obtainArtifactTypeFromGitRepository(
tempJsonTransformationDTO),
isRepositoryPrivateMonoCached,
Mono.just(gitAuth));
});
})
.flatMap(tuple4 -> {
String defaultBranch = tuple4.getT1();
ArtifactType artifactType = tuple4.getT2();
Boolean isRepoPrivate = tuple4.getT3();
GitAuth gitAuth = tuple4.getT4();
GitArtifactHelper<?> contextHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
AclPermission workspacePermission = contextHelper.getWorkspaceArtifactCreationPermission();
Mono<Workspace> workspaceMono = workspaceService
.findById(workspaceId, workspacePermission)
.switchIfEmpty(Mono.error(new AppsmithException(
AppsmithError.NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId)));
return workspaceMono
.flatMap(workspace -> contextHelper.createArtifactForImport(workspaceId, repoName))
.map(baseArtifact -> {
GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata();
gitArtifactMetadata.setGitAuth(gitAuth);
gitArtifactMetadata.setDefaultArtifactId(baseArtifact.getId());
gitArtifactMetadata.setDefaultBranchName(defaultBranch);
gitArtifactMetadata.setRefName(defaultBranch);
gitArtifactMetadata.setRepoName(repoName);
gitArtifactMetadata.setIsRepoPrivate(isRepoPrivate);
gitArtifactMetadata.setLastCommittedAt(Instant.now());
gitHandlingService.setRepositoryDetailsInGitArtifactMetadata(
gitConnectDTO, gitArtifactMetadata);
baseArtifact.setGitArtifactMetadata(gitArtifactMetadata);
return baseArtifact;
});
});
Mono<? extends Artifact> containerArtifactForImport = Mono.usingWhen(
blankArtifactForImportMono,
baseArtifact -> {
GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata();
String defaultBranch = baseGitMetadata.getDefaultBranchName();
jsonDTOPostRefCreation.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId());
jsonDTOPostRefCreation.setRefType(RefType.branch);
jsonDTOPostRefCreation.setRefName(defaultBranch);
jsonDTOPostRefCreation.setArtifactType(baseArtifact.getArtifactType());
return Mono.just(baseArtifact);
},
// in any case repository details needs to be updated with the base artifact id
baseArtifact ->
gitHandlingService.updateImportedRepositoryDetails(baseArtifact, tempJsonTransformationDTO));
Mono<? extends ArtifactImportDTO> importGitArtifactMono = Mono.usingWhen(
containerArtifactForImport,
baseArtifact -> {
GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata();
String defaultBranch = baseGitMetadata.getDefaultBranchName();
GitArtifactHelper<?> gitArtifactHelper =
gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType());
Mono<List<Datasource>> datasourceMono = datasourceService
.getAllByWorkspaceIdWithStorages(workspaceId, datasourcePermission.getEditPermission())
.collectList();
Mono<List<Plugin>> pluginMono =
pluginService.getDefaultPlugins().collectList();
Mono<? extends ArtifactExchangeJson> artifactExchangeJsonMono = gitHandlingService
.reconstructArtifactJsonFromGitRepository(jsonDTOPostRefCreation)
.onErrorResume(error -> {
log.error("Error while constructing artifact from git repo", error);
return Mono.error(
new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, error.getMessage()));
});
return Mono.zip(artifactExchangeJsonMono, datasourceMono, pluginMono)
.flatMap(data -> {
ArtifactExchangeJson artifactExchangeJson = data.getT1();
List<Datasource> datasourceList = data.getT2();
List<Plugin> pluginList = data.getT3();
if (artifactExchangeJson.getArtifact() == null
|| gitArtifactHelper.isContextInArtifactEmpty(artifactExchangeJson)) {
return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED,
"import",
"Cannot import artifact from an empty repo"));
}
// If there is an existing datasource with the same name but a different type from that
// in the repo, the import api should fail
// TODO: change the implementation to compare datasource with gitSyncIds instead.
if (checkIsDatasourceNameConflict(
datasourceList, artifactExchangeJson.getDatasourceList(), pluginList)) {
return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED,
"import",
"Datasource already exists with the same name"));
}
artifactExchangeJson.getArtifact().setGitArtifactMetadata(baseGitMetadata);
return importService
.importArtifactInWorkspaceFromGit(
workspaceId, baseArtifact.getId(), artifactExchangeJson, defaultBranch)
.onErrorResume(throwable -> {
log.error("Error in importing the artifact {}", baseArtifact.getId());
return Mono.error(new AppsmithException(
AppsmithError.GIT_FILE_SYSTEM_ERROR, throwable.getMessage()));
});
})
.flatMap(artifact -> gitArtifactHelper.publishArtifact(artifact, false))
.flatMap(artifact -> importService.getArtifactImportDTO(
artifact.getWorkspaceId(), artifact.getId(), artifact, artifact.getArtifactType()));
},
baseArtifact -> {
// on success send analytics
return gitAnalyticsUtils.addAnalyticsForGitOperation(
AnalyticsEvents.GIT_IMPORT,
baseArtifact,
baseArtifact.getGitArtifactMetadata().getIsRepoPrivate());
},
(baseArtifact, throwableError) -> {
// on error
return deleteArtifactCreatedFromGitImport(jsonDTOPostRefCreation, gitType);
},
baseArtifact -> {
// on publisher cancellation
return deleteArtifactCreatedFromGitImport(jsonDTOPostRefCreation, gitType);
});
return Mono.create(
sink -> importGitArtifactMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
}
@Override
public Mono<? extends ArtifactImportDTO> importArtifactFromGit(
String workspaceId, GitConnectDTO gitConnectDTO, ArtifactType artifactType, GitType gitType) {

View File

@ -5,6 +5,7 @@ import com.appsmith.external.dtos.GitStatusDTO;
import com.appsmith.external.dtos.MergeStatusDTO;
import com.appsmith.external.git.dtos.FetchRemoteDTO;
import com.appsmith.git.dto.CommitDTO;
import com.appsmith.server.constants.ArtifactType;
import com.appsmith.server.domains.Artifact;
import com.appsmith.server.domains.GitArtifactMetadata;
import com.appsmith.server.domains.GitAuth;
@ -15,6 +16,7 @@ import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
@ -33,6 +35,15 @@ public interface GitHandlingServiceCE {
Boolean isGitAuthInvalid(GitAuth gitAuth);
// TODO: use only the required params
Mono<Path> updateImportedRepositoryDetails(
Artifact baseArtifact, ArtifactJsonTransformationDTO jsonTransformationDTO);
Mono<ArtifactType> obtainArtifactTypeFromGitRepository(ArtifactJsonTransformationDTO jsonTransformationDTO);
Mono<String> fetchRemoteRepository(
GitConnectDTO gitConnectDTO, GitAuth gitAuth, ArtifactJsonTransformationDTO jsonTransformationDTO);
Mono<String> fetchRemoteRepository(
GitConnectDTO gitConnectDTO, GitAuth gitAuth, Artifact artifact, String repoName);

View File

@ -1,7 +1,6 @@
package com.appsmith.server.git.controllers;
import com.appsmith.external.views.Views;
import com.appsmith.server.constants.ArtifactType;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.GitAuth;
import com.appsmith.server.domains.GitProfile;
@ -88,7 +87,7 @@ public class GitArtifactControllerCE {
// TODO: remove artifact type from methods.
return centralGitService
.importArtifactFromGit(workspaceId, gitConnectDTO, ArtifactType.APPLICATION, GIT_TYPE)
.importArtifactFromGit(workspaceId, gitConnectDTO, GIT_TYPE)
.map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null));
}

View File

@ -164,6 +164,67 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE {
return !StringUtils.hasText(gitAuth.getPrivateKey()) || !StringUtils.hasText(gitAuth.getPublicKey());
}
public Mono<String> fetchRemoteRepository(
GitConnectDTO gitConnectDTO, GitAuth gitAuth, ArtifactJsonTransformationDTO jsonTransformationDTO) {
String workspaceId = jsonTransformationDTO.getWorkspaceId();
String placeHolder = jsonTransformationDTO.getBaseArtifactId();
String repoName = jsonTransformationDTO.getRepoName();
Path temporaryStorage = Path.of(workspaceId, placeHolder, repoName);
return fsGitHandler
.cloneRemoteIntoArtifactRepo(
temporaryStorage, gitConnectDTO.getRemoteUrl(), gitAuth.getPrivateKey(), gitAuth.getPublicKey())
.onErrorResume(error -> {
log.error("Error in cloning the remote repo, {}", error.getMessage());
return gitAnalyticsUtils
.addAnalyticsForGitOperation(
AnalyticsEvents.GIT_IMPORT,
workspaceId,
error.getClass().getName(),
error.getMessage(),
false,
false)
.flatMap(user -> commonGitFileUtils.deleteLocalRepo(temporaryStorage))
.flatMap(isDeleted -> {
if (error instanceof TransportException) {
return Mono.error(
new AppsmithException(AppsmithError.INVALID_GIT_SSH_CONFIGURATION));
} else if (error instanceof InvalidRemoteException) {
return Mono.error(
new AppsmithException(AppsmithError.INVALID_PARAMETER, "remote url"));
} else if (error instanceof TimeoutException) {
return Mono.error(new AppsmithException(AppsmithError.GIT_EXECUTION_TIMEOUT));
}
return Mono.error(new AppsmithException(
AppsmithError.GIT_ACTION_FAILED, "clone", error.getMessage()));
});
});
}
public Mono<ArtifactType> obtainArtifactTypeFromGitRepository(ArtifactJsonTransformationDTO jsonTransformationDTO) {
String workspaceId = jsonTransformationDTO.getWorkspaceId();
String placeHolder = jsonTransformationDTO.getBaseArtifactId();
String repoName = jsonTransformationDTO.getRepoName();
Path temporaryStorage = Path.of(workspaceId, placeHolder, repoName);
return commonGitFileUtils.getArtifactJsonTypeOfRepository(temporaryStorage);
}
@Override
public Mono<Path> updateImportedRepositoryDetails(
Artifact baseArtifact, ArtifactJsonTransformationDTO jsonTransformationDTO) {
String workspaceId = jsonTransformationDTO.getWorkspaceId();
String placeHolder = jsonTransformationDTO.getBaseArtifactId();
String repoName = jsonTransformationDTO.getRepoName();
Path temporaryStorage = Path.of(workspaceId, placeHolder, repoName);
ArtifactType artifactType = baseArtifact.getArtifactType();
GitArtifactHelper<?> gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType);
Path newPath = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifact.getId(), repoName);
return commonGitFileUtils.moveArtifactFromTemporaryToBaseArtifactIdRepository(temporaryStorage, newPath);
}
@Override
public Mono<String> fetchRemoteRepository(
GitConnectDTO gitConnectDTO, GitAuth gitAuth, Artifact artifact, String repoName) {

View File

@ -72,13 +72,46 @@ public class GitAnalyticsUtils {
Boolean isSystemGenerated,
Boolean isMergeable) {
String branchName = artifact.getGitArtifactMetadata() != null
? artifact.getGitArtifactMetadata().getRefName()
: null;
String branchName = (artifact == null || artifact.getGitArtifactMetadata() == null)
? null
: artifact.getGitArtifactMetadata().getRefName();
return addAnalyticsForGitOperation(
event, artifact, errorType, errorMessage, isRepoPrivate, isSystemGenerated, isMergeable, branchName);
}
public Mono<Void> addAnalyticsForGitOperation(
AnalyticsEvents event,
String workspaceId,
String errorType,
String errorMessage,
Boolean isRepoPrivate,
Boolean isSystemGenerated) {
Map<String, Object> analyticsProps = new HashMap<>();
// Do not include the error data points in the map for success states
if (StringUtils.hasText(errorMessage) || StringUtils.hasText(errorType)) {
analyticsProps.put("errorMessage", errorMessage);
analyticsProps.put("errorType", errorType);
}
analyticsProps.putAll(Map.of(
FieldName.WORKSPACE_ID,
defaultIfNull(workspaceId, ""),
FieldName.ARTIFACT_ID,
defaultIfNull("", ""),
"isRepoPrivate",
defaultIfNull(isRepoPrivate, ""),
"isSystemGenerated",
defaultIfNull(isSystemGenerated, "")));
final Map<String, Object> eventData = Map.of(FieldName.APP_MODE, ApplicationMode.EDIT.toString());
analyticsProps.put(FieldName.EVENT_DATA, eventData);
return sessionUserService
.getCurrentUser()
.flatMap(user -> analyticsService.sendEvent(event.getEventName(), user.getUsername(), analyticsProps));
}
public Mono<? extends Artifact> addAnalyticsForGitOperation(
AnalyticsEvents event,
Artifact artifact,
@ -88,10 +121,12 @@ public class GitAnalyticsUtils {
Boolean isSystemGenerated,
Boolean isMergeable,
String branchName) {
GitArtifactMetadata gitData = artifact.getGitArtifactMetadata();
Map<String, Object> analyticsProps = new HashMap<>();
if (gitData != null) {
analyticsProps.put(FieldName.APPLICATION_ID, gitData.getDefaultArtifactId());
if (artifact != null && artifact.getGitArtifactMetadata() != null) {
GitArtifactMetadata gitData = artifact.getGitArtifactMetadata();
analyticsProps.put(FieldName.ARTIFACT_ID, gitData.getDefaultArtifactId());
analyticsProps.put("artifactType", artifact.getArtifactType());
analyticsProps.put("appId", gitData.getDefaultArtifactId());
analyticsProps.put(FieldName.BRANCH_NAME, branchName);
analyticsProps.put(FieldName.GIT_HOSTING_PROVIDER, GitUtils.getGitProviderName(gitData.getRemoteUrl()));
@ -113,14 +148,14 @@ public class GitAnalyticsUtils {
analyticsProps.putAll(Map.of(
"workspaceId",
defaultIfNull(artifact.getWorkspaceId(), ""),
"branchApplicationId",
"branchedArtifactId",
defaultIfNull(artifact.getId(), ""),
"isRepoPrivate",
defaultIfNull(isRepoPrivate, ""),
"isSystemGenerated",
defaultIfNull(isSystemGenerated, "")));
final Map<String, Object> eventData =
Map.of(FieldName.APP_MODE, ApplicationMode.EDIT.toString(), FieldName.APPLICATION, artifact);
Map.of(FieldName.APP_MODE, ApplicationMode.EDIT.toString(), FieldName.ARTIFACT, artifact);
analyticsProps.put(FieldName.EVENT_DATA, eventData);
return sessionUserService.getCurrentUser().flatMap(user -> analyticsService
.sendEvent(event.getEventName(), user.getUsername(), analyticsProps)

View File

@ -2,6 +2,7 @@ package com.appsmith.server.helpers;
import com.appsmith.external.git.FileInterface;
import com.appsmith.external.git.operations.FileOperations;
import com.appsmith.git.configurations.GitServiceConfig;
import com.appsmith.git.files.FileUtilsImpl;
import com.appsmith.server.actioncollections.base.ActionCollectionService;
import com.appsmith.server.dtos.ApplicationJson;
@ -22,6 +23,7 @@ public class CommonGitFileUtils extends CommonGitFileUtilsCE {
public CommonGitFileUtils(
ArtifactGitFileUtils<ApplicationJson> applicationGitFileUtils,
GitServiceConfig gitServiceConfig,
FileInterface fileUtils,
FileOperations fileOperations,
AnalyticsService analyticsService,
@ -32,6 +34,7 @@ public class CommonGitFileUtils extends CommonGitFileUtilsCE {
ObjectMapper objectMapper) {
super(
applicationGitFileUtils,
gitServiceConfig,
fileUtils,
fileOperations,
analyticsService,

View File

@ -14,6 +14,7 @@ import com.appsmith.external.models.BaseDomain;
import com.appsmith.external.models.CreatorContextType;
import com.appsmith.external.models.DatasourceStorage;
import com.appsmith.external.models.PluginType;
import com.appsmith.git.configurations.GitServiceConfig;
import com.appsmith.git.constants.CommonConstants;
import com.appsmith.git.files.FileUtilsImpl;
import com.appsmith.server.actioncollections.base.ActionCollectionService;
@ -53,6 +54,7 @@ import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
@ -62,6 +64,7 @@ import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import static com.appsmith.external.git.constants.ce.GitConstantsCE.ARTIFACT_JSON_TYPE;
import static com.appsmith.external.git.constants.ce.GitConstantsCE.GitCommandConstantsCE.CHECKOUT_BRANCH;
import static com.appsmith.external.git.constants.ce.GitConstantsCE.RECONSTRUCT_PAGE;
import static com.appsmith.git.constants.CommonConstants.CLIENT_SCHEMA_VERSION;
@ -79,6 +82,7 @@ import static com.appsmith.git.constants.ce.GitDirectoriesCE.DATASOURCE_DIRECTOR
import static com.appsmith.git.constants.ce.GitDirectoriesCE.JS_LIB_DIRECTORY;
import static com.appsmith.git.constants.ce.GitDirectoriesCE.PAGE_DIRECTORY;
import static com.appsmith.git.files.FileUtilsCEImpl.getJsLibFileName;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.springframework.util.StringUtils.hasText;
@Slf4j
@ -87,6 +91,7 @@ import static org.springframework.util.StringUtils.hasText;
public class CommonGitFileUtilsCE {
protected final ArtifactGitFileUtils<ApplicationJson> applicationGitFileUtils;
protected final GitServiceConfig gitServiceConfig;
private final FileInterface fileUtils;
private final FileOperations fileOperations;
private final AnalyticsService analyticsService;
@ -104,6 +109,7 @@ public class CommonGitFileUtilsCE {
public CommonGitFileUtilsCE(
ArtifactGitFileUtils<ApplicationJson> applicationGitFileUtils,
GitServiceConfig gitServiceConfig,
FileInterface fileUtils,
FileOperations fileOperations,
AnalyticsService analyticsService,
@ -113,6 +119,7 @@ public class CommonGitFileUtilsCE {
JsonSchemaVersions jsonSchemaVersions,
ObjectMapper objectMapper) {
this.applicationGitFileUtils = applicationGitFileUtils;
this.gitServiceConfig = gitServiceConfig;
this.fileUtils = fileUtils;
this.fileOperations = fileOperations;
this.analyticsService = analyticsService;
@ -779,6 +786,53 @@ public class CommonGitFileUtilsCE {
});
}
public Mono<Path> moveArtifactFromTemporaryToBaseArtifactIdRepository(
Path currentRepositoryPath, Path newRepositoryPath) {
Path currentGitPath = Path.of(gitServiceConfig.getGitRootPath()).resolve(currentRepositoryPath);
Path targetPath = Path.of(gitServiceConfig.getGitRootPath()).resolve(newRepositoryPath);
return Mono.fromCallable(() -> {
if (!Files.exists(targetPath)) {
Files.createDirectories(targetPath);
}
return Files.move(currentGitPath, targetPath, REPLACE_EXISTING);
})
.subscribeOn(Schedulers.boundedElastic());
}
public Mono<ArtifactType> getArtifactJsonTypeOfRepository(Path repoSuffix) {
Mono<ArtifactType> artifactTypeMono = fileUtils
.reconstructMetadataFromGitRepository(repoSuffix)
.flatMap(metadata -> {
Gson gson = new Gson();
JsonObject metadataJsonObject =
gson.toJsonTree(metadata, Object.class).getAsJsonObject();
if (metadataJsonObject == null) {
log.error(
"Error in retrieving the metadata from the file system for repository {}", repoSuffix);
return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR));
}
JsonElement artifactJsonType = metadataJsonObject.get(ARTIFACT_JSON_TYPE);
if (artifactJsonType == null) {
log.error(
"artifactJsonType attribute not found in the metadata file for repository {}",
repoSuffix);
return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR));
}
return Mono.just(artifactJsonType.getAsString());
})
.flatMap(artifactJsonType -> {
return Mono.justOrEmpty(ArtifactType.valueOf(artifactJsonType));
});
return Mono.create(sink -> artifactTypeMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
}
/**
* Provides the server schema version in the application json for the given branch
*

View File

@ -161,8 +161,9 @@ public class CustomApplicationRepositoryCEImpl extends BaseAppsmithRepositoryImp
public Flux<Application> getApplicationByGitBaseApplicationId(String baseApplicationId, AclPermission permission) {
return queryBuilder()
.criteria(
Bridge.equal(Application.Fields.gitApplicationMetadata_defaultApplicationId, baseApplicationId))
.criteria(Bridge.or(
Bridge.equal(Application.Fields.gitApplicationMetadata_defaultApplicationId, baseApplicationId),
Bridge.equal(Application.Fields.gitApplicationMetadata_defaultArtifactId, baseApplicationId)))
.permission(permission)
.all();
}