Blame · Line-by-line history
repo.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 63fe719 | 1 | /** |
| 2 | * Workspace-aware helpers that combine VS Code APIs with the pure parser | |
| 3 | * in `git.ts`. Returns `null` whenever the active workspace can't be | |
| 4 | * resolved to a Gluecron-hosted repo. | |
| 5 | */ | |
| 6 | ||
| 7 | import * as vscode from "vscode"; | |
| 8 | import { execFile } from "node:child_process"; | |
| 9 | import { promisify } from "node:util"; | |
| 10 | import { parseGitRemote, isGluecronRemote, type RepoInfo } from "./git"; | |
| 11 | ||
| 12 | const execFileP = promisify(execFile); | |
| 13 | ||
| 14 | export function getHost(): string { | |
| 15 | const v = vscode.workspace | |
| 16 | .getConfiguration("gluecron") | |
| 17 | .get<string>("host"); | |
| 18 | return (v && v.trim()) || "https://gluecron.com"; | |
| 19 | } | |
| 20 | ||
| 21 | export function getDefaultBranch(): string { | |
| 22 | const v = vscode.workspace | |
| 23 | .getConfiguration("gluecron") | |
| 24 | .get<string>("defaultBranch"); | |
| 25 | return (v && v.trim()) || "main"; | |
| 26 | } | |
| 27 | ||
| 28 | /** | |
| 29 | * Pick a workspace folder — prefers the active editor's folder, falls back | |
| 30 | * to the first workspace folder. Returns `null` if there is no workspace. | |
| 31 | */ | |
| 32 | export function pickWorkspaceFolder(): vscode.WorkspaceFolder | null { | |
| 33 | const editor = vscode.window.activeTextEditor; | |
| 34 | if (editor) { | |
| 35 | const folder = vscode.workspace.getWorkspaceFolder(editor.document.uri); | |
| 36 | if (folder) return folder; | |
| 37 | } | |
| 38 | const folders = vscode.workspace.workspaceFolders; | |
| 39 | if (folders && folders.length > 0) return folders[0]; | |
| 40 | return null; | |
| 41 | } | |
| 42 | ||
| 43 | /** | |
| 44 | * Resolve the current workspace's Gluecron repo. Returns `null` if there | |
| 45 | * is no workspace, no git remote, or the remote isn't hosted on the | |
| 46 | * configured Gluecron instance. | |
| 47 | */ | |
| 48 | export async function getRepoInfo(): Promise<RepoInfo | null> { | |
| 49 | const folder = pickWorkspaceFolder(); | |
| 50 | if (!folder) return null; | |
| 51 | let url: string; | |
| 52 | try { | |
| 53 | const { stdout } = await execFileP( | |
| 54 | "git", | |
| 55 | ["remote", "get-url", "origin"], | |
| 56 | { cwd: folder.uri.fsPath } | |
| 57 | ); | |
| 58 | url = stdout.trim(); | |
| 59 | } catch { | |
| 60 | return null; | |
| 61 | } | |
| 62 | const info = parseGitRemote(url); | |
| 63 | if (!info) return null; | |
| 64 | if (!isGluecronRemote(info.host, getHost())) { | |
| 65 | // We still return the parse — callers may want the bare info for | |
| 66 | // building cross-host URLs — but most callers should use | |
| 67 | // `getGluecronRepoInfo` which filters this out. | |
| 68 | return info; | |
| 69 | } | |
| 70 | return info; | |
| 71 | } | |
| 72 | ||
| 73 | /** | |
| 74 | * Like `getRepoInfo` but returns `null` for non-Gluecron remotes. | |
| 75 | */ | |
| 76 | export async function getGluecronRepoInfo(): Promise<RepoInfo | null> { | |
| 77 | const info = await getRepoInfo(); | |
| 78 | if (!info) return null; | |
| 79 | if (!isGluecronRemote(info.host, getHost())) return null; | |
| 80 | return info; | |
| 81 | } | |
| 82 | ||
| 83 | /** | |
| 84 | * Build a URL inside the configured Gluecron host. | |
| 85 | */ | |
| 86 | export function hostUrl(path: string): string { | |
| 87 | const host = getHost().replace(/\/+$/, ""); | |
| 88 | const p = path.startsWith("/") ? path : `/${path}`; | |
| 89 | return host + p; | |
| 90 | } |