Skip to content

Commit 6ecee68

Browse files
fix: V2 API artifact list returns latest version metadata (#6855)
Fixes #6848 In the V2 API, artifact-level metadata should always reflect the latest version's metadata (name, description, labels). This was working correctly for some operations but not others. This fix ensures that when artifact metadata is updated via PUT /groups/{groupId}/artifacts/{artifactId}/meta or when a new version is created via POST /groups/{groupId}/artifacts/{artifactId}/versions, both the version-level AND artifact-level metadata are updated. Changes: - Modified updateArtifactMetaData() to update artifact-level metadata after updating version metadata - Modified createArtifactVersionWithRefs() to update artifact-level metadata after creating a new version - Added 4 comprehensive tests covering all V2 artifact operations: * POST /groups/{groupId}/artifacts (create artifact) * PUT /groups/{groupId}/artifacts/{artifactId} (update content) * PUT /groups/{groupId}/artifacts/{artifactId}/meta (update metadata) * POST /groups/{groupId}/artifacts/{artifactId}/versions (create version) All changes follow the existing pattern from updateArtifactInternal() which was already correctly maintaining V2 API semantics. Co-authored-by: Carles Arnal <[email protected]>
1 parent 2f63993 commit 6ecee68

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

app/src/main/java/io/apicurio/registry/rest/v2/GroupsResourceImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,9 +299,16 @@ public ArtifactMetaData getArtifactMetaData(String groupId, String artifactId) {
299299
public void updateArtifactMetaData(String groupId, String artifactId, EditableMetaData data) {
300300
GAV latestGAV = storage.getBranchTip(new GA(groupId, artifactId), BranchId.LATEST,
301301
RetrievalBehavior.ALL_STATES);
302+
303+
// Update the latest version's metadata
302304
storage.updateArtifactVersionMetaData(groupId, artifactId, latestGAV.getRawVersionId(),
303305
EditableVersionMetaDataDto.builder().name(data.getName()).description(data.getDescription())
304306
.labels(V2ApiUtil.toV3Labels(data.getLabels(), data.getProperties())).build());
307+
308+
// Also update the artifact-level metadata (for V2 API semantics)
309+
storage.updateArtifactMetaData(defaultGroupIdToNull(groupId), artifactId,
310+
EditableArtifactMetaDataDto.builder().name(data.getName()).description(data.getDescription())
311+
.labels(V2ApiUtil.toV3Labels(data.getLabels(), data.getProperties())).build());
305312
}
306313

307314
@Override
@@ -1245,6 +1252,15 @@ private VersionMetaData createArtifactVersionWithRefs(String groupId, String art
12451252
ArtifactVersionMetaDataDto vmdDto = storage.createArtifactVersion(defaultGroupIdToNull(groupId),
12461253
artifactId, xRegistryVersion, artifactType, contentDto, metaData, List.of(), false, false,
12471254
owner);
1255+
1256+
// Update the artifact metadata to reflect the new version (for V2 API semantics)
1257+
EditableArtifactMetaDataDto artifactMD = EditableArtifactMetaDataDto.builder()
1258+
.name(artifactName)
1259+
.description(artifactDescription)
1260+
.labels(metaData != null ? metaData.getLabels() : null)
1261+
.build();
1262+
storage.updateArtifactMetaData(defaultGroupIdToNull(groupId), artifactId, artifactMD);
1263+
12481264
return V2ApiUtil.dtoToVersionMetaData(defaultGroupIdToNull(groupId), artifactId, artifactType,
12491265
vmdDto);
12501266
}

app/src/test/java/io/apicurio/registry/noprofile/rest/v2/LegacyV2ApiTest.java

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,138 @@ public void testLegacyPropertiesWithLabels() throws Exception {
9696
.body("labels", equalToObject(labels)).body("properties", equalToObject(properties));
9797
}
9898

99+
/**
100+
* Test for issue #6848 - Scenario 1: POST /groups/{groupId}/artifacts (create artifact)
101+
* Verifies that creating an artifact properly sets the artifact name and description, and that
102+
* listing artifacts returns the correct values.
103+
*/
104+
@Test
105+
public void testCreateArtifactSetsName() throws Exception {
106+
String artifactContent = resourceToString("openapi-empty.json");
107+
String artifactId = "testCreateArtifactSetsName";
108+
109+
// Create artifact with name "1.0.0" and description
110+
given().when().contentType(CT_JSON).header("X-Registry-ArtifactId", artifactId)
111+
.header("X-Registry-ArtifactType", ArtifactType.OPENAPI).header("X-Registry-Name", "1.0.0")
112+
.header("X-Registry-Description", "Initial version").pathParam("groupId", GROUP)
113+
.body(artifactContent).post("/registry/v2/groups/{groupId}/artifacts").then()
114+
.statusCode(200).body("name", equalTo("1.0.0"))
115+
.body("description", equalTo("Initial version"));
116+
117+
// List artifacts - should return name "1.0.0" and description
118+
given().when().pathParam("groupId", GROUP).get("/registry/v2/groups/{groupId}/artifacts").then()
119+
.statusCode(200).body("artifacts.find { it.id == '" + artifactId + "' }.name",
120+
equalTo("1.0.0"))
121+
.body("artifacts.find { it.id == '" + artifactId + "' }.description",
122+
equalTo("Initial version"));
123+
}
124+
125+
/**
126+
* Test for issue #6848 - Scenario 2: PUT /groups/{groupId}/artifacts/{artifactId} (update artifact
127+
* = create new version) Verifies that updating artifact content creates a new version and updates
128+
* the artifact name and description.
129+
*/
130+
@Test
131+
public void testUpdateArtifactContentUpdatesName() throws Exception {
132+
String artifactContent = resourceToString("openapi-empty.json");
133+
String artifactId = "testUpdateArtifactContentUpdatesName";
134+
135+
// Create artifact with name "1.0.0" and description
136+
given().when().contentType(CT_JSON).header("X-Registry-ArtifactId", artifactId)
137+
.header("X-Registry-ArtifactType", ArtifactType.OPENAPI).header("X-Registry-Name", "1.0.0")
138+
.header("X-Registry-Description", "Initial version").pathParam("groupId", GROUP)
139+
.body(artifactContent).post("/registry/v2/groups/{groupId}/artifacts").then()
140+
.statusCode(200);
141+
142+
// Update artifact content with name "2.0.0" and new description (creates new version)
143+
given().when().contentType(CT_JSON).header("X-Registry-Name", "2.0.0")
144+
.header("X-Registry-Description", "Second version").pathParam("groupId", GROUP)
145+
.pathParam("artifactId", artifactId).body(artifactContent)
146+
.put("/registry/v2/groups/{groupId}/artifacts/{artifactId}").then().statusCode(200)
147+
.body("name", equalTo("2.0.0")).body("description", equalTo("Second version"));
148+
149+
// List artifacts - should return name "2.0.0" and description from latest version
150+
given().when().pathParam("groupId", GROUP).get("/registry/v2/groups/{groupId}/artifacts").then()
151+
.statusCode(200).body("artifacts.find { it.id == '" + artifactId + "' }.name",
152+
equalTo("2.0.0"))
153+
.body("artifacts.find { it.id == '" + artifactId + "' }.description",
154+
equalTo("Second version"));
155+
}
156+
157+
/**
158+
* Test for issue #6848 - Scenario 3: PUT /groups/{groupId}/artifacts/{artifactId}/meta (update
159+
* artifact metadata) Verifies that updating artifact metadata updates both the version metadata
160+
* AND the artifact-level metadata.
161+
*/
162+
@Test
163+
public void testUpdateArtifactMetaDataUpdatesName() throws Exception {
164+
String artifactContent = resourceToString("openapi-empty.json");
165+
String artifactId = "testUpdateArtifactMetaDataUpdatesName";
166+
167+
// Create artifact with name "1.0.0"
168+
given().when().contentType(CT_JSON).header("X-Registry-ArtifactId", artifactId)
169+
.header("X-Registry-ArtifactType", ArtifactType.OPENAPI).header("X-Registry-Name", "1.0.0")
170+
.pathParam("groupId", GROUP).body(artifactContent)
171+
.post("/registry/v2/groups/{groupId}/artifacts").then().statusCode(200);
172+
173+
// Update artifact metadata with name "2.0.0"
174+
EditableMetaData metaData = new EditableMetaData();
175+
metaData.setName("2.0.0");
176+
metaData.setDescription("Updated description");
177+
given().when().contentType(CT_JSON).pathParam("groupId", GROUP).pathParam("artifactId", artifactId)
178+
.body(metaData).put("/registry/v2/groups/{groupId}/artifacts/{artifactId}/meta").then()
179+
.statusCode(204);
180+
181+
// Get artifact metadata - should return name "2.0.0"
182+
given().when().pathParam("groupId", GROUP).pathParam("artifactId", artifactId)
183+
.get("/registry/v2/groups/{groupId}/artifacts/{artifactId}/meta").then().statusCode(200)
184+
.body("name", equalTo("2.0.0")).body("description", equalTo("Updated description"));
185+
186+
// List artifacts - should return name "2.0.0" and description
187+
given().when().pathParam("groupId", GROUP).get("/registry/v2/groups/{groupId}/artifacts").then()
188+
.statusCode(200).body("artifacts.find { it.id == '" + artifactId + "' }.name",
189+
equalTo("2.0.0"))
190+
.body("artifacts.find { it.id == '" + artifactId + "' }.description",
191+
equalTo("Updated description"));
192+
}
193+
194+
/**
195+
* Test for issue #6848 - Scenario 4: POST /groups/{groupId}/artifacts/{artifactId}/versions
196+
* (create new version) Verifies that creating a new version updates the artifact-level metadata to
197+
* reflect the latest version's name and description.
198+
*/
199+
@Test
200+
public void testCreateVersionUpdatesArtifactName() throws Exception {
201+
String artifactContent = resourceToString("openapi-empty.json");
202+
String artifactId = "testCreateVersionUpdatesArtifactName";
203+
204+
// Create artifact with name "1.0.0" and description
205+
given().when().contentType(CT_JSON).header("X-Registry-ArtifactId", artifactId)
206+
.header("X-Registry-ArtifactType", ArtifactType.OPENAPI).header("X-Registry-Name", "1.0.0")
207+
.header("X-Registry-Description", "First version").pathParam("groupId", GROUP)
208+
.body(artifactContent).post("/registry/v2/groups/{groupId}/artifacts").then()
209+
.statusCode(200).body("name", equalTo("1.0.0"))
210+
.body("description", equalTo("First version"));
211+
212+
// Create a second version with name "2.0.0" and new description
213+
given().when().contentType(CT_JSON).header("X-Registry-Name", "2.0.0")
214+
.header("X-Registry-Description", "Second version").pathParam("groupId", GROUP)
215+
.pathParam("artifactId", artifactId).body(artifactContent)
216+
.post("/registry/v2/groups/{groupId}/artifacts/{artifactId}/versions").then()
217+
.statusCode(200).body("name", equalTo("2.0.0"))
218+
.body("description", equalTo("Second version"));
219+
220+
// Get artifact metadata - should return name "2.0.0" and description from latest version
221+
given().when().pathParam("groupId", GROUP).pathParam("artifactId", artifactId)
222+
.get("/registry/v2/groups/{groupId}/artifacts/{artifactId}/meta").then().statusCode(200)
223+
.body("name", equalTo("2.0.0")).body("description", equalTo("Second version"));
224+
225+
// List artifacts - should return name "2.0.0" and description from latest version
226+
given().when().pathParam("groupId", GROUP).get("/registry/v2/groups/{groupId}/artifacts").then()
227+
.statusCode(200).body("artifacts.find { it.id == '" + artifactId + "' }.name",
228+
equalTo("2.0.0"))
229+
.body("artifacts.find { it.id == '" + artifactId + "' }.description",
230+
equalTo("Second version"));
231+
}
232+
99233
}

0 commit comments

Comments
 (0)