Files
superwork/vscode/src/git/remote.ts
T

57 lines
1.6 KiB
TypeScript

/**
* Detects the workspace's forge repo coordinates (host / owner / repo) from `git remote get-url origin`.
*
* Supports both HTTPS forms (`https://git.example.com/owner/repo.git`) and SSH
* forms (`git@git.example.com:owner/repo.git`, with or without a leading
* `ssh://`). The pure URL parser is exported separately so it's unit-testable
* without spawning a child process.
*/
import { execFile } from 'node:child_process'
export interface Remote {
host: string
owner: string
repo: string
}
const HTTPS_RE = /^https?:\/\/(?:[^@]+@)?([^/:]+)(?::\d+)?\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/
const SSH_RE = /^(?:ssh:\/\/)?(?:[^@]+@)?([^/:]+)[:/]([^/]+)\/([^/]+?)(?:\.git)?\/?$/
export function parseRemoteUrl(url: string): Remote | undefined {
const trimmed = url.trim()
if (!trimmed)
return undefined
const https = trimmed.match(HTTPS_RE)
if (https)
return { host: https[1], owner: https[2], repo: https[3] }
const ssh = trimmed.match(SSH_RE)
if (ssh)
return { host: ssh[1], owner: ssh[2], repo: ssh[3] }
return undefined
}
/**
* Resolves `{host, owner, repo}` for the origin remote of the given workspace
* root, or `undefined` if git fails or the URL is unparseable.
*/
export function detectRepo(workspaceRoot: string): Promise<Remote | undefined> {
return new Promise((resolve) => {
execFile(
'git',
['-C', workspaceRoot, 'remote', 'get-url', 'origin'],
{ encoding: 'utf8' },
(err, stdout) => {
if (err) {
resolve(undefined)
return
}
resolve(parseRemoteUrl(stdout))
},
)
})
}