feat: update worker to use Gitea API for deployments and remove GitHub references
This commit is contained in:
12
.env.example
12
.env.example
@@ -4,10 +4,12 @@
|
|||||||
REDIS_URL=redis://username:your_password@HOST:PORT
|
REDIS_URL=redis://username:your_password@HOST:PORT
|
||||||
|
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# GitHub Configuration
|
# Gitea Configuration
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
# Scopes required: 'repo' (to create repos and push code)
|
GITEA_API_URL=https://git.mworld.cloud/api/v1
|
||||||
GITHUB_TOKEN=ghp_xxxxxx
|
|
||||||
|
|
||||||
# The GitHub username associated with the token above
|
# Scopes required: 'repo' (to create repos and push code)
|
||||||
GITHUB_USERNAME=github_username
|
GITEA_TOKEN=github_username
|
||||||
|
|
||||||
|
# The Gitea username associated with the token above
|
||||||
|
GITEA_USERNAME=gitea_username
|
||||||
220
package-lock.json
generated
220
package-lock.json
generated
@@ -8,7 +8,6 @@
|
|||||||
"name": "worker-for-website-generator",
|
"name": "worker-for-website-generator",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/rest": "^21.0.0",
|
|
||||||
"bullmq": "^5.66.4",
|
"bullmq": "^5.66.4",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"ioredis": "^5.4.1"
|
"ioredis": "^5.4.1"
|
||||||
@@ -145,191 +144,6 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/auth-token": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/core": {
|
|
||||||
"version": "6.1.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.6.tgz",
|
|
||||||
"integrity": "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/auth-token": "^5.0.0",
|
|
||||||
"@octokit/graphql": "^8.2.2",
|
|
||||||
"@octokit/request": "^9.2.3",
|
|
||||||
"@octokit/request-error": "^6.1.8",
|
|
||||||
"@octokit/types": "^14.0.0",
|
|
||||||
"before-after-hook": "^3.0.2",
|
|
||||||
"universal-user-agent": "^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/endpoint": {
|
|
||||||
"version": "10.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz",
|
|
||||||
"integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^14.0.0",
|
|
||||||
"universal-user-agent": "^7.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/graphql": {
|
|
||||||
"version": "8.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.2.tgz",
|
|
||||||
"integrity": "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/request": "^9.2.3",
|
|
||||||
"@octokit/types": "^14.0.0",
|
|
||||||
"universal-user-agent": "^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/openapi-types": {
|
|
||||||
"version": "25.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz",
|
|
||||||
"integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-paginate-rest": {
|
|
||||||
"version": "11.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.6.0.tgz",
|
|
||||||
"integrity": "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^13.10.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@octokit/core": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
|
|
||||||
"version": "24.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
|
||||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
|
|
||||||
"version": "13.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
|
||||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/openapi-types": "^24.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-request-log": {
|
|
||||||
"version": "5.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz",
|
|
||||||
"integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@octokit/core": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
|
||||||
"version": "13.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.5.0.tgz",
|
|
||||||
"integrity": "sha512-9Pas60Iv9ejO3WlAX3maE1+38c5nqbJXV5GrncEfkndIpZrJ/WPMRd2xYDcPPEt5yzpxcjw9fWNoPhsSGzqKqw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^13.10.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@octokit/core": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
|
|
||||||
"version": "24.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
|
||||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
|
|
||||||
"version": "13.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
|
||||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/openapi-types": "^24.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/request": {
|
|
||||||
"version": "9.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.4.tgz",
|
|
||||||
"integrity": "sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/endpoint": "^10.1.4",
|
|
||||||
"@octokit/request-error": "^6.1.8",
|
|
||||||
"@octokit/types": "^14.0.0",
|
|
||||||
"fast-content-type-parse": "^2.0.0",
|
|
||||||
"universal-user-agent": "^7.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/request-error": {
|
|
||||||
"version": "6.1.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.8.tgz",
|
|
||||||
"integrity": "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/types": "^14.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/rest": {
|
|
||||||
"version": "21.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
|
||||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/core": "^6.1.4",
|
|
||||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
|
||||||
"@octokit/plugin-request-log": "^5.3.1",
|
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@octokit/types": {
|
|
||||||
"version": "14.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz",
|
|
||||||
"integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@octokit/openapi-types": "^25.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@tsconfig/node10": {
|
"node_modules/@tsconfig/node10": {
|
||||||
"version": "1.0.12",
|
"version": "1.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
||||||
@@ -423,12 +237,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/before-after-hook": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||||
@@ -629,22 +437,6 @@
|
|||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fast-content-type-parse": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/fastify"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/fastify"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
@@ -704,9 +496,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/ioredis": {
|
"node_modules/ioredis": {
|
||||||
"version": "5.9.0",
|
"version": "5.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.1.tgz",
|
||||||
"integrity": "sha512-T3VieIilNumOJCXI9SDgo4NnF6sZkd6XcmPi6qWtw4xqbt8nNz/ZVNiIH1L9puMTSHZh1mUWA4xKa2nWPF4NwQ==",
|
"integrity": "sha512-BXNqFQ66oOsR82g9ajFFsR8ZKrjVvYCLyeML9IvSMAsP56XH2VXBdZjmI11p65nXXJxTEt1hie3J2QeFJVgrtQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ioredis/commands": "1.5.0",
|
"@ioredis/commands": "1.5.0",
|
||||||
@@ -1111,12 +903,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/universal-user-agent": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "11.1.0",
|
"version": "11.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||||
|
|||||||
@@ -5,11 +5,10 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"start": "node dist/worker.js",
|
"start": "node --import=dotenv/config dist/worker.js",
|
||||||
"dev": "nodemon --exec ts-node worker.ts"
|
"dev": "nodemon --exec 'ts-node --require dotenv/config' worker.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/rest": "^21.0.0",
|
|
||||||
"bullmq": "^5.66.4",
|
"bullmq": "^5.66.4",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"ioredis": "^5.4.1"
|
"ioredis": "^5.4.1"
|
||||||
|
|||||||
165
worker.ts
165
worker.ts
@@ -1,11 +1,10 @@
|
|||||||
import { Octokit } from "@octokit/rest";
|
|
||||||
import { Job, Worker } from "bullmq";
|
import { Job, Worker } from "bullmq";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { redisConfig } from "./redis.js";
|
import { redisConfig } from "./redis.js";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
console.log("👷 Deploy Worker Started...");
|
console.log("👷 Gitea Deploy Worker Started...");
|
||||||
|
|
||||||
export interface DeployJobData {
|
export interface DeployJobData {
|
||||||
repoName: string;
|
repoName: string;
|
||||||
@@ -13,16 +12,42 @@ export interface DeployJobData {
|
|||||||
files: Record<string, string>;
|
files: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const GITEA_API_URL = process.env.GITEA_API_URL || "https://git.mworld.cloud/api/v1";
|
||||||
|
const GITEA_TOKEN = process.env.GITEA_TOKEN;
|
||||||
|
const GITEA_USERNAME = process.env.GITEA_USERNAME;
|
||||||
|
|
||||||
|
if (!GITEA_TOKEN || !GITEA_USERNAME) {
|
||||||
|
throw new Error("Missing GITEA_TOKEN or GITEA_USERNAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to call Gitea API
|
||||||
|
async function callGitea(method: string, path: string, body?: any) {
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
Authorization: `token ${GITEA_TOKEN}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(`${GITEA_API_URL}${path}`, {
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
body: body ? JSON.stringify(body) : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok && response.status !== 404) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`Gitea API Error ${response.status}: ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
const worker = new Worker<DeployJobData>(
|
const worker = new Worker<DeployJobData>(
|
||||||
"github-deployments",
|
"github-deployments",
|
||||||
async (job: Job) => {
|
async (job: Job) => {
|
||||||
const {
|
const { repoName, chatId, files } = job.data;
|
||||||
repoName,
|
|
||||||
chatId,
|
|
||||||
files,
|
|
||||||
} = job.data;
|
|
||||||
|
|
||||||
// 1. Sanitize Repo Name (e.g. "Hono Vite Health Check" -> "hono-vite-health-check")
|
// 1. Sanitize Repo Name
|
||||||
const sanitizedRepoName = repoName
|
const sanitizedRepoName = repoName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.trim()
|
.trim()
|
||||||
@@ -33,110 +58,70 @@ const worker = new Worker<DeployJobData>(
|
|||||||
`[Job ${job.id}] Processing deployment for ${sanitizedRepoName} (Chat: ${chatId})...`
|
`[Job ${job.id}] Processing deployment for ${sanitizedRepoName} (Chat: ${chatId})...`
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2. Auth
|
|
||||||
const token = process.env.GITHUB_TOKEN;
|
|
||||||
const username = process.env.GITHUB_USERNAME;
|
|
||||||
|
|
||||||
if (!token || !username) {
|
|
||||||
throw new Error("Missing GitHub Token or Username. Cannot deploy.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize GitHub Client
|
|
||||||
const octokit = new Octokit({ auth: token });
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await job.updateProgress(10);
|
await job.updateProgress(10);
|
||||||
|
|
||||||
// 3. Ensure Repo Exists or Create it
|
let repoDetails: any;
|
||||||
let latestCommitSha: string;
|
|
||||||
|
|
||||||
try {
|
const checkRepo = await callGitea("GET", `/repos/${GITEA_USERNAME}/${sanitizedRepoName}`);
|
||||||
// Check if repo exists
|
|
||||||
await octokit.repos.get({ owner: username, repo: sanitizedRepoName });
|
|
||||||
|
|
||||||
// If exists, get HEAD commit
|
if (checkRepo.status === 404) {
|
||||||
const ref = await octokit.git.getRef({
|
console.log(`[Job ${job.id}] Repo not found, creating new repo: ${sanitizedRepoName}`);
|
||||||
owner: username,
|
|
||||||
repo: sanitizedRepoName,
|
// Create Repo
|
||||||
ref: "heads/main",
|
const createRes = await callGitea("POST", "/user/repos", {
|
||||||
|
name: sanitizedRepoName,
|
||||||
|
private: true,
|
||||||
|
auto_init: true,
|
||||||
|
description: `Generated by MWorld for chat ${chatId}`,
|
||||||
});
|
});
|
||||||
latestCommitSha = ref.data.object.sha;
|
|
||||||
} catch (e: any) {
|
|
||||||
if (e.status === 404) {
|
|
||||||
console.log(
|
|
||||||
`[Job ${job.id}] Repo not found, creating new repo: ${sanitizedRepoName}`
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create Repo
|
if (!createRes.ok) throw new Error("Failed to create repository");
|
||||||
await octokit.repos.createForAuthenticatedUser({
|
|
||||||
name: sanitizedRepoName,
|
|
||||||
private: true, // Set to true if you want private repos
|
|
||||||
auto_init: true, // Creates an initial commit (README) so we have a HEAD
|
|
||||||
description: `Generated by MWorld for chat ${chatId}`,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Wait a brief moment for GitHub propagation
|
repoDetails = await createRes.json();
|
||||||
await new Promise((r) => setTimeout(r, 2000));
|
|
||||||
|
|
||||||
// Get the initial commit SHA
|
await new Promise((r) => setTimeout(r, 2000));
|
||||||
const ref = await octokit.git.getRef({
|
} else {
|
||||||
owner: username,
|
repoDetails = await checkRepo.json();
|
||||||
repo: sanitizedRepoName,
|
|
||||||
ref: "heads/main",
|
|
||||||
});
|
|
||||||
latestCommitSha = ref.data.object.sha;
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultBranch = repoDetails.default_branch || "main"; //
|
||||||
|
|
||||||
await job.updateProgress(30);
|
await job.updateProgress(30);
|
||||||
|
|
||||||
// 4. Create Tree (Blobs)
|
// 3. Prepare Batch File Operations
|
||||||
// The API expects an array of file objects.
|
const fileOperations = Object.entries(files).map(([path, content]) => ({
|
||||||
const treeData = Object.entries(files).map(([path, content]) => ({
|
operation: "upload",
|
||||||
path, // e.g., "src/main.jsx" or "package.json"
|
path: path,
|
||||||
mode: "100644" as const,
|
content: Buffer.from(content as string).toString("base64"),
|
||||||
type: "blob" as const,
|
|
||||||
content: content as string, // The actual string content from Redis
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Create a tree based on the latest commit
|
|
||||||
const { data: tree } = await octokit.git.createTree({
|
|
||||||
owner: username,
|
|
||||||
repo: sanitizedRepoName,
|
|
||||||
base_tree: latestCommitSha,
|
|
||||||
tree: treeData,
|
|
||||||
});
|
|
||||||
|
|
||||||
await job.updateProgress(60);
|
await job.updateProgress(60);
|
||||||
|
|
||||||
// 5. Create Commit
|
// 4. Commit and Push (Atomic Batch Operation)
|
||||||
const { data: commit } = await octokit.git.createCommit({
|
const commitRes = await callGitea(
|
||||||
owner: username,
|
"POST",
|
||||||
repo: sanitizedRepoName,
|
`/repos/${GITEA_USERNAME}/${sanitizedRepoName}/contents`,
|
||||||
message: `Deploy updates from MWorld ⚡️ (Chat ${chatId})`,
|
{
|
||||||
tree: tree.sha,
|
branch: defaultBranch,
|
||||||
parents: [latestCommitSha],
|
message: `Deploy updates from MWorld ⚡️ (Chat ${chatId})`,
|
||||||
});
|
files: fileOperations,
|
||||||
|
author: {
|
||||||
|
name: "MWorld Bot",
|
||||||
|
email: "bot@mworld.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await job.updateProgress(80);
|
if (!commitRes.ok) {
|
||||||
|
throw new Error(`Failed to commit files: ${await commitRes.text()}`);
|
||||||
// 6. Push (Update Reference)
|
}
|
||||||
await octokit.git.updateRef({
|
|
||||||
owner: username,
|
|
||||||
repo: sanitizedRepoName,
|
|
||||||
ref: "heads/main",
|
|
||||||
sha: commit.sha,
|
|
||||||
});
|
|
||||||
|
|
||||||
await job.updateProgress(100);
|
await job.updateProgress(100);
|
||||||
|
|
||||||
const repoUrl = `https://github.com/${username}/${sanitizedRepoName}`;
|
const repoUrl = `${GITEA_API_URL.replace("/api/v1", "")}/${GITEA_USERNAME}/${sanitizedRepoName}`;
|
||||||
console.log(`[Job ${job.id}] Deployment Complete! 🚀 URL: ${repoUrl}`);
|
console.log(`[Job ${job.id}] Deployment Complete! 🚀 URL: ${repoUrl}`);
|
||||||
|
|
||||||
// TODO: USE SUPABASE TO UPDATE THE REPO URL
|
|
||||||
|
|
||||||
return { success: true, url: repoUrl };
|
return { success: true, url: repoUrl };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`[Job ${job.id}] Failed:`, error.message);
|
console.error(`[Job ${job.id}] Failed:`, error.message);
|
||||||
@@ -148,7 +133,7 @@ const worker = new Worker<DeployJobData>(
|
|||||||
concurrency: 5,
|
concurrency: 5,
|
||||||
limiter: {
|
limiter: {
|
||||||
max: 10,
|
max: 10,
|
||||||
duration: 1000, // Rate limit protection for GitHub API
|
duration: 1000,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user