1.0.1: check both tea-cli and tea for every tea command, with a test for each case
This commit is contained in:
1 parent
e303c51b23
commit
25cea75eb5
6 files changed
+93
-19
No files matched your search
@@ -5,17 +5,35 @@ import { randomUUID } from 'node:crypto'
|
||||
import { ForgeError, listAccounts, publicAccount, resetAccountCache, run } from './forge.mjs'
|
||||
|
||||
const TEA_BINARIES = ['tea-cli', 'tea']
|
||||
let teaBinary
|
||||
const TEA_MISSING = 'neither tea-cli nor tea is installed on the host'
|
||||
let teaBinary // the binary that worked last (tried first). A miss is never cached, so installing one later just works.
|
||||
|
||||
async function which(cmd) {
|
||||
const r = await run(cmd, ['--version'], { timeoutMs: 10000 })
|
||||
return r.code === 0 ? (r.stdout || r.stderr).replace(/\x1b\[[0-9;]*m/g, "").trim().split("\n")[0] : null
|
||||
}
|
||||
|
||||
/** Candidate order for tea commands: the last working binary first, then the rest of tea-cli / tea. */
|
||||
const teaOrder = () => (teaBinary ? [teaBinary, ...TEA_BINARIES.filter((b) => b !== teaBinary)] : TEA_BINARIES)
|
||||
|
||||
/** First of tea-cli / tea that runs on this host, or null. */
|
||||
async function teaBin() {
|
||||
if (teaBinary !== undefined) return teaBinary
|
||||
for (const b of TEA_BINARIES) if (await which(b)) return (teaBinary = b)
|
||||
return (teaBinary = null)
|
||||
for (const b of teaOrder()) if (await which(b)) return (teaBinary = b)
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a tea command with whichever of tea-cli / tea exists: both names are tried, and a binary that is not
|
||||
* there (ENOENT) is skipped. Resolves like `run`, plus the `bin` that ran it.
|
||||
*/
|
||||
async function runTea(args, opts) {
|
||||
for (const bin of teaOrder()) {
|
||||
const r = await run(bin, args, opts)
|
||||
if (r.error?.code === 'ENOENT') continue
|
||||
teaBinary = bin
|
||||
return { ...r, bin }
|
||||
}
|
||||
throw new ForgeError(TEA_MISSING, 400)
|
||||
}
|
||||
|
||||
export async function cliStatus() {
|
||||
@@ -34,8 +52,6 @@ const cleanHost = (h) => String(h || 'github.com').trim().replace(/^https?:\/\//
|
||||
|
||||
/** Add a Gitea/Forgejo login with a token (or user+password, from which tea creates a token). */
|
||||
export async function giteaLogin({ name, url, token, user, password, insecure }) {
|
||||
const bin = await teaBin()
|
||||
if (!bin) throw new ForgeError('tea-cli is not installed on the host', 400)
|
||||
if (!url) throw new ForgeError('server URL is required', 400)
|
||||
if (!token && !(user && password)) throw new ForgeError('an access token (or user and password) is required', 400)
|
||||
let u
|
||||
@@ -46,8 +62,8 @@ export async function giteaLogin({ name, url, token, user, password, insecure })
|
||||
if (token) env.GITEA_SERVER_TOKEN = token
|
||||
else { env.GITEA_SERVER_USER = user; env.GITEA_SERVER_PASSWORD = password }
|
||||
if (insecure) args.push('--insecure')
|
||||
const r = await run(bin, args, { env, timeoutMs: 60000 })
|
||||
if (r.code !== 0) throw fail(r, 'tea-cli logins add')
|
||||
const r = await runTea(args, { env, timeoutMs: 60000 })
|
||||
if (r.code !== 0) throw fail(r, `${r.bin} logins add`)
|
||||
done()
|
||||
return { ok: true, message: (r.stdout || '').trim() }
|
||||
}
|
||||
@@ -132,11 +148,7 @@ export async function logout(accountId) {
|
||||
if (!a) throw new ForgeError(`unknown account ${accountId}`, 404)
|
||||
let r
|
||||
if (a.kind === 'github') r = await run('gh', ['auth', 'logout', '--hostname', a.host, '--user', a.user], { timeoutMs: 30000 })
|
||||
else {
|
||||
const bin = await teaBin()
|
||||
if (!bin) throw new ForgeError('tea-cli is not installed on the host', 400)
|
||||
r = await run(bin, ['logins', 'delete', a.name], { timeoutMs: 30000 })
|
||||
}
|
||||
else r = await runTea(['logins', 'delete', a.name], { timeoutMs: 30000 })
|
||||
if (r.code !== 0) throw fail(r, 'logout')
|
||||
done()
|
||||
return { ok: true }
|
||||
|
||||
Reference in new issue
Block a user