Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Bitbucket Cloud URL generation #333

Merged
merged 1 commit into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import uk.co.ben_gibson.git.link.git.*
import uk.co.ben_gibson.git.link.pipeline.Pass
import uk.co.ben_gibson.git.link.settings.ProjectSettings
import uk.co.ben_gibson.git.link.url.UrlOptions
import uk.co.ben_gibson.git.link.url.UrlOptionsCommit
import uk.co.ben_gibson.git.link.url.UrlOptionsFileAtBranch
import uk.co.ben_gibson.git.link.url.UrlOptionsFileAtCommit
import uk.co.ben_gibson.git.link.url.factory.UrlFactoryLocator
import uk.co.ben_gibson.url.URL

Expand All @@ -26,12 +23,12 @@ class GenerateUrl : Middleware {

val platform = pass.platformOrThrow()

val urlOptions = createUrlOptions(pass, baseUrl, platform.pullRequestWorkflowSupported)
val options = createUrlOptions(pass, platform.pullRequestWorkflowSupported)

return service<UrlFactoryLocator>().locate(platform).createUrl(urlOptions)
return service<UrlFactoryLocator>().locate(platform).createUrl(baseUrl, options)
}

private fun createUrlOptions(pass: Pass, baseUrl: URL, pullRequestWorkflowSupported: Boolean): UrlOptions {
private fun createUrlOptions(pass: Pass, pullRequestWorkflowSupported: Boolean): UrlOptions {
val remote = pass.remoteOrThrow()
val repository = pass.repositoryOrThrow()
val context = pass.context
Expand All @@ -40,16 +37,15 @@ class GenerateUrl : Middleware {
val repositoryFile = File.forRepository(context.file, repository)

return when (context) {
is ContextFileAtCommit -> UrlOptionsFileAtCommit(baseUrl, repositoryFile, context.commit, context.lineSelection)
is ContextCommit -> UrlOptionsCommit(baseUrl, context.commit)
is ContextFileAtCommit -> UrlOptions.UrlOptionsFileAtCommit(repositoryFile, context.commit, context.lineSelection)
is ContextCommit -> UrlOptions.UrlOptionsCommit(context.commit)
is ContextCurrentFile -> {
val commit = resolveCommit(repository, remote, settings, pullRequestWorkflowSupported)

if (commit != null) {
UrlOptionsFileAtCommit(baseUrl, repositoryFile, commit, context.lineSelection)
UrlOptions.UrlOptionsFileAtCommit(repositoryFile, commit, context.lineSelection)
} else {
UrlOptionsFileAtBranch(
baseUrl,
UrlOptions.UrlOptionsFileAtBranch(
repositoryFile,
resolveBranch(repository, remote, settings),
context.lineSelection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ fun ValidationInfoBuilder.fileAtCommitTemplate(value: String): ValidationInfo? {
return null
}

val options = UrlOptionsFileAtCommit(
URL.fromString("https://example.com"),
val options = UrlOptions.UrlOptionsFileAtCommit(
File("foo.kt", false, "src/main", false),
Commit("734232a3c18f0625843bd161c3f5da272b9d53c1"),
LineSelection(10, 20)
Expand All @@ -76,8 +75,7 @@ fun ValidationInfoBuilder.fileAtBranchTemplate(value: String): ValidationInfo? {
return null
}

val options = UrlOptionsFileAtBranch(
URL.fromString("https://example.com"),
val options = UrlOptions.UrlOptionsFileAtBranch(
File("foo.kt", false, "src/main", false),
"master",
LineSelection(10, 20)
Expand All @@ -91,10 +89,7 @@ fun ValidationInfoBuilder.commitTemplate(value: String): ValidationInfo? {
return null
}

val options = UrlOptionsCommit(
URL.fromString("https://example.com"),
Commit("734232a3c18f0625843bd161c3f5da272b9d53c1")
)
val options = UrlOptions.UrlOptionsCommit(Commit("734232a3c18f0625843bd161c3f5da272b9d53c1"))

return urlTemplate(options, commit = value)
}
Expand All @@ -108,7 +103,7 @@ private fun ValidationInfoBuilder.urlTemplate(
val factory = TemplatedUrlFactory(UrlTemplates(fileAtBranch, fileAtCommit, commit))

return try {
factory.createUrl(options)
factory.createUrl(URL.fromString("https://example.com"), options)
null
} catch (e: Exception) {
when(e) {
Expand Down
32 changes: 4 additions & 28 deletions src/main/kotlin/uk/co/ben_gibson/git/link/url/UrlOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,9 @@ package uk.co.ben_gibson.git.link.url
import uk.co.ben_gibson.git.link.git.Commit
import uk.co.ben_gibson.git.link.git.File
import uk.co.ben_gibson.git.link.ui.LineSelection
import uk.co.ben_gibson.url.URL

sealed class UrlOptions(val baseUrl: URL)

class UrlOptionsCommit(baseUrl: URL, val commit: Commit) : UrlOptions(baseUrl)

interface UrlOptionsFileAware {
val baseUrl: URL
val file: File
val ref: String
val lineSelection: LineSelection?
}

class UrlOptionsFileAtCommit(
baseUrl: URL,
override val file: File,
val commit: Commit,
override val lineSelection: LineSelection? = null
) : UrlOptions(baseUrl), UrlOptionsFileAware {
override val ref: String get() = commit.toString()
}

class UrlOptionsFileAtBranch(
baseUrl: URL,
override val file: File,
val branch: String,
override val lineSelection: LineSelection? = null
) : UrlOptions(baseUrl), UrlOptionsFileAware {
override val ref: String get() = branch
sealed interface UrlOptions {
class UrlOptionsCommit(val commit: Commit) : UrlOptions
class UrlOptionsFileAtCommit(val file: File, val commit: Commit, val lineSelection: LineSelection? = null) : UrlOptions
class UrlOptionsFileAtBranch(val file: File, val branch: String, val lineSelection: LineSelection? = null) : UrlOptions
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import uk.co.ben_gibson.url.*
class AzureUrlFactory: UrlFactory {
private val host = Host("dev.azure.com")

override fun createUrl(options: UrlOptions): URL {
val basePathParts = options.baseUrl.path.toString()
override fun createUrl(baseUrl: URL, options: UrlOptions): URL {
val basePathParts = baseUrl.path.toString()
.split("/")
.toMutableList()

Expand All @@ -25,13 +25,13 @@ class AzureUrlFactory: UrlFactory {
val baseUrl = URL(scheme = Scheme.https(), host = host, path = Path(basePathParts.joinToString("/")))

return when (options) {
is UrlOptionsFileAtBranch -> createUrlToFileAtBranch(baseUrl, options)
is UrlOptionsFileAtCommit -> createUrlToFileAtCommit(baseUrl, options)
is UrlOptionsCommit -> createUrlToCommit(baseUrl, options)
is UrlOptions.UrlOptionsFileAtBranch -> createUrlToFileAtBranch(baseUrl, options)
is UrlOptions.UrlOptionsFileAtCommit -> createUrlToFileAtCommit(baseUrl, options)
is UrlOptions.UrlOptionsCommit -> createUrlToCommit(baseUrl, options)
}
}

private fun createUrlToFileAtCommit(baseUrl: URL, options: UrlOptionsFileAtCommit) : URL {
private fun createUrlToFileAtCommit(baseUrl: URL, options: UrlOptions.UrlOptionsFileAtCommit) : URL {
var queryString = QueryString.fromMap(
mapOf(
"version" to listOf("GC".plus(options.commit)),
Expand All @@ -46,7 +46,7 @@ class AzureUrlFactory: UrlFactory {
return baseUrl.withQueryString(queryString)
}

private fun createUrlToFileAtBranch(baseUrl: URL, options: UrlOptionsFileAtBranch) : URL {
private fun createUrlToFileAtBranch(baseUrl: URL, options: UrlOptions.UrlOptionsFileAtBranch) : URL {
var queryString = QueryString.fromMap(
mapOf(
"version" to listOf("GB".plus(options.branch)),
Expand All @@ -67,7 +67,7 @@ class AzureUrlFactory: UrlFactory {
return file.path.plus("/").plus(fileName)
}

private fun createUrlToCommit(baseUrl: URL, options: UrlOptionsCommit): URL {
private fun createUrlToCommit(baseUrl: URL, options: UrlOptions.UrlOptionsCommit): URL {
val path = requireNotNull(baseUrl.path) { "Unexpected error: repository path must be present in remote URL" }
return baseUrl.withPath(path.with(Path.fromSegments(listOf("commit", options.commit.toString()))))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package uk.co.ben_gibson.git.link.url.factory

import uk.co.ben_gibson.git.link.url.UrlOptions
import uk.co.ben_gibson.git.link.url.template.UrlTemplates
import uk.co.ben_gibson.url.Path
import uk.co.ben_gibson.url.URL

class BitbucketCloudUrlFactory : TemplatedUrlFactory(UrlTemplates.bitbucketCloud()) {
override fun createUrl(baseUrl: URL, options: UrlOptions): URL {
return super.createUrl(normaliseBaseUrl(baseUrl), options)
}

private fun normaliseBaseUrl(baseUrl: URL): URL {
return baseUrl.copy(path = Path(baseUrl.path.toString().removePrefix("scm/")))
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package uk.co.ben_gibson.git.link.url.factory

import com.intellij.openapi.components.Service
import uk.co.ben_gibson.git.link.git.File
import uk.co.ben_gibson.git.link.ui.LineSelection
import uk.co.ben_gibson.git.link.url.*
import uk.co.ben_gibson.url.Host
Expand All @@ -13,70 +14,71 @@ private const val IDENTIFIER_CHROMIUMOS = "chromiumos"

@Service
class ChromiumUrlFactory: UrlFactory {
override fun createUrl(options: UrlOptions): URL {
val path = if (options.baseUrl.path.toString().contains(IDENTIFIER_CHROMIUMOS))
createPathForChromiumos(options)
override fun createUrl(baseUrl: URL, options: UrlOptions): URL {
val path = if (baseUrl.path.toString().contains(IDENTIFIER_CHROMIUMOS))
createPathForChromiumos(baseUrl, options)
else
createPathForChromium(options)
createPathForChromium(baseUrl, options)

return URL(scheme = options.baseUrl.scheme, host = HOST, path = path)
return URL(scheme = baseUrl.scheme, host = HOST, path = path)
}

private fun createPathForChromium(options: UrlOptions) : Path {
private fun createPathForChromium(baseUrl: URL, options: UrlOptions) : Path {
val path = Path("chromium")
.with(Path(options.baseUrl.path.toString()))
.with(Path(baseUrl.path.toString()))
.with(Path("+"))

return when (options) {
is UrlOptionsFileAtBranch -> path.with(createChromiumFileSubPath(options))
is UrlOptionsFileAtCommit -> path.with(createChromiumFileSubPath(options))
is UrlOptionsCommit -> path.with(Path(options.commit.toString()))
is UrlOptions.UrlOptionsFileAtBranch -> path.with(createChromiumFileSubPath(options.file, options.branch, options.lineSelection))
is UrlOptions.UrlOptionsFileAtCommit -> path.with(createChromiumFileSubPath(options.file, options.commit.toString(), options.lineSelection))
is UrlOptions.UrlOptionsCommit -> path.with(Path(options.commit.toString()))
}
}

private fun createPathForChromiumos(options: UrlOptions) : Path {
private fun createPathForChromiumos(baseUrl: URL, options: UrlOptions) : Path {
return when (options) {
is UrlOptionsFileAtBranch -> createChromiumosFileSubPath(options)
is UrlOptionsFileAtCommit -> createChromiumosFileSubPath(options)
is UrlOptionsCommit -> Path("chromiumos/_/chromium/chromiumos")
.withSegments(options.baseUrl.path.toString().split('/').filter{ it.isNotBlank() }.drop(1))
is UrlOptions.UrlOptionsFileAtBranch -> createChromiumosFileSubPath(baseUrl, options.file, options.branch, options.lineSelection)
is UrlOptions.UrlOptionsFileAtCommit -> createChromiumosFileSubPath(baseUrl, options.file, options.commit.toString(), options.lineSelection)
is UrlOptions.UrlOptionsCommit -> Path("chromiumos/_/chromium/chromiumos")
.withSegments(baseUrl.path.toString().split('/').filter{ it.isNotBlank() }.drop(1))
.with(Path("+"))
.with(Path(options.commit.toString()))
}
}

private fun createChromiumFileSubPath(options: UrlOptionsFileAware): Path {
var path = Path.fromSegments("${options.ref}:".plus(options.file.path.trim('/')).split("/"))
private fun createChromiumFileSubPath(file: File, ref: String, lineSelection: LineSelection?): Path {

if (!options.file.isRoot) {
path = path.withSegment(options.file.name)
var path = Path.fromSegments("${ref}:".plus(file.path.trim('/')).split("/"))

if (!file.isRoot) {
path = path.withSegment(file.name)
}

if (options.file.isDirectory) {
if (file.isDirectory) {
return path
}

val lineSelection = options.lineSelection ?: return path
lineSelection ?: return path

return Path(path.toString() + createLineSelection(lineSelection))
}

private fun createChromiumosFileSubPath(options: UrlOptionsFileAware): Path {
private fun createChromiumosFileSubPath(baseUrl: URL, file: File, ref: String, lineSelection: LineSelection?): Path {
var path = Path("chromiumos/chromiumos/codesearch")
.with("+")
.with(options.ref.plus(":src"))
.withSegments(options.baseUrl.path.toString().split('/').filter{ it.isNotBlank() }.drop(1))
.withSegments(options.file.path.split("/").filter { it.isNotBlank() })
.with(ref.plus(":src"))
.withSegments(baseUrl.path.toString().split('/').filter{ it.isNotBlank() }.drop(1))
.withSegments(file.path.split("/").filter { it.isNotBlank() })

if (!options.file.isRoot) {
path = path.withSegment(options.file.name)
if (!file.isRoot) {
path = path.withSegment(file.name)
}

if (options.file.isDirectory) {
if (file.isDirectory) {
return path
}

val lineSelection = options.lineSelection ?: return path
lineSelection ?: return path

return Path(path.toString() + createLineSelection(lineSelection))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ import uk.co.ben_gibson.url.URL
import java.util.regex.Pattern
import com.google.common.net.UrlEscapers

class TemplatedUrlFactory(private val templates: UrlTemplates) : UrlFactory {
open class TemplatedUrlFactory(private val templates: UrlTemplates) : UrlFactory {
private val escape = UrlEscapers.urlPathSegmentEscaper().asFunction()

private val remotePathPattern = Pattern.compile("\\{remote:url:path:(\\d)}")

override fun createUrl(options: UrlOptions): URL {
override fun createUrl(baseUrl: URL, options: UrlOptions): URL {
var processTemplate = when (options) {
is UrlOptionsFileAtCommit -> processTemplate(options)
is UrlOptionsFileAtBranch -> processTemplate(options)
is UrlOptionsCommit -> processTemplate(options)
is UrlOptions.UrlOptionsFileAtCommit -> processTemplate(options)
is UrlOptions.UrlOptionsFileAtBranch -> processTemplate(options)
is UrlOptions.UrlOptionsCommit -> processTemplate(options)
}

processTemplate = processBaseUrl(processTemplate, options.baseUrl)
processTemplate = processBaseUrl(processTemplate, baseUrl)
processTemplate = removeUnmatchedSubstitutions(processTemplate)
processTemplate = processTemplate.replace("(?<!:)/{2,}".toRegex(), "/")

Expand All @@ -30,7 +30,7 @@ class TemplatedUrlFactory(private val templates: UrlTemplates) : UrlFactory {

private fun removeUnmatchedSubstitutions(template: String) = template.replace("\\{.+?}".toRegex(), "")

private fun processTemplate(options: UrlOptionsFileAtBranch): String {
private fun processTemplate(options: UrlOptions.UrlOptionsFileAtBranch): String {
var template = templates.fileAtBranch

template = processFile(template, options.file)
Expand All @@ -40,7 +40,7 @@ class TemplatedUrlFactory(private val templates: UrlTemplates) : UrlFactory {
return template
}

private fun processTemplate(options: UrlOptionsFileAtCommit): String {
private fun processTemplate(options: UrlOptions.UrlOptionsFileAtCommit): String {
var template = templates.fileAtCommit

template = processFile(template, options.file)
Expand All @@ -50,7 +50,7 @@ class TemplatedUrlFactory(private val templates: UrlTemplates) : UrlFactory {
return template
}

private fun processTemplate(options: UrlOptionsCommit): String {
private fun processTemplate(options: UrlOptions.UrlOptionsCommit): String {
var template = templates.commit

template = processCommit(template, options.commit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ val PLATFORM_MAP = mapOf(
Gogs::class.java to UrlTemplates.gogs(),
Srht::class.java to UrlTemplates.srht(),
BitbucketServer::class.java to UrlTemplates.bitbucketServer(),
BitbucketCloud::class.java to UrlTemplates.bitbucketCloud(),
Gerrit::class.java to UrlTemplates.gerrit(),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import uk.co.ben_gibson.git.link.url.UrlOptions
import uk.co.ben_gibson.url.URL

interface UrlFactory {
fun createUrl(options: UrlOptions) : URL
fun createUrl(baseUrl: URL, options: UrlOptions) : URL
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package uk.co.ben_gibson.git.link.url.factory
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import uk.co.ben_gibson.git.link.platform.Azure
import uk.co.ben_gibson.git.link.platform.BitbucketCloud
import uk.co.ben_gibson.git.link.platform.Chromium
import uk.co.ben_gibson.git.link.platform.Platform

Expand All @@ -12,6 +13,7 @@ class UrlFactoryLocator {
return when(platform) {
is Chromium -> service<ChromiumUrlFactory>()
is Azure -> service<AzureUrlFactory>()
is BitbucketCloud -> service<BitbucketCloudUrlFactory>()
else -> service<TemplatedUrlFactoryProvider>().forPlatform(platform)
}
}
Expand Down
Loading
Loading