99 lines
2.7 KiB
JavaScript
99 lines
2.7 KiB
JavaScript
import { log } from './util.js';
|
|
|
|
/**
|
|
* 極簡的 Gitea API client,只實作這個 action 需要的 PR 相關操作。
|
|
*/
|
|
export class GiteaClient {
|
|
/**
|
|
* @param {object} opts
|
|
* @param {string} opts.serverUrl Gitea base URL(不含結尾斜線)
|
|
* @param {string} opts.owner
|
|
* @param {string} opts.repo
|
|
* @param {string} opts.token
|
|
*/
|
|
constructor({ serverUrl, owner, repo, token }) {
|
|
this.apiBase = `${serverUrl}/api/v1`;
|
|
this.owner = owner;
|
|
this.repo = repo;
|
|
this.token = token;
|
|
}
|
|
|
|
async _request(method, path, body) {
|
|
const url = `${this.apiBase}${path}`;
|
|
const res = await fetch(url, {
|
|
method,
|
|
headers: {
|
|
Authorization: `token ${this.token}`,
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
},
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
|
|
const text = await res.text();
|
|
let json;
|
|
try {
|
|
json = text ? JSON.parse(text) : {};
|
|
} catch {
|
|
json = { message: text };
|
|
}
|
|
return { ok: res.ok, status: res.status, json };
|
|
}
|
|
|
|
/**
|
|
* 查詢 head -> base 是否已存在開啟中的 PR。
|
|
*
|
|
* @param {string} head 來源分支
|
|
* @param {string} base 目標分支
|
|
* @returns {Promise<object|null>}
|
|
*/
|
|
async findOpenPull(head, base) {
|
|
// Gitea pulls 不直接支援 head/base 過濾,這裡撈開啟中的 PR 自行比對
|
|
const { ok, json } = await this._request(
|
|
'GET',
|
|
`/repos/${this.owner}/${this.repo}/pulls?state=open&limit=50`,
|
|
);
|
|
if (!ok || !Array.isArray(json)) return null;
|
|
return (
|
|
json.find(
|
|
(pr) => pr?.head?.ref === head && pr?.base?.ref === base,
|
|
) || null
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 建立 Pull Request。若已存在相同 head/base 的 PR 則回傳既有 PR。
|
|
*
|
|
* @param {object} opts
|
|
* @param {string} opts.head 來源分支
|
|
* @param {string} opts.base 目標分支
|
|
* @param {string} opts.title
|
|
* @param {string} opts.body
|
|
* @returns {Promise<{ pull: object, created: boolean }>}
|
|
*/
|
|
async createPull({ head, base, title, body }) {
|
|
log.info(`建立 PR: ${head} → ${base}`);
|
|
const { ok, status, json } = await this._request(
|
|
'POST',
|
|
`/repos/${this.owner}/${this.repo}/pulls`,
|
|
{ head, base, title, body },
|
|
);
|
|
|
|
if (ok) {
|
|
return { pull: json, created: true };
|
|
}
|
|
|
|
// 422 通常代表 PR 已存在
|
|
if (status === 422 || status === 409) {
|
|
const existing = await this.findOpenPull(head, base);
|
|
if (existing) {
|
|
log.warn(`PR 已存在: #${existing.number}`);
|
|
return { pull: existing, created: false };
|
|
}
|
|
}
|
|
|
|
const message = json?.message || JSON.stringify(json);
|
|
throw new Error(`建立 PR 失敗 (${status}): ${message}`);
|
|
}
|
|
}
|