Skip to content

Commit

Permalink
#1236 Refactoring of the file download service
Browse files Browse the repository at this point in the history
  • Loading branch information
dcoraboeuf committed Dec 11, 2024
1 parent 54880eb commit 15af154
Show file tree
Hide file tree
Showing 34 changed files with 318 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.nemerosa.ontrack.extension.api

import net.nemerosa.ontrack.common.Document
import net.nemerosa.ontrack.model.extension.Extension

/**
* Extension used to support a protocol to download a file.
*/
interface FileRefExtension : Extension {

/**
* Supported protocol
*/
val protocol: String

/**
* Downloading a document using its path
*
* @param path Path extracted from the file ref URI
* @param type Expected MIME type of the document
* @return Document or null if not found
*/
fun download(path: String, type: String): Document?

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import net.nemerosa.ontrack.extension.casc.schema.CascType
import net.nemerosa.ontrack.extension.casc.schema.cascArray
import net.nemerosa.ontrack.extension.casc.schema.cascField
import net.nemerosa.ontrack.extension.casc.schema.cascObject
import net.nemerosa.ontrack.extension.scm.service.SCMRefService
import net.nemerosa.ontrack.extension.scm.service.downloadDocument
import net.nemerosa.ontrack.json.asJson
import net.nemerosa.ontrack.json.parse
import net.nemerosa.ontrack.model.files.FileRefService
import net.nemerosa.ontrack.model.files.downloadDocument
import net.nemerosa.ontrack.model.settings.PredefinedPromotionLevelService
import net.nemerosa.ontrack.model.structure.ID
import net.nemerosa.ontrack.model.structure.NameDescription
Expand All @@ -22,7 +22,7 @@ import org.springframework.stereotype.Component
@Component
class PredefinedPromotionLevelsAdminContext(
private val predefinedPromotionLevelService: PredefinedPromotionLevelService,
private val scmRefService: SCMRefService,
private val scmRefService: FileRefService,
) : AbstractCascContext(), SubAdminContext {

private val logger: Logger = LoggerFactory.getLogger(PredefinedPromotionLevelsAdminContext::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import net.nemerosa.ontrack.extension.casc.schema.CascType
import net.nemerosa.ontrack.extension.casc.schema.cascArray
import net.nemerosa.ontrack.extension.casc.schema.cascField
import net.nemerosa.ontrack.extension.casc.schema.cascObject
import net.nemerosa.ontrack.extension.scm.service.SCMRefService
import net.nemerosa.ontrack.extension.scm.service.downloadDocument
import net.nemerosa.ontrack.json.asJson
import net.nemerosa.ontrack.json.parse
import net.nemerosa.ontrack.model.files.FileRefService
import net.nemerosa.ontrack.model.files.downloadDocument
import net.nemerosa.ontrack.model.settings.PredefinedValidationStampService
import net.nemerosa.ontrack.model.structure.ID
import net.nemerosa.ontrack.model.structure.NameDescription
Expand All @@ -22,7 +22,7 @@ import org.springframework.stereotype.Component
@Component
class PredefinedValidationStampsAdminContext(
private val predefinedValidationStampService: PredefinedValidationStampService,
private val scmRefService: SCMRefService,
private val scmRefService: FileRefService,
) : AbstractCascContext(), SubAdminContext {

private val logger: Logger = LoggerFactory.getLogger(PredefinedValidationStampsAdminContext::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import net.nemerosa.ontrack.extension.environments.workflows.SlotWorkflowService
import net.nemerosa.ontrack.extension.workflows.definition.Workflow
import net.nemerosa.ontrack.json.asJson
import net.nemerosa.ontrack.json.parse
import net.nemerosa.ontrack.model.files.FileRef
import net.nemerosa.ontrack.model.files.FileRefService
import net.nemerosa.ontrack.model.structure.StructureService
import net.nemerosa.ontrack.model.support.ImageHelper
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import kotlin.io.encoding.Base64
Expand All @@ -29,6 +32,7 @@ class EnvironmentsCascContext(
private val structureService: StructureService,
private val slotService: SlotService,
private val slotWorkflowService: SlotWorkflowService,
private val fileRefService: FileRefService,
) : AbstractCascContext(), SubConfigContext {

private val logger = LoggerFactory.getLogger(EnvironmentsCascContext::class.java)
Expand Down Expand Up @@ -166,15 +170,15 @@ class EnvironmentsCascContext(
) {
equality { a, b -> a.name == b.name }
onCreation { env ->
environmentService.save(
Environment(
name = env.name,
description = env.description,
order = env.order,
tags = env.tags,
image = false, // TODO
)
val environment = Environment(
name = env.name,
description = env.description,
order = env.order,
tags = env.tags,
image = false,
)
environmentService.save(environment)
setImage(env, environment)
}
onModification { env, existing ->
val adapted = Environment(
Expand All @@ -183,9 +187,10 @@ class EnvironmentsCascContext(
description = env.description,
order = env.order,
tags = env.tags,
image = false, // TODO
image = existing.image,
)
environmentService.save(adapted)
setImage(env, adapted)
}
onDeletion { existing ->
if (!model.keepEnvironments) {
Expand All @@ -195,6 +200,22 @@ class EnvironmentsCascContext(
}
}

private fun setImage(
env: EnvironmentCasc,
environment: Environment
) {
if (!env.image.isNullOrBlank()) {
val image = fileRefService.downloadDocument(
ref = FileRef.parseUri(env.image) ?: error("Cannot parse image URI: ${env.image}"),
type = ImageHelper.IMAGE_PNG,
) ?: error("Cannot download image at ${env.image}")
environmentService.setEnvironmentImage(
id = environment.id,
document = image
)
}
}

@OptIn(ExperimentalEncodingApi::class)
override fun render(): JsonNode {
val environments = environmentService.findAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class EnvironmentsCascModelTest {
structureService = mockk(),
slotService = mockk(),
slotWorkflowService = mockk(),
fileRefService = mockk(),
)
val type = context.type
println(type)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package net.nemerosa.ontrack.extension.github.ingestion.support

import net.nemerosa.ontrack.common.Document
import net.nemerosa.ontrack.extension.github.client.OntrackGitHubClientFactory
import net.nemerosa.ontrack.extension.github.model.GitHubEngineConfiguration
import net.nemerosa.ontrack.extension.github.property.GitHubProjectConfigurationPropertyType
import net.nemerosa.ontrack.extension.scm.service.SCMRefService
import net.nemerosa.ontrack.extension.scm.service.downloadDocument
import net.nemerosa.ontrack.model.files.FileRefService
import net.nemerosa.ontrack.model.files.downloadDocument
import net.nemerosa.ontrack.model.structure.Project
import net.nemerosa.ontrack.model.structure.PropertyService
import org.springframework.stereotype.Component
Expand All @@ -15,7 +14,7 @@ import org.springframework.transaction.annotation.Transactional
@Transactional
class DefaultIngestionImageService(
private val propertyService: PropertyService,
private val scmRefService: SCMRefService,
private val scmRefService: FileRefService,
) : IngestionImageService {

override fun downloadImage(project: Project, ref: String): Document {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package net.nemerosa.ontrack.extension.scm.service
package net.nemerosa.ontrack.extension.scm.files

data class SCMRef(
val protocol: String,
val type: String,
val config: String,
val ref: String,
) {
companion object {

const val PROTOCOL = "scm"
private val regex = "^${PROTOCOL}:\\/\\/([^\\/]*)\\/([^\\/]*)\\/(.*)\$".toRegex()
private val regex = "^\\/\\/([^\\/]*)\\/([^\\/]*)\\/(.*)\$".toRegex()

/**
* The URI must be formatted as `scm://<type>/<config>/<ref>` where:
* The URI must be formatted as `//<type>/<config>/<ref>` where:
*
* * type is the SCM type: github, bitbucket-server, etc.
* * config is the name of the configuration for the SCM type as stored in Ontrack
Expand All @@ -21,7 +19,6 @@ data class SCMRef(
fun parseUri(uri: String): SCMRef? {
val m = regex.matchEntire(uri) ?: return null
return SCMRef(
protocol = PROTOCOL,
type = m.groupValues[1],
config = m.groupValues[2],
ref = m.groupValues[3],
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.nemerosa.ontrack.extension.scm.files

import net.nemerosa.ontrack.common.Document
import net.nemerosa.ontrack.extension.api.ExtensionManager
import net.nemerosa.ontrack.extension.api.FileRefExtension
import net.nemerosa.ontrack.extension.scm.SCMExtensionFeature
import net.nemerosa.ontrack.extension.scm.service.SCMExtension
import net.nemerosa.ontrack.extension.support.AbstractExtension
import org.springframework.stereotype.Component

@Component
class SCMFileRefExtension(
extensionFeature: SCMExtensionFeature,
private val extensionManager: ExtensionManager,
) : AbstractExtension(extensionFeature), FileRefExtension {

override val protocol: String = "scm"

private val scmExtensions: Map<String, SCMExtension> by lazy {
extensionManager.getExtensions(SCMExtension::class.java)
.associateBy { it.type }
}

override fun download(path: String, type: String): Document? {
val ref = SCMRef.parseUri(path) ?: throw SCMRefParsingException(path)
val extension = scmExtensions[ref.type]
?: throw SCMRefUnknownSCMTypeException(ref.type)

val (scm, scmPath) = extension.getSCMPath(ref.config, ref.ref) ?: return null

val bytes = scm.download(
scmBranch = null, // Using the default branch
path = scmPath,
retryOnNotFound = false,
) ?: return null

return Document(type, bytes)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.nemerosa.ontrack.extension.scm.files

import net.nemerosa.ontrack.common.BaseException

class SCMRefParsingException(path: String): BaseException(
"""Cannot parse SCM path: $path"""
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package net.nemerosa.ontrack.extension.scm.service
package net.nemerosa.ontrack.extension.scm.files

import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
Expand All @@ -7,38 +7,31 @@ import kotlin.test.assertNull
class SCMRefTest {

@Test
fun `Missing protocol`() {
assertNull(SCMRef.parseUri("//test/config/ref"))
}

@Test
fun `Wrong protocol`() {
assertNull(SCMRef.parseUri("https://github.com/nemerosa/ontrack/some/path"))
fun `Wrong format, missing type`() {
assertNull(SCMRef.parseUri("/github.com/nemerosa/ontrack/some/path"))
}

@Test
fun `GitHub URI`() {
assertEquals(
SCMRef(
protocol = SCMRef.PROTOCOL,
type = "github",
config = "github.com",
ref = "nemerosa/ontrack/some/path"
),
SCMRef.parseUri("scm://github/github.com/nemerosa/ontrack/some/path")
SCMRef.parseUri("//github/github.com/nemerosa/ontrack/some/path")
)
}

@Test
fun `Test URI`() {
assertEquals(
SCMRef(
protocol = SCMRef.PROTOCOL,
type = "test",
config = "my-config",
ref = "some/path"
),
SCMRef.parseUri("scm://test/my-config/some/path")
SCMRef.parseUri("//test/my-config/some/path")
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.nemerosa.ontrack.extension.scm.files

import net.nemerosa.ontrack.common.BaseException

class SCMRefUnknownSCMTypeException(type: String): BaseException(
"""SCM type is not supported: $type."""
)
Loading

0 comments on commit 15af154

Please sign in to comment.