Compare commits
11 Commits
819cbcebac
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c222a007c1 | ||
|
|
c5a8d22249 | ||
|
|
88a688d5e3 | ||
|
|
2b7b541cb6 | ||
|
|
998783ea4e | ||
|
|
62b70712aa | ||
|
|
aed05790ea | ||
|
|
5bf3a7a063 | ||
|
|
28a5f9a7f1 | ||
|
|
cbdaeffd16 | ||
|
|
83ac00588e |
21
.cnb.yml
21
.cnb.yml
@@ -0,0 +1,21 @@
|
||||
.crontab-job: &crontab-job
|
||||
- docker:
|
||||
image: docker.cnb.cool/kevisual/dev-env/ubuntu-bun:latest
|
||||
runner:
|
||||
cpus: 2
|
||||
imports:
|
||||
- https://cnb.cool/kevisual/env/-/blob/main/.env
|
||||
- https://cnb.cool/kevisual/env/-/blob/main/ssh.yml
|
||||
- https://cnb.cool/kevisual/env/-/blob/main/ssh-config.yml
|
||||
stages:
|
||||
- name: 检测版本更新
|
||||
script: |
|
||||
bun i
|
||||
bun run src/cli.ts repo sync
|
||||
timeout: 20s
|
||||
|
||||
main:
|
||||
"crontab: 0 11,23 * * *": !reference [.crontab-job]
|
||||
|
||||
$:
|
||||
push: !reference [.crontab-job]
|
||||
87
bun.lock
Normal file
87
bun.lock
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "to-my-gitea",
|
||||
"dependencies": {
|
||||
"@kevisual/cnb": "^0.0.56",
|
||||
"@kevisual/context": "^0.0.8",
|
||||
"@kevisual/gitea": "^0.0.6",
|
||||
"@kevisual/router": "^0.1.6",
|
||||
"dayjs": "^1.11.20",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@kevisual/cnb": ["@kevisual/cnb@0.0.56", "https://registry.npmmirror.com/@kevisual/cnb/-/cnb-0.0.56.tgz", { "dependencies": { "@kevisual/query": "^0.0.53", "@kevisual/router": "^0.1.3", "@kevisual/use-config": "^1.0.30", "@opencode-ai/sdk": "^1.2.27", "es-toolkit": "^1.45.1", "nanoid": "^5.1.7", "unstorage": "^1.17.4", "ws": "npm:@kevisual/ws" }, "bin": { "cnb": "bin/index.js", "cloud": "bin/index.js", "cloud-npc": "bin/npc.js" } }, "sha512-Pa70TI/zVC7DOSecrRztB8QrRlf+iuFCGDH/O3YEQw/eMoyDdBtIxR3Ewnsu+n+BN0od6jcsSOhDW6kzqeX8cA=="],
|
||||
|
||||
"@kevisual/context": ["@kevisual/context@0.0.8", "https://registry.npmmirror.com/@kevisual/context/-/context-0.0.8.tgz", {}, "sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA=="],
|
||||
|
||||
"@kevisual/gitea": ["@kevisual/gitea@0.0.6", "https://registry.npmmirror.com/@kevisual/gitea/-/gitea-0.0.6.tgz", {}, "sha512-/qJha6IQ5VO+8WOGkLIMROmP0CvAaID0rPPyd5gtzl6yATqQLJS13Fm6Lfp5U5ImjTNmsq08khZqrj93Mz60cw=="],
|
||||
|
||||
"@kevisual/load": ["@kevisual/load@0.0.6", "https://registry.npmmirror.com/@kevisual/load/-/load-0.0.6.tgz", { "dependencies": { "eventemitter3": "^5.0.1" } }, "sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA=="],
|
||||
|
||||
"@kevisual/query": ["@kevisual/query@0.0.53", "https://registry.npmmirror.com/@kevisual/query/-/query-0.0.53.tgz", {}, "sha512-PAhpCLBr0emz0lGNlTVHMbJiC5wrtGLbInPddRzgKE35fiyNt+SWSsUWABiD0DeNrLN/OxWyAFobt880Z/e5MQ=="],
|
||||
|
||||
"@kevisual/router": ["@kevisual/router@0.1.6", "https://registry.npmmirror.com/@kevisual/router/-/router-0.1.6.tgz", { "dependencies": { "crypto-js": "^4.2.0", "es-toolkit": "^1.45.1", "zod": "^4.3.6" } }, "sha512-uQYxDd4j0ZKuuPXduSMSvckjEKi99hVRp7vz5AUFVDVbEBmNQBgDGbwmz9+X/DR/Gjx++x3m8XvYcAwuEzPOKw=="],
|
||||
|
||||
"@kevisual/use-config": ["@kevisual/use-config@1.0.30", "https://registry.npmmirror.com/@kevisual/use-config/-/use-config-1.0.30.tgz", { "dependencies": { "@kevisual/load": "^0.0.6" }, "peerDependencies": { "dotenv": "^17" } }, "sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw=="],
|
||||
|
||||
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.27", "https://registry.npmmirror.com/@opencode-ai/sdk/-/sdk-1.2.27.tgz", {}, "sha512-Wk0o/I+Fo+wE3zgvlJDs8Fb67KlKqX0PrV8dK5adSDkANq6r4Z25zXJg2iOir+a8ntg3rAcpel1OY4FV/TwRUA=="],
|
||||
|
||||
"anymatch": ["anymatch@3.1.3", "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||
|
||||
"chokidar": ["chokidar@5.0.0", "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
||||
|
||||
"cookie-es": ["cookie-es@1.2.2", "https://registry.npmmirror.com/cookie-es/-/cookie-es-1.2.2.tgz", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
|
||||
|
||||
"crossws": ["crossws@0.3.5", "https://registry.npmmirror.com/crossws/-/crossws-0.3.5.tgz", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
|
||||
|
||||
"crypto-js": ["crypto-js@4.2.0", "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="],
|
||||
|
||||
"dayjs": ["dayjs@1.11.20", "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="],
|
||||
|
||||
"defu": ["defu@6.1.4", "https://registry.npmmirror.com/defu/-/defu-6.1.4.tgz", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
|
||||
|
||||
"destr": ["destr@2.0.5", "https://registry.npmmirror.com/destr/-/destr-2.0.5.tgz", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
|
||||
|
||||
"dotenv": ["dotenv@17.3.1", "https://registry.npmmirror.com/dotenv/-/dotenv-17.3.1.tgz", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
|
||||
|
||||
"es-toolkit": ["es-toolkit@1.45.1", "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.45.1.tgz", {}, "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.4", "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
|
||||
|
||||
"h3": ["h3@1.15.8", "https://registry.npmmirror.com/h3/-/h3-1.15.8.tgz", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-iOH6Vl8mGd9nNfu9C0IZ+GuOAfJHcyf3VriQxWaSWIB76Fg4BnFuk4cxBxjmQSSxJS664+pgjP6e7VBnUzFfcg=="],
|
||||
|
||||
"iron-webcrypto": ["iron-webcrypto@1.2.1", "https://registry.npmmirror.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
|
||||
|
||||
"lru-cache": ["lru-cache@11.2.7", "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.2.7.tgz", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="],
|
||||
|
||||
"nanoid": ["nanoid@5.1.7", "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.7.tgz", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ=="],
|
||||
|
||||
"node-fetch-native": ["node-fetch-native@1.6.7", "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.6.7.tgz", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||
|
||||
"node-mock-http": ["node-mock-http@1.0.4", "https://registry.npmmirror.com/node-mock-http/-/node-mock-http-1.0.4.tgz", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
||||
"ofetch": ["ofetch@1.5.1", "https://registry.npmmirror.com/ofetch/-/ofetch-1.5.1.tgz", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"radix3": ["radix3@1.1.2", "https://registry.npmmirror.com/radix3/-/radix3-1.1.2.tgz", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
|
||||
|
||||
"readdirp": ["readdirp@5.0.0", "https://registry.npmmirror.com/readdirp/-/readdirp-5.0.0.tgz", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
|
||||
|
||||
"ufo": ["ufo@1.6.3", "https://registry.npmmirror.com/ufo/-/ufo-1.6.3.tgz", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
|
||||
|
||||
"uncrypto": ["uncrypto@0.1.3", "https://registry.npmmirror.com/uncrypto/-/uncrypto-0.1.3.tgz", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
||||
|
||||
"unstorage": ["unstorage@1.17.4", "https://registry.npmmirror.com/unstorage/-/unstorage-1.17.4.tgz", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="],
|
||||
|
||||
"ws": ["@kevisual/ws@8.19.0", "https://registry.npmmirror.com/@kevisual/ws/-/ws-8.19.0.tgz", {}, "sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw=="],
|
||||
|
||||
"zod": ["zod@4.3.6", "https://registry.npmmirror.com/zod/-/zod-4.3.6.tgz", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
}
|
||||
}
|
||||
0
compose.yml
Normal file
0
compose.yml
Normal file
@@ -4,7 +4,7 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"cli": "bun run src/cli.ts "
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||
@@ -12,10 +12,10 @@
|
||||
"packageManager": "pnpm@10.32.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@kevisual/cnb": "^0.0.51",
|
||||
"@kevisual/cnb": "^0.0.56",
|
||||
"@kevisual/context": "^0.0.8",
|
||||
"@kevisual/gitea": "^0.0.6",
|
||||
"@kevisual/router": "^0.1.3",
|
||||
"@kevisual/router": "^0.1.6",
|
||||
"dayjs": "^1.11.20"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { App } from "@kevisual/router";
|
||||
import { useContextKey } from "@kevisual/context";
|
||||
import { useContextKey, useKey } from "@kevisual/context";
|
||||
import { CNB } from "@kevisual/cnb";
|
||||
import { Gitea } from '@kevisual/gitea';
|
||||
import path from "node:path";
|
||||
@@ -9,15 +9,15 @@ export const app = useContextKey("app", () => {
|
||||
});
|
||||
return app;
|
||||
});
|
||||
export const token = useKey("CNB_API_KEY") || useKey('CNB_TOKEN')
|
||||
|
||||
export const cnb = useContextKey("cnb", () => {
|
||||
const token = useContextKey("CNB_API_KEY") || useContextKey('CNB_TOKEN')
|
||||
return new CNB({ token });
|
||||
});
|
||||
|
||||
export const gitea = useContextKey('gitea', () => {
|
||||
const GITEA_TOKEN = useContextKey("GITEA_TOKEN")
|
||||
const GITEA_URL = useContextKey("GITEA_URL")
|
||||
const GITEA_TOKEN = useKey("GITEA_TOKEN")
|
||||
const GITEA_URL = useKey("GITEA_URL")
|
||||
return new Gitea({
|
||||
token: GITEA_TOKEN,
|
||||
baseURL: GITEA_URL,
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
export * from './app.ts';
|
||||
import './routes/cnb.ts';
|
||||
import { app } from './app.ts';
|
||||
import './routes/cnb.ts';
|
||||
import './routes/sync.ts';
|
||||
|
||||
app.createAuth((ctx) => { });
|
||||
app.createRouteList()
|
||||
@@ -1,18 +1,111 @@
|
||||
import { useRepoInfoEnv } from '@kevisual/cnb';
|
||||
import { app, cnb } from '../app';
|
||||
import dayjs from 'dayjs';
|
||||
import { z } from 'zod';
|
||||
|
||||
const repoSchema = z.object({
|
||||
path: z.string().describe('仓库路径'),
|
||||
name: z.string().describe('仓库名称'),
|
||||
web_url: z.string().describe('仓库链接'),
|
||||
description: z.string().describe('仓库描述'),
|
||||
topics: z.array(z.string()).describe('仓库标签'),
|
||||
giteaUrl: z.string().optional().describe('gitea仓库链接'),
|
||||
updatedAt: z.string().describe('仓库更新时间'),
|
||||
}).describe('仓库信息');
|
||||
export type Repo = z.infer<typeof repoSchema>;
|
||||
|
||||
app.route({
|
||||
path: 'cnb',
|
||||
key: 'list-today',
|
||||
description: '获取今日更新的仓库列表',
|
||||
middleware: ['auth']
|
||||
}).define(async (ctx) => {
|
||||
const res = await cnb.repo.getRepoList({ page_size: 100 });
|
||||
const today = dayjs().format('YYYY-MM-DD');
|
||||
const res = await cnb.repo.getRepoList({ status: 'active', page_size: 100 });
|
||||
const list = res.data || [];
|
||||
const twelveHoursAgo = dayjs().subtract(12, 'hour');
|
||||
const todayList = list.filter(item => {
|
||||
const updatedAt = dayjs(item.updated_at).format('YYYY-MM-DD');
|
||||
return updatedAt === today;
|
||||
const updatedAt = dayjs(item.updated_at);
|
||||
return updatedAt.isAfter(twelveHoursAgo);
|
||||
});
|
||||
ctx.body = {
|
||||
list: todayList,
|
||||
const _todayList = todayList.map(item => ({
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
web_url: item.web_url,
|
||||
description: item.description,
|
||||
topics: item.topics ? item.topics.split(',').filter(Boolean) : [],
|
||||
updatedAt: dayjs(item.updated_at).format('YYYY-MM-DD HH:mm:ss'),
|
||||
}))
|
||||
const repositories = _todayList.filter(item => item.topics.includes('gitea'));
|
||||
if (_todayList.length > 5) {
|
||||
app.run({ path: 'cnb', key: 'report', payload: { repoList: _todayList } });
|
||||
}
|
||||
}).addTo(app)
|
||||
ctx.body = {
|
||||
list: repositories
|
||||
}
|
||||
}).addTo(app)
|
||||
|
||||
app.route({
|
||||
path: 'cnb',
|
||||
key: 'report',
|
||||
description: '上报仓库信息',
|
||||
middleware: ['auth'],
|
||||
metadata: {
|
||||
args: {
|
||||
repoList: z.array(repoSchema).describe('仓库列表')
|
||||
}
|
||||
}
|
||||
}).define(async (ctx) => {
|
||||
const { repoList } = ctx.args;
|
||||
// 处理上报的仓库信息
|
||||
await closeOldReports();
|
||||
if (Array.isArray(repoList)) {
|
||||
let infoTable = '| 仓库路径 | 仓库链接 | 仓库描述 | 仓库标签 | 更新时间 |\n';
|
||||
infoTable += '| --- | --- | --- | --- | --- |\n';
|
||||
repoList.forEach(repo => {
|
||||
const topics = repo.topics.join(', ');
|
||||
infoTable += `| ${repo.path} | [链接](${repo.web_url}) | ${repo.description} | ${topics} | ${repo.updatedAt} |\n`;
|
||||
});
|
||||
console.log('上报的仓库信息表格:\n', infoTable);
|
||||
const repoInfo = useRepoInfoEnv();
|
||||
let afterInfo = '来源:CNB,';
|
||||
if (repoInfo) {
|
||||
afterInfo += `构建仓库:[${repoInfo.repoSlug}](${repoInfo.repoUrlHttps})`;
|
||||
}
|
||||
cnb.issue.createIssue('kevisual/kevisual', {
|
||||
title: `仓库信息上报 - ${dayjs().format('YYYY-MM-DD HH:mm:ss')}`,
|
||||
body: `以下是上报的仓库信息:\n\n${infoTable}\n\n${afterInfo}`,
|
||||
// @ts-ignore
|
||||
labels: ['report']
|
||||
})
|
||||
}
|
||||
}).addTo(app)
|
||||
app.route({
|
||||
path: 'cnb',
|
||||
key: 'close-old-reports',
|
||||
middleware: ['auth'],
|
||||
description: '关闭过期的报告',
|
||||
}).define(async (ctx) => {
|
||||
await closeOldReports();
|
||||
}).addTo(app)
|
||||
export const closeOldReports = async () => {
|
||||
const res = await cnb.issue.getList('kevisual/kevisual', {
|
||||
state: 'open',
|
||||
// @ts-ignore
|
||||
labels: ['report']
|
||||
});
|
||||
const issues = res.data || [];
|
||||
const oneDayAgo = dayjs().subtract(1, 'day');
|
||||
let closedCount = 0;
|
||||
for (const issue of issues) {
|
||||
const updatedAt = dayjs(issue.updated_at);
|
||||
if (updatedAt.isBefore(oneDayAgo)) {
|
||||
const res = await cnb.issue.updateIssue('kevisual/kevisual', issue.number, { state: 'closed', state_reason: 'completed' });
|
||||
if (res.code !== 200) {
|
||||
console.error(`关闭 issue ${issue.number} 失败`, res);
|
||||
} else {
|
||||
closedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`已处理 ${issues.length} 个报告,关闭了 ${closedCount} 个过期报告`);
|
||||
}
|
||||
79
src/routes/sync.ts
Normal file
79
src/routes/sync.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { app, gitea, rootPath, token } from '../app'
|
||||
import { Repo } from './cnb';
|
||||
import { execSync } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
import fs from 'fs';
|
||||
import { useKey } from '@kevisual/context';
|
||||
|
||||
app.route({
|
||||
path: 'repo',
|
||||
key: 'sync',
|
||||
middleware: ['auth'],
|
||||
description: '同步仓库数据',
|
||||
}).define(async (ctx) => {
|
||||
const res = await app.run({ path: 'cnb', key: 'list-today' });
|
||||
if (res.code === 200) {
|
||||
const list: Repo[] = res.data.list || [];
|
||||
let syncList: Repo[] = [];
|
||||
for (const item of list) {
|
||||
try {
|
||||
const [owner, repo] = item.path.split('/');
|
||||
const giteaRepo = await gitea.repo.getRepo(owner, repo);
|
||||
const giteaUsername = 'oauth2';
|
||||
const giteaPassword = useKey('GITEA_TOKEN');
|
||||
const giteaHost = useKey('GITEA_HOST') || 'git.xiongxiao.me';
|
||||
item.giteaUrl = `https://${giteaUsername}:${giteaPassword}@${giteaHost}/${owner}/${repo}.git`;
|
||||
if (giteaRepo.code === 200) {
|
||||
// 已经存在了
|
||||
} else {
|
||||
await gitea.repo.createRepo({
|
||||
name: owner + '/' + repo,
|
||||
description: item.description,
|
||||
});
|
||||
}
|
||||
syncList.push(item);
|
||||
} catch (err) {
|
||||
console.error(`处理 ${item.path} 失败`, item);
|
||||
}
|
||||
}
|
||||
// 开始同步
|
||||
for (const repo of syncList) {
|
||||
try {
|
||||
await sync(repo);
|
||||
} catch (err) {
|
||||
console.error(`同步 ${repo.path} 失败`, repo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).addTo(app)
|
||||
|
||||
const sync = async (repo: Repo) => {
|
||||
const cwd = path.join(rootPath, repo.name);
|
||||
if (!fs.existsSync(cwd)) {
|
||||
const webUrl = repo.web_url;
|
||||
let cloneUrl: string;
|
||||
if (webUrl.startsWith('http://')) {
|
||||
cloneUrl = webUrl.replace('http://', `http://cnb:${token}@`);
|
||||
} else if (webUrl.startsWith('https://')) {
|
||||
cloneUrl = webUrl.replace('https://', `https://cnb:${token}@`);
|
||||
} else {
|
||||
cloneUrl = webUrl;
|
||||
}
|
||||
execSync(`git clone ${cloneUrl} ${cwd}`);
|
||||
}
|
||||
// 添加一个remote 叫做gitea的远程仓库,指向gitea的地址
|
||||
const remoteUrl = repo.giteaUrl!;
|
||||
try {
|
||||
execSync(`git remote add gitea ${remoteUrl}`, { cwd });
|
||||
} catch (err) {
|
||||
// 已经添加过了
|
||||
}
|
||||
try {
|
||||
// 拉取最新的代码
|
||||
execSync(`git pull origin main`, { cwd });
|
||||
// 推送到gitea
|
||||
execSync(`git push gitea main`, { cwd });
|
||||
} catch (err) {
|
||||
console.error(`同步推送 ${repo.path} 失败`, repo);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user