Merge pull request #6585 from ViacheslavKlimov/entities-vc-refactoring
Git api usage improvements
This commit is contained in:
commit
490a0c2ae3
@ -24,37 +24,39 @@ import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.ExportableEntity;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.EntityIdFactory;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.sync.vc.*;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadConfig;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.entity.EntityService;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.permission.Operation;
|
||||
|
||||
import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
|
||||
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
|
||||
import org.thingsboard.server.common.data.sync.ThrowingRunnable;
|
||||
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
|
||||
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
|
||||
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
|
||||
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
|
||||
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
|
||||
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
|
||||
import org.thingsboard.server.common.data.sync.vc.VersionControlAuthMethod;
|
||||
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
|
||||
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
|
||||
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.create.ComplexVersionCreateRequest;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.create.SingleEntityVersionCreateRequest;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.create.SyncStrategy;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateConfig;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadConfig;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadRequest;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.load.SingleEntityVersionLoadRequest;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadConfig;
|
||||
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
|
||||
import org.thingsboard.server.common.data.sync.ThrowingRunnable;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.permission.Operation;
|
||||
import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
|
||||
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -76,7 +78,6 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
|
||||
private final EntitiesExportImportService exportImportService;
|
||||
private final ExportableEntitiesService exportableEntitiesService;
|
||||
private final AdminSettingsService adminSettingsService;
|
||||
private final EntityService entityService;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
|
||||
@Override
|
||||
|
||||
@ -135,7 +135,13 @@ public class LocalGitVersionControlService implements GitVersionControlService {
|
||||
if (old != null) {
|
||||
gitRepositoryService.abort(old);
|
||||
}
|
||||
gitRepositoryService.prepareCommit(pendingCommit);
|
||||
try {
|
||||
gitRepositoryService.prepareCommit(pendingCommit);
|
||||
} catch (Exception e) {
|
||||
pendingCommitMap.remove(tenantId);
|
||||
gitRepositoryService.cleanUp(pendingCommit);
|
||||
throw e;
|
||||
}
|
||||
return pendingCommit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -171,7 +177,9 @@ public class LocalGitVersionControlService implements GitVersionControlService {
|
||||
|
||||
@Override
|
||||
public VersionCreationResult push(PendingCommit commit) {
|
||||
return executeInsideLock(commit, gitRepositoryService::push);
|
||||
VersionCreationResult result = executeInsideLock(commit, gitRepositoryService::push);
|
||||
pendingCommitMap.remove(commit.getTenantId());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -256,6 +264,10 @@ public class LocalGitVersionControlService implements GitVersionControlService {
|
||||
try {
|
||||
checkCommit(commit);
|
||||
r.accept(commit);
|
||||
} catch (Exception e) {
|
||||
pendingCommitMap.remove(commit.getTenantId());
|
||||
gitRepositoryService.cleanUp(commit);
|
||||
throw e;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -267,6 +279,10 @@ public class LocalGitVersionControlService implements GitVersionControlService {
|
||||
try {
|
||||
checkCommit(commit);
|
||||
return c.apply(commit);
|
||||
} catch (Exception e) {
|
||||
pendingCommitMap.remove(commit.getTenantId());
|
||||
gitRepositoryService.cleanUp(commit);
|
||||
throw e;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@ -1119,6 +1119,7 @@ vc:
|
||||
git:
|
||||
service: "${JS_VC_GIT_SERVICE:local}" # local/remote
|
||||
repos-poll-interval: "${TB_VC_GIT_REPOS_POLL_INTERVAL_SEC:60}"
|
||||
repositories-folder: "${TB_VC_GIT_REPOSITORIES_FOLDER:${java.io.tmpdir}/repositories}"
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.server.common.data.sync.vc;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class EntitiesVersionControlSettings {
|
||||
private String repositoryUri;
|
||||
@ -26,4 +27,4 @@ public class EntitiesVersionControlSettings {
|
||||
private String privateKey;
|
||||
private String privateKeyPassword;
|
||||
private String defaultBranch;
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,8 +20,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.api.errors.JGitInternalException;
|
||||
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -55,7 +53,7 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class DefaultGitRepositoryService implements GitRepositoryService {
|
||||
|
||||
@Value("${vc.git.repos-poll-interval:${java.io.tmpdir}/repositories}")
|
||||
@Value("${vc.git.repositories-folder}")
|
||||
private String repositoriesFolder;
|
||||
|
||||
@Value("${vc.git.repos-poll-interval:60}")
|
||||
@ -92,22 +90,12 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
|
||||
String branch = commit.getRequest().getBranch();
|
||||
try {
|
||||
repository.fetch();
|
||||
if (repository.listBranches().contains(branch)) {
|
||||
repository.checkout("origin/" + branch, false);
|
||||
try {
|
||||
repository.checkout(branch, true);
|
||||
} catch (RefAlreadyExistsException e) {
|
||||
repository.checkout(branch, false);
|
||||
}
|
||||
|
||||
repository.createAndCheckoutOrphanBranch(commit.getWorkingBranch());
|
||||
repository.resetAndClean();
|
||||
|
||||
if (repository.listRemoteBranches().contains(branch)) {
|
||||
repository.merge(branch);
|
||||
} else { // TODO [viacheslav]: rollback orphan branch on failure
|
||||
try {
|
||||
repository.createAndCheckoutOrphanBranch(branch); // FIXME [viacheslav]: Checkout returned unexpected result NO_CHANGE for master branch
|
||||
} catch (JGitInternalException e) {
|
||||
if (!e.getMessage().contains("NO_CHANGE")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | GitAPIException gitAPIException) {
|
||||
//TODO: analyze and return meaningful exceptions that we can show to the client;
|
||||
@ -140,32 +128,49 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
|
||||
result.setRemoved(status.getRemoved().size());
|
||||
|
||||
GitRepository.Commit gitCommit = repository.commit(commit.getRequest().getVersionName());
|
||||
repository.push();
|
||||
repository.push(commit.getWorkingBranch(), commit.getRequest().getBranch());
|
||||
|
||||
result.setVersion(toVersion(gitCommit));
|
||||
return result;
|
||||
} catch (GitAPIException gitAPIException) {
|
||||
//TODO: analyze and return meaningful exceptions that we can show to the client;
|
||||
throw new RuntimeException(gitAPIException);
|
||||
} finally {
|
||||
cleanUp(commit);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void cleanUp(PendingCommit commit) {
|
||||
GitRepository repository = checkRepository(commit.getTenantId());
|
||||
try {
|
||||
repository.createAndCheckoutOrphanBranch(EntityId.NULL_UUID.toString());
|
||||
} catch (Exception e) {
|
||||
if (!e.getMessage().contains("NO_CHANGE")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
repository.resetAndClean();
|
||||
repository.deleteLocalBranchIfExists(commit.getWorkingBranch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort(PendingCommit commit) {
|
||||
//TODO: implement;
|
||||
cleanUp(commit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileContentAtCommit(TenantId tenantId, String relativePath, String versionId) throws IOException {
|
||||
GitRepository repository = checkRepository(tenantId);
|
||||
return repository.getFileContentAtCommit(relativePath, versionId);
|
||||
GitRepository repository = checkRepository(tenantId);
|
||||
return repository.getFileContentAtCommit(relativePath, versionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listBranches(TenantId tenantId) {
|
||||
GitRepository repository = checkRepository(tenantId);
|
||||
try {
|
||||
return repository.listBranches();
|
||||
return repository.listRemoteBranches();
|
||||
} catch (GitAPIException gitAPIException) {
|
||||
//TODO: analyze and return meaningful exceptions that we can show to the client;
|
||||
throw new RuntimeException(gitAPIException);
|
||||
|
||||
@ -18,8 +18,16 @@ package org.thingsboard.server.service.sync.vc;
|
||||
import com.google.common.collect.Streams;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.sshd.common.util.security.SecurityUtils;
|
||||
import org.eclipse.jgit.api.*;
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.GitCommand;
|
||||
import org.eclipse.jgit.api.ListBranchCommand;
|
||||
import org.eclipse.jgit.api.LogCommand;
|
||||
import org.eclipse.jgit.api.LsRemoteCommand;
|
||||
import org.eclipse.jgit.api.ResetCommand;
|
||||
import org.eclipse.jgit.api.TransportCommand;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
@ -28,6 +36,7 @@ import org.eclipse.jgit.lib.ObjectReader;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.filter.RevFilter;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
import org.eclipse.jgit.transport.RefSpec;
|
||||
import org.eclipse.jgit.transport.SshTransport;
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.eclipse.jgit.transport.sshd.JGitKeyCache;
|
||||
@ -36,7 +45,6 @@ import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
|
||||
import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
|
||||
import org.thingsboard.server.common.data.sync.vc.VersionControlAuthMethod;
|
||||
|
||||
@ -116,15 +124,18 @@ public class GitRepository {
|
||||
.setRemoveDeletedRefs(true));
|
||||
}
|
||||
|
||||
public void checkout(String branch, boolean createBranch) throws GitAPIException {
|
||||
execute(git.checkout()
|
||||
.setCreateBranch(createBranch)
|
||||
.setName(branch));
|
||||
public void deleteLocalBranchIfExists(String branch) throws GitAPIException {
|
||||
execute(git.branchDelete()
|
||||
.setBranchNames(branch)
|
||||
.setForce(true));
|
||||
}
|
||||
|
||||
public void reset() throws GitAPIException {
|
||||
public void resetAndClean() throws GitAPIException {
|
||||
execute(git.reset()
|
||||
.setMode(ResetCommand.ResetType.HARD));
|
||||
execute(git.clean()
|
||||
.setForce(true)
|
||||
.setCleanDirectories(true));
|
||||
}
|
||||
|
||||
public void merge(String branch) throws IOException, GitAPIException {
|
||||
@ -137,9 +148,9 @@ public class GitRepository {
|
||||
}
|
||||
|
||||
|
||||
public List<String> listBranches() throws GitAPIException {
|
||||
public List<String> listRemoteBranches() throws GitAPIException {
|
||||
return execute(git.branchList()
|
||||
.setListMode(ListBranchCommand.ListMode.ALL)).stream()
|
||||
.setListMode(ListBranchCommand.ListMode.REMOTE)).stream()
|
||||
.filter(ref -> !ref.getName().equals(Constants.HEAD))
|
||||
.map(ref -> org.eclipse.jgit.lib.Repository.shortenRefName(ref.getName()))
|
||||
.map(name -> StringUtils.removeStart(name, "origin/"))
|
||||
@ -209,16 +220,9 @@ public class GitRepository {
|
||||
.setOrphan(true)
|
||||
.setForced(true)
|
||||
.setName(name));
|
||||
// Set<String> uncommittedChanges = git.status().call().getUncommittedChanges();
|
||||
// if (!uncommittedChanges.isEmpty()) {
|
||||
// RmCommand rm = git.rm();
|
||||
// uncommittedChanges.forEach(rm::addFilepattern);
|
||||
// execute(rm);
|
||||
// }
|
||||
// execute(git.clean());
|
||||
}
|
||||
|
||||
public void add(String filesPattern) throws GitAPIException { // FIXME [viacheslav]
|
||||
public void add(String filesPattern) throws GitAPIException {
|
||||
execute(git.add().setUpdate(true).addFilepattern(filesPattern));
|
||||
execute(git.add().addFilepattern(filesPattern));
|
||||
}
|
||||
@ -230,13 +234,14 @@ public class GitRepository {
|
||||
|
||||
public Commit commit(String message) throws GitAPIException {
|
||||
RevCommit revCommit = execute(git.commit()
|
||||
.setMessage(message)); // TODO [viacheslav]: set configurable author for commit
|
||||
.setMessage(message));
|
||||
return toCommit(revCommit);
|
||||
}
|
||||
|
||||
|
||||
public void push() throws GitAPIException {
|
||||
execute(git.push());
|
||||
public void push(String localBranch, String remoteBranch) throws GitAPIException {
|
||||
execute(git.push()
|
||||
.setRefSpecs(new RefSpec(localBranch + ":" + remoteBranch)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@ public interface GitRepositoryService {
|
||||
|
||||
VersionCreationResult push(PendingCommit commit);
|
||||
|
||||
void cleanUp(PendingCommit commit);
|
||||
|
||||
void abort(PendingCommit commit);
|
||||
|
||||
List<String> listBranches(TenantId tenantId);
|
||||
|
||||
@ -27,10 +27,12 @@ public class PendingCommit {
|
||||
private final UUID txId;
|
||||
private final TenantId tenantId;
|
||||
private final VersionCreateRequest request;
|
||||
private final String workingBranch;
|
||||
|
||||
public PendingCommit(TenantId tenantId, VersionCreateRequest request) {
|
||||
this.txId = UUID.randomUUID();
|
||||
this.tenantId = tenantId;
|
||||
this.request = request;
|
||||
this.workingBranch = txId.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user