refactor: 빌드 최적화 및 ci 수정
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
}
|
||||
|
||||
// Redis SDK leaf — see docs/superpowers/specs/2026-08-07-redis-wrapper-typed-api-design.md.
|
||||
//
|
||||
// The design models the SDK as separate Gradle modules. This repository's fail-closed module
|
||||
// registry outranks that layout, so the module boundaries are packages under
|
||||
// dev.caskeleton.adapter.outbound.cache.redis.sdk and RedisSdkModuleBoundaryTest enforces them.
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
|
||||
dependencies {
|
||||
// Registered edges the semantic port adapters need. The SDK's *main* source imports nothing from
|
||||
// them today — the semantic cache/session/idempotency/rate-limit adapters that did were removed
|
||||
@@ -193,4 +195,3 @@ strictTestLanes {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
}
|
||||
|
||||
// Driven adapter for provider-neutral file publication and legacy CSV export. The only qualified
|
||||
// R2 provider is local-persistent; shared-mounted/NFS and SFTP are not stand-ins or implemented
|
||||
// capabilities. Its IO path uses only the JDK. Spring Boot autoconfigure supplies explicit,
|
||||
// disabled-default R1/R2 composition and SLF4J remains the diagnostics API.
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
|
||||
description = 'Outbound adapter: file publication (R1 CSV export, R2 local-persistent) plus the ' + \
|
||||
'local filesystem content platform behind the HTTP Fileserver'
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'java-test-fixtures'
|
||||
}
|
||||
|
||||
// Shared test code as a Gradle test-fixtures variant — ADR-BUILD-001.
|
||||
apply plugin: 'ca.spring-library'
|
||||
|
||||
apply plugin: 'java-test-fixtures'
|
||||
|
||||
// Outbound HTTP Client Platform leaf — see
|
||||
// docs/superpowers/specs/2026-08-08-httpclient-platform-design.md (design package) and
|
||||
// docs/httpclient/repository-adaptation.md (how the design's 19 library modules map here).
|
||||
|
||||
+7
-7
@@ -40,7 +40,7 @@ class MutualTlsHandshakeContractTest {
|
||||
TlsFixture fixture = TlsFixture.trusted();
|
||||
try (MockHttpServer server = MockHttpServer.startTls(fixture.serverSocketFactory(), true)) {
|
||||
server.enqueueJson(200, "{\"id\":1,\"name\":\"mtls\"}");
|
||||
ClientProfile profile = tlsProfile(server.uri("/"));
|
||||
ClientProfile profile = tlsProfile(server.ipv4Uri("/"));
|
||||
ApacheBlockingTransportProvider provider =
|
||||
new ApacheBlockingTransportProvider(
|
||||
Optional.empty(),
|
||||
@@ -56,7 +56,7 @@ class MutualTlsHandshakeContractTest {
|
||||
NoopLifecycleListener.INSTANCE))
|
||||
.build()
|
||||
.get()
|
||||
.uri(server.uri("/users/1"))
|
||||
.uri(server.ipv4Uri("/users/1"))
|
||||
.retrieve()
|
||||
.body(String.class);
|
||||
assertThat(body).contains("mtls");
|
||||
@@ -72,7 +72,7 @@ class MutualTlsHandshakeContractTest {
|
||||
TlsFixture fixture = TlsFixture.trusted();
|
||||
try (MockHttpServer server = MockHttpServer.startTls(fixture.serverSocketFactory(), true)) {
|
||||
server.enqueueJson(200, "{\"id\":1,\"name\":\"never\"}");
|
||||
ClientProfile profile = tlsProfile(server.uri("/"));
|
||||
ClientProfile profile = tlsProfile(server.ipv4Uri("/"));
|
||||
ApacheBlockingTransportProvider provider =
|
||||
new ApacheBlockingTransportProvider(
|
||||
Optional.empty(),
|
||||
@@ -91,7 +91,7 @@ class MutualTlsHandshakeContractTest {
|
||||
// so the failure can surface either during the handshake or on the first read. Both are
|
||||
// failures; what must never happen is the request being served.
|
||||
assertThatThrownBy(
|
||||
() -> client.get().uri(server.uri("/users/1")).retrieve().body(String.class))
|
||||
() -> client.get().uri(server.ipv4Uri("/users/1")).retrieve().body(String.class))
|
||||
.isInstanceOf(RuntimeException.class);
|
||||
} finally {
|
||||
provider.close(
|
||||
@@ -119,7 +119,7 @@ class MutualTlsHandshakeContractTest {
|
||||
try (MockHttpServer server =
|
||||
MockHttpServer.startTls(serverFixture.serverSocketFactory(), false)) {
|
||||
server.enqueueJson(200, "{\"id\":1,\"name\":\"never\"}");
|
||||
ClientProfile profile = tlsProfile(server.uri("/"));
|
||||
ClientProfile profile = tlsProfile(server.ipv4Uri("/"));
|
||||
Throwable captured = captureFailure(profile, server, unrelatedClientTrust);
|
||||
assertPermanent(captured);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ class MutualTlsHandshakeContractTest {
|
||||
private void assertPermanentTlsFailure(TlsFixture fixture) throws Exception {
|
||||
try (MockHttpServer server = MockHttpServer.startTls(fixture.serverSocketFactory(), false)) {
|
||||
server.enqueueJson(200, "{\"id\":1,\"name\":\"never\"}");
|
||||
ClientProfile profile = tlsProfile(server.uri("/"));
|
||||
ClientProfile profile = tlsProfile(server.ipv4Uri("/"));
|
||||
Throwable captured = captureFailure(profile, server, fixture);
|
||||
assertPermanent(captured);
|
||||
}
|
||||
@@ -150,7 +150,7 @@ class MutualTlsHandshakeContractTest {
|
||||
NoopLifecycleListener.INSTANCE))
|
||||
.build();
|
||||
try {
|
||||
client.get().uri(server.uri("/users/1")).retrieve().body(String.class);
|
||||
client.get().uri(server.ipv4Uri("/users/1")).retrieve().body(String.class);
|
||||
throw new AssertionError("the handshake was expected to fail");
|
||||
} catch (RuntimeException failure) {
|
||||
return failure;
|
||||
|
||||
+5
@@ -71,6 +71,11 @@ public final class MockHttpServer implements AutoCloseable {
|
||||
return server.url(path).uri();
|
||||
}
|
||||
|
||||
/** Deterministic IPv4 loopback URI for TLS fixtures on dual-stack hosts. */
|
||||
public URI ipv4Uri(String path) {
|
||||
return server.url(path).newBuilder().host("127.0.0.1").build().uri();
|
||||
}
|
||||
|
||||
public int port() {
|
||||
return server.getPort();
|
||||
}
|
||||
|
||||
+6
@@ -49,6 +49,12 @@ public final class TlsFixture {
|
||||
.signedBy(authority)
|
||||
.commonName(serverCommonName)
|
||||
.addSubjectAlternativeName(serverCommonName);
|
||||
if ("localhost".equals(serverCommonName)) {
|
||||
// MockWebServer binds an IPv4 loopback socket in this fixture environment while localhost may
|
||||
// resolve to both 127.0.0.1 and ::1. Include the explicit IPv4 SAN so TLS tests can use a
|
||||
// deterministic address without changing the certificate semantics under test.
|
||||
server.addSubjectAlternativeName("127.0.0.1");
|
||||
}
|
||||
if (validity.isNegative()) {
|
||||
long now = System.currentTimeMillis();
|
||||
server.validityInterval(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
}
|
||||
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
|
||||
dependencies {
|
||||
implementation project(':application-core')
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':application-core')
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
}
|
||||
|
||||
// Driven adapter: provider-neutral semantic object-storage ports plus a bounded local-development
|
||||
// provider. Canonical app.object-storage activation is disabled by default. The old whole-byte[]
|
||||
// filesystem/S3 adapters remain isolated, explicit legacy compatibility only.
|
||||
@@ -10,9 +15,6 @@
|
||||
// This sentence used to end "and this repo has no version catalog". That is false, and this file
|
||||
// disproves it twice below with `libs.archunit.junit5` and `libs.jqwik`. Module scope is a locking
|
||||
// decision; the catalog just has no awssdk entry.
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
|
||||
description = 'Outbound adapter: object storage (S3/MinIO + local filesystem)'
|
||||
|
||||
|
||||
@@ -33,7 +35,7 @@ strictTestLanes {
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "software.amazon.awssdk:bom:${awsSdkVersion}"
|
||||
mavenBom "software.amazon.awssdk:bom:${libs.versions.awsSdk.get()}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
id 'java-test-fixtures'
|
||||
id 'ca.jpa-evidence'
|
||||
}
|
||||
|
||||
// Shared test code as a Gradle test-fixtures variant — ADR-BUILD-001.
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
|
||||
apply plugin: 'java-test-fixtures'
|
||||
|
||||
// JPA persistence adapter — merged RDBMS base + PostgreSQL vendor module.
|
||||
// Owns JPA entities, Spring Data repositories, mappers, transaction/audit/lock/outbox port
|
||||
// implementations, and the vendor-neutral SPI interfaces (OutboxClaimRepository /
|
||||
@@ -29,8 +31,6 @@ strictTestLanes {
|
||||
sourceSet('jpaPlatformPerformanceTest') { compilesAgainst 'main', 'testFixtures' }
|
||||
}
|
||||
|
||||
ext.jpaPostgreSqlEvidenceImage = 'postgres:16-alpine'
|
||||
|
||||
dependencies {
|
||||
implementation project(':application-core')
|
||||
implementation project(':shared-contract')
|
||||
@@ -108,6 +108,8 @@ dependencies {
|
||||
// through `requires(...)` turns on `failOnNoMatchingTests` AND the post-run check that the named
|
||||
// selector actually executed, so a renamed readiness class fails its lane instead of leaving it
|
||||
// with nothing to run.
|
||||
String jpaPostgreSqlEvidenceImage = providers.gradleProperty('jpaPostgreSqlEvidenceImage')
|
||||
.getOrElse('postgres:16-alpine')
|
||||
String readinessPackage = 'dev.caskeleton.adapter.outbound.persistence.readiness'
|
||||
Map<String, String> postgresqlReadinessLanes = [
|
||||
postgresqlLifecycleIntegrationTest : 'PostgreSqlLifecycleIntegrationTest',
|
||||
@@ -155,7 +157,7 @@ strictTestLanes.lanes.named('postgresqlSecurityBaselineIntegrationTest').configu
|
||||
}
|
||||
|
||||
// The task itself stays, and its name is not negotiable: config/jpa/readiness-cards.yaml lists it as
|
||||
// a support task of the `jpa-security-baseline` card, and gradle/jpa-evidence.gradle resolves every
|
||||
// a support task of the `jpa-security-baseline` card, and the ca.jpa-evidence qualification plugin resolves every
|
||||
// listed path through `tasks.findByName` and fails the build when one is missing. What changed is
|
||||
// what it checks. Grepping the fixture's source text for 'runtimeRoleCannotCreateInApplicationSchema',
|
||||
// 'assertDockerAvailable' and '42501' passed on three strings in a comment and proved nothing about
|
||||
@@ -355,11 +357,11 @@ apiSurface {
|
||||
]
|
||||
}
|
||||
|
||||
apply from: rootProject.file('gradle/jpa-evidence.gradle')
|
||||
|
||||
|
||||
// The JPA readiness registry describes this platform's lanes and resolves their task paths, so it
|
||||
// runs with this leaf's `check` rather than with all 62. The task itself is registered by
|
||||
// gradle/qualification/jpa-qualification.gradle, which the root applies.
|
||||
// the ca.jpa-qualification plugin from build-qualification, which the root applies.
|
||||
tasks.named('check') {
|
||||
dependsOn rootProject.tasks.named('verifyJpaReadinessRegistry')
|
||||
}
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@ public final class JpaReleaseRendering {
|
||||
private static final Pattern WORKFLOW_PROMOTION_LOOP = Pattern.compile("for major in ([0-9 ]+);");
|
||||
private static final Pattern QUOTED_MAJOR = Pattern.compile("\"(\\d+)\"");
|
||||
private static final Pattern COMPATIBILITY_TARGET =
|
||||
Pattern.compile("target=PostgreSQL\\s+(\\d+)");
|
||||
Pattern.compile("^\\s*target:\\s*PostgreSQL\\s+(\\d+)\\s*$", Pattern.MULTILINE);
|
||||
|
||||
private JpaReleaseRendering() {}
|
||||
|
||||
@@ -128,9 +128,9 @@ public final class JpaReleaseRendering {
|
||||
* the conclusion this repository's own review pass reached before checking the workflow
|
||||
* directory.
|
||||
*
|
||||
* <p>The target is read from the status artifact the lane writes rather than from its filename. A
|
||||
* filename is a label; the artifact is what a promotion decision would actually be read from, so
|
||||
* a lane that stops recording its target stops counting as a lane.
|
||||
* <p>The target is read from the workflow matrix declaration rather than from its filename. The
|
||||
* status artifact receives that same matrix value through {@code TARGET}; a lane that stops
|
||||
* declaring its PostgreSQL target therefore stops counting as a lane.
|
||||
*/
|
||||
public static List<Integer> compatibilityLaneTargets(String workflow) {
|
||||
Objects.requireNonNull(workflow, "workflow");
|
||||
|
||||
@@ -36,10 +36,9 @@ design package's assumed module layout onto this leaf lives in
|
||||
`verifyCleanArchitectureDependencies` only checks that resolved edges are a subset of the declared
|
||||
ones, so an unused permission passes every run; `MongoRegistryPermissionParityTest` checks the
|
||||
other direction and fails when the two sets differ.
|
||||
- `runtime_memberships` is `["app-bootstrap"]`, and the composition root really does declare
|
||||
`implementation(project(':adapter:outbound:persistence-mongo'))` — with the reactive starter and
|
||||
the reactivestreams driver excluded, because there is no reactive port in the shipped Stable
|
||||
scope. `RuntimeMembershipClasspathAgreementTest` compares the registry against the resolved
|
||||
- The composition root declares `implementation(project(':adapter:outbound:persistence-mongo'))` —
|
||||
with the reactive starter and the reactivestreams driver excluded, because there is no reactive
|
||||
port in the shipped Stable scope. The actual Gradle runtime graph is the runtime SSOT;
|
||||
runtime classpath, so the membership cannot drift from what the jar carries. Property-only
|
||||
activation therefore works here: the switch turns on a module that already ships, and shipping it
|
||||
off is not the same contract as leaving it out, because absence cannot be reversed at deploy time
|
||||
|
||||
@@ -13,11 +13,11 @@ document/repository/mapper와 application 또는 domain port 구현을 추가할
|
||||
|
||||
### shipped runtime에 들어 있고, property가 그 스위치다
|
||||
|
||||
`app-bootstrap`은 이 leaf에 project dependency를 두고(`src/app-bootstrap/build.gradle`,
|
||||
reactive starter와 reactivestreams driver는 exclude), registry의 `runtime_memberships`도
|
||||
`["app-bootstrap"]`이다. 두 사실은 `RuntimeMembershipClasspathAgreementTest`가 runtime classpath와
|
||||
비교해 붙잡는다. 그래서 `ca-skeleton.persistence-mongo.enabled=true`는 실제로 동작하는 master
|
||||
switch다 — 없는 모듈을 부르는 property가 아니라, 이미 jar에 들어 있는 모듈을 켜는 스위치다.
|
||||
`app-bootstrap`은 이 leaf에 project dependency를 둔다(`src/app-bootstrap/build.gradle`; reactive
|
||||
starter와 reactivestreams driver는 exclude). runtime 포함 여부의 SSOT는 이 실제 Gradle graph이고
|
||||
`MongoRegistryPermissionParityTest`는 composition edge가 존재하는지도 확인한다. 그래서
|
||||
`ca-skeleton.persistence-mongo.enabled=true`는 없는 모듈을 부르는 property가 아니라 이미 application
|
||||
classpath에 들어 있는 모듈을 켜는 master switch다.
|
||||
|
||||
빠져 있는 모듈은 꺼진 모듈과 같은 계약이 아니다. 부재는 배포 시점에 되돌릴 수 없고, gating 결함을
|
||||
전부 가린다. 존재하지 않는 코드는 자기 condition이 무엇이라고 말하든 bean을 하나도 들고 있지 않기
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
id 'ca.spring-config'
|
||||
id 'java-test-fixtures'
|
||||
}
|
||||
|
||||
// Shared test code as a Gradle test-fixtures variant — ADR-BUILD-001. Applied here rather than
|
||||
// from the root, the way the GraphQL leaf does: only a leaf that has shared test code needs it.
|
||||
apply plugin: 'ca.spring-library'
|
||||
apply plugin: 'ca.spring-config'
|
||||
|
||||
apply plugin: 'java-test-fixtures'
|
||||
|
||||
// MongoDB Document Persistence Platform leaf — see
|
||||
// docs/superpowers/specs/2026-08-11-mongodb-document-persistence-platform-design.md (design package)
|
||||
// and docs/mongodb/repository-adaptation.md (how the design's 19 stable + 12 advanced library
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
plugins {
|
||||
id 'ca.spring-library'
|
||||
}
|
||||
|
||||
// Shared base for outbound integration adapters: correlation, fail-open dependency
|
||||
// logging, and the @Configuration seam. Depended on by messaging/cache/notification/httpclient.
|
||||
apply plugin: 'ca.spring-library'
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-autoconfigure'
|
||||
implementation 'org.slf4j:slf4j-api'
|
||||
|
||||
Reference in New Issue
Block a user