review
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
// Substantially modified from:
|
||||||
|
// https://github.com/mitsuhiko/agent-stuff/blob/80e1e96/pi-extensions/review.ts
|
||||||
|
// Copyright Armin Ronacher and contributors
|
||||||
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
TuiPlugin,
|
TuiPlugin,
|
||||||
TuiPluginModule,
|
TuiPluginModule,
|
||||||
@@ -8,6 +14,7 @@ import path from "node:path"
|
|||||||
|
|
||||||
type BookmarkRef = { name: string; remote?: string }
|
type BookmarkRef = { name: string; remote?: string }
|
||||||
type Change = { changeId: string; title: string }
|
type Change = { changeId: string; title: string }
|
||||||
|
type JjRemote = { name: string; url: string }
|
||||||
|
|
||||||
type ReviewTarget =
|
type ReviewTarget =
|
||||||
| { type: "workingCopy" }
|
| { type: "workingCopy" }
|
||||||
@@ -205,19 +212,30 @@ function parseChanges(stdout: string): Change[] {
|
|||||||
|
|
||||||
function parsePrRef(ref: string): number | null {
|
function parsePrRef(ref: string): number | null {
|
||||||
const trimmed = ref.trim()
|
const trimmed = ref.trim()
|
||||||
const num = parseInt(trimmed, 10)
|
if (/^\d+$/.test(trimmed)) {
|
||||||
if (!isNaN(num) && num > 0) return num
|
const num = Number(trimmed)
|
||||||
const urlMatch = trimmed.match(/github\.com\/[^/]+\/[^/]+\/pull\/(\d+)/)
|
return Number.isSafeInteger(num) && num > 0 ? num : null
|
||||||
if (urlMatch) return parseInt(urlMatch[1], 10)
|
}
|
||||||
|
|
||||||
|
const urlMatch = trimmed.match(
|
||||||
|
/^(?:https?:\/\/)?github\.com\/[^/]+\/[^/]+\/pull\/(\d+)(?:[/?#].*)?$/i,
|
||||||
|
)
|
||||||
|
if (urlMatch) {
|
||||||
|
const num = Number(urlMatch[1])
|
||||||
|
return Number.isSafeInteger(num) && num > 0 ? num : null
|
||||||
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeRemoteUrl(value: string): string {
|
function normalizeRemoteUrl(value: string): string {
|
||||||
return value
|
return value
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/^git@github\.com:/, "https://github.com/")
|
.replace(/^git@([^:]+):/, "https://$1/")
|
||||||
.replace(/^ssh:\/\/git@github\.com\//, "https://github.com/")
|
.replace(/^ssh:\/\/git@([^/]+)\//, "https://$1/")
|
||||||
|
.replace(/^(https?:\/\/)[^/@]+@/i, "$1")
|
||||||
.replace(/\.git$/, "")
|
.replace(/\.git$/, "")
|
||||||
|
.replace(/\/+$/, "")
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +246,12 @@ function sanitizeRemoteName(value: string): string {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRepositoryUrl(value: string): string | null {
|
||||||
|
const match = normalizeRemoteUrl(value).match(/^https?:\/\/[^/]+\/[^/]+\/[^/]+/)
|
||||||
|
if (!match) return null
|
||||||
|
return match[0]
|
||||||
|
}
|
||||||
|
|
||||||
const plugin: TuiPlugin = async (api) => {
|
const plugin: TuiPlugin = async (api) => {
|
||||||
const cwd = api.state.path.directory
|
const cwd = api.state.path.directory
|
||||||
let reviewCustomInstructions = normalizeCustomInstructions(
|
let reviewCustomInstructions = normalizeCustomInstructions(
|
||||||
@@ -239,8 +263,6 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
api.kv.set(CUSTOM_INSTRUCTIONS_KEY, reviewCustomInstructions)
|
api.kv.set(CUSTOM_INSTRUCTIONS_KEY, reviewCustomInstructions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- shell helpers -------------------------------------------------------
|
|
||||||
|
|
||||||
async function exec(
|
async function exec(
|
||||||
cmd: string,
|
cmd: string,
|
||||||
args: string[],
|
args: string[],
|
||||||
@@ -276,8 +298,6 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
return { stdout: r.stdout, ok: r.exitCode === 0, stderr: r.stderr }
|
return { stdout: r.stdout, ok: r.exitCode === 0, stderr: r.stderr }
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- jj helpers ----------------------------------------------------------
|
|
||||||
|
|
||||||
async function isJjRepo(): Promise<boolean> {
|
async function isJjRepo(): Promise<boolean> {
|
||||||
return (await jj("root")).ok
|
return (await jj("root")).ok
|
||||||
}
|
}
|
||||||
@@ -287,56 +307,6 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
return r.ok && r.stdout.trim().length > 0
|
return r.ok && r.stdout.trim().length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getBookmarks(): Promise<BookmarkRef[]> {
|
|
||||||
const r = await jj(
|
|
||||||
"bookmark",
|
|
||||||
"list",
|
|
||||||
"--all-remotes",
|
|
||||||
"-T",
|
|
||||||
'name ++ "\\t" ++ remote ++ "\\n"',
|
|
||||||
)
|
|
||||||
if (!r.ok) return []
|
|
||||||
return parseBookmarks(r.stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getCurrentBookmarks(): Promise<BookmarkRef[]> {
|
|
||||||
const headRevset = (await hasWorkingCopyChanges()) ? "@" : "@-"
|
|
||||||
const r = await jj(
|
|
||||||
"bookmark",
|
|
||||||
"list",
|
|
||||||
"--all-remotes",
|
|
||||||
"-r",
|
|
||||||
headRevset,
|
|
||||||
"-T",
|
|
||||||
'name ++ "\\t" ++ remote ++ "\\n"',
|
|
||||||
)
|
|
||||||
if (!r.ok) return []
|
|
||||||
return parseBookmarks(r.stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getDefaultBookmark(): Promise<BookmarkRef | null> {
|
|
||||||
const trunkR = await jj(
|
|
||||||
"bookmark",
|
|
||||||
"list",
|
|
||||||
"--all-remotes",
|
|
||||||
"-r",
|
|
||||||
"trunk()",
|
|
||||||
"-T",
|
|
||||||
'name ++ "\\t" ++ remote ++ "\\n"',
|
|
||||||
)
|
|
||||||
if (trunkR.ok) {
|
|
||||||
const bookmarks = parseBookmarks(trunkR.stdout)
|
|
||||||
if (bookmarks.length > 0) return bookmarks[0]
|
|
||||||
}
|
|
||||||
const all = await getBookmarks()
|
|
||||||
return (
|
|
||||||
all.find((b) => !b.remote && b.name === "main") ??
|
|
||||||
all.find((b) => !b.remote && b.name === "master") ??
|
|
||||||
all[0] ??
|
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getRecentChanges(limit = 20): Promise<Change[]> {
|
async function getRecentChanges(limit = 20): Promise<Change[]> {
|
||||||
const r = await jj(
|
const r = await jj(
|
||||||
"log",
|
"log",
|
||||||
@@ -372,8 +342,6 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
return lines.length === 1 ? lines[0].trim() : null
|
return lines.length === 1 ? lines[0].trim() : null
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- PR materialization --------------------------------------------------
|
|
||||||
|
|
||||||
async function materializePr(prNumber: number): Promise<
|
async function materializePr(prNumber: number): Promise<
|
||||||
| {
|
| {
|
||||||
ok: true
|
ok: true
|
||||||
@@ -393,24 +361,19 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const savedR = await jj(
|
const savedChangeId = await getSingleChangeId("@")
|
||||||
"log",
|
if (!savedChangeId) {
|
||||||
"-r",
|
return { ok: false, error: "Failed to determine the current change" }
|
||||||
"@",
|
}
|
||||||
"--no-graph",
|
|
||||||
"-T",
|
|
||||||
"change_id.shortest(8)",
|
|
||||||
)
|
|
||||||
const savedChangeId = savedR.stdout.trim()
|
|
||||||
|
|
||||||
const prR = await gh(
|
const prResponse = await gh(
|
||||||
"pr",
|
"pr",
|
||||||
"view",
|
"view",
|
||||||
String(prNumber),
|
String(prNumber),
|
||||||
"--json",
|
"--json",
|
||||||
"baseRefName,title,headRefName,isCrossRepository,headRepository,headRepositoryOwner",
|
"baseRefName,title,headRefName,isCrossRepository,headRepository,headRepositoryOwner,url",
|
||||||
)
|
)
|
||||||
if (!prR.ok) {
|
if (!prResponse.ok) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
error: `Could not find PR #${prNumber}. Check gh auth and that the PR exists.`,
|
error: `Could not find PR #${prNumber}. Check gh auth and that the PR exists.`,
|
||||||
@@ -422,54 +385,36 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
title: string
|
title: string
|
||||||
headRefName: string
|
headRefName: string
|
||||||
isCrossRepository: boolean
|
isCrossRepository: boolean
|
||||||
|
url: string
|
||||||
headRepository?: { name: string; url: string }
|
headRepository?: { name: string; url: string }
|
||||||
headRepositoryOwner?: { login: string }
|
headRepositoryOwner?: { login: string }
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
prInfo = JSON.parse(prR.stdout)
|
prInfo = JSON.parse(prResponse.stdout)
|
||||||
} catch {
|
} catch {
|
||||||
return { ok: false, error: "Failed to parse PR info" }
|
return { ok: false, error: "Failed to parse PR info" }
|
||||||
}
|
}
|
||||||
|
|
||||||
const remotesR = await jj("git", "remote", "list")
|
const remotes = await getJjRemotes()
|
||||||
const remotes = remotesR.stdout
|
const defaultRemote = getDefaultRemote(remotes)
|
||||||
.trim()
|
|
||||||
.split("\n")
|
|
||||||
.filter(Boolean)
|
|
||||||
.map((line) => {
|
|
||||||
const [name, ...urlParts] = line.split(/\s+/)
|
|
||||||
return { name, url: urlParts.join(" ") }
|
|
||||||
})
|
|
||||||
.filter((r) => r.name && r.url)
|
|
||||||
|
|
||||||
const defaultRemote =
|
|
||||||
remotes.find((r) => r.name === "origin") ?? remotes[0]
|
|
||||||
if (!defaultRemote) {
|
if (!defaultRemote) {
|
||||||
return { ok: false, error: "No jj remotes configured" }
|
return { ok: false, error: "No jj remotes configured" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const baseRepoUrl = getRepositoryUrl(prInfo.url)
|
||||||
|
const baseRemote = baseRepoUrl
|
||||||
|
? remotes.find((remote) => getRepositoryUrl(remote.url) === baseRepoUrl)
|
||||||
|
: undefined
|
||||||
|
|
||||||
let remoteName = defaultRemote.name
|
let remoteName = defaultRemote.name
|
||||||
let addedTempRemote = false
|
let addedTempRemote = false
|
||||||
|
|
||||||
if (prInfo.isCrossRepository) {
|
if (prInfo.isCrossRepository) {
|
||||||
const repoSlug =
|
|
||||||
prInfo.headRepositoryOwner?.login && prInfo.headRepository?.name
|
|
||||||
? `${prInfo.headRepositoryOwner.login}/${prInfo.headRepository.name}`.toLowerCase()
|
|
||||||
: undefined
|
|
||||||
const forkUrl = prInfo.headRepository?.url
|
const forkUrl = prInfo.headRepository?.url
|
||||||
|
const forkRepoUrl = forkUrl ? getRepositoryUrl(forkUrl) : null
|
||||||
const existingRemote = remotes.find((r) => {
|
const existingRemote = forkRepoUrl
|
||||||
if (
|
? remotes.find((remote) => getRepositoryUrl(remote.url) === forkRepoUrl)
|
||||||
forkUrl &&
|
: undefined
|
||||||
normalizeRemoteUrl(r.url) === normalizeRemoteUrl(forkUrl)
|
|
||||||
)
|
|
||||||
return true
|
|
||||||
return repoSlug
|
|
||||||
? normalizeRemoteUrl(r.url).includes(
|
|
||||||
`github.com/${repoSlug}`,
|
|
||||||
)
|
|
||||||
: false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (existingRemote) {
|
if (existingRemote) {
|
||||||
remoteName = existingRemote.name
|
remoteName = existingRemote.name
|
||||||
@@ -483,21 +428,23 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
while (names.has(remoteName)) {
|
while (names.has(remoteName)) {
|
||||||
remoteName = `${baseName}-${suffix++}`
|
remoteName = `${baseName}-${suffix++}`
|
||||||
}
|
}
|
||||||
const addR = await jj(
|
const addRemoteResult = await jj(
|
||||||
"git",
|
"git",
|
||||||
"remote",
|
"remote",
|
||||||
"add",
|
"add",
|
||||||
remoteName,
|
remoteName,
|
||||||
forkUrl,
|
forkUrl,
|
||||||
)
|
)
|
||||||
if (!addR.ok) return { ok: false, error: "Failed to add PR remote" }
|
if (!addRemoteResult.ok) {
|
||||||
|
return { ok: false, error: "Failed to add PR remote" }
|
||||||
|
}
|
||||||
addedTempRemote = true
|
addedTempRemote = true
|
||||||
} else {
|
} else {
|
||||||
return { ok: false, error: "PR fork URL is unavailable" }
|
return { ok: false, error: "PR fork URL is unavailable" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchR = await jj(
|
const fetchHeadResult = await jj(
|
||||||
"git",
|
"git",
|
||||||
"fetch",
|
"fetch",
|
||||||
"--remote",
|
"--remote",
|
||||||
@@ -505,15 +452,15 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
"--branch",
|
"--branch",
|
||||||
prInfo.headRefName,
|
prInfo.headRefName,
|
||||||
)
|
)
|
||||||
if (!fetchR.ok) {
|
if (!fetchHeadResult.ok) {
|
||||||
if (addedTempRemote)
|
if (addedTempRemote)
|
||||||
await jj("git", "remote", "remove", remoteName)
|
await jj("git", "remote", "remove", remoteName)
|
||||||
return { ok: false, error: "Failed to fetch PR branch" }
|
return { ok: false, error: "Failed to fetch PR branch" }
|
||||||
}
|
}
|
||||||
|
|
||||||
const revset = `remote_bookmarks(exact:${JSON.stringify(prInfo.headRefName)}, exact:${JSON.stringify(remoteName)})`
|
const revset = `remote_bookmarks(exact:${JSON.stringify(prInfo.headRefName)}, exact:${JSON.stringify(remoteName)})`
|
||||||
const newR = await jj("new", revset)
|
const createChangeResult = await jj("new", revset)
|
||||||
if (!newR.ok) {
|
if (!createChangeResult.ok) {
|
||||||
if (addedTempRemote)
|
if (addedTempRemote)
|
||||||
await jj("git", "remote", "remove", remoteName)
|
await jj("git", "remote", "remove", remoteName)
|
||||||
return { ok: false, error: "Failed to create change on PR branch" }
|
return { ok: false, error: "Failed to create change on PR branch" }
|
||||||
@@ -521,14 +468,11 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
|
|
||||||
if (addedTempRemote) await jj("git", "remote", "remove", remoteName)
|
if (addedTempRemote) await jj("git", "remote", "remove", remoteName)
|
||||||
|
|
||||||
// Resolve base bookmark remote
|
|
||||||
const baseRef = await resolveBookmarkRef(prInfo.baseRefName)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
title: prInfo.title,
|
title: prInfo.title,
|
||||||
baseBookmark: prInfo.baseRefName,
|
baseBookmark: prInfo.baseRefName,
|
||||||
baseRemote: baseRef?.remote,
|
baseRemote: baseRemote?.name,
|
||||||
headBookmark: prInfo.headRefName,
|
headBookmark: prInfo.headRefName,
|
||||||
remote: remoteName,
|
remote: remoteName,
|
||||||
savedChangeId,
|
savedChangeId,
|
||||||
@@ -554,19 +498,6 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
return left.name === right.name && left.remote === right.remote
|
return left.name === right.name && left.remote === right.remote
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseBookmarkReference(value: string): BookmarkRef {
|
|
||||||
const trimmed = value.trim()
|
|
||||||
const separatorIndex = trimmed.lastIndexOf("@")
|
|
||||||
if (separatorIndex <= 0 || separatorIndex === trimmed.length - 1) {
|
|
||||||
return { name: trimmed }
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: trimmed.slice(0, separatorIndex),
|
|
||||||
remote: trimmed.slice(separatorIndex + 1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dedupeBookmarkRefs(bookmarks: BookmarkRef[]): BookmarkRef[] {
|
function dedupeBookmarkRefs(bookmarks: BookmarkRef[]): BookmarkRef[] {
|
||||||
const seen = new Set<string>()
|
const seen = new Set<string>()
|
||||||
const result: BookmarkRef[] = []
|
const result: BookmarkRef[] = []
|
||||||
@@ -625,7 +556,7 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
return revisions.length === 1 ? revisions[0] : null
|
return revisions.length === 1 ? revisions[0] : null
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getJjRemotes(): Promise<Array<{ name: string; url: string }>> {
|
async function getJjRemotes(): Promise<JjRemote[]> {
|
||||||
const r = await jj("git", "remote", "list")
|
const r = await jj("git", "remote", "list")
|
||||||
if (!r.ok) return []
|
if (!r.ok) return []
|
||||||
|
|
||||||
@@ -637,10 +568,16 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
.filter((remote) => remote.name && remote.url)
|
.filter((remote) => remote.name && remote.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDefaultRemote(remotes: JjRemote[]): JjRemote | null {
|
||||||
|
return (
|
||||||
|
remotes.find((remote) => remote.name === "origin") ??
|
||||||
|
remotes[0] ??
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async function getDefaultRemoteName(): Promise<string | null> {
|
async function getDefaultRemoteName(): Promise<string | null> {
|
||||||
const remotes = await getJjRemotes()
|
return getDefaultRemote(await getJjRemotes())?.name ?? null
|
||||||
if (remotes.length === 0) return null
|
|
||||||
return remotes.find((remote) => remote.name === "origin")?.name ?? remotes[0].name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function preferBookmarkRef(
|
function preferBookmarkRef(
|
||||||
@@ -759,8 +696,6 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- prompt building -----------------------------------------------------
|
|
||||||
|
|
||||||
async function buildTargetReviewPrompt(
|
async function buildTargetReviewPrompt(
|
||||||
target: ReviewTarget,
|
target: ReviewTarget,
|
||||||
options?: { includeLocalChanges?: boolean },
|
options?: { includeLocalChanges?: boolean },
|
||||||
@@ -841,7 +776,10 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function buildReviewPrompt(target: ReviewTarget): Promise<string> {
|
async function buildReviewPrompt(target: ReviewTarget): Promise<string> {
|
||||||
const prompt = await buildTargetReviewPrompt(target)
|
const prompt = await buildTargetReviewPrompt(target, {
|
||||||
|
includeLocalChanges:
|
||||||
|
target.type !== "workingCopy" && (await hasWorkingCopyChanges()),
|
||||||
|
})
|
||||||
const projectGuidelines = await loadProjectReviewGuidelines()
|
const projectGuidelines = await loadProjectReviewGuidelines()
|
||||||
const sharedInstructions = normalizeCustomInstructions(
|
const sharedInstructions = normalizeCustomInstructions(
|
||||||
reviewCustomInstructions,
|
reviewCustomInstructions,
|
||||||
@@ -910,17 +848,13 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- review execution ----------------------------------------------------
|
async function startReview(target: ReviewTarget): Promise<boolean> {
|
||||||
|
|
||||||
async function startReview(target: ReviewTarget): Promise<void> {
|
|
||||||
const prompt = await buildReviewPrompt(target)
|
const prompt = await buildReviewPrompt(target)
|
||||||
const hint = getUserFacingHint(target)
|
const hint = getUserFacingHint(target)
|
||||||
const cleared = await api.client.tui.clearPrompt()
|
const cleared = await api.client.tui.clearPrompt()
|
||||||
const appended = await api.client.tui.appendPrompt({
|
const appended = await api.client.tui.appendPrompt({
|
||||||
text: prompt,
|
text: prompt,
|
||||||
})
|
})
|
||||||
// `prompt.submit` is ignored unless the prompt input is focused.
|
|
||||||
// When this runs from a dialog, focus returns on the next tick.
|
|
||||||
await sleep(50)
|
await sleep(50)
|
||||||
const submitted = await api.client.tui.submitPrompt()
|
const submitted = await api.client.tui.submitPrompt()
|
||||||
|
|
||||||
@@ -929,16 +863,16 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
message: "Failed to start review prompt automatically",
|
message: "Failed to start review prompt automatically",
|
||||||
variant: "error",
|
variant: "error",
|
||||||
})
|
})
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
api.ui.toast({
|
api.ui.toast({
|
||||||
message: `Starting review: ${hint}`,
|
message: `Starting review: ${hint}`,
|
||||||
variant: "info",
|
variant: "info",
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// -- dialogs -------------------------------------------------------------
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
async function showReviewSelector(): Promise<void> {
|
async function showReviewSelector(): Promise<void> {
|
||||||
const smartDefault = await getSmartDefault()
|
const smartDefault = await getSmartDefault()
|
||||||
@@ -1206,13 +1140,22 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
variant: "info",
|
variant: "info",
|
||||||
})
|
})
|
||||||
|
|
||||||
await startReview({
|
const started = await startReview({
|
||||||
type: "pullRequest",
|
type: "pullRequest",
|
||||||
prNumber,
|
prNumber,
|
||||||
baseBookmark: result.baseBookmark,
|
baseBookmark: result.baseBookmark,
|
||||||
baseRemote: result.baseRemote,
|
baseRemote: result.baseRemote,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
})
|
})
|
||||||
|
if (started) return
|
||||||
|
|
||||||
|
const restored = await jj("edit", result.savedChangeId)
|
||||||
|
api.ui.toast({
|
||||||
|
message: restored.ok
|
||||||
|
? "Restored the previous change after the review prompt failed"
|
||||||
|
: `Review prompt failed and restoring the previous change also failed (${result.savedChangeId})`,
|
||||||
|
variant: restored.ok ? "info" : "error",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function showFolderInput(): void {
|
function showFolderInput(): void {
|
||||||
@@ -1240,12 +1183,8 @@ const plugin: TuiPlugin = async (api) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- jj repo check -------------------------------------------------------
|
|
||||||
|
|
||||||
const inJjRepo = await isJjRepo()
|
const inJjRepo = await isJjRepo()
|
||||||
|
|
||||||
// -- command registration ------------------------------------------------
|
|
||||||
|
|
||||||
api.command.register(() =>
|
api.command.register(() =>
|
||||||
inJjRepo
|
inJjRepo
|
||||||
? [
|
? [
|
||||||
|
|||||||
Reference in New Issue
Block a user