Skip to content

Commit e1f1f4f

Browse files
Allow retiring a DRAFT version directly; block only re-retiring so the audit trail stays intact
1 parent 13e59dc commit e1f1f4f

4 files changed

Lines changed: 46 additions & 7 deletions

File tree

Java/validation/src/main/java/com/lantanagroup/link/validation/controllers/RubricController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,11 @@ public ResponseEntity<ApiResponse<RubricVersionSummaryDto>> publish(
241241
RubricVersionSummaryDto.from(version, objectMapper)));
242242
}
243243

244-
@Operation(summary = "Mark a PUBLISHED version RETIRED (the only legal transition into RETIRED)")
244+
@Operation(summary = "Mark a version RETIRED. Both DRAFT (abandon without publishing) and PUBLISHED versions can be retired")
245245
@ApiResponses({
246246
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200"),
247247
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404"),
248-
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "Version is already retired, or still a draft")
248+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "Version is already retired")
249249
})
250250
@PostMapping("/{rubricId}/versions/{semver}/$retire")
251251
public ResponseEntity<ApiResponse<RubricVersionSummaryDto>> retire(

Java/validation/src/main/java/com/lantanagroup/link/validation/services/RubricRegistryService.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ public RubricVersion publish(String rubricId, String semver, String publishedBy)
180180
public RubricVersion retire(String rubricId, String semver, String retiredBy) {
181181
RubricVersion v = rubricVersionRepository.findByRubricIdAndSemver(rubricId, semver)
182182
.orElseThrow(() -> new RubricVersionNotFoundException(rubricId, semver));
183-
// if (v.getStatus() != RubricVersionStatus.PUBLISHED) {
184-
// throw new RubricLifecycleException(rubricId, semver, v.getStatus(), "retire");
185-
// }
183+
// drafts can be retired directly (abandoned without ever publishing), only
184+
// re-retiring is blocked so retiredAt/retiredBy and the audit trail stay intact
185+
if (v.getStatus() == RubricVersionStatus.RETIRED) {
186+
throw new RubricLifecycleException(rubricId, semver, v.getStatus(), "retire");
187+
}
186188
v.setStatus(RubricVersionStatus.RETIRED);
187189
v.setRetiredAt(OffsetDateTime.now());
188190
v.setRetiredBy(retiredBy);

Java/validation/src/test/java/com/lantanagroup/link/validation/controllers/RubricControllerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,11 +484,11 @@ void retire_notFound() throws Exception {
484484
}
485485

486486
@Test
487-
@DisplayName("still a draft -> 409 (documented)")
487+
@DisplayName("already retired -> 409 (documented)")
488488
void retire_wrongState() throws Exception {
489489
when(registry.retire(any(), any(), any()))
490490
.thenThrow(new RubricLifecycleException("piqi.core", "1.0.0",
491-
RubricVersionStatus.DRAFT, "retire"));
491+
RubricVersionStatus.RETIRED, "retire"));
492492
expectStatus(post(BASE + "/piqi.core/versions/1.0.0/$retire"), 409);
493493
}
494494
}

Java/validation/src/test/java/com/lantanagroup/link/validation/services/RubricRegistryServiceTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,43 @@ void publish_lifecycleCheckedBeforeDryRun() {
305305
.isInstanceOf(RubricLifecycleException.class);
306306
}
307307

308+
@Test
309+
@DisplayName("retire a DRAFT -> allowed, version goes straight to RETIRED")
310+
void retire_draftAllowed() {
311+
stubVersion(draftVersion());
312+
313+
RubricVersion retired = service().retire("piqi.core", "1.0.0", "qa");
314+
315+
assertThat(retired.getStatus()).isEqualTo(RubricVersionStatus.RETIRED);
316+
assertThat(retired.getRetiredAt()).isNotNull();
317+
assertThat(retired.getRetiredBy()).isEqualTo("qa");
318+
verify(eventRepository).save(any());
319+
}
320+
321+
@Test
322+
@DisplayName("retire a PUBLISHED version -> RETIRED")
323+
void retire_publishedAllowed() {
324+
RubricVersion version = draftVersion();
325+
version.setStatus(RubricVersionStatus.PUBLISHED);
326+
stubVersion(version);
327+
328+
RubricVersion retired = service().retire("piqi.core", "1.0.0", "qa");
329+
330+
assertThat(retired.getStatus()).isEqualTo(RubricVersionStatus.RETIRED);
331+
}
332+
333+
@Test
334+
@DisplayName("retire an already RETIRED version -> 409 lifecycle error")
335+
void retire_alreadyRetiredRejected() {
336+
RubricVersion version = draftVersion();
337+
version.setStatus(RubricVersionStatus.RETIRED);
338+
stubVersion(version);
339+
340+
assertThatThrownBy(() -> service().retire("piqi.core", "1.0.0", "qa"))
341+
.isInstanceOf(RubricLifecycleException.class);
342+
verify(eventRepository, never()).save(any());
343+
}
344+
308345
private RubricVersion versionOf(String rubricId, String semver, RubricVersionStatus status) {
309346
return RubricVersion.builder()
310347
.rubricVersionId(UUID.randomUUID())

0 commit comments

Comments
 (0)