Skip to content

Commit 612dc52

Browse files
authored
Merge pull request #450 from modelix/feature/delete-repository
Introduce delete repository endpoint
2 parents 36d190a + dc41ece commit 612dc52

File tree

6 files changed

+84
-5
lines changed

6 files changed

+84
-5
lines changed

api/model-server.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,20 @@ paths:
314314
$ref: '#/components/responses/500'
315315
"200":
316316
$ref: '#/components/responses/versionDelta'
317+
/v2/repositories/{repository}/delete:
318+
post:
319+
operationId: deleteRepository
320+
parameters:
321+
- name: repository
322+
in: "path"
323+
required: true
324+
schema:
325+
type: string
326+
responses:
327+
"204":
328+
$ref: '#/components/responses/204'
329+
"404":
330+
$ref: '#/components/responses/404'
317331
/v2/repositories/{repository}/versions/{versionHash}:
318332
get:
319333
operationId: getRepositoryVersionHash

model-client/src/commonMain/kotlin/org/modelix/model/client2/IModelClientV2.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ interface IModelClientV2 {
4141

4242
suspend fun initRepository(repository: RepositoryId): IVersion
4343
suspend fun listRepositories(): List<RepositoryId>
44-
44+
suspend fun deleteRepository(repository: RepositoryId): Boolean
4545
suspend fun listBranches(repository: RepositoryId): List<BranchReference>
4646

4747
@Deprecated("repository ID is required for permission checks")

model-client/src/commonMain/kotlin/org/modelix/model/client2/ModelClientV2.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ class ModelClientV2(
140140
}.bodyAsText().lines().map { RepositoryId(it) }
141141
}
142142

143+
override suspend fun deleteRepository(repository: RepositoryId): Boolean {
144+
try {
145+
return httpClient.post {
146+
url {
147+
takeFrom(baseUrl)
148+
appendPathSegmentsEncodingSlash("repositories", repository.id, "delete")
149+
}
150+
}.status == HttpStatusCode.NoContent
151+
} catch (ex: Exception) {
152+
LOG.error(ex) { ex.message }
153+
return false
154+
}
155+
}
156+
143157
override suspend fun listBranches(repository: RepositoryId): List<BranchReference> {
144158
return httpClient.get {
145159
url {

model-server/src/main/kotlin/org/modelix/model/server/handlers/ModelReplicationServer.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ class ModelReplicationServer(val repositoriesManager: RepositoriesManager) {
165165
call.respondDelta(initialVersion.getContentHash(), null)
166166
}
167167

168+
post<Paths.deleteRepository> {
169+
fun ApplicationCall.repositoryId() = RepositoryId(parameters["repository"]!!)
170+
fun PipelineContext<Unit, ApplicationCall>.repositoryId() = call.repositoryId()
171+
172+
val repositoryId = repositoryId()
173+
val foundAndDeleted = repositoriesManager.removeRepository(repositoryId)
174+
if (foundAndDeleted) {
175+
call.respond(HttpStatusCode.NoContent)
176+
} else {
177+
call.respond(HttpStatusCode.NotFound)
178+
}
179+
}
180+
168181
post<Paths.postRepositoryBranch> {
169182
fun ApplicationCall.repositoryId() = RepositoryId(parameters["repository"]!!)
170183
fun PipelineContext<Unit, ApplicationCall>.repositoryId() = call.repositoryId()

model-server/src/main/kotlin/org/modelix/model/server/handlers/RepositoriesManager.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,23 @@ class RepositoriesManager(val client: LocalModelClient) {
7676
}
7777

7878
fun getRepositories(): Set<RepositoryId> {
79-
return store[REPOSITORIES_LIST_KEY]?.lines()?.map { RepositoryId(it) }?.toSet() ?: emptySet()
79+
val repositoriesList = store[REPOSITORIES_LIST_KEY]
80+
val emptyRepositoriesList = repositoriesList.isNullOrBlank()
81+
return if (emptyRepositoriesList) {
82+
emptySet()
83+
} else {
84+
repositoriesList!!.lines().map { RepositoryId(it) }.toSet()
85+
}
8086
}
8187

88+
fun repositoryExists(repositoryId: RepositoryId) = getRepositories().contains(repositoryId)
89+
8290
fun createRepository(repositoryId: RepositoryId, userName: String?, useRoleIds: Boolean = true): CLVersion {
8391
var initialVersion: CLVersion? = null
8492
store.runTransaction {
8593
val masterBranch = repositoryId.getBranchReference()
94+
if (repositoryExists(repositoryId)) throw RepositoryAlreadyExistsException(repositoryId.id)
8695
val existingRepositories = getRepositories()
87-
if (existingRepositories.contains(repositoryId)) throw RepositoryAlreadyExistsException(repositoryId.id)
8896
store.put(REPOSITORIES_LIST_KEY, (existingRepositories + repositoryId).joinToString("\n") { it.id }, false)
8997
store.put(branchListKey(repositoryId), masterBranch.branchName, false)
9098
initialVersion = CLVersion.createRegularVersion(
@@ -137,15 +145,21 @@ class RepositoriesManager(val client: LocalModelClient) {
137145
}
138146
}
139147

140-
fun removeRepository(repository: RepositoryId) {
141-
store.runTransaction {
148+
fun removeRepository(repository: RepositoryId): Boolean {
149+
return store.runTransaction {
150+
if (!repositoryExists(repository)) {
151+
return@runTransaction false
152+
}
153+
142154
for (branchName in getBranchNames(repository)) {
143155
putVersionHash(repository.getBranchReference(branchName), null)
144156
}
145157
store.put(branchListKey(repository), null)
146158
val existingRepositories = getRepositories()
147159
val remainingRepositories = existingRepositories - repository
148160
store.put(REPOSITORIES_LIST_KEY, remainingRepositories.joinToString("\n") { it.id })
161+
162+
true
149163
}
150164
}
151165

model-server/src/test/kotlin/org/modelix/model/server/ModelClientV2Test.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import org.modelix.model.server.handlers.ModelReplicationServer
3636
import org.modelix.model.server.store.InMemoryStoreClient
3737
import org.modelix.modelql.core.count
3838
import org.modelix.modelql.untyped.allChildren
39+
import java.util.UUID
3940
import kotlin.test.Test
4041
import kotlin.test.assertEquals
4142

@@ -154,4 +155,27 @@ class ModelClientV2Test {
154155

155156
assertEquals("localhost", modelClient.getUserId())
156157
}
158+
159+
@Test
160+
fun `newly created repository can be removed`() = runTest {
161+
val url = "http://localhost/v2"
162+
val client = ModelClientV2.builder().url(url).client(client).build().also { it.init() }
163+
val repositoryId = RepositoryId(UUID.randomUUID().toString())
164+
client.initRepository(repositoryId)
165+
166+
val success = client.deleteRepository(repositoryId)
167+
168+
assertEquals(true, success)
169+
}
170+
171+
@Test
172+
fun `non-existing repository cannot be removed`() = runTest {
173+
val url = "http://localhost/v2"
174+
val client = ModelClientV2.builder().url(url).client(client).build().also { it.init() }
175+
val repositoryId = RepositoryId(UUID.randomUUID().toString())
176+
177+
val success = client.deleteRepository(repositoryId)
178+
179+
assertEquals(false, success)
180+
}
157181
}

0 commit comments

Comments
 (0)