Improve upstream parity for level fixtures
- Add native per-level fixtures for complex histories, tags, branch graphs, rebases, resets, restores, stashes, and local remotes. - Strengthen repository inspection so branch commit counts, remote-tracking branches, and detached tag checkouts reflect real Git state. - Align Fetch, Pull, Push Branch, Branch At, and Rebase validators/tests with upstream-style repository state. - Keep the prompt callout and native filesystem tab-completion fixes from the previous batch.
This commit is contained in:
@@ -103,6 +103,34 @@ class GitRepositoryRuntime private constructor(
|
||||
return augmentObservedRepoFacts(currentRepo, inspectedRepo, expandedTokens) to result.second
|
||||
}
|
||||
|
||||
fun completionCandidates(level: Level, currentRepo: RepoState, directoriesOnly: Boolean): List<String> {
|
||||
val nativeGit = nativeGitBinary()
|
||||
val sandbox = sandboxDir(level)
|
||||
if (nativeGit == null || !sandbox.exists()) {
|
||||
return if (directoriesOnly) {
|
||||
directoryCompletionCandidates(currentRepo)
|
||||
} else {
|
||||
fileCompletionCandidates(currentRepo)
|
||||
}
|
||||
}
|
||||
|
||||
val sandboxRoot = sandbox.canonicalFile
|
||||
val workingDir = File(sandboxRoot, currentRepo.currentDir).canonicalFile
|
||||
.takeIf { it.path == sandboxRoot.path || it.path.startsWith(sandboxRoot.path + File.separator) }
|
||||
?: sandboxRoot
|
||||
if (!workingDir.exists() || !workingDir.isDirectory) return emptyList()
|
||||
|
||||
return workingDir.walkTopDown()
|
||||
.drop(1)
|
||||
.filter { file -> !directoriesOnly || file.isDirectory }
|
||||
.map { file ->
|
||||
val relativePath = file.relativeTo(workingDir).path
|
||||
if (file.isDirectory) "$relativePath/" else relativePath
|
||||
}
|
||||
.filter { it.isNotBlank() }
|
||||
.toList()
|
||||
}
|
||||
|
||||
fun commandReferenceLines(): List<String> {
|
||||
return buildList {
|
||||
addAll(GitSandboxEngine.commandReferenceLines())
|
||||
@@ -390,6 +418,12 @@ class GitRepositoryRuntime private constructor(
|
||||
materializeNativePushLevel(nativeGit, sandbox)
|
||||
return
|
||||
}
|
||||
if (materializeNativeLevelFixture(levelId, sandbox) { directory, arguments ->
|
||||
runGit(nativeGit, directory, arguments).exitCode
|
||||
}
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
desired.config.forEach { (key, value) ->
|
||||
runGit(nativeGit, sandbox, listOf("config", key, value))
|
||||
@@ -466,8 +500,17 @@ class GitRepositoryRuntime private constructor(
|
||||
|
||||
val remoteWorkTree = File(sandbox.parentFile ?: sandbox, "${sandbox.name}-origin")
|
||||
remoteWorkTree.deleteRecursively()
|
||||
runGit(nativeGit, sandbox.parentFile ?: sandbox, listOf("clone", sandbox.absolutePath, remoteWorkTree.absolutePath))
|
||||
remoteWorkTree.mkdirs()
|
||||
val initResult = runGit(nativeGit, remoteWorkTree, listOf("init", "-b", "master"))
|
||||
if (initResult.exitCode != 0) {
|
||||
runGit(nativeGit, remoteWorkTree, listOf("init"))
|
||||
runGit(nativeGit, remoteWorkTree, listOf("checkout", "-B", "master"))
|
||||
}
|
||||
runGit(nativeGit, remoteWorkTree, listOf("config", "receive.denyCurrentBranch", "ignore"))
|
||||
runGit(nativeGit, sandbox, listOf("remote", "add", "push-setup-origin", File(remoteWorkTree, ".git").absolutePath))
|
||||
runGit(nativeGit, sandbox, listOf("push", "push-setup-origin", "master"))
|
||||
runGit(nativeGit, sandbox, listOf("remote", "remove", "push-setup-origin"))
|
||||
runGit(nativeGit, remoteWorkTree, listOf("checkout", "-f", "master"))
|
||||
File(remoteWorkTree, "file4").writeText("file4\n")
|
||||
commitIn(remoteWorkTree, "Fourth commit", "file4")
|
||||
|
||||
@@ -580,9 +623,11 @@ class GitRepositoryRuntime private constructor(
|
||||
|
||||
val logResult = runGit(nativeGit, sandbox, listOf("log", "--pretty=format:%h\t%s"))
|
||||
val branchResult = runGit(nativeGit, sandbox, listOf("branch", "--list"))
|
||||
val remoteBranchResult = runGit(nativeGit, sandbox, listOf("branch", "-r", "--list"))
|
||||
val tagResult = runGit(nativeGit, sandbox, listOf("tag", "--list"))
|
||||
val remoteResult = runGit(nativeGit, sandbox, listOf("remote", "-v"))
|
||||
val headResult = runGit(nativeGit, sandbox, listOf("branch", "--show-current"))
|
||||
val exactTagResult = runGit(nativeGit, sandbox, listOf("describe", "--tags", "--exact-match"))
|
||||
val userNameResult = runGit(nativeGit, sandbox, listOf("config", "--get", "user.name"))
|
||||
val userEmailResult = runGit(nativeGit, sandbox, listOf("config", "--get", "user.email"))
|
||||
val config = buildMap {
|
||||
@@ -606,6 +651,23 @@ class GitRepositoryRuntime private constructor(
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val branches = branchResult.outputLines
|
||||
.map { it.removePrefix("*").trim() }
|
||||
.filter { it.isNotBlank() && !it.startsWith("(") }
|
||||
.associateWith { branch ->
|
||||
runGit(nativeGit, sandbox, listOf("rev-list", "--count", branch))
|
||||
.outputLines
|
||||
.firstOrNull()
|
||||
?.toIntOrNull()
|
||||
?: 0
|
||||
}
|
||||
val headBranch = headResult.outputLines.firstOrNull()
|
||||
?.ifBlank { null }
|
||||
?: exactTagResult.outputLines.firstOrNull()
|
||||
?.takeIf { exactTagResult.exitCode == 0 && it.isNotBlank() }
|
||||
?.let { "tags/$it" }
|
||||
?: "DETACHED"
|
||||
|
||||
return RepoState(
|
||||
initialized = true,
|
||||
files = filesOnDisk.map { file ->
|
||||
@@ -627,16 +689,20 @@ class GitRepositoryRuntime private constructor(
|
||||
tracked = tracked,
|
||||
deleted = true,
|
||||
)
|
||||
},
|
||||
},
|
||||
commits = commits,
|
||||
headBranch = headResult.outputLines.firstOrNull()?.ifBlank { null } ?: "master",
|
||||
branches = branchResult.outputLines.map { it.removePrefix("*").trim() }.filter { it.isNotBlank() }.associateWith { 0 },
|
||||
headBranch = headBranch,
|
||||
branches = branches,
|
||||
tags = tagResult.outputLines.filter { it.isNotBlank() },
|
||||
remotes = remoteResult.outputLines.mapNotNull { line ->
|
||||
val parts = line.trim().split(Regex("\\s+"))
|
||||
if (parts.size >= 2) parts[0] to parts[1] else null
|
||||
}.toMap(),
|
||||
config = config,
|
||||
fetchedBranches = remoteBranchResult.outputLines
|
||||
.map { it.removePrefix("*").trim() }
|
||||
.filter { it.isNotBlank() && " -> " !in it }
|
||||
.toSet(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user