Skip to content

Commit 5681861

Browse files
authored
Merge pull request #91 from GradleUp/add-wait-option
Add `publishingTimeout` and restore log messages
2 parents a89275b + aaa4d89 commit 5681861

File tree

2 files changed

+84
-48
lines changed

2 files changed

+84
-48
lines changed

src/main/kotlin/nmcp/CentralPortalOptions.kt

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,37 @@ abstract class CentralPortalOptions {
3232
abstract val publicationName: Property<String>
3333

3434
/**
35-
* After a deployment has been uploaded, the central portal verifies that it matches the
35+
* The timeout until the deployment reaches the `VALIDATED` or `FAILED` status.
36+
*
37+
* After a deployment has been uploaded, the central portal validates that it matches the
3638
* maven central requirements, which may take some time.
3739
*
38-
* After waiting, the deployment is either:
39-
* - VALIDATED: it needs to be manually published in the Central Portal UI.
40-
* - PUBLISHED: it is published and available on Maven Central.
41-
* - FAILED: the deployment has failed. You
40+
* - If [publishingType] is `AUTOMATIC`, the status transitions to `PUBLISHING` automatically after validation.
41+
* - If [publishingType] is `USER_MANAGED`, the status stays `VALIDATED`. Visit the portal UI
42+
* to manually trigger the publishing.
43+
*
44+
* [validationTimeout] specifies what duration to wait for the verification to complete.
45+
* You may pass the special value '0' to disable waiting for validation altogether.
46+
*
47+
* Default: 10 minutes.
48+
*/
49+
abstract val validationTimeout: Property<Duration>
50+
51+
/**
52+
* The timeout until the deployment reaches the `PUBLISHED` or `FAILED` status.
53+
*
54+
* After publishing, the deployment is published and available in Maven Central.
55+
*
56+
* Note: it should be very rare that publishing ends in the `FAILED` status. There are
57+
* no documented instances of this happening. If you see one, please [open an issue](https://github.com/GradleUp/nmcp/issues/new)
58+
* so we can document this behavior.
4259
*
43-
* [verificationTimeout] specifies what duration to wait for the verification to complete.
44-
* You may pass the special value '0' to disable waiting for verification altogether.
60+
* [publishingTimeout] specifies what duration to wait for the publishing to complete.
61+
* You may pass the special value '0' to disable waiting for publishing altogether.
4562
*
4663
* Default: 10 minutes.
4764
*/
48-
abstract val verificationTimeout: Property<Duration>
65+
abstract val publishingTimeout: Property<Duration>
4966

5067
/**
5168
* The API endpoint to use (optional).

src/main/kotlin/nmcp/internal/task/publishRelease.kt

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import gratatouille.GInputFile
44
import gratatouille.GLogger
55
import gratatouille.GTask
66
import java.net.SocketTimeoutException
7+
import kotlin.time.Duration
78
import kotlinx.serialization.json.Json
89
import kotlinx.serialization.json.JsonObject
910
import kotlinx.serialization.json.JsonPrimitive
@@ -23,7 +24,6 @@ import kotlin.time.Duration.Companion.minutes
2324
import kotlin.time.Duration.Companion.seconds
2425
import kotlin.time.TimeSource.Monotonic.markNow
2526

26-
2727
@GTask(pure = false)
2828
fun publishRelease(
2929
logger: GLogger,
@@ -32,7 +32,8 @@ fun publishRelease(
3232
publicationName: String,
3333
publishingType: String?,
3434
baseUrl: String?,
35-
verificationTimeoutSeconds: Long?,
35+
validationTimeoutSeconds: Long?,
36+
publishingTimeoutSeconds: Long?,
3637
inputFile: GInputFile,
3738
) {
3839
check(!username.isNullOrBlank()) {
@@ -50,7 +51,7 @@ fun publishRelease(
5051
.addFormDataPart(
5152
"bundle",
5253
publicationName,
53-
inputFile.asRequestBody("application/zip".toMediaType())
54+
inputFile.asRequestBody("application/zip".toMediaType()),
5455
)
5556
.build()
5657

@@ -75,44 +76,60 @@ fun publishRelease(
7576

7677
logger.lifecycle("Nmcp: deployment bundle '$deploymentId' uploaded to '$baseUrl'.")
7778

78-
val timeout = verificationTimeoutSeconds?.seconds ?: 10.minutes
79-
val pollingInterval = 5.seconds
80-
if (timeout.isPositive()) {
81-
logger.lifecycle("Nmcp: verifying deployment status...")
82-
val mark = markNow()
83-
while (true) {
84-
check (mark.elapsedNow() < timeout) {
85-
"Nmcp: timeout while waiting for the deployment $deploymentId to publish. You might need to check the deployment on the Central Portal UI (see $baseUrl$), or you could increase the wait timeout (the current timeout is $timeout)."
79+
val timeout1 = validationTimeoutSeconds?.seconds ?: 10.minutes
80+
if (timeout1.isPositive()) {
81+
logger.lifecycle("Nmcp: waiting for validation...")
82+
waitFor(setOf(VALIDATED, PUBLISHED), timeout1, logger, deploymentId, baseUrl, token)
83+
84+
val timeout2 = publishingTimeoutSeconds?.seconds ?: 0.seconds
85+
if (publishingType == "AUTOMATIC") {
86+
if (timeout2.isPositive()) {
87+
logger.lifecycle("Nmcp: deployment is validated, waiting for publication...")
88+
waitFor(setOf(PUBLISHED), timeout1, logger, deploymentId, baseUrl, token)
89+
logger.lifecycle("Nmcp: deployment is published.")
90+
} else {
91+
logger.lifecycle("Nmcp: deployment is publishing... Check the central portal UI to verify its status.")
8692
}
87-
when (val status = verifyStatus(
88-
deploymentId = deploymentId,
89-
baseUrl = baseUrl,
90-
token = token,
91-
)) {
92-
UNKNOWN_QUERY_LATER,
93-
PENDING,
94-
VALIDATING,
95-
PUBLISHING -> {
96-
logger.debug("Deployment status is '$status', will try again in ${pollingInterval.inWholeSeconds}s (${timeout - mark.elapsedNow()} left)...")
97-
// Wait for the next attempt to reduce the load on the Central Portal API
98-
Thread.sleep(pollingInterval.inWholeMilliseconds)
99-
continue
100-
}
101-
102-
VALIDATED -> {
103-
logger.lifecycle("Deployment has passed validation, publish it manually from the Central Portal UI.")
104-
break
105-
}
93+
} else {
94+
check(publishingTimeoutSeconds == null) {
95+
"Nmcp: 'publishingTimeout' has no effect if 'publishingType' is USER_MANAGED. Either set 'publishingType = AUTOMATIC' or remove 'publishingTimeout'"
96+
}
97+
logger.lifecycle("Nmcp: deployment has passed validation, publish it manually from the Central Portal UI.")
98+
}
99+
} else {
100+
logger.lifecycle("Nmcp: deployment is validating... Check the central portal UI to verify its status.")
101+
}
102+
}
106103

107-
PUBLISHED -> {
108-
logger.lifecycle("Deployment is published.")
109-
break
110-
}
104+
private fun waitFor(
105+
target: Set<Status>,
106+
timeout: Duration,
107+
logger: GLogger,
108+
deploymentId: String,
109+
baseUrl: String,
110+
token: String,
111+
) {
112+
val pollingInterval = 5.seconds
113+
val mark = markNow()
114+
while (true) {
115+
check(mark.elapsedNow() < timeout) {
116+
"Nmcp: timeout while checking deployment '$deploymentId'. You might need to check the deployment status on the Central Portal UI (see $baseUrl$), or you could increase the timeout."
117+
}
111118

112-
is FAILED -> {
113-
error("Deployment has failed:\n${status.error}")
114-
}
115-
}
119+
val status = verifyStatus(
120+
deploymentId = deploymentId,
121+
baseUrl = baseUrl,
122+
token = token,
123+
)
124+
if (status is FAILED) {
125+
error("Nmcp: deployment has failed:\n${status.error}")
126+
} else if (status in target) {
127+
return
128+
} else {
129+
logger.lifecycle("Nmcp: deployment status is '$status', will try again in ${pollingInterval.inWholeSeconds}s (${timeout - mark.elapsedNow()} left)...")
130+
// Wait for the next attempt to reduce the load on the Central Portal API
131+
Thread.sleep(pollingInterval.inWholeMilliseconds)
132+
continue
116133
}
117134
}
118135
}
@@ -190,7 +207,7 @@ internal fun Project.registerPublishReleaseTask(
190207
taskName: String,
191208
inputFile: Provider<RegularFile>,
192209
artifactId: Provider<String>,
193-
spec: CentralPortalOptions
210+
spec: CentralPortalOptions,
194211
): TaskProvider<PublishReleaseTask> {
195212
val defaultPublicationName = artifactId.map { "${project.group}:${it}:${project.version}.zip" }
196213
return registerPublishReleaseTask(
@@ -201,7 +218,9 @@ internal fun Project.registerPublishReleaseTask(
201218
publicationName = spec.publicationName.orElse(defaultPublicationName),
202219
publishingType = spec.publishingType,
203220
baseUrl = spec.baseUrl,
204-
verificationTimeoutSeconds = spec.verificationTimeout.map { it.seconds }
221+
validationTimeoutSeconds = spec.validationTimeout.map { it.seconds },
222+
publishingTimeoutSeconds = spec.publishingTimeout.map { it.seconds },
223+
205224
)
206225
}
207226

0 commit comments

Comments
 (0)