mirror of https://github.com/certd/certd
perf: 支持github 新版本检查并发布通知
parent
1cae709b2b
commit
356703c83e
|
@ -13,13 +13,14 @@ import ExpiresTimeText from "./expires-time-text.vue";
|
|||
import FileInput from "./file-input.vue";
|
||||
import PemInput from "./pem-input.vue";
|
||||
import { defineAsyncComponent } from "vue";
|
||||
import NotificationSelector from "../views/certd/notification/notification-selector/index.vue";
|
||||
export default {
|
||||
install(app: any) {
|
||||
app.component(
|
||||
"CodeEditor",
|
||||
defineAsyncComponent(() => import("./code-editor/index.vue"))
|
||||
);
|
||||
|
||||
app.component("NotificationSelector", NotificationSelector);
|
||||
app.component("PiContainer", PiContainer);
|
||||
app.component("TextEditable", TextEditable);
|
||||
app.component("FileInput", FileInput);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="notification-selector">
|
||||
<div class="flex-o w-100">
|
||||
<fs-dict-select class="flex-1" :value="modelValue" :dict="optionsDictRef" :disabled="disabled" :render-label="renderLabel" :slots="selectSlots" :allow-clear="true" @update:value="onChange" />
|
||||
<fs-dict-select class="flex-1" :value="modelValue" :dict="optionsDictRef" :disabled="disabled" :render-label="renderLabel" :slots="selectSlots" :allow-clear="true" v-bind="select" @update:value="onChange" />
|
||||
<fs-table-select
|
||||
ref="tableSelectRef"
|
||||
class="flex-0"
|
||||
|
@ -21,6 +21,7 @@
|
|||
:dialog="{ width: 960 }"
|
||||
:destroy-on-close="false"
|
||||
height="400px"
|
||||
v-bind="tableSelect"
|
||||
@update:model-value="onChange"
|
||||
@dialog-closed="doRefresh"
|
||||
>
|
||||
|
@ -39,17 +40,20 @@ import { message } from "ant-design-vue";
|
|||
import { dict } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "../crud";
|
||||
import { notificationProvide } from "/@/views/certd/notification/common";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
|
||||
defineOptions({
|
||||
name: "NotificationSelector",
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: number | string;
|
||||
modelValue?: number | string | number[] | string[];
|
||||
type?: string;
|
||||
placeholder?: string;
|
||||
size?: string;
|
||||
disabled?: boolean;
|
||||
select?: any;
|
||||
tableSelect?: any;
|
||||
}>();
|
||||
|
||||
const onChange = async (value: number) => {
|
||||
|
@ -118,9 +122,12 @@ function clear() {
|
|||
emitValue(null);
|
||||
}
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
async function emitValue(value: any) {
|
||||
target.value = optionsDictRef.dataMap[value];
|
||||
if (value !== 0 && pipeline?.value && target && pipeline.value.userId !== target.value.userId) {
|
||||
// target.value = optionsDictRef.dataMap[value];
|
||||
const userId = userStore.userInfo.id;
|
||||
if (pipeline?.value && pipeline.value.userId !== userId) {
|
||||
message.error("对不起,您不能修改他人流水线的通知");
|
||||
return;
|
||||
}
|
||||
|
@ -134,6 +141,7 @@ watch(
|
|||
},
|
||||
async value => {
|
||||
await optionsDictRef.loadDict();
|
||||
//@ts-ignore
|
||||
target.value = optionsDictRef.dataMap[value];
|
||||
emit("selectedChange", target.value);
|
||||
},
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline";
|
||||
import { HttpRequestConfig } from "@certd/basic";
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@IsAccess({
|
||||
name: "github",
|
||||
title: "Github授权",
|
||||
desc: "",
|
||||
icon: "ion:logo-github"
|
||||
})
|
||||
export class GithubAccess extends BaseAccess {
|
||||
|
||||
@AccessInput({
|
||||
title: "接口地址",
|
||||
component: {
|
||||
placeholder: "可以使用反向代理地址",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
helper:"默认值:https://api.github.com",
|
||||
encrypt: false,
|
||||
required: false
|
||||
})
|
||||
endpoint!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "GithubToken",
|
||||
component: {
|
||||
placeholder: "GithubToken",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
helper:"支持匿名访问的接口可以不填",
|
||||
encrypt: true,
|
||||
required: false
|
||||
})
|
||||
githubToken!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "HttpProxy",
|
||||
component: {
|
||||
placeholder: "http://192.168.x.x:10811",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
encrypt: false,
|
||||
required: false
|
||||
})
|
||||
httpProxy!: string;
|
||||
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
helper: "点击测试接口是否正常"
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
await this.getRelease({repoName:"certd/certd"})
|
||||
return "ok"
|
||||
}
|
||||
|
||||
async getRelease(req:{repoName:string}){
|
||||
const url = `/repos/${req.repoName}/releases/latest`;
|
||||
return await this.doRequest({
|
||||
url,
|
||||
method: "GET",
|
||||
data:{}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async doRequest(req:HttpRequestConfig){
|
||||
/**
|
||||
* async function getLatestRelease() {
|
||||
* const { REPO_OWNER, REPO_NAME, API_URL, TOKEN } = CONFIG.GITHUB;
|
||||
* const url = `${API_URL}/${REPO_OWNER}/${REPO_NAME}/releases/latest`;
|
||||
*
|
||||
* try {
|
||||
* const response = await axios.get(url, {
|
||||
* headers: TOKEN ? { Authorization: `token ${TOKEN}` } : {}
|
||||
* });
|
||||
*
|
||||
* return {
|
||||
* tag_name: response.data.tag_name,
|
||||
* name: response.data.name || '无标题',
|
||||
* body: response.data.body || '无描述内容',
|
||||
* html_url: response.data.html_url,
|
||||
* published_at: new Date(response.data.published_at).toLocaleString(),
|
||||
* assets: response.data.assets.map(a => ({
|
||||
* name: a.name,
|
||||
* download_url: a.browser_download_url
|
||||
* }))
|
||||
* };
|
||||
* } catch (error) {
|
||||
* if (error.response?.status === 404) {
|
||||
* return { success: false, error: '仓库未找到或没有Release' };
|
||||
* }
|
||||
* return { success: false, error: `请求失败: ${error.message}` };
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
const headers:any = {}
|
||||
if(this.githubToken){
|
||||
headers.Authorization = `token ${this.githubToken}`
|
||||
}
|
||||
const baseURL= this.endpoint || "https://api.github.com";
|
||||
const res = await this.ctx.http.request({
|
||||
url: req.url,
|
||||
baseURL,
|
||||
method: req.method || "POST",
|
||||
data: req.data,
|
||||
headers,
|
||||
httpProxy: this.httpProxy||undefined,
|
||||
});
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
throw new Error(res.message || res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
new GithubAccess();
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./plugins/index.js";
|
||||
export * from "./access.js";
|
|
@ -0,0 +1 @@
|
|||
export * from "./plugin-check-release.js";
|
|
@ -0,0 +1,99 @@
|
|||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { GithubAccess } from "../access.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名
|
||||
name: "GithubCheckRelease",
|
||||
title: "Github-检查Release版本",
|
||||
desc:"检查最新Release版本并推送消息",
|
||||
icon: "ion:logo-github",
|
||||
//插件分组
|
||||
group: pluginGroups.other.key,
|
||||
needPlus: false,
|
||||
default: {
|
||||
//默认值配置照抄即可
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.AlwaysRun
|
||||
}
|
||||
}
|
||||
})
|
||||
//类名规范,跟上面插件名称(name)一致
|
||||
export class GithubCheckRelease extends AbstractTaskPlugin {
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "Github授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "github" //固定授权类型
|
||||
},
|
||||
required: true //必填
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
|
||||
@TaskInput({
|
||||
title: "仓库名称",
|
||||
helper:"owner/name,比如 certd/certd",
|
||||
required:true,
|
||||
})
|
||||
repoName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "通知渠道",
|
||||
component:{
|
||||
name:"notification-selector",
|
||||
select:{
|
||||
mode:"tags"
|
||||
}
|
||||
},
|
||||
required:true,
|
||||
})
|
||||
notificationIds!: number[];
|
||||
|
||||
@TaskOutput({
|
||||
title: "最后版本",
|
||||
})
|
||||
lastVersion?: string;
|
||||
|
||||
|
||||
//插件实例化时执行的方法
|
||||
async onInstance() {
|
||||
}
|
||||
|
||||
//插件执行方法
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<GithubAccess>(this.accessId);
|
||||
|
||||
const res = await access.getRelease({repoName:this.repoName})
|
||||
|
||||
const lastVersion = this.ctx.lastStatus?.status?.output?.lastVersion;
|
||||
|
||||
if(res.tag_name == null || res.tag_name ==lastVersion){
|
||||
this.logger.info(`暂无更新,${res.tag_name}`);
|
||||
return
|
||||
}
|
||||
//有更新
|
||||
this.logger.info(`有更新,${lastVersion}->${res.tag_name}`)
|
||||
this.lastVersion = res.tag_name;
|
||||
|
||||
//发送通知
|
||||
for (const notificationId of this.notificationIds) {
|
||||
await this.ctx.notificationService.send({
|
||||
id: notificationId,
|
||||
useDefault: false,
|
||||
useEmail:false,
|
||||
logger: this.logger,
|
||||
body: {
|
||||
title: `${this.repoName} 新版本 ${this.lastVersion} 发布`,
|
||||
content: `${res.body}`,
|
||||
url: `https://github.com/${this.repoName}/releases/tag/${this.lastVersion}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new GithubCheckRelease();
|
Loading…
Reference in New Issue