/
Nexus.kt
157 lines (129 loc) · 5.05 KB
/
Nexus.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package com.vanniktech.maven.publish.nexus
import java.io.IOException
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
internal class Nexus(
baseUrl: String,
private val username: String,
password: String,
private val stagingRepository: String?
) {
private val service by lazy {
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(NexusOkHttpInterceptor(username, password))
.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create())
.client(okHttpClient)
.baseUrl(baseUrl)
.build()
retrofit.create(NexusService::class.java)
}
private fun getProfileRepositories(): List<Repository>? {
val profileRepositoriesResponse = service.getProfileRepositories().execute()
if (!profileRepositoriesResponse.isSuccessful) {
throw IOException("Cannot get profileRepositories: ${profileRepositoriesResponse.errorBody()?.string()}")
}
return profileRepositoriesResponse.body()?.data
}
private fun findStagingRepository(): Repository {
val allRepositories = getProfileRepositories() ?: emptyList()
if (allRepositories.isEmpty()) {
throw IllegalArgumentException("No staging repositories found in account ${username}. Make sure you called \"./gradlew publish\".")
}
val candidateRepositories = if (stagingRepository != null) {
allRepositories.filter { it.repositoryId == stagingRepository }
} else {
allRepositories
}
if (candidateRepositories.isEmpty()) {
throw IllegalArgumentException(
"No matching staging repository found. You can can explicitly choose one by " +
"passing it as an option like this \"./gradlew closeAndReleaseRepository --repository=comexample-123\". " +
"Available repositories are: ${allRepositories.joinToString(separator = ", ") { it.repositoryId }}"
)
}
if (candidateRepositories.size > 1) {
throw IllegalArgumentException(
"More than 1 matching staging repository found. You can can explicitly choose " +
"one by passing it as an option like this \"./gradlew closeAndReleaseRepository --repository comexample-123\". " +
"Available repositories are: ${allRepositories.joinToString(separator = ", ") { it.repositoryId }}"
)
}
return candidateRepositories[0]
}
fun findAndCloseStagingRepository(): String {
val stagingRepository = findStagingRepository()
val repositoryId = stagingRepository.repositoryId
if (stagingRepository.type != "open") {
throw IllegalArgumentException("Repository $repositoryId is of type '${stagingRepository.type}' and not 'open'")
}
println("Closing repository: $repositoryId")
val response = service.closeRepository(TransitionRepositoryInput(TransitionRepositoryInputData(listOf(repositoryId)))).execute()
if (!response.isSuccessful) {
throw IOException("Cannot close repository: ${response.errorBody()?.string()}")
}
waitForClose(repositoryId)
return repositoryId
}
private fun waitForClose(repositoryId: String) {
val startMillis = System.currentTimeMillis()
val waitingChars = listOf(
PROGRESS_1,
PROGRESS_2,
PROGRESS_3,
PROGRESS_4,
PROGRESS_5,
PROGRESS_6,
PROGRESS_7
)
var i = 0
while (true) {
if (System.currentTimeMillis() - startMillis > CLOSE_TIMEOUT_MILLIS) {
throw IOException("Timeout waiting for repository close")
}
print("\r${waitingChars[i++ % waitingChars.size]} waiting for close...")
System.out.flush()
Thread.sleep(CLOSE_WAIT_INTERVAL_MILLIS)
try {
val repository = service.getRepository(repositoryId).execute().body()
if (repository?.type == "closed" && !repository.transitioning) {
break
}
} catch (e: IOException) {
System.err.println("Exception trying to get repository status: ${e.message}")
}
}
}
fun releaseStagingRepository(repositoryId: String) {
println("Releasing repository: $repositoryId")
val response = service.releaseRepository(
TransitionRepositoryInput(
TransitionRepositoryInputData(
stagedRepositoryIds = listOf(repositoryId),
autoDropAfterRelease = true
)
)
).execute()
if (!response.isSuccessful) {
throw IOException("Cannot release repository: ${response.errorBody()?.string()}")
}
println("Repository $repositoryId released")
}
fun closeAndReleaseRepository() {
val repositoryId = findAndCloseStagingRepository()
releaseStagingRepository(repositoryId)
}
companion object {
private const val PROGRESS_1 = "\u2839"
private const val PROGRESS_2 = "\u2838"
private const val PROGRESS_3 = "\u2834"
private const val PROGRESS_4 = "\u2826"
private const val PROGRESS_5 = "\u2807"
private const val PROGRESS_6 = "\u280F"
private const val PROGRESS_7 = "\u2819"
private const val CLOSE_TIMEOUT_MILLIS = 15 * 60 * 1000L
private const val CLOSE_WAIT_INTERVAL_MILLIS = 10_000L
}
}