♻️ refactor(vscode): 代码托管仓库抽成统一接口,Gitea 实现搬到 provider 后面,翻页改看 Link 头
This commit is contained in:
1 parent
c90d84d7f2
commit
14bee9f505
64 files changed
+1881
-2718
No files matched your search
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 当前工作区对应哪个代码托管仓库:读 git 的 origin 地址,按 host 认出是哪一家,带上凭据造出 [ForgeProvider]。
|
||||
*
|
||||
* 所有要访问仓库的地方都从这里拿 [ForgeContext],不再各自去读 remote 和 token。
|
||||
*/
|
||||
|
||||
import type { ExtensionContext } from 'vscode'
|
||||
import type { Remote } from '../git/remote'
|
||||
import type { ForgeKind, ForgeProvider } from './types'
|
||||
import { workspace } from 'vscode'
|
||||
import { getToken } from '../auth/secrets'
|
||||
import { detectRepo } from '../git/remote'
|
||||
import { GiteaProvider } from './gitea/provider'
|
||||
|
||||
/** 一个工作区对应的代码托管仓库,和访问它用的 [ForgeProvider]。 */
|
||||
export interface ForgeContext {
|
||||
workspaceRoot: string
|
||||
kind: ForgeKind
|
||||
host: string
|
||||
owner: string
|
||||
repo: string
|
||||
provider: ForgeProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析结果;失败时 `message` 是可以直接给人看的原因,`reason` 给需要分情况处理的调用方:
|
||||
* `no-workspace` 没打开工作区,`no-remote` 没有能认出的 origin,`no-credentials` 没有凭据,`unsupported` 这一家还不支持。
|
||||
*/
|
||||
export type ForgeResolution
|
||||
= | { ok: true, forge: ForgeContext }
|
||||
| { ok: false, reason: 'no-workspace' | 'no-remote', message: string }
|
||||
| { ok: false, reason: 'no-credentials' | 'unsupported', message: string, kind: ForgeKind, host: string }
|
||||
|
||||
/** host 小写后是 `github.com` 的是 GitHub,其余都当 Gitea;不认 GitHub Enterprise。 */
|
||||
export function forgeKindForHost(host: string): ForgeKind {
|
||||
return host.toLowerCase() === 'github.com' ? 'github' : 'gitea'
|
||||
}
|
||||
|
||||
/** 给指定的仓库造 [ForgeContext];webhook 记下的仓库不一定是当前工作区的 origin,所以单独开放。 */
|
||||
export async function openForge(ctx: ExtensionContext, workspaceRoot: string, remote: Remote): Promise<ForgeResolution> {
|
||||
const kind = forgeKindForHost(remote.host)
|
||||
if (kind === 'github')
|
||||
return { ok: false, reason: 'unsupported', kind, host: remote.host, message: '暂未支持 GitHub 仓库' }
|
||||
const token = await getToken(ctx, remote.host)
|
||||
if (!token)
|
||||
return { ok: false, reason: 'no-credentials', kind, host: remote.host, message: `请先配置 ${remote.host} 的访问令牌` }
|
||||
return {
|
||||
ok: true,
|
||||
forge: {
|
||||
workspaceRoot,
|
||||
kind,
|
||||
host: remote.host,
|
||||
owner: remote.owner,
|
||||
repo: remote.repo,
|
||||
provider: new GiteaProvider({ ...remote, token }),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/** 解析当前工作区(第一个工作区文件夹)的代码托管仓库。 */
|
||||
export async function resolveForge(ctx: ExtensionContext): Promise<ForgeResolution> {
|
||||
const workspaceRoot = workspace.workspaceFolders?.[0]?.uri.fsPath
|
||||
if (!workspaceRoot)
|
||||
return { ok: false, reason: 'no-workspace', message: '请先打开一个工作区文件夹' }
|
||||
const remote = await detectRepo(workspaceRoot)
|
||||
if (!remote)
|
||||
return { ok: false, reason: 'no-remote', message: '当前工作区没有能识别的 origin 远程仓库' }
|
||||
return openForge(ctx, workspaceRoot, remote)
|
||||
}
|
||||
|
||||
/**
|
||||
* 同 [resolveForge],解析不出来时抛错。
|
||||
*
|
||||
* @throws [Error] 解析失败,`message` 是给人看的原因
|
||||
*/
|
||||
export async function requireForge(ctx: ExtensionContext): Promise<ForgeContext> {
|
||||
const resolved = await resolveForge(ctx)
|
||||
if (!resolved.ok)
|
||||
throw new Error(resolved.message)
|
||||
return resolved.forge
|
||||
}
|
||||
Reference in new issue
Block a user