mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 08:07:49 +00:00
Run oxfmt once over the whole repository (formatting only, no logic changes) and add `pnpm format:check` to the frontend CI job so unformatted code no longer builds up. `.oxfmtrc.json` now skips the generated theme docs, test fixtures and code blocks inside Markdown. Co-authored-by: jaw52 <53564781+jaw52@users.noreply.github.com>
181 lines
5.7 KiB
TypeScript
181 lines
5.7 KiB
TypeScript
/** Pull request operations shared by the view and the `github.*` actions. */
|
||
import type { PrFile, PullRequestDetails, ReviewEvent } from "@/platform/ipc";
|
||
import { executeAction } from "@/platform/actions";
|
||
import { call, commands } from "@/platform/ipc";
|
||
import { notifications, toolWindowService } from "@/workbench/contributions";
|
||
import { createPullRequestDialog, numberDialog, reviewDialog } from "./dialogs";
|
||
import { fileDiffData } from "./model";
|
||
import {
|
||
diffRevisions,
|
||
errorMessage,
|
||
loadDetails,
|
||
loadList,
|
||
readyRepo,
|
||
refreshAll,
|
||
useGithub,
|
||
withBusy,
|
||
} from "./store";
|
||
|
||
export const WINDOW = "pullRequests";
|
||
|
||
export async function openUrl(url: string) {
|
||
try {
|
||
const { openUrl: open } = await import("@tauri-apps/plugin-opener");
|
||
await open(url);
|
||
} catch {
|
||
window.open(url, "_blank", "noopener");
|
||
}
|
||
}
|
||
|
||
/** Shows the tool window, (re)checking gh first when needed. */
|
||
export async function showPullRequests() {
|
||
toolWindowService().show(WINDOW, true);
|
||
if (useGithub.getState().availability?.kind !== "ready") await refreshAll();
|
||
}
|
||
|
||
function notReady(): boolean {
|
||
const a = useGithub.getState().availability;
|
||
if (a?.kind === "ready") return false;
|
||
void showPullRequests();
|
||
return true;
|
||
}
|
||
|
||
export async function checkoutPullRequest(number: number) {
|
||
const done = await withBusy(`Checking out #${number}…`, (r, out) => call(commands.ghPrCheckout(r, number, out)));
|
||
if (done !== null)
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "info",
|
||
title: `Checked out pull request #${number}`,
|
||
key: "github-checkout",
|
||
});
|
||
}
|
||
|
||
/** Git › GitHub › Checkout Pull Request…: the selected one, else asks for a number. */
|
||
export async function checkoutAction(arg: unknown) {
|
||
if (useGithub.getState().availability?.kind !== "ready") await refreshAll();
|
||
if (notReady()) return;
|
||
const n =
|
||
typeof arg === "number" ? arg : (useGithub.getState().selected ?? (await numberDialog("Checkout Pull Request")));
|
||
if (n) await checkoutPullRequest(n);
|
||
}
|
||
|
||
export async function openFileDiff(pr: PullRequestDetails, file: PrFile) {
|
||
const revs = await diffRevisions(pr);
|
||
if (!revs) return;
|
||
await executeAction("vcs.openDiff", fileDiffData(pr, file, revs, useGithub.getState().reviewComments));
|
||
}
|
||
|
||
/** Opens a review comment's file at its line in the PR diff. */
|
||
export async function openCommentLocation(pr: PullRequestDetails, path: string) {
|
||
const file = pr.files.find((f) => f.path === path) ?? { path, additions: 0, deletions: 0, changeType: "MODIFIED" };
|
||
await openFileDiff(pr, file);
|
||
}
|
||
|
||
export async function submitReview(number: number, initial: ReviewEvent) {
|
||
const r = await reviewDialog(number, initial);
|
||
if (!r) return;
|
||
try {
|
||
await call(commands.ghPrReview(number, r.event, r.body));
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "info",
|
||
title: `Review submitted on #${number}`,
|
||
key: "github-review",
|
||
});
|
||
await loadDetails(number);
|
||
} catch (e) {
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "error",
|
||
title: "Could not submit the review",
|
||
body: errorMessage(e),
|
||
key: "github-review",
|
||
});
|
||
}
|
||
}
|
||
|
||
export async function addComment(number: number, body: string): Promise<boolean> {
|
||
try {
|
||
await call(commands.ghPrComment(number, body));
|
||
await loadDetails(number);
|
||
return true;
|
||
} catch (e) {
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "error",
|
||
title: "Could not add the comment",
|
||
body: errorMessage(e),
|
||
key: "github-comment",
|
||
});
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/** Git › GitHub › Create Pull Request…: from the current branch. */
|
||
export async function createPullRequest() {
|
||
if (useGithub.getState().availability?.kind !== "ready") await refreshAll();
|
||
if (notReady()) return;
|
||
const repo = readyRepo();
|
||
let head: string | null = null;
|
||
let needsPush = true;
|
||
let title = "";
|
||
try {
|
||
const info = await call(commands.vcsBranchInfo(null));
|
||
head = info.head;
|
||
needsPush = !info.upstream || info.ahead > 0;
|
||
if (head)
|
||
title = head
|
||
.replace(/^[^/]+\//, "")
|
||
.replace(/[-_]+/g, " ")
|
||
.replace(/^\w/, (c) => c.toUpperCase());
|
||
} catch {
|
||
// Not a git repository: gh will explain.
|
||
}
|
||
if (!head) {
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "warning",
|
||
title: "Check out a branch to create a pull request from",
|
||
key: "github-create",
|
||
});
|
||
return;
|
||
}
|
||
if (head === repo?.defaultBranch) {
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "warning",
|
||
title: `'${head}' is the default branch`,
|
||
body: "Create a branch for your changes first.",
|
||
key: "github-create",
|
||
actions: [{ label: "New Branch…", run: () => void executeAction("vcs.newBranch") }],
|
||
});
|
||
return;
|
||
}
|
||
const input = await createPullRequestDialog({ head, defaultBase: repo?.defaultBranch ?? null, title, needsPush });
|
||
if (!input) return;
|
||
const url = await withBusy(`Creating pull request…`, (r, out) => call(commands.ghPrCreate(r, input, out)));
|
||
if (url === null) return;
|
||
notifications().notify({
|
||
group: "vcs",
|
||
level: "info",
|
||
title: "Pull request created",
|
||
body: url || undefined,
|
||
key: "github-create",
|
||
actions: url ? [{ label: "Open in Browser", run: () => void openUrl(url) }] : undefined,
|
||
});
|
||
toolWindowService().show(WINDOW);
|
||
await loadList();
|
||
const m = /\/pull\/(\d+)/.exec(url);
|
||
if (m) await loadDetails(Number(m[1]));
|
||
}
|
||
|
||
/** Opens the selected pull request, else the repository, on GitHub. */
|
||
export async function openInBrowser() {
|
||
if (useGithub.getState().availability?.kind !== "ready") await refreshAll();
|
||
if (notReady()) return;
|
||
const { details } = useGithub.getState();
|
||
const url = details?.summary.url ?? readyRepo()?.url;
|
||
if (url) await openUrl(url);
|
||
}
|