diff --git a/prometeu-packer/build.gradle.kts b/prometeu-packer/build.gradle.kts new file mode 100644 index 00000000..416c0cab --- /dev/null +++ b/prometeu-packer/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("gradle.java-library-conventions") +} + +dependencies { + implementation(project(":prometeu-infra")) +} diff --git a/prometeu-packer/src/main/java/p/packer/api/PackerOperationClass.java b/prometeu-packer/src/main/java/p/packer/api/PackerOperationClass.java new file mode 100644 index 00000000..bd8b608c --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/PackerOperationClass.java @@ -0,0 +1,7 @@ +package p.packer.api; + +public enum PackerOperationClass { + READ_ONLY, + REGISTRY_MUTATION, + WORKSPACE_MUTATION +} diff --git a/prometeu-packer/src/main/java/p/packer/api/PackerOperationStatus.java b/prometeu-packer/src/main/java/p/packer/api/PackerOperationStatus.java new file mode 100644 index 00000000..25f50786 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/PackerOperationStatus.java @@ -0,0 +1,7 @@ +package p.packer.api; + +public enum PackerOperationStatus { + SUCCESS, + PARTIAL, + FAILED +} diff --git a/prometeu-packer/src/main/java/p/packer/api/PackerProjectContext.java b/prometeu-packer/src/main/java/p/packer/api/PackerProjectContext.java new file mode 100644 index 00000000..3290afcc --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/PackerProjectContext.java @@ -0,0 +1,17 @@ +package p.packer.api; + +import java.nio.file.Path; +import java.util.Objects; + +public record PackerProjectContext( + String projectId, + Path rootPath) { + + public PackerProjectContext { + projectId = Objects.requireNonNull(projectId, "projectId").trim(); + rootPath = Objects.requireNonNull(rootPath, "rootPath").toAbsolutePath().normalize(); + if (projectId.isBlank()) { + throw new IllegalArgumentException("projectId must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetDetails.java b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetDetails.java new file mode 100644 index 00000000..f5a03313 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetDetails.java @@ -0,0 +1,24 @@ +package p.packer.api.assets; + +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public record PackerAssetDetails( + PackerAssetSummary summary, + String outputFormat, + String outputCodec, + Map> inputsByRole, + List diagnostics) { + + public PackerAssetDetails { + Objects.requireNonNull(summary, "summary"); + outputFormat = Objects.requireNonNullElse(outputFormat, "unknown").trim(); + outputCodec = Objects.requireNonNullElse(outputCodec, "unknown").trim(); + inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole")); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetIdentity.java b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetIdentity.java new file mode 100644 index 00000000..5e247dda --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetIdentity.java @@ -0,0 +1,20 @@ +package p.packer.api.assets; + +import java.nio.file.Path; +import java.util.Objects; + +public record PackerAssetIdentity( + Integer assetId, + String assetUuid, + String assetName, + Path assetRoot) { + + public PackerAssetIdentity { + assetUuid = assetUuid == null ? null : assetUuid.trim(); + assetName = Objects.requireNonNull(assetName, "assetName").trim(); + assetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize(); + if (assetName.isBlank()) { + throw new IllegalArgumentException("assetName must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetState.java b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetState.java new file mode 100644 index 00000000..a530c36e --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetState.java @@ -0,0 +1,7 @@ +package p.packer.api.assets; + +public enum PackerAssetState { + MANAGED, + ORPHAN, + INVALID +} diff --git a/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetSummary.java b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetSummary.java new file mode 100644 index 00000000..1ebb01f4 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/assets/PackerAssetSummary.java @@ -0,0 +1,20 @@ +package p.packer.api.assets; + +import java.util.Objects; + +public record PackerAssetSummary( + PackerAssetIdentity identity, + PackerAssetState state, + String assetFamily, + boolean preloadEnabled, + boolean hasDiagnostics) { + + public PackerAssetSummary { + Objects.requireNonNull(identity, "identity"); + Objects.requireNonNull(state, "state"); + assetFamily = Objects.requireNonNullElse(assetFamily, "unknown").trim(); + if (assetFamily.isBlank()) { + assetFamily = "unknown"; + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnostic.java b/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnostic.java new file mode 100644 index 00000000..c6848ede --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnostic.java @@ -0,0 +1,22 @@ +package p.packer.api.diagnostics; + +import java.nio.file.Path; +import java.util.Objects; + +public record PackerDiagnostic( + PackerDiagnosticSeverity severity, + PackerDiagnosticCategory category, + String message, + Path evidencePath, + boolean blocking) { + + public PackerDiagnostic { + Objects.requireNonNull(severity, "severity"); + Objects.requireNonNull(category, "category"); + message = Objects.requireNonNull(message, "message").trim(); + evidencePath = evidencePath == null ? null : evidencePath.toAbsolutePath().normalize(); + if (message.isBlank()) { + throw new IllegalArgumentException("message must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnosticCategory.java b/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnosticCategory.java new file mode 100644 index 00000000..a2a9e6ce --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnosticCategory.java @@ -0,0 +1,9 @@ +package p.packer.api.diagnostics; + +public enum PackerDiagnosticCategory { + STRUCTURAL, + HYGIENE, + VERSIONING, + MIGRATION, + BUILD +} diff --git a/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnosticSeverity.java b/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnosticSeverity.java new file mode 100644 index 00000000..30ad2c10 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/diagnostics/PackerDiagnosticSeverity.java @@ -0,0 +1,7 @@ +package p.packer.api.diagnostics; + +public enum PackerDiagnosticSeverity { + INFO, + WARNING, + ERROR +} diff --git a/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorMode.java b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorMode.java new file mode 100644 index 00000000..2e07dc3c --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorMode.java @@ -0,0 +1,6 @@ +package p.packer.api.doctor; + +public enum PackerDoctorMode { + MANAGED_WORLD, + EXPANDED_WORKSPACE +} diff --git a/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorRequest.java b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorRequest.java new file mode 100644 index 00000000..6aaf1f04 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorRequest.java @@ -0,0 +1,16 @@ +package p.packer.api.doctor; + +import p.packer.api.PackerProjectContext; + +import java.util.Objects; + +public record PackerDoctorRequest( + PackerProjectContext project, + PackerDoctorMode mode, + boolean includeSafeFixes) { + + public PackerDoctorRequest { + Objects.requireNonNull(project, "project"); + Objects.requireNonNull(mode, "mode"); + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorResult.java b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorResult.java new file mode 100644 index 00000000..d1bb7321 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorResult.java @@ -0,0 +1,24 @@ +package p.packer.api.doctor; + +import p.packer.api.PackerOperationStatus; +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.util.List; +import java.util.Objects; + +public record PackerDoctorResult( + PackerOperationStatus status, + String summary, + List diagnostics, + List safeFixes) { + + public PackerDoctorResult { + Objects.requireNonNull(status, "status"); + summary = Objects.requireNonNull(summary, "summary").trim(); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + safeFixes = List.copyOf(Objects.requireNonNull(safeFixes, "safeFixes")); + if (summary.isBlank()) { + throw new IllegalArgumentException("summary must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorService.java b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorService.java new file mode 100644 index 00000000..060d4728 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/doctor/PackerDoctorService.java @@ -0,0 +1,9 @@ +package p.packer.api.doctor; + +import p.packer.api.PackerOperationClass; + +public interface PackerDoctorService { + PackerOperationClass operationClass(); + + PackerDoctorResult doctor(PackerDoctorRequest request); +} diff --git a/prometeu-packer/src/main/java/p/packer/api/events/PackerEvent.java b/prometeu-packer/src/main/java/p/packer/api/events/PackerEvent.java new file mode 100644 index 00000000..254e951d --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/events/PackerEvent.java @@ -0,0 +1,31 @@ +package p.packer.api.events; + +import java.time.Instant; +import java.util.List; +import java.util.Objects; + +public record PackerEvent( + String projectId, + String operationId, + long sequence, + PackerEventKind kind, + Instant timestamp, + String summary, + PackerProgress progress, + List affectedAssets) { + + public PackerEvent { + projectId = Objects.requireNonNull(projectId, "projectId").trim(); + operationId = Objects.requireNonNull(operationId, "operationId").trim(); + Objects.requireNonNull(kind, "kind"); + timestamp = Objects.requireNonNull(timestamp, "timestamp"); + summary = Objects.requireNonNull(summary, "summary").trim(); + affectedAssets = List.copyOf(Objects.requireNonNull(affectedAssets, "affectedAssets")); + if (projectId.isBlank() || operationId.isBlank() || summary.isBlank()) { + throw new IllegalArgumentException("projectId, operationId, and summary must not be blank"); + } + if (sequence < 0L) { + throw new IllegalArgumentException("sequence must not be negative"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/events/PackerEventKind.java b/prometeu-packer/src/main/java/p/packer/api/events/PackerEventKind.java new file mode 100644 index 00000000..ac2279b6 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/events/PackerEventKind.java @@ -0,0 +1,15 @@ +package p.packer.api.events; + +public enum PackerEventKind { + ASSET_DISCOVERED, + ASSET_CHANGED, + DIAGNOSTICS_UPDATED, + BUILD_STARTED, + BUILD_FINISHED, + CACHE_HIT, + CACHE_MISS, + PREVIEW_READY, + ACTION_APPLIED, + ACTION_FAILED, + PROGRESS_UPDATED +} diff --git a/prometeu-packer/src/main/java/p/packer/api/events/PackerEventSink.java b/prometeu-packer/src/main/java/p/packer/api/events/PackerEventSink.java new file mode 100644 index 00000000..e9fc9313 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/events/PackerEventSink.java @@ -0,0 +1,11 @@ +package p.packer.api.events; + +@FunctionalInterface +public interface PackerEventSink { + void publish(PackerEvent event); + + static PackerEventSink noop() { + return ignored -> { + }; + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/events/PackerProgress.java b/prometeu-packer/src/main/java/p/packer/api/events/PackerProgress.java new file mode 100644 index 00000000..9ffc19f8 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/events/PackerProgress.java @@ -0,0 +1,12 @@ +package p.packer.api.events; + +public record PackerProgress( + double value, + boolean indeterminate) { + + public PackerProgress { + if (!indeterminate && (value < 0.0 || value > 1.0)) { + throw new IllegalArgumentException("value must be between 0.0 and 1.0 when determinate"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationPreview.java b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationPreview.java new file mode 100644 index 00000000..0472a05d --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationPreview.java @@ -0,0 +1,35 @@ +package p.packer.api.mutations; + +import p.packer.api.PackerOperationStatus; +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.util.List; +import java.util.Objects; + +public record PackerMutationPreview( + PackerOperationStatus status, + String summary, + String operationId, + PackerMutationRequest request, + List proposedActions, + List diagnostics, + List blockers, + boolean highRisk) { + + public PackerMutationPreview { + Objects.requireNonNull(status, "status"); + summary = Objects.requireNonNull(summary, "summary").trim(); + operationId = Objects.requireNonNull(operationId, "operationId").trim(); + Objects.requireNonNull(request, "request"); + proposedActions = List.copyOf(Objects.requireNonNull(proposedActions, "proposedActions")); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + blockers = List.copyOf(Objects.requireNonNull(blockers, "blockers")); + if (summary.isBlank() || operationId.isBlank()) { + throw new IllegalArgumentException("summary and operationId must not be blank"); + } + } + + public boolean canApply() { + return blockers.isEmpty(); + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationRequest.java b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationRequest.java new file mode 100644 index 00000000..3d437901 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationRequest.java @@ -0,0 +1,23 @@ +package p.packer.api.mutations; + +import p.packer.api.PackerProjectContext; + +import java.nio.file.Path; +import java.util.Objects; + +public record PackerMutationRequest( + PackerProjectContext project, + PackerMutationType type, + String assetReference, + Path targetRoot) { + + public PackerMutationRequest { + Objects.requireNonNull(project, "project"); + Objects.requireNonNull(type, "type"); + assetReference = Objects.requireNonNull(assetReference, "assetReference").trim(); + targetRoot = targetRoot == null ? null : targetRoot.toAbsolutePath().normalize(); + if (assetReference.isBlank()) { + throw new IllegalArgumentException("assetReference must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationResult.java b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationResult.java new file mode 100644 index 00000000..2436ce0e --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationResult.java @@ -0,0 +1,26 @@ +package p.packer.api.mutations; + +import p.packer.api.PackerOperationStatus; +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.util.List; +import java.util.Objects; + +public record PackerMutationResult( + PackerOperationStatus status, + String summary, + String operationId, + List appliedActions, + List diagnostics) { + + public PackerMutationResult { + Objects.requireNonNull(status, "status"); + summary = Objects.requireNonNull(summary, "summary").trim(); + operationId = Objects.requireNonNull(operationId, "operationId").trim(); + appliedActions = List.copyOf(Objects.requireNonNull(appliedActions, "appliedActions")); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + if (summary.isBlank() || operationId.isBlank()) { + throw new IllegalArgumentException("summary and operationId must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationService.java b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationService.java new file mode 100644 index 00000000..97af4c8b --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationService.java @@ -0,0 +1,11 @@ +package p.packer.api.mutations; + +import p.packer.api.PackerOperationClass; + +public interface PackerMutationService { + PackerOperationClass operationClass(); + + PackerMutationPreview preview(PackerMutationRequest request); + + PackerMutationResult apply(PackerMutationPreview preview); +} diff --git a/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationType.java b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationType.java new file mode 100644 index 00000000..0e9203d5 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerMutationType.java @@ -0,0 +1,10 @@ +package p.packer.api.mutations; + +public enum PackerMutationType { + REGISTER_ASSET, + ADOPT_ASSET, + FORGET_ASSET, + REMOVE_ASSET, + QUARANTINE_ASSET, + RELOCATE_ASSET +} diff --git a/prometeu-packer/src/main/java/p/packer/api/mutations/PackerProposedAction.java b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerProposedAction.java new file mode 100644 index 00000000..15b04014 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/mutations/PackerProposedAction.java @@ -0,0 +1,20 @@ +package p.packer.api.mutations; + +import p.packer.api.PackerOperationClass; + +import java.util.Objects; + +public record PackerProposedAction( + PackerOperationClass operationClass, + String verb, + String target) { + + public PackerProposedAction { + Objects.requireNonNull(operationClass, "operationClass"); + verb = Objects.requireNonNull(verb, "verb").trim(); + target = Objects.requireNonNull(target, "target").trim(); + if (verb.isBlank() || target.isBlank()) { + throw new IllegalArgumentException("verb and target must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/GetAssetDetailsRequest.java b/prometeu-packer/src/main/java/p/packer/api/workspace/GetAssetDetailsRequest.java new file mode 100644 index 00000000..bfe30543 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/GetAssetDetailsRequest.java @@ -0,0 +1,18 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerProjectContext; + +import java.util.Objects; + +public record GetAssetDetailsRequest( + PackerProjectContext project, + String assetReference) { + + public GetAssetDetailsRequest { + Objects.requireNonNull(project, "project"); + assetReference = Objects.requireNonNull(assetReference, "assetReference").trim(); + if (assetReference.isBlank()) { + throw new IllegalArgumentException("assetReference must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/GetAssetDetailsResult.java b/prometeu-packer/src/main/java/p/packer/api/workspace/GetAssetDetailsResult.java new file mode 100644 index 00000000..49584579 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/GetAssetDetailsResult.java @@ -0,0 +1,25 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerOperationStatus; +import p.packer.api.assets.PackerAssetDetails; +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.util.List; +import java.util.Objects; + +public record GetAssetDetailsResult( + PackerOperationStatus status, + String summary, + PackerAssetDetails details, + List diagnostics) { + + public GetAssetDetailsResult { + Objects.requireNonNull(status, "status"); + summary = Objects.requireNonNull(summary, "summary").trim(); + Objects.requireNonNull(details, "details"); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + if (summary.isBlank()) { + throw new IllegalArgumentException("summary must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/InitWorkspaceRequest.java b/prometeu-packer/src/main/java/p/packer/api/workspace/InitWorkspaceRequest.java new file mode 100644 index 00000000..b1354290 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/InitWorkspaceRequest.java @@ -0,0 +1,13 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerProjectContext; + +import java.util.Objects; + +public record InitWorkspaceRequest( + PackerProjectContext project) { + + public InitWorkspaceRequest { + Objects.requireNonNull(project, "project"); + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/InitWorkspaceResult.java b/prometeu-packer/src/main/java/p/packer/api/workspace/InitWorkspaceResult.java new file mode 100644 index 00000000..4b0ae31f --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/InitWorkspaceResult.java @@ -0,0 +1,25 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerOperationStatus; +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; + +public record InitWorkspaceResult( + PackerOperationStatus status, + String summary, + Path registryPath, + List diagnostics) { + + public InitWorkspaceResult { + Objects.requireNonNull(status, "status"); + summary = Objects.requireNonNull(summary, "summary").trim(); + registryPath = Objects.requireNonNull(registryPath, "registryPath").toAbsolutePath().normalize(); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + if (summary.isBlank()) { + throw new IllegalArgumentException("summary must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/ListAssetsRequest.java b/prometeu-packer/src/main/java/p/packer/api/workspace/ListAssetsRequest.java new file mode 100644 index 00000000..68f4122e --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/ListAssetsRequest.java @@ -0,0 +1,13 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerProjectContext; + +import java.util.Objects; + +public record ListAssetsRequest( + PackerProjectContext project) { + + public ListAssetsRequest { + Objects.requireNonNull(project, "project"); + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/ListAssetsResult.java b/prometeu-packer/src/main/java/p/packer/api/workspace/ListAssetsResult.java new file mode 100644 index 00000000..538edc0f --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/ListAssetsResult.java @@ -0,0 +1,25 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerOperationStatus; +import p.packer.api.assets.PackerAssetSummary; +import p.packer.api.diagnostics.PackerDiagnostic; + +import java.util.List; +import java.util.Objects; + +public record ListAssetsResult( + PackerOperationStatus status, + String summary, + List assets, + List diagnostics) { + + public ListAssetsResult { + Objects.requireNonNull(status, "status"); + summary = Objects.requireNonNull(summary, "summary").trim(); + assets = List.copyOf(Objects.requireNonNull(assets, "assets")); + diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics")); + if (summary.isBlank()) { + throw new IllegalArgumentException("summary must not be blank"); + } + } +} diff --git a/prometeu-packer/src/main/java/p/packer/api/workspace/PackerWorkspaceService.java b/prometeu-packer/src/main/java/p/packer/api/workspace/PackerWorkspaceService.java new file mode 100644 index 00000000..0d2fe4a7 --- /dev/null +++ b/prometeu-packer/src/main/java/p/packer/api/workspace/PackerWorkspaceService.java @@ -0,0 +1,13 @@ +package p.packer.api.workspace; + +import p.packer.api.PackerOperationClass; + +public interface PackerWorkspaceService { + PackerOperationClass operationClass(); + + InitWorkspaceResult initWorkspace(InitWorkspaceRequest request); + + ListAssetsResult listAssets(ListAssetsRequest request); + + GetAssetDetailsResult getAssetDetails(GetAssetDetailsRequest request); +} diff --git a/prometeu-packer/src/test/java/p/packer/testing/PackerFixtureCatalogTest.java b/prometeu-packer/src/test/java/p/packer/testing/PackerFixtureCatalogTest.java new file mode 100644 index 00000000..75d38857 --- /dev/null +++ b/prometeu-packer/src/test/java/p/packer/testing/PackerFixtureCatalogTest.java @@ -0,0 +1,21 @@ +package p.packer.testing; + +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +final class PackerFixtureCatalogTest { + @Test + void exposesWorkspaceFixturesForFuturePackerTests() { + final Path emptyWorkspace = PackerFixtureLocator.fixtureRoot("workspaces/empty"); + final Path managedWorkspace = PackerFixtureLocator.fixtureRoot("workspaces/managed-basic"); + + assertTrue(Files.isDirectory(emptyWorkspace)); + assertTrue(Files.isDirectory(managedWorkspace)); + assertTrue(Files.isRegularFile(managedWorkspace.resolve("assets/.prometeu/index.json"))); + assertTrue(Files.isRegularFile(managedWorkspace.resolve("assets/ui/atlas/asset.json"))); + } +} diff --git a/prometeu-packer/src/test/java/p/packer/testing/PackerFixtureLocator.java b/prometeu-packer/src/test/java/p/packer/testing/PackerFixtureLocator.java new file mode 100644 index 00000000..e05545db --- /dev/null +++ b/prometeu-packer/src/test/java/p/packer/testing/PackerFixtureLocator.java @@ -0,0 +1,23 @@ +package p.packer.testing; + +import java.net.URL; +import java.nio.file.Path; +import java.util.Objects; + +public final class PackerFixtureLocator { + private PackerFixtureLocator() { + } + + public static Path fixtureRoot(String relativePath) { + final String normalized = Objects.requireNonNull(relativePath, "relativePath").replace('\\', '/'); + final URL resource = PackerFixtureLocator.class.getClassLoader().getResource("fixtures/" + normalized); + if (resource == null) { + throw new IllegalArgumentException("fixture not found: " + normalized); + } + try { + return Path.of(resource.toURI()).toAbsolutePath().normalize(); + } catch (Exception exception) { + throw new IllegalStateException("unable to resolve fixture: " + normalized, exception); + } + } +} diff --git a/prometeu-packer/src/test/resources/fixtures/workspaces/empty/.gitkeep b/prometeu-packer/src/test/resources/fixtures/workspaces/empty/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/prometeu-packer/src/test/resources/fixtures/workspaces/empty/.gitkeep @@ -0,0 +1 @@ + diff --git a/prometeu-packer/src/test/resources/fixtures/workspaces/managed-basic/assets/.prometeu/index.json b/prometeu-packer/src/test/resources/fixtures/workspaces/managed-basic/assets/.prometeu/index.json new file mode 100644 index 00000000..b6b75c4f --- /dev/null +++ b/prometeu-packer/src/test/resources/fixtures/workspaces/managed-basic/assets/.prometeu/index.json @@ -0,0 +1,11 @@ +{ + "schema_version": 1, + "next_asset_id": 2, + "assets": [ + { + "asset_id": 1, + "asset_uuid": "fixture-uuid-1", + "root": "ui/atlas" + } + ] +} diff --git a/prometeu-packer/src/test/resources/fixtures/workspaces/managed-basic/assets/ui/atlas/asset.json b/prometeu-packer/src/test/resources/fixtures/workspaces/managed-basic/assets/ui/atlas/asset.json new file mode 100644 index 00000000..66c95444 --- /dev/null +++ b/prometeu-packer/src/test/resources/fixtures/workspaces/managed-basic/assets/ui/atlas/asset.json @@ -0,0 +1,15 @@ +{ + "schema_version": 1, + "name": "ui_atlas", + "type": "image_bank", + "inputs": { + "sprites": ["sprites/confirm.png"] + }, + "output": { + "format": "TILES/indexed_v1", + "codec": "RAW" + }, + "preload": { + "enabled": true + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 823a09bb..9358a877 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,7 @@ plugins { rootProject.name = "prometeu-studio" include("prometeu-infra") +include("prometeu-packer") include("prometeu-compiler:frontends:prometeu-frontend-pbs") include("prometeu-compiler:prometeu-compiler-core")