Skip to content

Commit db9adeb

Browse files
committed
Added new "drafts" system branch
1 parent b2ca216 commit db9adeb

File tree

7 files changed

+127
-17
lines changed

7 files changed

+127
-17
lines changed

app/src/main/java/io/apicurio/registry/storage/impl/kafkasql/serde/KafkaSqlMessageIndex.java

+3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateArtifactMetaData3Message;
5454
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateArtifactRule4Message;
5555
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateArtifactVersionComment5Message;
56+
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateArtifactVersionContent5Message;
5657
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateArtifactVersionMetaData4Message;
58+
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateArtifactVersionState5Message;
5759
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateBranchMetaData3Message;
5860
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateContentCanonicalHash3Message;
5961
import io.apicurio.registry.storage.impl.kafkasql.messages.UpdateGlobalRule2Message;
@@ -106,6 +108,7 @@ private static void indexMessageClasses(Class<? extends KafkaSqlMessage>... mcla
106108
UpdateArtifactVersionMetaData4Message.class, UpdateBranchMetaData3Message.class,
107109
UpdateContentCanonicalHash3Message.class, UpdateGlobalRule2Message.class,
108110
UpdateGroupMetaData2Message.class, UpdateRoleMapping2Message.class,
111+
UpdateArtifactVersionState5Message.class, UpdateArtifactVersionContent5Message.class,
109112
UpdateGroupRule3Message.class, DeleteGroupRule2Message.class, DeleteGroupRules1Message.class,
110113
ImportGroupRule1Message.class, ExecuteSqlStatement1Message.class);
111114
}

app/src/main/java/io/apicurio/registry/storage/impl/sql/AbstractSqlRegistryStorage.java

+39-13
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,12 @@ private ArtifactVersionMetaDataDto createArtifactVersionRaw(Handle handle, boole
647647
}
648648

649649
// Update system generated branches
650-
createOrUpdateBranchRaw(handle, gav, BranchId.LATEST, true);
651-
createOrUpdateSemverBranchesRaw(handle, gav);
650+
if (isDraft) {
651+
createOrUpdateBranchRaw(handle, gav, BranchId.DRAFTS, true);
652+
} else {
653+
createOrUpdateBranchRaw(handle, gav, BranchId.LATEST, true);
654+
createOrUpdateSemverBranchesRaw(handle, gav);
655+
}
652656

653657
// Create any user defined branches
654658
if (branches != null && !branches.isEmpty()) {
@@ -2046,20 +2050,29 @@ public void updateArtifactVersionState(String groupId, String artifactId, String
20462050
handle.setRollback(true);
20472051
}
20482052

2049-
int rowCount = handle.createUpdate(sqlStatements.updateArtifactVersionStateByGAV())
2050-
.bind(0, newState.name()).bind(1, normalizeGroupId(groupId)).bind(2, artifactId)
2051-
.bind(3, version).execute();
2052-
if (rowCount == 0) {
2053-
throw new VersionNotFoundException(groupId, artifactId, version);
2054-
}
2053+
Optional<VersionState> res = handle
2054+
.createQuery(sqlStatements.selectArtifactVersionStateForUpdate())
2055+
.bind(0, normalizeGroupId(groupId)).bind(1, artifactId).bind(2, version)
2056+
.map(VersionStateMapper.instance).findOne();
2057+
VersionState currentState = res
2058+
.orElseThrow(() -> new VersionNotFoundException(groupId, artifactId, version));
2059+
2060+
handle.createUpdate(sqlStatements.updateArtifactVersionStateByGAV()).bind(0, newState.name())
2061+
.bind(1, normalizeGroupId(groupId)).bind(2, artifactId).bind(3, version).execute();
2062+
20552063
String modifiedBy = securityIdentity.getPrincipal().getName();
20562064
Date modifiedOn = new Date();
2065+
handle.createUpdate(sqlStatements.updateArtifactVersionModifiedByOn()).bind(0, modifiedBy)
2066+
.bind(1, modifiedOn).bind(2, normalizeGroupId(groupId)).bind(3, artifactId)
2067+
.bind(4, version).execute();
20572068

2058-
rowCount = handle.createUpdate(sqlStatements.updateArtifactVersionModifiedByOn())
2059-
.bind(0, modifiedBy).bind(1, modifiedOn).bind(2, normalizeGroupId(groupId))
2060-
.bind(3, artifactId).bind(4, version).execute();
2061-
if (rowCount == 0) {
2062-
throw new VersionNotFoundException(groupId, artifactId, version);
2069+
// If transitioning from DRAFT state to something else, then we need to maintain
2070+
// the system branches.
2071+
if (currentState == VersionState.DRAFT) {
2072+
GAV gav = new GAV(groupId, artifactId, version);
2073+
createOrUpdateBranchRaw(handle, gav, BranchId.LATEST, true);
2074+
createOrUpdateSemverBranchesRaw(handle, gav);
2075+
removeVersionFromBranchRaw(handle, gav, BranchId.DRAFTS);
20632076
}
20642077

20652078
return null;
@@ -3633,6 +3646,19 @@ private void createOrUpdateBranchRaw(Handle handle, GAV gav, BranchId branchId,
36333646
appendVersionToBranchRaw(handle, gav, branchId, gav.getVersionId());
36343647
}
36353648

3649+
/**
3650+
* Removes a version from the given branch.
3651+
*
3652+
* @param handle
3653+
* @param gav
3654+
* @param branchId
3655+
*/
3656+
private void removeVersionFromBranchRaw(Handle handle, GAV gav, BranchId branchId) {
3657+
handle.createUpdate(sqlStatements.deleteVersionFromBranch()).bind(0, gav.getRawGroupIdWithNull())
3658+
.bind(1, gav.getRawArtifactId()).bind(2, branchId.getRawBranchId())
3659+
.bind(3, gav.getRawVersionId()).execute();
3660+
}
3661+
36363662
private void updateBranchModifiedTimeRaw(Handle handle, GA ga, BranchId branchId) {
36373663
String user = securityIdentity.getPrincipal().getName();
36383664
Date now = new Date();

app/src/main/java/io/apicurio/registry/storage/impl/sql/CommonSqlStatements.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ public String selectArtifactVersionState() {
182182
+ "WHERE v.groupId = ? AND v.artifactId = ? AND v.version = ?";
183183
}
184184

185+
@Override
186+
public String selectArtifactVersionStateForUpdate() {
187+
return "SELECT v.state FROM versions v "
188+
+ "WHERE v.groupId = ? AND v.artifactId = ? AND v.version = ? FOR UPDATE";
189+
}
190+
185191
/**
186192
* @see io.apicurio.registry.storage.impl.sql.SqlStatements#selectArtifactVersionMetaDataByContentHash()
187193
*/
@@ -1142,12 +1148,17 @@ public String appendBranchVersion() {
11421148

11431149
@Override
11441150
public String deleteBranchVersions() {
1145-
return "DELETE FROM branch_versions " + "WHERE groupId = ? AND artifactId = ? AND branchId = ?";
1151+
return "DELETE FROM branch_versions WHERE groupId = ? AND artifactId = ? AND branchId = ?";
1152+
}
1153+
1154+
@Override
1155+
public String deleteVersionFromBranch() {
1156+
return "DELETE FROM branch_versions WHERE groupId = ? AND artifactId = ? AND branchId = ? AND version = ?";
11461157
}
11471158

11481159
@Override
11491160
public String deleteBranch() {
1150-
return "DELETE FROM branches " + "WHERE groupId = ? AND artifactId = ? AND branchId = ?";
1161+
return "DELETE FROM branches WHERE groupId = ? AND artifactId = ? AND branchId = ?";
11511162
}
11521163

11531164
@Override

app/src/main/java/io/apicurio/registry/storage/impl/sql/SQLServerSqlStatements.java

+6
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ public String deleteAllOrphanedContent() {
129129
return "DELETE FROM content WHERE NOT EXISTS (SELECT 1 FROM versions v WHERE v.contentId = contentId )";
130130
}
131131

132+
@Override
133+
public String selectArtifactVersionStateForUpdate() {
134+
return "SELECT v.state FROM versions v WITH (UPDLOCK, ROWLOCK)"
135+
+ "WHERE v.groupId = ? AND v.artifactId = ? AND v.version = ?";
136+
}
137+
132138
@Override
133139
public String createDataSnapshot() {
134140
throw new IllegalStateException("Snapshot creation is not supported for Sqlserver storage");

app/src/main/java/io/apicurio/registry/storage/impl/sql/SqlStatements.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,11 @@ public interface SqlStatements {
455455
*/
456456
public String selectArtifactVersionState();
457457

458+
/**
459+
* A statement used to select the state of a version.
460+
*/
461+
public String selectArtifactVersionStateForUpdate();
462+
458463
/*
459464
* The next few statements support globalId and contentId management.
460465
*/
@@ -631,11 +636,18 @@ public interface SqlStatements {
631636

632637
public String deleteAllBranches();
633638

639+
public String deleteVersionFromBranch();
640+
641+
// ========== Snapshots ==========
642+
634643
public String createDataSnapshot();
635644

636645
public String restoreFromSnapshot();
637646

638-
String createOutboxEvent();
647+
// ========== Events ==========
648+
649+
public String createOutboxEvent();
650+
651+
public String deleteOutboxEvent();
639652

640-
String deleteOutboxEvent();
641653
}

app/src/test/java/io/apicurio/registry/noprofile/rest/v3/DraftContentTest.java

+51
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,55 @@ public void testCreateInvalidDraftVersion() throws Exception {
324324
Assertions.assertEquals("Syntax violation for Avro artifact.", error.getTitle());
325325
}
326326

327+
@Test
328+
public void testDraftVersionsWithBranches() throws Exception {
329+
String content = resourceToString("openapi-empty.json");
330+
String groupId = TestUtils.generateGroupId();
331+
String artifactId = TestUtils.generateArtifactId();
332+
333+
// First version is ENABLED
334+
CreateArtifact createArtifact = TestUtils.clientCreateArtifact(artifactId, ArtifactType.OPENAPI,
335+
content, ContentTypes.APPLICATION_JSON);
336+
createArtifact.getFirstVersion().setIsDraft(false);
337+
createArtifact.getFirstVersion().setVersion("1.0.0");
338+
339+
clientV3.groups().byGroupId(groupId).artifacts().post(createArtifact);
340+
341+
VersionSearchResults latestBranch = clientV3.groups().byGroupId(groupId).artifacts()
342+
.byArtifactId(artifactId).branches().byBranchId("latest").versions().get();
343+
Assertions.assertEquals(1, latestBranch.getVersions().size());
344+
ProblemDetails problemDetails = Assertions.assertThrows(ProblemDetails.class, () -> {
345+
clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).branches()
346+
.byBranchId("drafts").versions().get();
347+
});
348+
Assertions.assertEquals("BranchNotFoundException", problemDetails.getName());
349+
350+
// Second version is DRAFT
351+
CreateVersion createVersion = TestUtils.clientCreateVersion(content, ContentTypes.APPLICATION_JSON);
352+
createVersion.setVersion("1.0.1");
353+
createVersion.setIsDraft(true);
354+
clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).versions()
355+
.post(createVersion);
356+
357+
latestBranch = clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).branches()
358+
.byBranchId("latest").versions().get();
359+
Assertions.assertEquals(1, latestBranch.getVersions().size());
360+
VersionSearchResults draftsBranch = clientV3.groups().byGroupId(groupId).artifacts()
361+
.byArtifactId(artifactId).branches().byBranchId("drafts").versions().get();
362+
Assertions.assertEquals(1, draftsBranch.getVersions().size());
363+
364+
// Transition draft content to enabled
365+
WrappedVersionState enabled = new WrappedVersionState();
366+
enabled.setState(VersionState.ENABLED);
367+
clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).versions()
368+
.byVersionExpression("1.0.1").state().put(enabled);
369+
370+
latestBranch = clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).branches()
371+
.byBranchId("latest").versions().get();
372+
Assertions.assertEquals(2, latestBranch.getVersions().size());
373+
draftsBranch = clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).branches()
374+
.byBranchId("drafts").versions().get();
375+
Assertions.assertEquals(0, draftsBranch.getVersions().size());
376+
}
377+
327378
}

common/src/main/java/io/apicurio/registry/model/BranchId.java

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public final class BranchId {
1717
private static final Pattern VALID_PATTERN = Pattern.compile("[a-zA-Z0-9._\\-+]{1,256}");
1818

1919
public static final BranchId LATEST = new BranchId("latest");
20+
public static final BranchId DRAFTS = new BranchId("drafts");
2021

2122
private final String rawBranchId;
2223

0 commit comments

Comments
 (0)