初始化 Gitea 项目结构,添加核心 API 封装和相关配置文件

This commit is contained in:
2026-02-19 20:38:03 +08:00
commit 94c666a993
14 changed files with 943 additions and 0 deletions

19
.cnb.yml Normal file
View File

@@ -0,0 +1,19 @@
# .cnb.yml
include:
- https://cnb.cool/kevisual/cnb/-/blob/main/.cnb/template.yml
.common_env: &common_env
env:
USERNAME: root
imports:
- https://cnb.cool/kevisual/env/-/blob/main/.env.development
$:
vscode:
- docker:
image: docker.cnb.cool/kevisual/dev-env:latest
services:
- vscode
- docker
imports: !reference [.common_env, imports]
stages: !reference [.dev_template, stages]

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.env*
!.env*example
node_modules
.pnpm-store
dist
storage

3
.npmrc Normal file
View File

@@ -0,0 +1,3 @@
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
//npm.cnb.cool/kevisual/registry/-/packages/:_authToken=${CNB_API_KEY}
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

1
README.md Normal file
View File

@@ -0,0 +1 @@
# 基本的gitea的api封装

4
bun.config.ts Normal file
View File

@@ -0,0 +1,4 @@
import { buildWithBun } from '@kevisual/code-builder';
await buildWithBun({ naming: 'app', entry: 'src/index.ts', dts: true, clean: true });

18
bun.lock Normal file
View File

@@ -0,0 +1,18 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "@kevisual/gitea",
"devDependencies": {
"@kevisual/code-builder": "^0.0.6",
"@kevisual/context": "^0.0.8",
},
},
},
"packages": {
"@kevisual/code-builder": ["@kevisual/code-builder@0.0.6", "", { "bin": { "code-builder": "bin/code.js", "builder": "bin/code.js" } }, "sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw=="],
"@kevisual/context": ["@kevisual/context@0.0.8", "", {}, "sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA=="],
}
}

23
package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "@kevisual/gitea",
"version": "0.0.2",
"description": "",
"scripts": {
"build": "bun run bun.config.ts"
},
"files": [
"src",
"dist"
],
"keywords": [],
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"type": "module",
"devDependencies": {
"@kevisual/code-builder": "^0.0.6",
"@kevisual/context": "^0.0.8"
},
"publishConfig": {
"access": "public"
}
}

152
src/core/core.ts Normal file
View File

@@ -0,0 +1,152 @@
export type CNBCoreOptions<T = {}> = {
token: string;
gitea?: GiteaCore;
baseURL?: string;
cors?: {
baseUrl?: string
}
} & T;
export type RequestOptions = {
url?: string;
method?: string;
data?: Record<string, any>;
body?: any;
params?: Record<string, any>;
headers?: Record<string, any>;
useOrigin?: boolean;
};
const API_BASER_URL = 'https://git.xiongxiao.me'
export class GiteaCore {
baseURL = API_BASER_URL;
public token: string;
public cookie?: string;
isCors: boolean;
constructor(options: CNBCoreOptions) {
this.token = options.token;
if (options?.gitea) {
if (!options.token) {
this.token = options.gitea.token;
}
}
const baseURL = options.baseURL || API_BASER_URL;
if (options?.cors?.baseUrl) {
this.baseURL = options.cors.baseUrl + '/' + baseURL.replace('https://', '');
} else {
this.baseURL = baseURL;
}
this.isCors = !!options?.cors?.baseUrl;
}
async request({ url, method = 'GET', data, params, headers, body, useOrigin }: RequestOptions): Promise<any> {
const defaultHeaders: Record<string, string> = {
'Content-Type': 'application/json',
// 'Accept': 'application/json, application/vnd.cnb.api+json, application/vnd.cnb.web+json',
'Accept': 'application/json',
};
if (this.token) {
defaultHeaders['Authorization'] = `Bearer ${this.token}`;
}
if (params) {
const queryString = new URLSearchParams(params).toString();
url += `?${queryString}`;
defaultHeaders['Accept'] = 'application/json';
}
const _headers = { ...defaultHeaders, ...headers };
let _body = undefined;
if (data) {
_body = JSON.stringify(data);
}
if (body) {
_body = body;
}
if (!_headers.Authorization) {
delete _headers.Authorization;
}
console.log('Request URL:', url, data, _headers);
const response = await fetch(url || '', {
method,
headers: _headers,
body: _body,
});
const res = (data: any, message?: string, code?: number) => {
if (useOrigin) {
return data;
}
return {
code: code ?? 200,
message: message || 'success',
data,
};
}
if (!response.ok) {
const errorText = await response.text();
if (useOrigin)
throw new Error(`Request failed with status ${response.status}: ${errorText}`);
return res(null, `Request failed with status ${response.status}: ${errorText}`, response.status);
}
const contentType = response.headers.get('Content-Type');
if (contentType && contentType.includes('application/json')) {
const values = await response.json();
return res(values);
} else {
const text = await response.text();
return res(text);
}
}
makeUrl(url: string = '', version = '/api/v1'): string {
const baseUrl = this.baseURL + version;
if (!url) return baseUrl;
if (url && url.startsWith('http')) {
return url;
}
if (url.startsWith('/')) {
return baseUrl + url;
}
return baseUrl + '/' + url;
}
get<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
const fullUrl = this.makeUrl(url);
return this.request({ url: fullUrl, method: 'GET', ...REST });
}
post<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
const fullUrl = this.makeUrl(url);
return this.request({ url: fullUrl, method: 'POST', ...REST });
}
put<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
const fullUrl = this.makeUrl(url);
return this.request({ url: fullUrl, method: 'PUT', ...REST });
}
delete<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
const fullUrl = this.makeUrl(url);
return this.request({ url: fullUrl, method: 'DELETE', ...REST });
}
patch<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
const fullUrl = this.makeUrl(url);
return this.request({ url: fullUrl, method: 'PATCH', ...REST });
}
/**
* 通过 PUT 请求上传文件内容
* @param data 包含 URL、token 和文件内容
* @returns 上传结果
*/
async putFile(data: { url: string, token: string, content: string | Buffer }): Promise<any> {
return this.request({
url: data.url,
method: 'PUT',
body: data.content,
headers: {
'Authorization': `Bearer ${data.token}`,
'Content-Type': 'application/octet-stream'
}
});
}
}
export type Result<T = any> = {
code: number;
message: string;
data: T
};

29
src/index.ts Normal file
View File

@@ -0,0 +1,29 @@
import { GiteaRepo } from './repo';
import { GiteaIssue } from './issue';
import { GiteaUser } from './user';
import { GiteaOrg } from './org';
import { GiteaCore, CNBCoreOptions, Result } from './core/core';
export class Gitea {
repo: GiteaRepo;
issue: GiteaIssue;
user: GiteaUser;
org: GiteaOrg;
constructor(options: CNBCoreOptions) {
const core = new GiteaCore(options);
this.repo = new GiteaRepo(core);
this.issue = new GiteaIssue(core);
this.user = new GiteaUser(core);
this.org = new GiteaOrg(core);
}
}
export {
GiteaRepo,
GiteaIssue,
GiteaUser,
GiteaOrg,
GiteaCore,
CNBCoreOptions,
Result,
}

172
src/issue/index.ts Normal file
View File

@@ -0,0 +1,172 @@
import { GiteaCore } from "../core/core";
export interface CreateIssueOptions {
title: string;
body?: string;
assignee?: string;
milestone?: number;
labels?: number[];
due_date?: string;
}
export interface UpdateIssueOptions {
title?: string;
body?: string;
assignee?: string;
milestone?: number | null;
state?: 'open' | 'closed';
due_date?: string | null;
}
export interface CreateCommentOptions {
body: string;
attachments?: Array<{
name: string;
url: string;
}>;
}
export class GiteaIssue extends GiteaCore {
/**
* 获取仓库问题列表
*/
async listIssues(owner: string, repo: string, options?: {
page?: number;
limit?: number;
state?: 'open' | 'closed' | 'all';
labels?: string;
milestone?: number;
assignee?: string;
since?: string;
before?: string;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取单个问题
*/
async getIssue(owner: string, repo: string, index: number) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/${index}`);
return this.request({ url });
}
/**
* 创建问题
*/
async createIssue(owner: string, repo: string, data: CreateIssueOptions) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues`);
return this.request({ url, method: 'POST', data });
}
/**
* 更新问题
*/
async updateIssue(owner: string, repo: string, index: number, data: UpdateIssueOptions) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/${index}`);
return this.request({ url, method: 'PATCH', data });
}
/**
* 删除问题
*/
async deleteIssue(owner: string, repo: string, index: number) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/${index}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取问题的评论列表
*/
async listComments(owner: string, repo: string, index: number, options?: {
page?: number;
limit?: number;
since?: string;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/${index}/comments`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 创建评论
*/
async createComment(owner: string, repo: string, index: number, data: CreateCommentOptions) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/${index}/comments`);
return this.request({ url, method: 'POST', data });
}
/**
* 更新评论
*/
async updateComment(owner: string, repo: string, commentId: number, body: string) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/comments/${commentId}`);
return this.request({ url, method: 'PATCH', data: { body } });
}
/**
* 删除评论
*/
async deleteComment(owner: string, repo: string, commentId: number) {
const url = this.makeUrl(`/repos/${owner}/${repo}/issues/comments/${commentId}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取标签列表
*/
async listLabels(owner: string, repo: string) {
const url = this.makeUrl(`/repos/${owner}/${repo}/labels`);
return this.request({ url, method: 'GET' });
}
/**
* 创建标签
*/
async createLabel(owner: string, repo: string, data: {
name: string;
color: string;
description?: string;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/labels`);
return this.request({ url, method: 'POST', data });
}
/**
* 删除标签
*/
async deleteLabel(owner: string, repo: string, id: number) {
const url = this.makeUrl(`/repos/${owner}/${repo}/labels/${id}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取里程碑列表
*/
async listMilestones(owner: string, repo: string, options?: {
state?: 'open' | 'closed' | 'all';
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/milestones`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 创建里程碑
*/
async createMilestone(owner: string, repo: string, data: {
title: string;
description?: string;
due_date?: string;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/milestones`);
return this.request({ url, method: 'POST', data });
}
/**
* 关闭里程碑
*/
async closeMilestone(owner: string, repo: string, id: number) {
const url = this.makeUrl(`/repos/${owner}/${repo}/milestones/${id}`);
return this.request({ url, method: 'DELETE' });
}
}

227
src/org/index.ts Normal file
View File

@@ -0,0 +1,227 @@
import { GiteaCore } from "../core/core";
export interface CreateOrgOptions {
username: string;
full_name?: string;
description?: string;
website?: string;
location?: string;
visibility?: 'public' | 'limited' | 'private';
}
export interface UpdateOrgOptions {
full_name?: string;
description?: string;
website?: string;
location?: string;
visibility?: 'public' | 'limited' | 'private';
}
export interface CreateTeamOptions {
name: string;
description?: string;
permission?: 'read' | 'write' | 'admin';
repositories?: string[];
includes_all_repositories?: boolean;
}
export interface UpdateTeamOptions {
name?: string;
description?: string;
permission?: 'read' | 'write' | 'admin';
}
export class GiteaOrg extends GiteaCore {
/**
* 获取当前用户所属组织列表
*/
async listOrgs(options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/user/orgs`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取指定组织信息
*/
async getOrg(org: string) {
const url = this.makeUrl(`/orgs/${org}`);
return this.request({ url });
}
/**
* 创建组织
*/
async createOrg(data: CreateOrgOptions) {
const url = this.makeUrl(`/admin/users/${data.username}/orgs`);
return this.request({ url, method: 'POST', data });
}
/**
* 更新组织信息
*/
async updateOrg(org: string, data: UpdateOrgOptions) {
const url = this.makeUrl(`/orgs/${org}`);
return this.request({ url, method: 'PATCH', data });
}
/**
* 删除组织
*/
async deleteOrg(org: string) {
const url = this.makeUrl(`/orgs/${org}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取组织成员列表
*/
async listMembers(org: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/orgs/${org}/members`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取组织成员信息
*/
async getMember(org: string, username: string) {
const url = this.makeUrl(`/orgs/${org}/members/${username}`);
return this.request({ url });
}
/**
* 添加组织成员
*/
async addMember(org: string, username: string) {
const url = this.makeUrl(`/orgs/${org}/members/${username}`);
return this.request({ url, method: 'PUT' });
}
/**
* 删除组织成员
*/
async removeMember(org: string, username: string) {
const url = this.makeUrl(`/orgs/${org}/members/${username}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取组织仓库列表
*/
async listRepos(org: string, options?: {
page?: number;
limit?: number;
type?: 'all' | 'fork' | 'source' | 'mirror';
}) {
const url = this.makeUrl(`/orgs/${org}/repos`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 创建组织仓库
*/
async createRepo(org: string, data: {
name: string;
description?: string;
private?: boolean;
gitignores?: string;
license?: string;
readme?: string;
}) {
const url = this.makeUrl(`/orgs/${org}/repos`);
return this.request({ url, method: 'POST', data });
}
/**
* 获取团队列表
*/
async listTeams(org: string) {
const url = this.makeUrl(`/orgs/${org}/teams`);
return this.request({ url, method: 'GET' });
}
/**
* 获取团队信息
*/
async getTeam(org: string, teamId: number) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}`);
return this.request({ url });
}
/**
* 创建团队
*/
async createTeam(org: string, data: CreateTeamOptions) {
const url = this.makeUrl(`/orgs/${org}/teams`);
return this.request({ url, method: 'POST', data });
}
/**
* 更新团队信息
*/
async updateTeam(org: string, teamId: number, data: UpdateTeamOptions) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}`);
return this.request({ url, method: 'PATCH', data });
}
/**
* 删除团队
*/
async deleteTeam(org: string, teamId: number) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取团队成员列表
*/
async listTeamMembers(org: string, teamId: number) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}/members`);
return this.request({ url, method: 'GET' });
}
/**
* 添加团队成员
*/
async addTeamMember(org: string, teamId: number, username: string) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}/members/${username}`);
return this.request({ url, method: 'PUT' });
}
/**
* 删除团队成员
*/
async removeTeamMember(org: string, teamId: number, username: string) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}/members/${username}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取团队仓库列表
*/
async listTeamRepos(org: string, teamId: number) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}/repos`);
return this.request({ url, method: 'GET' });
}
/**
* 添加团队仓库
*/
async addTeamRepo(org: string, teamId: number, repo: string) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}/repos/${repo}`);
return this.request({ url, method: 'PUT' });
}
/**
* 删除团队仓库
*/
async removeTeamRepo(org: string, teamId: number, repo: string) {
const url = this.makeUrl(`/orgs/${org}/teams/${teamId}/repos/${repo}`);
return this.request({ url, method: 'DELETE' });
}
}

132
src/repo/index.ts Normal file
View File

@@ -0,0 +1,132 @@
import { GiteaCore } from "../core/core";
export interface CreateRepoOptions {
name: string;
description?: string;
private?: boolean;
auto_init?: boolean;
gitignores?: string;
license?: string;
readme?: string;
}
export interface UpdateRepoOptions {
name?: string;
description?: string;
private?: boolean;
allow_rebase?: boolean;
allow_rebase_explicit?: boolean;
allow_merge_commits?: boolean;
allow_squash_merge?: boolean;
allow_rebase_update?: boolean;
default_branch?: string;
}
export class GiteaRepo extends GiteaCore {
/**
* 获取仓库信息
*/
async getRepo(owner: string, repo: string) {
const url = this.makeUrl(`/repos/${owner}/${repo}`);
return this.request({ url });
}
/**
* 创建仓库
* 格式: name="repo" -> 当前用户
* 格式: name="org/repo" -> 组织
*/
async createRepo(data: CreateRepoOptions) {
const name = data.name;
const parts = name.split('/');
if (parts.length === 2) {
const [orgOrUser, repoName] = parts;
const url = this.makeUrl(`/${orgOrUser}/repos`);
return this.request({ url, method: 'POST', data: { ...data, name: repoName } });
}
const url = this.makeUrl(`/user/repos`);
return this.request({ url, method: 'POST', data });
}
/**
* 更新仓库
*/
async updateRepo(owner: string, repo: string, data: UpdateRepoOptions) {
const url = this.makeUrl(`/repos/${owner}/${repo}`);
return this.request({ url, method: 'PATCH', data });
}
/**
* 删除仓库
*/
async deleteRepo(owner: string, repo: string) {
const url = this.makeUrl(`/repos/${owner}/${repo}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 获取仓库列表
*/
async listRepos(options?: {
page?: number;
limit?: number;
type?: 'all' | 'owner' | 'public' | 'private';
}) {
const url = this.makeUrl(`/user/repos`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取组织仓库列表
*/
async listOrgRepos(org: string, options?: {
page?: number;
limit?: number;
type?: 'all' | 'fork' | 'source' | 'mirror';
}) {
const url = this.makeUrl(`/orgs/${org}/repos`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取仓库内容(文件或目录)
*/
async getContents(owner: string, repo: string, path: string, options?: {
ref?: string;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/contents/${path}`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取仓库分支列表
*/
async listBranches(owner: string, repo: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/branches`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取仓库标签列表
*/
async listTags(owner: string, repo: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/repos/${owner}/${repo}/tags`);
return this.request({ url, method: 'GET', params: options });
}
/**
* Fork 仓库
*/
async forkRepo(owner: string, repo: string, organization?: string) {
const url = this.makeUrl(`/repos/${owner}/${repo}/forks`);
return this.request({ url, method: 'POST', data: { organization } });
}
}

141
src/user/index.ts Normal file
View File

@@ -0,0 +1,141 @@
import { GiteaCore } from "../core/core";
export interface UpdateUserOptions {
email?: string;
full_name?: string;
location?: string;
website?: string;
description?: string;
visibility?: 'public' | 'limited' | 'private';
}
export class GiteaUser extends GiteaCore {
/**
* 获取当前用户信息
*/
async getCurrentUser() {
const url = this.makeUrl(`/user`);
return this.request({ url });
}
/**
* 获取指定用户信息
*/
async getUser(username: string) {
const url = this.makeUrl(`/users/${username}`);
return this.request({ url });
}
/**
* 更新当前用户信息
*/
async updateCurrentUser(data: UpdateUserOptions) {
const url = this.makeUrl(`/user`);
return this.request({ url, method: 'PATCH', data });
}
/**
* 获取当前用户邮箱列表
*/
async listEmails() {
const url = this.makeUrl(`/user/emails`);
return this.request({ url, method: 'GET' });
}
/**
* 添加邮箱
*/
async addEmail(email: string) {
const url = this.makeUrl(`/user/emails`);
return this.request({ url, method: 'POST', data: { email } });
}
/**
* 删除邮箱
*/
async deleteEmail(email: string) {
const url = this.makeUrl(`/user/emails`);
return this.request({ url, method: 'DELETE', data: { email } });
}
/**
* 获取当前用户关注者
*/
async listFollowers(username: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/users/${username}/followers`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取用户关注的用户列表
*/
async listFollowing(username: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/users/${username}/following`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 关注用户
*/
async followUser(username: string) {
const url = this.makeUrl(`/user/following/${username}`);
return this.request({ url, method: 'PUT' });
}
/**
* 取消关注用户
*/
async unfollowUser(username: string) {
const url = this.makeUrl(`/user/following/${username}`);
return this.request({ url, method: 'DELETE' });
}
/**
* 检查是否关注用户
*/
async checkFollowing(username: string, target: string) {
const url = this.makeUrl(`/users/${username}/following/${target}`);
return this.request({ url });
}
/**
* 获取用户仓库列表
*/
async listRepos(username: string, options?: {
page?: number;
limit?: number;
type?: 'all' | 'owner' | 'public' | 'private';
sort?: 'created' | 'updated' | 'pushed' | 'full_name';
}) {
const url = this.makeUrl(`/users/${username}/repos`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 获取用户活动流
*/
async listActivities(username: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/users/${username}/activities`);
return this.request({ url, method: 'GET', params: options });
}
/**
* 搜索用户
*/
async searchUsers(query: string, options?: {
page?: number;
limit?: number;
}) {
const url = this.makeUrl(`/users/search`);
return this.request({ url, method: 'GET', params: { q: query, ...options } });
}
}

13
test/common.ts Normal file
View File

@@ -0,0 +1,13 @@
import { GiteaRepo } from "../src/repo";
import { useKey } from "@kevisual/context";
const repo = new GiteaRepo({
token: useKey("GITEA_TOKEN"),
baseURL: useKey("GITEA_URL"),
});
const createRepo = async () => {
const res = await repo.createRepo({ name: "kevisual/test-repo", description: "This is a test repository", private: false });
console.log('createRepo', res);
};
createRepo();