Merge branch 'feature/entities-version-control' of github.com:thingsboard/thingsboard into feature/entities-version-control
This commit is contained in:
		
						commit
						bf03475987
					
				@ -119,7 +119,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
 | 
			
		||||
    @SuppressWarnings("UnstableApiUsage")
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<VersionCreationResult> saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
 | 
			
		||||
        var pendingCommit = gitServiceQueue.prepareCommit(user.getTenantId(), request);
 | 
			
		||||
        var pendingCommit = gitServiceQueue.prepareCommit(user, request);
 | 
			
		||||
 | 
			
		||||
        return transformAsync(pendingCommit, commit -> {
 | 
			
		||||
            List<ListenableFuture<Void>> gitFutures = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ import org.thingsboard.server.cluster.TbClusterService;
 | 
			
		||||
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.User;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityIdFactory;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
@ -66,10 +67,7 @@ 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.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
@ -96,12 +94,12 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<CommitGitRequest> prepareCommit(TenantId tenantId, VersionCreateRequest request) {
 | 
			
		||||
    public ListenableFuture<CommitGitRequest> prepareCommit(User user, VersionCreateRequest request) {
 | 
			
		||||
        SettableFuture<CommitGitRequest> future = SettableFuture.create();
 | 
			
		||||
 | 
			
		||||
        CommitGitRequest commit = new CommitGitRequest(tenantId, request);
 | 
			
		||||
        CommitGitRequest commit = new CommitGitRequest(user.getTenantId(), request);
 | 
			
		||||
        registerAndSend(commit, builder -> builder.setCommitRequest(
 | 
			
		||||
                buildCommitRequest(commit).setPrepareMsg(getCommitPrepareMsg(request)).build()
 | 
			
		||||
                buildCommitRequest(commit).setPrepareMsg(getCommitPrepareMsg(user, request)).build()
 | 
			
		||||
        ).build(), wrap(future, commit));
 | 
			
		||||
        return future;
 | 
			
		||||
    }
 | 
			
		||||
@ -356,7 +354,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
 | 
			
		||||
            } else if (vcResponseMsg.hasCommitResponse()) {
 | 
			
		||||
                var commitResponse = vcResponseMsg.getCommitResponse();
 | 
			
		||||
                var commitResult = new VersionCreationResult();
 | 
			
		||||
                commitResult.setVersion(new EntityVersion(commitResponse.getTs(), commitResponse.getCommitId(), commitResponse.getName()));
 | 
			
		||||
                commitResult.setVersion(new EntityVersion(commitResponse.getTs(), commitResponse.getCommitId(), commitResponse.getName(), commitResponse.getAuthor()));
 | 
			
		||||
                commitResult.setAdded(commitResponse.getAdded());
 | 
			
		||||
                commitResult.setRemoved(commitResponse.getRemoved());
 | 
			
		||||
                commitResult.setModified(commitResponse.getModified());
 | 
			
		||||
@ -405,7 +403,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private EntityVersion getEntityVersion(TransportProtos.EntityVersionProto proto) {
 | 
			
		||||
        return new EntityVersion(proto.getTs(), proto.getId(), proto.getName());
 | 
			
		||||
        return new EntityVersion(proto.getTs(), proto.getId(), proto.getName(), proto.getAuthor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private VersionedEntityInfo getVersionedEntityInfo(TransportProtos.VersionedEntityInfoProto proto) {
 | 
			
		||||
@ -453,8 +451,23 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static PrepareMsg getCommitPrepareMsg(VersionCreateRequest request) {
 | 
			
		||||
        return PrepareMsg.newBuilder().setCommitMsg(request.getVersionName()).setBranchName(request.getBranch()).build();
 | 
			
		||||
    private static PrepareMsg getCommitPrepareMsg(User user, VersionCreateRequest request) {
 | 
			
		||||
        return PrepareMsg.newBuilder().setCommitMsg(request.getVersionName())
 | 
			
		||||
                .setBranchName(request.getBranch()).setAuthorName(getAuthorName(user)).setAuthorEmail(user.getEmail()).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String getAuthorName(User user) {
 | 
			
		||||
        List<String> parts = new ArrayList<>();
 | 
			
		||||
        if (StringUtils.isNotBlank(user.getFirstName())) {
 | 
			
		||||
            parts.add(user.getFirstName());
 | 
			
		||||
        }
 | 
			
		||||
        if (StringUtils.isNotBlank(user.getLastName())) {
 | 
			
		||||
            parts.add(user.getLastName());
 | 
			
		||||
        }
 | 
			
		||||
        if (parts.isEmpty()) {
 | 
			
		||||
            parts.add(user.getName());
 | 
			
		||||
        }
 | 
			
		||||
        return String.join(" ", parts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ToVersionControlServiceMsg.Builder newRequestProto(PendingGitRequest<?> request, RepositorySettings settings) {
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ 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.ExportableEntity;
 | 
			
		||||
import org.thingsboard.server.common.data.User;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
@ -36,7 +37,7 @@ import java.util.List;
 | 
			
		||||
 | 
			
		||||
public interface GitVersionControlQueueService {
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<CommitGitRequest> prepareCommit(TenantId tenantId, VersionCreateRequest request);
 | 
			
		||||
    ListenableFuture<CommitGitRequest> prepareCommit(User user, VersionCreateRequest request);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Void> addToCommit(CommitGitRequest commit, EntityExportData<ExportableEntity<EntityId>> entityData);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -692,14 +692,17 @@ message CommitResponseMsg {
 | 
			
		||||
  int64 ts = 1;
 | 
			
		||||
  string commitId = 2;
 | 
			
		||||
  string name = 3;
 | 
			
		||||
  int32 added = 4;
 | 
			
		||||
  int32 modified = 5;
 | 
			
		||||
  int32 removed = 6;
 | 
			
		||||
  string author = 4;
 | 
			
		||||
  int32 added = 5;
 | 
			
		||||
  int32 modified = 6;
 | 
			
		||||
  int32 removed = 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message PrepareMsg {
 | 
			
		||||
  string commitMsg = 1;
 | 
			
		||||
  string branchName = 2;
 | 
			
		||||
  string authorName = 3;
 | 
			
		||||
  string authorEmail = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message AddMsg {
 | 
			
		||||
@ -733,6 +736,7 @@ message EntityVersionProto {
 | 
			
		||||
  int64 ts = 1;
 | 
			
		||||
  string id = 2;
 | 
			
		||||
  string name = 3;
 | 
			
		||||
  string author = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ListVersionsResponseMsg {
 | 
			
		||||
 | 
			
		||||
@ -26,4 +26,5 @@ public class EntityVersion {
 | 
			
		||||
    private long timestamp;
 | 
			
		||||
    private String id;
 | 
			
		||||
    private String name;
 | 
			
		||||
    private String author;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -312,7 +312,7 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
 | 
			
		||||
                        .setTotalElements(data.getTotalElements())
 | 
			
		||||
                        .setHasNext(data.hasNext())
 | 
			
		||||
                        .addAllVersions(data.getData().stream().map(
 | 
			
		||||
                                v -> EntityVersionProto.newBuilder().setTs(v.getTimestamp()).setId(v.getId()).setName(v.getName()).build()
 | 
			
		||||
                                v -> EntityVersionProto.newBuilder().setTs(v.getTimestamp()).setId(v.getId()).setName(v.getName()).setAuthor(v.getAuthor()).build()
 | 
			
		||||
                        ).collect(Collectors.toList())))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@ -397,7 +397,8 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
 | 
			
		||||
 | 
			
		||||
    private void prepareCommit(VersionControlRequestCtx ctx, UUID txId, PrepareMsg prepareMsg) {
 | 
			
		||||
        var tenantId = ctx.getTenantId();
 | 
			
		||||
        var pendingCommit = new PendingCommit(tenantId, ctx.getNodeId(), txId, prepareMsg.getBranchName(), prepareMsg.getCommitMsg());
 | 
			
		||||
        var pendingCommit = new PendingCommit(tenantId, ctx.getNodeId(), txId, prepareMsg.getBranchName(),
 | 
			
		||||
                prepareMsg.getCommitMsg(), prepareMsg.getAuthorName(), prepareMsg.getAuthorEmail());
 | 
			
		||||
        PendingCommit old = pendingCommitMap.get(tenantId);
 | 
			
		||||
        if (old != null) {
 | 
			
		||||
            doAbortCurrentCommit(tenantId, old);
 | 
			
		||||
@ -460,6 +461,7 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
 | 
			
		||||
                .setTs(result.getVersion().getTimestamp())
 | 
			
		||||
                .setCommitId(result.getVersion().getId())
 | 
			
		||||
                .setName(result.getVersion().getName())
 | 
			
		||||
                .setAuthor(result.getVersion().getAuthor())
 | 
			
		||||
                .setAdded(result.getAdded())
 | 
			
		||||
                .setModified(result.getModified())
 | 
			
		||||
                .setRemoved(result.getRemoved())));
 | 
			
		||||
 | 
			
		||||
@ -117,7 +117,7 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
 | 
			
		||||
            result.setModified(status.getModified().size());
 | 
			
		||||
            result.setRemoved(status.getRemoved().size());
 | 
			
		||||
 | 
			
		||||
            GitRepository.Commit gitCommit = repository.commit(commit.getVersionName());
 | 
			
		||||
            GitRepository.Commit gitCommit = repository.commit(commit.getVersionName(), commit.getAuthorName(), commit.getAuthorEmail());
 | 
			
		||||
            repository.push(commit.getWorkingBranch(), commit.getBranch());
 | 
			
		||||
 | 
			
		||||
            result.setVersion(toVersion(gitCommit));
 | 
			
		||||
@ -255,7 +255,15 @@ public class DefaultGitRepositoryService implements GitRepositoryService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private EntityVersion toVersion(GitRepository.Commit commit) {
 | 
			
		||||
        return new EntityVersion(commit.getTimestamp(), commit.getId(), commit.getMessage());
 | 
			
		||||
        return new EntityVersion(commit.getTimestamp(), commit.getId(), commit.getMessage(), this.getAuthor(commit));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getAuthor(GitRepository.Commit commit) {
 | 
			
		||||
        String author = String.format("<%s>", commit.getAuthorEmail());
 | 
			
		||||
        if (StringUtils.isNotBlank(commit.getAuthorName())) {
 | 
			
		||||
            author = String.format("%s %s", commit.getAuthorName(), author);
 | 
			
		||||
        }
 | 
			
		||||
        return author;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static EntityId fromRelativePath(String path) {
 | 
			
		||||
 | 
			
		||||
@ -255,8 +255,9 @@ public class GitRepository {
 | 
			
		||||
        return new Status(status.getAdded(), modified, status.getRemoved());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Commit commit(String message) throws GitAPIException {
 | 
			
		||||
    public Commit commit(String message, String authorName, String authorEmail) throws GitAPIException {
 | 
			
		||||
        RevCommit revCommit = execute(git.commit()
 | 
			
		||||
                .setAuthor(authorName, authorEmail)
 | 
			
		||||
                .setMessage(message));
 | 
			
		||||
        return toCommit(revCommit);
 | 
			
		||||
    }
 | 
			
		||||
@ -325,7 +326,8 @@ public class GitRepository {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Commit toCommit(RevCommit revCommit) {
 | 
			
		||||
        return new Commit(revCommit.getCommitTime() * 1000l, revCommit.getName(), revCommit.getFullMessage(), revCommit.getAuthorIdent().getName());
 | 
			
		||||
        return new Commit(revCommit.getCommitTime() * 1000l, revCommit.getName(),
 | 
			
		||||
                revCommit.getFullMessage(), revCommit.getAuthorIdent().getName(), revCommit.getAuthorIdent().getEmailAddress());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RevCommit resolveCommit(String id) throws IOException {
 | 
			
		||||
@ -470,6 +472,7 @@ public class GitRepository {
 | 
			
		||||
        private final String id;
 | 
			
		||||
        private final String message;
 | 
			
		||||
        private final String authorName;
 | 
			
		||||
        private final String authorEmail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Data
 | 
			
		||||
 | 
			
		||||
@ -30,12 +30,18 @@ public class PendingCommit {
 | 
			
		||||
    private String branch;
 | 
			
		||||
    private String versionName;
 | 
			
		||||
 | 
			
		||||
    public PendingCommit(TenantId tenantId, String nodeId, UUID txId, String branch, String versionName) {
 | 
			
		||||
    private String authorName;
 | 
			
		||||
 | 
			
		||||
    private String authorEmail;
 | 
			
		||||
 | 
			
		||||
    public PendingCommit(TenantId tenantId, String nodeId, UUID txId, String branch, String versionName, String authorName, String authorEmail) {
 | 
			
		||||
        this.tenantId = tenantId;
 | 
			
		||||
        this.nodeId = nodeId;
 | 
			
		||||
        this.txId = txId;
 | 
			
		||||
        this.branch = branch;
 | 
			
		||||
        this.versionName = versionName;
 | 
			
		||||
        this.authorName = authorName;
 | 
			
		||||
        this.authorEmail = authorEmail;
 | 
			
		||||
        this.workingBranch = txId.toString();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -101,11 +101,17 @@
 | 
			
		||||
          </mat-cell>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
        <ng-container matColumnDef="name">
 | 
			
		||||
          <mat-header-cell *matHeaderCellDef style="width: 100%"> {{ 'version-control.version-name' | translate }} </mat-header-cell>
 | 
			
		||||
          <mat-header-cell *matHeaderCellDef style="width: 50%"> {{ 'version-control.version-name' | translate }} </mat-header-cell>
 | 
			
		||||
          <mat-cell *matCellDef="let entityVersion">
 | 
			
		||||
            {{ entityVersion.name }}
 | 
			
		||||
          </mat-cell>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
        <ng-container matColumnDef="author">
 | 
			
		||||
          <mat-header-cell *matHeaderCellDef style="width: 50%"> {{ 'version-control.author' | translate }} </mat-header-cell>
 | 
			
		||||
          <mat-cell *matCellDef="let entityVersion">
 | 
			
		||||
            {{ entityVersion.author }}
 | 
			
		||||
          </mat-cell>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
        <ng-container matColumnDef="actions" stickyEnd>
 | 
			
		||||
          <mat-header-cell *matHeaderCellDef [ngStyle]="singleEntityMode ? {minWidth: '80px', maxWidth: '80px', width: '80px'} :
 | 
			
		||||
                                                                           {minWidth: '40px', maxWidth: '40px', width: '40px'}">
 | 
			
		||||
 | 
			
		||||
@ -62,7 +62,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
 | 
			
		||||
  @Input()
 | 
			
		||||
  singleEntityMode = false;
 | 
			
		||||
 | 
			
		||||
  displayedColumns = ['timestamp', 'id', 'name', 'actions'];
 | 
			
		||||
  displayedColumns = ['timestamp', 'id', 'name', 'author', 'actions'];
 | 
			
		||||
  pageLink: PageLink;
 | 
			
		||||
  textSearchMode = false;
 | 
			
		||||
  dataSource: EntityVersionsDatasource;
 | 
			
		||||
 | 
			
		||||
@ -138,6 +138,7 @@ export interface EntityVersion {
 | 
			
		||||
  timestamp: number;
 | 
			
		||||
  id: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  author: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface VersionCreationResult {
 | 
			
		||||
 | 
			
		||||
@ -3119,6 +3119,7 @@
 | 
			
		||||
        "create-entity-version": "Create entity version",
 | 
			
		||||
        "version-name": "Version name",
 | 
			
		||||
        "version-name-required": "Version name is required",
 | 
			
		||||
        "author": "Author",
 | 
			
		||||
        "export-entity-relations": "Export entity relations",
 | 
			
		||||
        "entity-versions": "Entity versions",
 | 
			
		||||
        "versions": "Versions",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user