Browse Source

Merge branch 'feature/entities-version-control' of github.com:thingsboard/thingsboard into feature/entities-version-control

pull/6615/head
Igor Kulikov 4 years ago
parent
commit
351de50cbc
  1. 13
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  2. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java
  3. 10
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  4. 32
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  5. 83
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
  6. 5
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  7. 6
      application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java
  8. 2
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/ClearRepositoryGitRequest.java
  9. 2
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/CommitGitRequest.java
  10. 33
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/ContentsDiffGitRequest.java
  11. 3
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesContentGitRequest.java
  12. 2
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntityContentGitRequest.java
  13. 3
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/ListBranchesGitRequest.java
  14. 3
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/ListEntitiesGitRequest.java
  15. 6
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/ListVersionsGitRequest.java
  16. 2
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/PendingGitRequest.java
  17. 38
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionsDiffGitRequest.java
  18. 5
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/VoidGitRequest.java
  19. 32
      common/cluster-api/src/main/proto/queue.proto
  20. 28
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataDiff.java
  21. 34
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityVersionsDiff.java
  22. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadConfig.java
  23. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadConfig.java
  24. 13
      common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java
  25. 39
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java
  26. 21
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java
  27. 106
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java
  28. 5
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java

13
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.sync.vc.EntityDataDiff;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
@ -236,6 +237,18 @@ public class EntitiesVersionControlController extends BaseController {
}
}
@GetMapping("/diff/{branch}/{entityType}/{internalEntityUuid}")
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@PathVariable String branch,
@PathVariable EntityType entityType,
@PathVariable UUID internalEntityUuid,
@RequestParam String versionId) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid);
return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), branch, entityId, versionId));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "", notes = "" +
"SINGLE_ENTITY:" + NEW_LINE +

4
application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java

@ -27,8 +27,10 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.entitiy.queue.TbQueueService;
import org.thingsboard.server.service.install.InstallScripts;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Service
@TbCoreComponent
@ -38,6 +40,7 @@ public class DefaultTbTenantService extends AbstractTbEntityService implements T
private final InstallScripts installScripts;
private final TbQueueService tbQueueService;
private final TenantProfileService tenantProfileService;
private final EntitiesVersionControlService versionControlService;
@Override
public Tenant save(Tenant tenant) throws ThingsboardException {
@ -70,6 +73,7 @@ public class DefaultTbTenantService extends AbstractTbEntityService implements T
tenantService.deleteTenant(tenantId);
tenantProfileCache.evict(tenantId);
notificationEntityService.notifyDeleteTenant(tenant);
versionControlService.deleteVersionControlSettings(tenantId).get(1, TimeUnit.MINUTES);
} catch (Exception e) {
throw handleException(e);
}

10
application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -24,18 +24,18 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
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.dao.exception.DataValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.DefaultEntityExportService;
import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
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.ThrowingRunnable;
import java.util.ArrayList;
import java.util.Collection;

32
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -25,6 +25,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
@ -33,6 +34,7 @@ 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.HasId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -42,6 +44,7 @@ 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.EntityDataDiff;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
@ -57,11 +60,13 @@ import org.thingsboard.server.common.data.sync.vc.request.load.SingleEntityVersi
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.dao.DaoUtil;
import org.thingsboard.server.dao.attributes.AttributesService;
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.service.sync.vc.data.CommitGitRequest;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@ -75,6 +80,9 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.Futures.transformAsync;
@Service
@TbCoreComponent
@RequiredArgsConstructor
@ -109,7 +117,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
public ListenableFuture<VersionCreationResult> saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
var pendingCommit = gitServiceQueue.prepareCommit(user.getTenantId(), request);
return Futures.transformAsync(pendingCommit, commit -> {
return transformAsync(pendingCommit, commit -> {
List<ListenableFuture<Void>> gitFutures = new ArrayList<>();
switch (request.getType()) {
case SINGLE_ENTITY: {
@ -146,7 +154,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
break;
}
}
return Futures.transformAsync(Futures.allAsList(gitFutures), success -> gitServiceQueue.push(commit), executor);
return transformAsync(Futures.allAsList(gitFutures), success -> gitServiceQueue.push(commit), executor);
}, executor);
}
@ -195,7 +203,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
try {
return exportImportService.importEntity(user, entityData, EntityImportSettings.builder()
.updateRelations(config.isLoadRelations())
.findExistingByName(config.isFindExistingEntityByName())
.findExistingByName(false)
.build(), true, true);
} catch (Exception e) {
throw new RuntimeException(e);
@ -298,6 +306,24 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
}
}
@Override
public ListenableFuture<EntityDataDiff> compareEntityDataToVersion(SecurityUser user, String branch, EntityId entityId, String versionId) throws Exception {
HasId<EntityId> entity = exportableEntitiesService.findEntityByTenantIdAndId(user.getTenantId(), entityId);
if (!(entity instanceof ExportableEntity)) throw new IllegalArgumentException("Unsupported entity type");
EntityId externalId = ((ExportableEntity<EntityId>) entity).getExternalId();
if (externalId == null) externalId = entityId;
EntityExportData<?> currentVersion = exportImportService.exportEntity(user, entityId, EntityExportSettings.builder()
.exportRelations(true)
.build());
return transformAsync(gitServiceQueue.getEntity(user.getTenantId(), versionId, externalId),
otherVersion -> transform(gitServiceQueue.getContentsDiff(user.getTenantId(),
JacksonUtil.toPrettyString(currentVersion),
JacksonUtil.toPrettyString(otherVersion)), rawDiff -> {
return new EntityDataDiff(currentVersion, otherVersion, rawDiff);
}, MoreExecutors.directExecutor()), MoreExecutors.directExecutor());
}
@Override
public ListenableFuture<List<String>> listBranches(TenantId tenantId) throws Exception {

83
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java

@ -15,8 +15,6 @@
*/
package org.thingsboard.server.service.sync.vc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.ByteString;
@ -24,6 +22,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
@ -36,6 +35,7 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
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.EntityVersionsDiff;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
@ -54,12 +54,23 @@ import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.ClearRepositoryGitRequest;
import org.thingsboard.server.service.sync.vc.data.CommitGitRequest;
import org.thingsboard.server.service.sync.vc.data.ContentsDiffGitRequest;
import org.thingsboard.server.service.sync.vc.data.EntitiesContentGitRequest;
import org.thingsboard.server.service.sync.vc.data.EntityContentGitRequest;
import org.thingsboard.server.service.sync.vc.data.ListBranchesGitRequest;
import org.thingsboard.server.service.sync.vc.data.ListEntitiesGitRequest;
import org.thingsboard.server.service.sync.vc.data.ListVersionsGitRequest;
import org.thingsboard.server.service.sync.vc.data.PendingGitRequest;
import org.thingsboard.server.service.sync.vc.data.VersionsDiffGitRequest;
import org.thingsboard.server.service.sync.vc.data.VoidGitRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -74,7 +85,6 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
private final DefaultEntitiesVersionControlService entitiesVersionControlService;
private final Map<UUID, PendingGitRequest<?>> pendingRequestMap = new HashMap<>();
private final ObjectMapper jsonMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
public DefaultGitVersionControlQueueService(TbServiceInfoProvider serviceInfoProvider, TbClusterService clusterService,
DataDecodingEncodingService encodingService,
@ -101,13 +111,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
SettableFuture<Void> future = SettableFuture.create();
String path = getRelativePath(entityData.getEntityType(), entityData.getEntity().getId());
String entityDataJson;
try {
entityDataJson = jsonMapper.writeValueAsString(entityData);
} catch (IOException e) {
//TODO: analyze and return meaningful exceptions that we can show to the client;
throw new RuntimeException(e);
}
String entityDataJson = JacksonUtil.toPrettyString(entityData);
registerAndSend(commit, builder -> builder.setCommitRequest(
buildCommitRequest(commit).setAddMsg(
@ -198,10 +202,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
private ListenableFuture<PageData<EntityVersion>> listVersions(TenantId tenantId, ListVersionsRequestMsg requestMsg) {
ListVersionsGitRequest request = new ListVersionsGitRequest(tenantId);
registerAndSend(request, builder -> builder.setListVersionRequest(requestMsg).build(), wrap(request.getFuture()));
return request.getFuture();
return sendRequest(request, builder -> builder.setListVersionRequest(requestMsg));
}
@Override
@ -223,19 +224,32 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
private ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, TransportProtos.ListEntitiesRequestMsg requestMsg) {
ListEntitiesGitRequest request = new ListEntitiesGitRequest(tenantId);
registerAndSend(request, builder -> builder.setListEntitiesRequest(requestMsg).build(), wrap(request.getFuture()));
return request.getFuture();
return sendRequest(request, builder -> builder.setListEntitiesRequest(requestMsg));
}
@Override
public ListenableFuture<List<String>> listBranches(TenantId tenantId) {
ListBranchesGitRequest request = new ListBranchesGitRequest(tenantId);
return sendRequest(request, builder -> builder.setListBranchesRequest(TransportProtos.ListBranchesRequestMsg.newBuilder().build()));
}
registerAndSend(request, builder -> builder.setListBranchesRequest(TransportProtos.ListBranchesRequestMsg.newBuilder().build()).build(), wrap(request.getFuture()));
@Override
public ListenableFuture<List<EntityVersionsDiff>> getVersionsDiff(TenantId tenantId, EntityType entityType, EntityId externalId, String versionId1, String versionId2) {
String path = entityType != null ? getRelativePath(entityType, externalId) : "";
VersionsDiffGitRequest request = new VersionsDiffGitRequest(tenantId, path, versionId1, versionId2);
return sendRequest(request, builder -> builder.setVersionsDiffRequest(TransportProtos.VersionsDiffRequestMsg.newBuilder()
.setPath(request.getPath())
.setVersionId1(request.getVersionId1())
.setVersionId2(request.getVersionId2())
.build()));
}
return request.getFuture();
@Override
public ListenableFuture<String> getContentsDiff(TenantId tenantId, String content1, String content2) {
ContentsDiffGitRequest request = new ContentsDiffGitRequest(tenantId, content1, content2);
return sendRequest(request, builder -> builder.setContentsDiffRequest(TransportProtos.ContentsDiffRequestMsg.newBuilder()
.setContent1(content1)
.setContent2(content2)));
}
@Override
@ -268,6 +282,14 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
}
}
private <T> ListenableFuture<T> sendRequest(PendingGitRequest<T> request, Consumer<ToVersionControlServiceMsg.Builder> enrichFunction) {
registerAndSend(request, builder -> {
enrichFunction.accept(builder);
return builder.build();
}, wrap(request.getFuture()));
return request.getFuture();
}
@Override
@SuppressWarnings("rawtypes")
public ListenableFuture<List<EntityExportData>> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) {
@ -356,6 +378,23 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
var dataList = vcResponseMsg.getEntitiesContentResponse().getDataList();
((EntitiesContentGitRequest) request).getFuture()
.set(dataList.stream().map(this::toData).collect(Collectors.toList()));
} else if (vcResponseMsg.hasVersionsDiffResponse()) {
TransportProtos.VersionsDiffResponseMsg diffResponse = vcResponseMsg.getVersionsDiffResponse();
List<EntityVersionsDiff> entityVersionsDiffList = diffResponse.getDiffList().stream()
.map(diff -> EntityVersionsDiff.builder()
.externalId(EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(diff.getEntityType()),
new UUID(diff.getEntityIdMSB(), diff.getEntityIdLSB())))
.entityDataAtVersion1(StringUtils.isNotEmpty(diff.getEntityDataAtVersion1()) ?
toData(diff.getEntityDataAtVersion1()) : null)
.entityDataAtVersion2(StringUtils.isNotEmpty(diff.getEntityDataAtVersion2()) ?
toData(diff.getEntityDataAtVersion2()) : null)
.rawDiff(diff.getRawDiff())
.build())
.collect(Collectors.toList());
((VersionsDiffGitRequest) request).getFuture().set(entityVersionsDiffList);
} else if (vcResponseMsg.hasContentsDiffResponse()) {
String diff = vcResponseMsg.getContentsDiffResponse().getDiff();
((ContentsDiffGitRequest) request).getFuture().set(diff);
}
}
}
@ -376,7 +415,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@SuppressWarnings("rawtypes")
@SneakyThrows
private EntityExportData toData(String data) {
return jsonMapper.readValue(data, EntityExportData.class);
return JacksonUtil.fromString(data, EntityExportData.class);
}
private static <T> TbQueueCallback wrap(SettableFuture<T> future) {

5
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -17,11 +17,11 @@ package org.thingsboard.server.service.sync.vc;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.sync.vc.EntityDataDiff;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadReques
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import java.util.List;
import java.util.concurrent.ExecutionException;
public interface EntitiesVersionControlService {
@ -50,6 +49,8 @@ public interface EntitiesVersionControlService {
ListenableFuture<List<VersionLoadResult>> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception;
ListenableFuture<EntityDataDiff> compareEntityDataToVersion(SecurityUser user, String branch, EntityId entityId, String versionId) throws Exception;
ListenableFuture<List<String>> listBranches(TenantId tenantId) throws Exception;
EntitiesVersionControlSettings getVersionControlSettings(TenantId tenantId);

6
application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java

@ -29,6 +29,8 @@ import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.gen.transport.TransportProtos.VersionControlResponseMsg;
import org.thingsboard.server.service.sync.vc.data.CommitGitRequest;
import org.thingsboard.server.common.data.sync.vc.EntityVersionsDiff;
import java.util.List;
@ -58,6 +60,10 @@ public interface GitVersionControlQueueService {
ListenableFuture<List<EntityExportData>> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit);
ListenableFuture<List<EntityVersionsDiff>> getVersionsDiff(TenantId tenantId, EntityType entityType, EntityId externalId, String versionId1, String versionId2);
ListenableFuture<String> getContentsDiff(TenantId tenantId, String rawEntityData1, String rawEntityData2);
ListenableFuture<Void> initRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
ListenableFuture<Void> testRepository(TenantId tenantId, EntitiesVersionControlSettings settings);

2
application/src/main/java/org/thingsboard/server/service/sync/vc/ClearRepositoryGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/ClearRepositoryGitRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import org.thingsboard.server.common.data.id.TenantId;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/CommitGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/CommitGitRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import lombok.Getter;
import org.thingsboard.server.common.data.id.TenantId;

33
application/src/main/java/org/thingsboard/server/service/sync/vc/data/ContentsDiffGitRequest.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc.data;
import lombok.Getter;
import org.thingsboard.server.common.data.id.TenantId;
@Getter
public class ContentsDiffGitRequest extends PendingGitRequest<String> {
private final String content1;
private final String content2;
public ContentsDiffGitRequest(TenantId tenantId, String content1, String content2) {
super(tenantId);
this.content1 = content1;
this.content2 = content2;
}
}

3
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesContentGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesContentGitRequest.java

@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import lombok.Getter;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;

2
application/src/main/java/org/thingsboard/server/service/sync/vc/EntityContentGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntityContentGitRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import lombok.Getter;
import org.thingsboard.server.common.data.id.EntityId;

3
application/src/main/java/org/thingsboard/server/service/sync/vc/ListBranchesGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/ListBranchesGitRequest.java

@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import java.util.List;

3
application/src/main/java/org/thingsboard/server/service/sync/vc/ListEntitiesGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/ListEntitiesGitRequest.java

@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import java.util.List;

6
application/src/main/java/org/thingsboard/server/service/sync/vc/ListVersionsGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/ListVersionsGitRequest.java

@ -13,15 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import java.util.List;
public class ListVersionsGitRequest extends PendingGitRequest<PageData<EntityVersion>> {

2
application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/PendingGitRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import com.google.common.util.concurrent.SettableFuture;
import lombok.Getter;

38
application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionsDiffGitRequest.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc.data;
import lombok.Getter;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntityVersionsDiff;
import java.util.List;
@Getter
public class VersionsDiffGitRequest extends PendingGitRequest<List<EntityVersionsDiff>> {
private final String path;
private final String versionId1;
private final String versionId2;
public VersionsDiffGitRequest(TenantId tenantId, String path, String versionId1, String versionId2) {
super(tenantId);
this.path = path;
this.versionId1 = versionId1;
this.versionId2 = versionId2;
}
}

5
application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/VoidGitRequest.java

@ -13,12 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc;
package org.thingsboard.server.service.sync.vc.data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import java.util.List;
public class VoidGitRequest extends PendingGitRequest<Void> {

32
common/cluster-api/src/main/proto/queue.proto

@ -787,6 +787,34 @@ message EntitiesContentResponseMsg {
repeated string data = 1;
}
message VersionsDiffRequestMsg {
string path = 1;
string versionId1 = 2;
string versionId2 = 3;
}
message VersionsDiffResponseMsg {
repeated EntityVersionsDiff diff = 1;
}
message EntityVersionsDiff {
string entityType = 1;
int64 entityIdMSB = 2;
int64 entityIdLSB = 3;
string entityDataAtVersion1 = 4;
string entityDataAtVersion2 = 5;
string rawDiff = 6;
}
message ContentsDiffRequestMsg {
string content1 = 1;
string content2 = 2;
}
message ContentsDiffResponseMsg {
string diff = 1;
}
message GenericRepositoryRequestMsg {}
message GenericRepositoryResponseMsg {}
@ -807,6 +835,8 @@ message ToVersionControlServiceMsg {
ListBranchesRequestMsg listBranchesRequest = 13;
EntityContentRequestMsg entityContentRequest = 14;
EntitiesContentRequestMsg entitiesContentRequest = 15;
VersionsDiffRequestMsg versionsDiffRequest = 16;
ContentsDiffRequestMsg contentsDiffRequest = 17;
}
message VersionControlResponseMsg {
@ -820,6 +850,8 @@ message VersionControlResponseMsg {
ListVersionsResponseMsg listVersionsResponse = 8;
EntityContentResponseMsg entityContentResponse = 9;
EntitiesContentResponseMsg entitiesContentResponse = 10;
VersionsDiffResponseMsg versionsDiffResponse = 11;
ContentsDiffResponseMsg contentsDiffResponse = 12;
}
/**

28
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataDiff.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.sync.vc;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
@Data
@AllArgsConstructor
public class EntityDataDiff {
private EntityExportData<?> currentVersion;
private EntityExportData<?> otherVersion;
private String rawDiff;
}

34
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityVersionsDiff.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.sync.vc;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EntityVersionsDiff {
private EntityId externalId;
private EntityExportData<?> entityDataAtVersion1;
private EntityExportData<?> entityDataAtVersion2;
private String rawDiff;
}

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/EntityTypeVersionLoadConfig.java

@ -23,5 +23,6 @@ import lombok.EqualsAndHashCode;
public class EntityTypeVersionLoadConfig extends VersionLoadConfig {
private boolean removeOtherEntities;
private boolean findExistingEntityByName;
}

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadConfig.java

@ -21,6 +21,5 @@ import lombok.Data;
public class VersionLoadConfig {
private boolean loadRelations;
private boolean findExistingEntityByName;
}

13
common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java

@ -19,12 +19,11 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Created by Valerii Sosliuk on 5/12/2017.
@ -32,6 +31,8 @@ import java.util.Set;
public class JacksonUtil {
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static final ObjectMapper PRETTY_JSON_MAPPER = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT);
public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
try {
@ -96,6 +97,14 @@ public class JacksonUtil {
}
}
public static String toPrettyString(Object o) {
try {
return PRETTY_JSON_MAPPER.writeValueAsString(o);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static JsonNode toJsonNode(String value) {
if (value == null || value.isEmpty()) {
return null;

39
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java

@ -31,6 +31,7 @@ import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
@ -92,6 +93,8 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.thingsboard.server.service.sync.vc.DefaultGitRepositoryService.fromRelativePath;
@Slf4j
@TbVersionControlComponent
@Service
@ -238,17 +241,18 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
vcService.fetch(ctx.getTenantId());
handleListBranches(ctx, msg.getListBranchesRequest());
} else if (msg.hasListEntitiesRequest()) {
vcService.fetch(ctx.getTenantId());
handleListEntities(ctx, msg.getListEntitiesRequest());
} else if (msg.hasListVersionRequest()) {
vcService.fetch(ctx.getTenantId());
handleListVersions(ctx, msg.getListVersionRequest());
} else if (msg.hasEntityContentRequest()) {
vcService.fetch(ctx.getTenantId());
handleEntityContentRequest(ctx, msg.getEntityContentRequest());
} else if (msg.hasEntitiesContentRequest()) {
vcService.fetch(ctx.getTenantId());
handleEntitiesContentRequest(ctx, msg.getEntitiesContentRequest());
} else if (msg.hasVersionsDiffRequest()) {
handleVersionsDiffRequest(ctx, msg.getVersionsDiffRequest());
} else if (msg.hasContentsDiffRequest()) {
handleContentsDiffRequest(ctx, msg.getContentsDiffRequest());
}
}
}
@ -332,6 +336,31 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
reply(ctx, Optional.empty(), builder -> builder.setListBranchesResponse(ListBranchesResponseMsg.newBuilder().addAllBranches(branches)));
}
private void handleVersionsDiffRequest(VersionControlRequestCtx ctx, TransportProtos.VersionsDiffRequestMsg request) throws IOException {
List<TransportProtos.EntityVersionsDiff> diffList = vcService.getVersionsDiffList(ctx.getTenantId(), request.getPath(), request.getVersionId1(), request.getVersionId2()).stream()
.map(diff -> {
EntityId entityId = fromRelativePath(diff.getFilePath());
return TransportProtos.EntityVersionsDiff.newBuilder()
.setEntityType(entityId.getEntityType().name())
.setEntityIdMSB(entityId.getId().getMostSignificantBits())
.setEntityIdLSB(entityId.getId().getLeastSignificantBits())
.setEntityDataAtVersion1(diff.getFileContentAtCommit1())
.setEntityDataAtVersion2(diff.getFileContentAtCommit2())
.setRawDiff(diff.getDiffStringValue())
.build();
})
.collect(Collectors.toList());
reply(ctx, builder -> builder.setVersionsDiffResponse(TransportProtos.VersionsDiffResponseMsg.newBuilder()
.addAllDiff(diffList)));
}
private void handleContentsDiffRequest(VersionControlRequestCtx ctx, TransportProtos.ContentsDiffRequestMsg request) throws IOException {
String diff = vcService.getContentsDiff(ctx.getTenantId(), request.getContent1(), request.getContent2());
reply(ctx, builder -> builder.setContentsDiffResponse(TransportProtos.ContentsDiffResponseMsg.newBuilder()
.setDiff(diff)));
}
private void handleCommitRequest(VersionControlRequestCtx ctx, CommitRequestMsg request) throws Exception {
var tenantId = ctx.getTenantId();
UUID txId = UUID.fromString(request.getTxId());
@ -440,6 +469,10 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
reply(ctx, e, null);
}
private void reply(VersionControlRequestCtx ctx, Function<VersionControlResponseMsg.Builder, VersionControlResponseMsg.Builder> enrichFunction) {
reply(ctx, Optional.empty(), enrichFunction);
}
private void reply(VersionControlRequestCtx ctx, Optional<Exception> e, Function<VersionControlResponseMsg.Builder, VersionControlResponseMsg.Builder> enrichFunction) {
TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, ctx.getNodeId());
VersionControlResponseMsg.Builder builder = VersionControlResponseMsg.newBuilder()

21
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitRepositoryService.java

@ -33,6 +33,7 @@ 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.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.GitRepository.Diff;
import javax.annotation.PostConstruct;
import java.io.File;
@ -167,6 +168,18 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
return repository.getFileContentAtCommit(relativePath, versionId);
}
@Override
public List<Diff> getVersionsDiffList(TenantId tenantId, String path, String versionId1, String versionId2) throws IOException {
GitRepository repository = checkRepository(tenantId);
return repository.getDiffList(versionId1, versionId2, path);
}
@Override
public String getContentsDiff(TenantId tenantId, String content1, String content2) throws IOException {
GitRepository repository = checkRepository(tenantId);
return repository.getContentsDiff(content1, content2);
}
@Override
public List<String> listBranches(TenantId tenantId) {
GitRepository repository = checkRepository(tenantId);
@ -178,12 +191,6 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
}
}
private EntityVersion checkVersion(TenantId tenantId, String branch, String versionId) throws Exception {
return listVersions(tenantId, branch, null, new PageLink(Integer.MAX_VALUE)).getData().stream()
.filter(version -> version.getId().equals(versionId))
.findFirst().orElseThrow(() -> new IllegalArgumentException("Version not found"));
}
private GitRepository checkRepository(TenantId tenantId) {
return Optional.ofNullable(repositories.get(tenantId))
.orElseThrow(() -> new IllegalStateException("Repository is not initialized"));
@ -251,7 +258,7 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
return new EntityVersion(commit.getTimestamp(), commit.getId(), commit.getMessage());
}
private EntityId fromRelativePath(String path) {
public static EntityId fromRelativePath(String path) {
EntityType entityType = EntityType.valueOf(StringUtils.substringBefore(path, "/").toUpperCase());
String entityId = StringUtils.substringBetween(path, "/", ".json");
return EntityIdFactory.getByTypeAndUuid(entityType, entityId);

106
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java

@ -31,6 +31,12 @@ 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.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.EditList;
import org.eclipse.jgit.diff.HistogramDiff;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@ -46,6 +52,7 @@ import org.eclipse.jgit.transport.sshd.JGitKeyCache;
import org.eclipse.jgit.transport.sshd.ServerKeyDatabase;
import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.thingsboard.server.common.data.page.PageData;
@ -55,6 +62,7 @@ import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings
import org.thingsboard.server.common.data.sync.vc.VersionControlAuthMethod;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -215,7 +223,7 @@ public class GitRepository {
RevCommit revCommit = resolveCommit(commitId);
try (TreeWalk treeWalk = TreeWalk.forPath(git.getRepository(), file, revCommit.getTree())) {
if (treeWalk == null) {
throw new IllegalArgumentException("Not found");
throw new IllegalArgumentException("File not found");
}
ObjectId blobId = treeWalk.getObjectId(0);
try (ObjectReader objectReader = git.getRepository().newObjectReader()) {
@ -259,37 +267,62 @@ public class GitRepository {
.setRefSpecs(new RefSpec(localBranch + ":" + remoteBranch)));
}
public String getContentsDiff(String content1, String content2) throws IOException {
RawText rawContent1 = new RawText(content1.getBytes());
RawText rawContent2 = new RawText(content2.getBytes());
// public List<Diff> getCommitChanges(Commit commit) throws IOException, GitAPIException {
// RevCommit revCommit = resolveCommit(commit.getId());
// if (revCommit.getParentCount() == 0) {
// return null; // just takes the first parent of a commit, but should find a parent in branch provided
// }
// return execute(git.diff()
// .setOldTree(prepareTreeParser(git.getRepository().parseCommit(revCommit.getParent(0))))
// .setNewTree(prepareTreeParser(revCommit))).stream()
// .map(diffEntry -> new Diff(diffEntry.getChangeType().name(), diffEntry.getOldPath(), diffEntry.getNewPath()))
// .collect(Collectors.toList());
// }
//
//
// private AbstractTreeIterator prepareTreeParser(RevCommit revCommit) throws IOException {
// // from the commit we can build the tree which allows us to construct the TreeParser
// //noinspection Duplicates
// org.eclipse.jgit.lib.Repository repository = git.getRepository();
// try (RevWalk walk = new RevWalk(repository)) {
// RevTree tree = walk.parseTree(revCommit.getTree().getId());
//
// CanonicalTreeParser treeParser = new CanonicalTreeParser();
// try (ObjectReader reader = repository.newObjectReader()) {
// treeParser.reset(reader, tree.getId());
// }
//
// walk.dispose();
//
// return treeParser;
// }
// }
ByteArrayOutputStream out = new ByteArrayOutputStream();
DiffFormatter diffFormatter = new DiffFormatter(out);
diffFormatter.setRepository(git.getRepository());
EditList edits = new EditList();
edits.addAll(new HistogramDiff().diff(RawTextComparator.DEFAULT, rawContent1, rawContent2));
diffFormatter.format(edits, rawContent1, rawContent2);
return out.toString();
}
public List<Diff> getDiffList(String commit1, String commit2, String path) throws IOException {
ObjectReader reader = git.getRepository().newObjectReader();
CanonicalTreeParser tree1Iter = new CanonicalTreeParser();
ObjectId tree1 = resolveCommit(commit1).getTree();
tree1Iter.reset(reader, tree1);
CanonicalTreeParser tree2Iter = new CanonicalTreeParser();
ObjectId tree2 = resolveCommit(commit2).getTree();
tree2Iter.reset(reader, tree2);
ByteArrayOutputStream out = new ByteArrayOutputStream();
DiffFormatter diffFormatter = new DiffFormatter(out);
diffFormatter.setRepository(git.getRepository());
if (StringUtils.isNotEmpty(path)) {
diffFormatter.setPathFilter(PathFilter.create(path));
}
return diffFormatter.scan(tree1, tree2).stream()
.map(diffEntry -> {
Diff diff = new Diff();
try {
out.reset();
diffFormatter.format(diffEntry);
diff.setDiffStringValue(out.toString());
diff.setFilePath(diffEntry.getChangeType() != DiffEntry.ChangeType.DELETE ? diffEntry.getNewPath() : diffEntry.getOldPath());
diff.setChangeType(diffEntry.getChangeType());
try {
diff.setFileContentAtCommit1(getFileContentAtCommit(diff.getFilePath(), commit1));
} catch (IllegalArgumentException ignored) {
}
try {
diff.setFileContentAtCommit2(getFileContentAtCommit(diff.getFilePath(), commit2));
} catch (IllegalArgumentException ignored) {
}
return diff;
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
private Commit toCommit(RevCommit revCommit) {
return new Commit(revCommit.getCommitTime() * 1000l, revCommit.getName(), revCommit.getFullMessage(), revCommit.getAuthorIdent().getName());
@ -320,7 +353,7 @@ public class GitRepository {
return null;
};
private static <T,R> PageData<R> iterableToPageData (Iterable<T> iterable,
private static <T, R> PageData<R> iterableToPageData(Iterable<T> iterable,
Function<? super T, ? extends R> mapper,
PageLink pageLink,
Function<PageLink, Comparator<T>> comparatorFunction) {
@ -446,4 +479,13 @@ public class GitRepository {
private final Set<String> removed;
}
@Data
public static class Diff {
private String filePath;
private DiffEntry.ChangeType changeType;
private String fileContentAtCommit1;
private String fileContentAtCommit2;
private String diffStringValue;
}
}

5
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepositoryService.java

@ -23,6 +23,7 @@ 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.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.GitRepository.Diff;
import java.io.IOException;
import java.util.List;
@ -60,5 +61,9 @@ public interface GitRepositoryService {
String getFileContentAtCommit(TenantId tenantId, String relativePath, String versionId) throws IOException;
List<Diff> getVersionsDiffList(TenantId tenantId, String path, String versionId1, String versionId2) throws IOException;
String getContentsDiff(TenantId tenantId, String content1, String content2) throws IOException;
void fetch(TenantId tenantId) throws GitAPIException;
}

Loading…
Cancel
Save