Skip to content

Commit 05de8f1

Browse files
authored
Merge pull request #271 from Open-MBEE/release/4.0.20
Release/4.0.20
2 parents adc1e8c + 95a9d95 commit 05de8f1

File tree

22 files changed

+1772
-47
lines changed

22 files changed

+1772
-47
lines changed

.circleci/config.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,21 @@ jobs:
2020

2121
- setup_remote_docker
2222

23-
- run:
23+
- run:
2424
name: "Create and start all services from the docker-compose configuration"
2525
command: |
2626
cp example/src/main/resources/application.properties.example ./example/src/main/resources/application.properties
2727
docker-compose up --build -d
2828
docker run --network container:mms curlimages/curl --retry 8 --retry-delay 10 --retry-max-time 90 --retry-connrefused http://mms:8080/healthcheck
2929
30-
- run:
30+
- run:
3131
name: "Run and test Postman Collection"
3232
command: |
3333
docker create -v /etc/newman --name mms_test_configs alpine:3.4 /bin/true
3434
docker cp example/. mms_test_configs:/etc/newman
3535
docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run crud.postman_collection.json -e test-env.json --delay-request 500
36+
docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run getAtCommits.postman_collection.json -e test-env.json --delay-request 500
37+
docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run makeBranchFromCommit.postman_collection.json -e test-env.json --delay-request 500
3638
docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run cameo.postman_collection.json -e test-env.json --delay-request 1000
3739
docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run jupyter.postman_collection.json -e test-env.json --delay-request 500
3840
docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run localauth.postman_collection.json -e test-env.json --delay-request 500

.readthedocs.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ sphinx:
1717

1818
# We recommend specifying your dependencies to enable reproducible builds:
1919
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
20-
# python:
21-
# install:
22-
# - requirements: docs/requirements.txt
20+
python:
21+
install:
22+
- requirements: docs/requirements.txt

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ subprojects {
6262

6363
group = "org.openmbee.mms"
6464
version = rootProject.version
65+
ext['jackson-bom.version'] = jacksonVersion
6566

6667
Map<String, String> commonDependencies = rootProject.ext.commonDependencies
6768

@@ -157,4 +158,4 @@ subprojects {
157158
sign publishing.publications.mavenJava
158159
}
159160
}
160-
}
161+
}

core/src/main/java/org/openmbee/mms/core/dao/CommitIndexDAO.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public interface CommitIndexDAO {
2525

2626
List<CommitJson> elementHistory(String id, Set<String> commitIds);
2727

28+
List<CommitJson> elementDeletedHistory(String id, Collection<String> commitIds);
29+
2830
CommitJson update(CommitJson commitJson);
2931

3032
}

core/src/main/java/org/openmbee/mms/core/services/BranchService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public interface BranchService {
1010
RefsResponse getBranch(String projectId, String id);
1111

1212
RefJson createBranch(String projectId, RefJson branch);
13+
RefJson createBranchfromCommit(String projectId, RefJson branch, NodeService nodeService);
1314

1415
RefsResponse deleteBranch(String projectId, String id);
1516
}

crud/src/main/java/org/openmbee/mms/crud/controllers/branches/BranchesController.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ public RefsResponse createRefs(
9696
if (branch.getParentCommitId() == null || branch.getParentCommitId().isEmpty()) {
9797
res = branchService.createBranch(projectId, branch);
9898
} else {
99-
//TODO implement branching from historical commit
100-
response.addRejection(new Rejection(branch, 400, "Branching from historical commits is not implemented."));
101-
continue;
99+
res = branchService.createBranchfromCommit(projectId, branch, getNodeService(projectId));
102100
}
103101

104102
permissionService.initBranchPerms(projectId, branch.getId(), true, auth.getName());

crud/src/main/java/org/openmbee/mms/crud/services/DefaultBranchService.java

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@
55
import org.openmbee.mms.core.config.Constants;
66
import org.openmbee.mms.core.config.ContextHolder;
77
import org.openmbee.mms.core.config.Formats;
8-
import org.openmbee.mms.core.dao.BranchDAO;
9-
import org.openmbee.mms.core.dao.BranchIndexDAO;
10-
import org.openmbee.mms.core.dao.CommitDAO;
11-
import org.openmbee.mms.core.dao.NodeDAO;
12-
import org.openmbee.mms.core.dao.NodeIndexDAO;
8+
import org.openmbee.mms.core.dao.*;
139
import org.openmbee.mms.core.exceptions.BadRequestException;
1410
import org.openmbee.mms.core.exceptions.DeletedException;
1511
import org.openmbee.mms.core.exceptions.InternalErrorException;
@@ -18,9 +14,11 @@
1814
import org.openmbee.mms.core.objects.RefsResponse;
1915
import org.openmbee.mms.core.services.BranchService;
2016
import org.openmbee.mms.core.services.EventService;
17+
import org.openmbee.mms.core.services.NodeService;
2118
import org.openmbee.mms.data.domains.scoped.Branch;
2219
import org.openmbee.mms.data.domains.scoped.Commit;
2320
import org.openmbee.mms.data.domains.scoped.Node;
21+
import org.openmbee.mms.json.ElementJson;
2422
import org.openmbee.mms.json.RefJson;
2523
import org.slf4j.Logger;
2624
import org.slf4j.LoggerFactory;
@@ -45,6 +43,15 @@ public class DefaultBranchService implements BranchService {
4543
private NodeIndexDAO nodeIndex;
4644

4745
protected Collection<EventService> eventPublisher;
46+
protected NodeGetHelper nodeGetHelper;
47+
48+
49+
50+
@Autowired
51+
public void setNodeGetHelper(NodeGetHelper nodeGetHelper) {
52+
this.nodeGetHelper = nodeGetHelper;
53+
}
54+
4855

4956
@Autowired
5057
public void setBranchRepository(BranchDAO branchRepository) {
@@ -129,8 +136,8 @@ public RefJson createBranch(String projectId, RefJson branch) {
129136
branch.setCreated(Formats.FORMATTER.format(now));
130137
branch.setDeleted(false);
131138
branch.setProjectId(projectId);
132-
branch.setStatus("created");
133-
139+
boolean fromCommit = branch.getParentCommitId() == null ? false : true;
140+
branch.setStatus(fromCommit ? "creating" : "created");
134141
if (branch.getDocId() == null || branch.getDocId().isEmpty()) {
135142
String docId = branchIndex.createDocId(branch);
136143
branch.setDocId(docId);
@@ -145,18 +152,26 @@ public RefJson createBranch(String projectId, RefJson branch) {
145152
b.setParentRefId(Constants.MASTER_BRANCH);
146153
}
147154

148-
//This service cannot create branches from historic versions
149-
if (branch.getParentCommitId() != null) {
150-
throw new BadRequestException("Internal Error: Invalid branch creation logic.");
151-
}
152-
153155
Optional<Branch> refOption = branchRepository.findByBranchId(b.getParentRefId());
154156
if (refOption.isPresent()) {
155-
Optional<Commit> parentCommit = commitRepository.findLatestByRef(refOption.get());
156-
parentCommit.ifPresent(parent -> {
157-
b.setParentCommit(parent.getId());
158-
branch.setParentCommitId(parent.getCommitId()); //commit id is same as its docId
159-
});
157+
if(branch.getParentCommitId() != null){
158+
Optional<Commit> commitRequestId = commitRepository.findByCommitId(branch.getParentCommitId());
159+
commitRequestId.ifPresentOrElse(commit -> {
160+
Optional<Commit> parentCommit = commitRepository.findByRefAndTimestamp(refOption.get(), commit.getTimestamp());
161+
parentCommit.ifPresent(parent -> {
162+
b.setParentCommit(parent.getId());
163+
branch.setParentCommitId(parent.getCommitId());
164+
});
165+
},
166+
() -> { throw new BadRequestException(new RefsResponse().addMessage("parentCommitId not found " + now.toString()));
167+
});
168+
} else {
169+
Optional<Commit> parentCommit = commitRepository.findLatestByRef(refOption.get());
170+
parentCommit.ifPresent(parent -> {
171+
b.setParentCommit(parent.getId());
172+
branch.setParentCommitId(parent.getCommitId()); //commit id is same as its docId
173+
});
174+
}
160175
}
161176

162177
if (b.getParentCommit() == null) {
@@ -167,11 +182,14 @@ public RefJson createBranch(String projectId, RefJson branch) {
167182
try {
168183
branchIndex.update(branch);
169184
branchRepository.save(b);
170-
Set<String> docIds = new HashSet<>();
171-
for (Node n: nodeRepository.findAllByDeleted(false)) {
172-
docIds.add(n.getDocId());
185+
if(!fromCommit) {
186+
Set<String> docIds = new HashSet<>();
187+
for (Node n: nodeRepository.findAllByDeleted(false)) {
188+
docIds.add(n.getDocId());
189+
}
190+
191+
try { nodeIndex.addToRef(docIds); } catch(Exception e) {}
173192
}
174-
try { nodeIndex.addToRef(docIds); } catch(Exception e) {}
175193
eventPublisher.forEach((pub) -> pub.publish(
176194
EventObject.create(projectId, branch.getId(), "branch_created", branch)));
177195
return branch;
@@ -181,6 +199,60 @@ public RefJson createBranch(String projectId, RefJson branch) {
181199
throw new InternalErrorException(e);
182200
}
183201
}
202+
public RefJson createBranchfromCommit(String projectId, RefJson parentCommitIdRef, NodeService nodeService) {
203+
Instant now = Instant.now();
204+
205+
if(parentCommitIdRef.getParentCommitId().isEmpty()){
206+
throw new BadRequestException(new RefsResponse().addMessage("parentCommitId not provided " + now.toString()));
207+
}
208+
209+
ContextHolder.setContext(projectId);
210+
Optional<Commit> parentCommit = commitRepository.findByCommitId(parentCommitIdRef.getParentCommitId());
211+
212+
// Get Commit object
213+
String parentCommitID = parentCommit.map(Commit::getCommitId).orElseThrow(() ->
214+
new BadRequestException(new RefsResponse().addMessage("parentCommitId not found " + now.toString())));
215+
216+
// Get Commit parentRef, the branch will be created from this
217+
String parentRef = parentCommit.map(Commit::getBranchId).orElseThrow(() ->
218+
new BadRequestException(new RefsResponse().addMessage("Ref from parentCommitId not found" + now.toString())));
219+
220+
parentCommitIdRef.setParentRefId(parentRef);
221+
ContextHolder.setContext(projectId, parentRef);
222+
223+
RefJson branchFromCommit = this.createBranch(projectId, parentCommitIdRef);
224+
ContextHolder.setContext(projectId, branchFromCommit.getId());
225+
226+
// Get current nodes from database
227+
List<Node> nodes = nodeRepository.findAll();
228+
// Get elements from index
229+
Collection<ElementJson> result = nodeGetHelper.processGetJsonFromNodes(nodes, parentCommitID, nodeService)
230+
.getActiveElementMap().values();
231+
232+
Map<String, ElementJson> nodeCommitData = new HashMap<>();
233+
for (ElementJson element : result) {
234+
nodeCommitData.put(element.getId(), element);
235+
}
236+
237+
// Update database table to match index
238+
Set<String> docIds = new HashSet<>();
239+
for (Node node : nodes) {
240+
if(nodeCommitData.containsKey(node.getNodeId())){
241+
node.setDocId(nodeCommitData.get(node.getNodeId()).getDocId());
242+
node.setLastCommit(nodeCommitData.get(node.getNodeId()).getCommitId());
243+
node.setDeleted(false);
244+
docIds.add(node.getDocId());
245+
} else {
246+
node.setDeleted(true);
247+
}
248+
}
249+
nodeRepository.updateAll(nodes);
250+
branchFromCommit.setStatus("created");
251+
branchIndex.update(branchFromCommit);
252+
try { nodeIndex.addToRef(docIds); } catch(Exception e) {}
253+
254+
return branchFromCommit;
255+
}
184256

185257
public RefsResponse deleteBranch(String projectId, String id) {
186258
ContextHolder.setContext(projectId);

crud/src/main/java/org/openmbee/mms/crud/services/NodeGetHelper.java

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,24 @@
1313
import org.openmbee.mms.data.domains.scoped.Branch;
1414
import org.openmbee.mms.data.domains.scoped.Commit;
1515
import org.openmbee.mms.data.domains.scoped.Node;
16+
import org.openmbee.mms.core.dao.CommitIndexDAO;
17+
import org.openmbee.mms.json.CommitJson;
1618
import org.openmbee.mms.json.ElementJson;
19+
import org.springframework.beans.factory.annotation.Autowired;
1720
import org.springframework.stereotype.Service;
1821

1922
import static org.openmbee.mms.core.config.ContextHolder.getContext;
2023

2124
@Service
2225
public class NodeGetHelper extends NodeOperation {
2326

27+
protected CommitIndexDAO commitIndex;
28+
29+
@Autowired
30+
public void setCommitIndex(CommitIndexDAO commitIndex) {
31+
this.commitIndex = commitIndex;
32+
}
33+
2434
public NodeGetInfo processGetJsonFromNodes(List<Node> nodes, NodeService service) {
2535
NodeGetInfo info = initInfoFromNodes(nodes, null);
2636
return processLatest(info, service);
@@ -122,21 +132,45 @@ private NodeGetInfo processCommit(NodeGetInfo info, String commitId, NodeService
122132
Optional<ElementJson> e = nodeIndex.getElementLessThanOrEqualTimestamp(nodeId,
123133
formatter.format(time), refCommitIds);
124134
if (e.isPresent()) { // found version of element at commit time
125-
//TODO determine if element was deleted at the time?
126-
e.get().setRefId(ContextHolder.getContext().getBranchId());
127-
info.getActiveElementMap().put(nodeId, e.get());
135+
Instant realModified = Instant.from(formatter.parse(e.get().getModified()));
136+
if (elementDeleted(nodeId, commitId, time, realModified, refCommitIds)) {
137+
rejectDeleted(info, nodeId, e.get());
138+
} else {
139+
e.get().setRefId(ContextHolder.getContext().getBranchId());
140+
info.getActiveElementMap().put(nodeId, e.get());
141+
}
128142
} else {
129143
rejectNotFound(info, nodeId); // element not found at commit time
130144
}
131145
} else if (info.getExistingNodeMap().get(nodeId).isDeleted()) { // latest element is before commit, but deleted
132-
rejectDeleted(info, nodeId, indexElement);
146+
if (refCommitIds == null) { // need list of commitIds of current ref to filter on
147+
refCommitIds = getRefCommitIds(time);
148+
}
149+
if (elementDeleted(nodeId, commitId, time, modified, refCommitIds)) {
150+
rejectDeleted(info, nodeId, indexElement);
151+
} else {
152+
info.getActiveElementMap().put(nodeId, indexElement);
153+
}
133154
} else { // latest element version is version at commit, not deleted
134155
info.getActiveElementMap().put(nodeId, indexElement);
135156
}
136157
}
137158
return info;
138159
}
139160

161+
private boolean elementDeleted(String nodeId, String commitId, Instant time, Instant modified, List<String> refCommitIds) {
162+
List<CommitJson> commits = commitIndex.elementDeletedHistory(nodeId, refCommitIds);
163+
for (CommitJson c: commits) {
164+
Instant deletedTime = Instant.from(formatter.parse(c.getCreated()));
165+
if ((deletedTime.isBefore(time) || c.getId().equals(commitId)) && deletedTime.isAfter(modified)) {
166+
//there's a delete between element last modified time and requested commit time
167+
//or element is deleted at commit
168+
return true;
169+
}
170+
}
171+
return false;
172+
}
173+
140174
public NodeGetInfo processGetJson(List<ElementJson> elements, Instant time, NodeService service) {
141175
Optional<Branch> ref = branchRepository.findByBranchId(getContext().getBranchId());
142176
if (ref.isPresent()) {

data/data.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ dependencies {
1010
api commonDependencies.'hibernate-core'
1111

1212
testImplementation commonDependencies.'spring-boot-starter-test'
13-
}
13+
}

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
master_doc = 'index'
2727

2828
# The full version, including alpha/beta/rc tags
29-
release = '4.0.19'
29+
release = '4.0.20'
3030

3131

3232
# -- General configuration ---------------------------------------------------
@@ -57,4 +57,4 @@
5757
# Add any paths that contain custom static files (such as style sheets) here,
5858
# relative to this directory. They are copied after the builtin static files,
5959
# so a file named "default.css" will overwrite the builtin "default.css".
60-
html_static_path = ['_static']
60+
html_static_path = ['_static']

0 commit comments

Comments
 (0)