From 910791532bf71f64122ce413673aa7455166b70c Mon Sep 17 00:00:00 2001 From: HuitaePark Date: Wed, 26 Aug 2026 14:51:58 +0900 Subject: [PATCH 1/2] =?UTF-8?q?build:=20#41=20=EB=A6=B4=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=20=ED=9B=84=EB=B3=B4=20=ED=86=B5=ED=95=A9=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=20=EA=B2=8C=EC=9D=B4=ED=8A=B8=EB=A5=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 4 +- AGENTS.md | 17 +++++++++ build.gradle | 82 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aed58e8..83dfb9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,5 +24,5 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - - name: Build and Test - run: ./gradlew build + - name: Build, Test, and Verify Release Candidate + run: ./gradlew build verifyReleaseCandidate diff --git a/AGENTS.md b/AGENTS.md index a2c6b41..83336d9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -390,6 +390,17 @@ Verify the published Spring AI adapter API and the starter with one explicitly s ./gradlew verifyPublishedIntegrationConsumer ``` +Run the complete release-candidate gate, including module-local staging and +binary/source/Javadoc/POM/module-metadata artifact checks: + +```bash +./gradlew verifyReleaseCandidate +``` + +Use `-PprojectVersion=0.1.0` for the signed release-candidate path. Non-snapshot +staging requires signing material; the default `0.0.1-SNAPSHOT` path is +secretless. + Run sample app after implementation work: ```bash @@ -436,6 +447,12 @@ Stage and deploy a Central release: ## Update History +### 2026-08-26 + +- Added root publication aggregation and a release-candidate verification gate + that stages every public module and checks the complete artifact/signature + set for the selected version. + ### 2026-08-25 - Connected supported Spring AI 2.0 non-streaming `ChatClient` requests to text-scope adaptation, model/output resolution, conservative preflight, atomic reservation, in-flight tracking, provider usage extraction, and `ReservationAccounting` reconciliation in one around-call lifecycle. diff --git a/build.gradle b/build.gradle index 0595052..2d9ca8c 100644 --- a/build.gradle +++ b/build.gradle @@ -303,6 +303,87 @@ subprojects { } } +def stagingPublicationTasks = publishedModuleDescriptions.keySet().collect { + ":${it}:publishAllPublicationsToStagingRepository" +} + +tasks.register('publishAllPublicationsToStagingRepository') { + group = 'publishing' + description = 'Publishes every public Token Pilot module to its module-local staging repository.' + dependsOn stagingPublicationTasks +} + +tasks.register('verifyReleaseCandidate') { + group = 'verification' + description = 'Runs release checks, stages every public module, and verifies the complete artifact set.' + dependsOn subprojects.collect { "${it.path}:test" } + dependsOn tasks.named('check') + dependsOn tasks.named('publishAllPublicationsToStagingRepository') + + doLast { + def version = project.version.toString() + def requiredArtifacts = [ + 'binary JAR': { String name -> + name.endsWith('.jar') && + !name.endsWith('-sources.jar') && + !name.endsWith('-javadoc.jar') + }, + 'sources JAR': { String name -> name.endsWith('-sources.jar') }, + 'Javadoc JAR': { String name -> name.endsWith('-javadoc.jar') }, + 'POM': { String name -> name.endsWith('.pom') }, + 'Gradle module metadata': { String name -> name.endsWith('.module') } + ] + def requiredSignatures = [ + 'binary JAR signature': { String name -> + name.endsWith('.jar.asc') && + !name.endsWith('-sources.jar.asc') && + !name.endsWith('-javadoc.jar.asc') + }, + 'sources JAR signature': { String name -> name.endsWith('-sources.jar.asc') }, + 'Javadoc JAR signature': { String name -> name.endsWith('-javadoc.jar.asc') }, + 'POM signature': { String name -> name.endsWith('.pom.asc') }, + 'Gradle module metadata signature': { String name -> name.endsWith('.module.asc') } + ] + + publishedModuleDescriptions.keySet().each { moduleName -> + def moduleProject = project(":${moduleName}") + def versionDirectory = moduleProject.file( + "build/staging-deploy/cloud/token-pilot/${moduleName}/${version}" + ) + if (!versionDirectory.isDirectory()) { + throw new GradleException( + "${moduleName} staging directory is missing for version ${version}: ${versionDirectory}" + ) + } + + def artifactNames = versionDirectory.listFiles() + ?.findAll { it.isFile() } + ?.collect { it.name } ?: [] + def missingArtifacts = requiredArtifacts.findAll { label, matcher -> + !artifactNames.any { artifactName -> matcher(artifactName) } + }.keySet() + if (!missingArtifacts.isEmpty()) { + throw new GradleException( + "${moduleName}:${version} is missing published artifacts: ${missingArtifacts}" + ) + } + + if (!version.endsWith('-SNAPSHOT')) { + def missingSignatures = requiredSignatures.findAll { label, matcher -> + !artifactNames.any { artifactName -> matcher(artifactName) } + }.keySet() + if (!missingSignatures.isEmpty()) { + throw new GradleException( + "${moduleName}:${version} is missing release signatures: ${missingSignatures}" + ) + } + } + } + + println "Verified ${publishedModuleDescriptions.size()} Token Pilot release candidates at ${version}." + } +} + def publicationPomTasks = publishedModuleDescriptions.keySet().collect { ":${it}:generatePomFileForMavenJavaPublication" } @@ -346,6 +427,7 @@ tasks.register('verifyPublicationMetadata') { .asFile def pom = new XmlSlurper(false, false).parse(pomFile) + requirePomValue(moduleName, 'version', pom.version.text(), project.version.toString()) requirePomValue(moduleName, 'name', pom.name.text(), moduleName) requirePomValue(moduleName, 'description', pom.description.text(), moduleDescription) requirePomValue(moduleName, 'url', pom.url.text(), 'https://github.com/tokenpliot/tokenpilot') From 463009141a83ed79523aebae6106720767e79f8d Mon Sep 17 00:00:00 2001 From: HuitaePark Date: Wed, 26 Aug 2026 15:00:53 +0900 Subject: [PATCH 2/2] =?UTF-8?q?ci:=20#41=20PR=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=EC=9D=84=20=EC=9D=BD=EA=B8=B0=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83dfb9b..d99bf2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,8 @@ on: jobs: build: + permissions: + contents: read runs-on: ubuntu-latest steps: