#!/usr/bin/env node /** * 创建/推送到 Gitea(默认 http://10.126.232.10:3000)。 * 用法: * GITEA_TOKEN= node scripts/push-to-gitea.mjs * 可选环境变量:GITEA_URL、GITEA_REPO、GITEA_PUBLIC=1 * 令牌只从环境变量读取,不写入仓库文件;推送完成后 origin 会还原为不含凭据的 URL。 */ import { spawnSync } from 'node:child_process'; const base = (process.env.GITEA_URL || 'http://10.126.232.10:3000').replace(/\/+$/, ''); const token = (process.env.GITEA_TOKEN || '').trim(); const repo = process.env.GITEA_REPO || 'classhelper-island-refactor-prompt'; const isPublic = process.env.GITEA_PUBLIC === '1'; if (!token) { console.error('缺少环境变量 GITEA_TOKEN(Gitea 访问令牌)。'); process.exit(2); } const headers = { Authorization: `token ${token}`, 'Content-Type': 'application/json', Accept: 'application/json' }; async function api(path, init = {}) { const res = await fetch(`${base}/api/v1${path}`, { ...init, headers, signal: AbortSignal.timeout(20000) }); const text = await res.text(); let data = null; try { data = text ? JSON.parse(text) : null; } catch { data = text; } return { res, data }; } function git(args, opts = {}) { return spawnSync('git', args, { stdio: 'inherit', ...opts }); } const main = async () => { console.log(`[1/4] 校验令牌:GET ${base}/api/v1/user`); const u = await api('/user'); if (!u.res.ok || !u.data?.login) { throw new Error(`无法获取当前用户(HTTP ${u.res.status})。请检查 Gitea 地址、网络与令牌。`); } const login = u.data.login; console.log(` 当前用户:${login}`); console.log(`[2/4] 创建仓库:${repo}(${isPublic ? '公开' : '私有'})`); const existing = await api(`/repos/${encodeURIComponent(login)}/${encodeURIComponent(repo)}`); if (existing.res.ok) { console.log(' 仓库已存在,直接推送。'); } else if (existing.res.status !== 404) { console.log(` 仓库探测返回 HTTP ${existing.res.status},继续尝试创建。`); } if (!existing.res.ok) { const created = await api('/user/repos', { method: 'POST', body: JSON.stringify({ name: repo, private: !isPublic, auto_init: false, description: 'ClassIsland / ClassHelper 灵动岛提示词套件(静态分析产物)', }), }); if (created.res.ok) { console.log(` 已创建:${created.data.full_name}`); console.log(` 网页地址:${created.data.html_url}`); } else if (created.res.status === 409) { console.log(' 仓库已存在(409),继续推送。'); } else { throw new Error(`创建仓库失败(HTTP ${created.res.status}):${JSON.stringify(created.data)}`); } } console.log('[3/4] 推送 main 分支'); const cleanUrl = `${base}/${login}/${repo}.git`; const scheme = base.split('://')[0]; const host = base.split('://')[1]; const authUrl = `${scheme}://${encodeURIComponent(login)}:${encodeURIComponent(token)}@${host}/${login}/${repo}.git`; git(['remote', 'remove', 'origin']); git(['remote', 'add', 'origin', authUrl]); try { const pushed = git(['push', '-u', 'origin', 'HEAD:main']); if (pushed.status !== 0) throw new Error(`git push 失败(exit ${pushed.status})`); } finally { git(['remote', 'set-url', 'origin', cleanUrl]); console.log(` 已将 origin 还原为不含凭据的地址:${cleanUrl}`); } console.log(`[4/4] 完成\n仓库:${cleanUrl}`); }; main().catch((e) => { console.error(`错误:${e.message}`); process.exit(1); });