完善拉取私有仓库

This commit is contained in:
whyour 2022-05-18 01:14:10 +08:00
parent 1695b8c0fe
commit 7caabe9063
6 changed files with 96 additions and 34 deletions

View File

@ -28,17 +28,16 @@ export default (app: Router) => {
celebrate({ celebrate({
body: Joi.object({ body: Joi.object({
type: Joi.string().required(), type: Joi.string().required(),
schedule: Joi.string().optional(), schedule: Joi.string().optional().allow('').allow(null),
interval_schedule: Joi.object().optional(), interval_schedule: Joi.object().optional().allow('').allow(null),
name: Joi.string().optional(), name: Joi.string().optional().allow('').allow(null),
url: Joi.string().required(), url: Joi.string().required(),
whitelist: Joi.string().optional(), whitelist: Joi.string().optional().allow('').allow(null),
blacklist: Joi.string().optional(), blacklist: Joi.string().optional().allow('').allow(null),
branch: Joi.string().optional(), branch: Joi.string().optional().allow('').allow(null),
dependences: Joi.string().optional(), dependences: Joi.string().optional().allow('').allow(null),
status: Joi.number().optional(), pull_type: Joi.string().optional().allow('').allow(null),
pull_type: Joi.string().optional(), pull_option: Joi.object().optional().allow('').allow(null),
pull_option: Joi.object().optional(),
schedule_type: Joi.string().required(), schedule_type: Joi.string().required(),
alias: Joi.string().required(), alias: Joi.string().required(),
}), }),
@ -157,18 +156,17 @@ export default (app: Router) => {
celebrate({ celebrate({
body: Joi.object({ body: Joi.object({
type: Joi.string().required(), type: Joi.string().required(),
schedule: Joi.string().optional(), schedule: Joi.string().optional().allow('').allow(null),
interval_schedule: Joi.object().optional(), interval_schedule: Joi.object().optional().allow('').allow(null),
name: Joi.string().optional(), name: Joi.string().optional().allow('').allow(null),
url: Joi.string().required(), url: Joi.string().required(),
whitelist: Joi.string().optional(), whitelist: Joi.string().optional().allow('').allow(null),
blacklist: Joi.string().optional(), blacklist: Joi.string().optional().allow('').allow(null),
branch: Joi.string().optional(), branch: Joi.string().optional().allow('').allow(null),
dependences: Joi.string().optional(), dependences: Joi.string().optional().allow('').allow(null),
status: Joi.number().optional(), pull_type: Joi.string().optional().allow('').allow(null),
pull_type: Joi.string().optional(), pull_option: Joi.object().optional().allow('').allow(null),
pull_option: Joi.object().optional(), schedule_type: Joi.string().optional().allow('').allow(null),
schedule_type: Joi.string().optional(),
alias: Joi.string().required(), alias: Joi.string().required(),
id: Joi.number().required(), id: Joi.number().required(),
}), }),

View File

@ -13,6 +13,7 @@ import UserService from '../services/user';
import handler from 'serve-handler'; import handler from 'serve-handler';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import { EnvModel } from '../data/env'; import { EnvModel } from '../data/env';
import { errors } from 'celebrate';
export default ({ app }: { app: Application }) => { export default ({ app }: { app: Application }) => {
app.enable('trust proxy'); app.enable('trust proxy');
@ -134,6 +135,7 @@ export default ({ app }: { app: Application }) => {
next(err); next(err);
}); });
app.use(errors());
app.use(Sentry.Handlers.errorHandler()); app.use(Sentry.Handlers.errorHandler());
app.use( app.use(

View File

@ -1,5 +1,6 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import os from 'os';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import Logger from './logger'; import Logger from './logger';
import { fileExist } from '../config/util'; import { fileExist } from '../config/util';
@ -15,6 +16,8 @@ const confFile = path.join(configPath, 'config.sh');
const authConfigFile = path.join(configPath, 'auth.json'); const authConfigFile = path.join(configPath, 'auth.json');
const sampleConfigFile = path.join(samplePath, 'config.sample.sh'); const sampleConfigFile = path.join(samplePath, 'config.sample.sh');
const sampleAuthFile = path.join(samplePath, 'auth.sample.json'); const sampleAuthFile = path.join(samplePath, 'auth.sample.json');
const homedir = os.homedir();
const sshPath = path.resolve(homedir, '.ssh');
export default async () => { export default async () => {
const authFileExist = await fileExist(authConfigFile); const authFileExist = await fileExist(authConfigFile);
@ -23,6 +26,7 @@ export default async () => {
const logDirExist = await fileExist(logPath); const logDirExist = await fileExist(logPath);
const configDirExist = await fileExist(configPath); const configDirExist = await fileExist(configPath);
const uploadDirExist = await fileExist(uploadPath); const uploadDirExist = await fileExist(uploadPath);
const sshDirExist = await fileExist(sshPath);
if (!configDirExist) { if (!configDirExist) {
fs.mkdirSync(configPath); fs.mkdirSync(configPath);
@ -48,6 +52,10 @@ export default async () => {
fs.mkdirSync(uploadPath); fs.mkdirSync(uploadPath);
} }
if (!sshDirExist) {
fs.mkdirSync(sshPath);
}
dotenv.config({ path: confFile }); dotenv.config({ path: confFile });
Logger.info('✌️ Init file down'); Logger.info('✌️ Init file down');

View File

@ -27,6 +27,7 @@ import path from 'path';
import ScheduleService, { TaskCallbacks } from './schedule'; import ScheduleService, { TaskCallbacks } from './schedule';
import { SimpleIntervalSchedule } from 'toad-scheduler'; import { SimpleIntervalSchedule } from 'toad-scheduler';
import SockService from './sock'; import SockService from './sock';
import SshKeyService from './sshKey';
@Service() @Service()
export default class SubscriptionService { export default class SubscriptionService {
@ -34,6 +35,7 @@ export default class SubscriptionService {
@Inject('logger') private logger: winston.Logger, @Inject('logger') private logger: winston.Logger,
private scheduleService: ScheduleService, private scheduleService: ScheduleService,
private sockService: SockService, private sockService: SockService,
private sshKeyService: SshKeyService,
) {} ) {}
public async list(searchText?: string): Promise<Subscription[]> { public async list(searchText?: string): Promise<Subscription[]> {
@ -92,21 +94,44 @@ export default class SubscriptionService {
} }
} }
private formatCommand(doc: Subscription) { private formatCommand(doc: Subscription, url?: string) {
let command = 'ql '; let command = 'ql ';
const { type, url, whitelist, blacklist, dependences, branch } = doc; let _url = url || doc.url;
const { type, whitelist, blacklist, dependences, branch } = doc;
if (type === 'file') { if (type === 'file') {
command += `raw "${url}"`; command += `raw "${_url}"`;
} else { } else {
command += `repo "${url}" "${whitelist || ''}" "${blacklist || ''}" "${ command += `repo "${_url}" "${whitelist || ''}" "${blacklist || ''}" "${
dependences || '' dependences || ''
}" "${branch || ''}"`; }" "${branch || ''}"`;
} }
return command; return command;
} }
private handleTask(doc: Subscription, needCreate = true) { private handleTask(doc: Subscription, needCreate = true, needAddKey = true) {
doc.command = this.formatCommand(doc); let url = doc.url;
if (doc.type === 'private-repo') {
if (doc.pull_type === 'ssh-key') {
const host = doc.url!.replace(/.*\@([^\:]+)\:.*/, '$1');
url = doc.url!.replace(host, doc.alias);
if (needAddKey) {
this.sshKeyService.addSSHKey(
(doc.pull_option as any).private_key,
doc.alias,
host,
);
} else {
this.sshKeyService.removeSSHKey(doc.alias, host);
}
} else {
const host = doc.url!.replace(/.*\:\/\/([^\/]+)\/.*/, '$1');
const { username, password } = doc.pull_option as any;
url = doc.url!.replace(host, `${username}:${password}@${host}`);
}
}
doc.command = this.formatCommand(doc, url as string);
if (doc.schedule_type === 'crontab') { if (doc.schedule_type === 'crontab') {
this.scheduleService.cancelCronTask(doc as any); this.scheduleService.cancelCronTask(doc as any);
needCreate && needCreate &&
@ -191,7 +216,6 @@ export default class SubscriptionService {
public async create(payload: Subscription): Promise<Subscription> { public async create(payload: Subscription): Promise<Subscription> {
const tab = new Subscription(payload); const tab = new Subscription(payload);
console.log(tab);
const doc = await this.insert(tab); const doc = await this.insert(tab);
this.handleTask(doc); this.handleTask(doc);
return doc; return doc;
@ -246,7 +270,7 @@ export default class SubscriptionService {
public async remove(ids: number[]) { public async remove(ids: number[]) {
const docs = await SubscriptionModel.findAll({ where: { id: ids } }); const docs = await SubscriptionModel.findAll({ where: { id: ids } });
for (const doc of docs) { for (const doc of docs) {
this.handleTask(doc, false); this.handleTask(doc, false, false);
} }
await SubscriptionModel.destroy({ where: { id: ids } }); await SubscriptionModel.destroy({ where: { id: ids } });
} }

View File

@ -51,6 +51,12 @@ export enum IntervalSchedule {
'seconds' = '秒', 'seconds' = '秒',
} }
export enum SubscriptionType {
'private-repo' = '私有仓库',
'public-repo' = '公开仓库',
'file' = '单文件',
}
const Subscription = ({ headerStyle, isPhone, socketMessage }: any) => { const Subscription = ({ headerStyle, isPhone, socketMessage }: any) => {
const columns: any = [ const columns: any = [
{ {
@ -88,6 +94,16 @@ const Subscription = ({ headerStyle, isPhone, socketMessage }: any) => {
); );
}, },
}, },
{
title: '类型',
dataIndex: 'type',
key: 'type',
width: 130,
align: 'center' as const,
render: (text: string, record: any) => {
return (SubscriptionType as any)[record.type];
},
},
{ {
title: '分支', title: '分支',
dataIndex: 'branch', dataIndex: 'branch',

View File

@ -56,7 +56,9 @@ const SubscriptionModal = ({
form.setFieldsValue({ form.setFieldsValue({
alias: formatAlias(_url, _branch, e.target.value), alias: formatAlias(_url, _branch, e.target.value),
}); });
form.validateFields(['url']); if (_url) {
form.validateFields(['url']);
}
}; };
const scheduleTypeChange = (e) => { const scheduleTypeChange = (e) => {
@ -149,16 +151,28 @@ const SubscriptionModal = ({
onChange?: (param: any) => void; onChange?: (param: any) => void;
}) => { }) => {
return type === 'ssh-key' ? ( return type === 'ssh-key' ? (
<Form.Item name="private_key" label="私钥" rules={[{ required: true }]}> <Form.Item
<Input.TextArea rows={4} autoSize={true} placeholder="请输入私钥" /> name={['pull_option', 'private_key']}
label="私钥"
rules={[{ required: true }]}
>
<Input.TextArea
rows={4}
autoSize={{ minRows: 1, maxRows: 6 }}
placeholder="请输入私钥"
/>
</Form.Item> </Form.Item>
) : ( ) : (
<> <>
<Form.Item name="username" label="用户名" rules={[{ required: true }]}> <Form.Item
name={['pull_option', 'username']}
label="用户名"
rules={[{ required: true }]}
>
<Input placeholder="请输入认证用户名" /> <Input placeholder="请输入认证用户名" />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="password" name={['pull_option', 'password']}
tooltip="Github已不支持密码认证请使用Token方式" tooltip="Github已不支持密码认证请使用Token方式"
label="密码/Token" label="密码/Token"
rules={[{ required: true }]} rules={[{ required: true }]}