From 67694183eb8ca3e4239b7cb83294e4673fab5986 Mon Sep 17 00:00:00 2001 From: ClassIsland Prompt Kit Date: Thu, 12 Nov 2026 22:00:47 +0800 Subject: [PATCH] chore: add Gitea push helper (Node/PowerShell) --- scripts/push-to-gitea.mjs | 89 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 scripts/push-to-gitea.mjs diff --git a/scripts/push-to-gitea.mjs b/scripts/push-to-gitea.mjs new file mode 100644 index 0000000..2b767cc --- /dev/null +++ b/scripts/push-to-gitea.mjs @@ -0,0 +1,89 @@ +#!/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); +});