mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 13:39:53 +00:00
feat: support configuring repeatable deploy in deployment
This commit is contained in:
parent
c71d14cafa
commit
5b613bcf84
@ -76,7 +76,7 @@ type WorkflowNodeConfigForDeploy struct {
|
|||||||
Provider string `json:"provider"` // 主机提供商
|
Provider string `json:"provider"` // 主机提供商
|
||||||
ProviderAccessId string `json:"providerAccessId"` // 主机提供商授权记录 ID
|
ProviderAccessId string `json:"providerAccessId"` // 主机提供商授权记录 ID
|
||||||
ProviderConfig map[string]any `json:"providerConfig"` // 主机提供商额外配置
|
ProviderConfig map[string]any `json:"providerConfig"` // 主机提供商额外配置
|
||||||
SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // TODO: 上次部署成功时是否跳过
|
SkipOnLastSucceeded bool `json:"skipOnLastSucceeded"` // 上次部署成功时是否跳过
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkflowNodeConfigForNotify struct {
|
type WorkflowNodeConfigForNotify struct {
|
||||||
|
@ -136,5 +136,5 @@ func (a *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workflo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, "无历史申请记录"
|
return false, ""
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,6 @@ func (d *deployNode) Run(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *deployNode) checkCanSkip(ctx context.Context, lastOutput *domain.WorkflowOutput) (skip bool, reason string) {
|
func (d *deployNode) checkCanSkip(ctx context.Context, lastOutput *domain.WorkflowOutput) (skip bool, reason string) {
|
||||||
// TODO: 可控制是否强制部署
|
|
||||||
if lastOutput != nil && lastOutput.Succeeded {
|
if lastOutput != nil && lastOutput.Succeeded {
|
||||||
// 比较和上次部署时的关键配置(即影响证书部署的)参数是否一致
|
// 比较和上次部署时的关键配置(即影响证书部署的)参数是否一致
|
||||||
currentNodeConfig := d.node.GetConfigForDeploy()
|
currentNodeConfig := d.node.GetConfigForDeploy()
|
||||||
@ -111,8 +110,10 @@ func (d *deployNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workfl
|
|||||||
return false, "配置项变化:主机提供商参数"
|
return false, "配置项变化:主机提供商参数"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if currentNodeConfig.SkipOnLastSucceeded {
|
||||||
return true, "已部署过证书"
|
return true, "已部署过证书"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false, "无历史部署记录"
|
|
||||||
|
return false, ""
|
||||||
}
|
}
|
||||||
|
@ -391,11 +391,11 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
|||||||
label={t("workflow_node.apply.form.skip_before_expiry_days.label")}
|
label={t("workflow_node.apply.form.skip_before_expiry_days.label")}
|
||||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.skip_before_expiry_days.tooltip") }}></span>}
|
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.skip_before_expiry_days.tooltip") }}></span>}
|
||||||
>
|
>
|
||||||
<Flex align="center" gap={8}>
|
<Flex align="center" gap={8} wrap="wrap">
|
||||||
<div>{t("workflow_node.apply.form.skip_before_expiry_days.prefix")}</div>
|
<div>{t("workflow_node.apply.form.skip_before_expiry_days.prefix")}</div>
|
||||||
<Form.Item name="skipBeforeExpiryDays" noStyle rules={[formRule]}>
|
<Form.Item name="skipBeforeExpiryDays" noStyle rules={[formRule]}>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
className="flex-1"
|
className="w-36"
|
||||||
min={1}
|
min={1}
|
||||||
max={60}
|
max={60}
|
||||||
placeholder={t("workflow_node.apply.form.skip_before_expiry_days.placeholder")}
|
placeholder={t("workflow_node.apply.form.skip_before_expiry_days.placeholder")}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } from "react";
|
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
|
import { PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
|
||||||
import { Button, Divider, Form, type FormInstance, Select, Tooltip, Typography } from "antd";
|
import { Button, Divider, Flex, Form, type FormInstance, Select, Switch, Tooltip, Typography } from "antd";
|
||||||
import { createSchemaFieldRule } from "antd-zod";
|
import { createSchemaFieldRule } from "antd-zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@ -65,7 +65,9 @@ export type DeployNodeConfigFormInstance = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const initFormModel = (): DeployNodeConfigFormFieldValues => {
|
const initFormModel = (): DeployNodeConfigFormFieldValues => {
|
||||||
return {};
|
return {
|
||||||
|
skipOnLastSucceeded: true,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNodeConfigFormProps>(
|
const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNodeConfigFormProps>(
|
||||||
@ -91,6 +93,7 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
|||||||
.nonempty(t("workflow_node.deploy.form.provider_access.placeholder"))
|
.nonempty(t("workflow_node.deploy.form.provider_access.placeholder"))
|
||||||
.refine(() => !!formInst.getFieldValue("provider"), t("workflow_node.deploy.form.provider.placeholder")),
|
.refine(() => !!formInst.getFieldValue("provider"), t("workflow_node.deploy.form.provider.placeholder")),
|
||||||
providerConfig: z.any(),
|
providerConfig: z.any(),
|
||||||
|
skipOnLastSucceeded: z.boolean(),
|
||||||
});
|
});
|
||||||
const formRule = createSchemaFieldRule(formSchema);
|
const formRule = createSchemaFieldRule(formSchema);
|
||||||
const { form: formInst, formProps } = useAntdForm({
|
const { form: formInst, formProps } = useAntdForm({
|
||||||
@ -340,6 +343,27 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
|||||||
|
|
||||||
{nestedFormEl}
|
{nestedFormEl}
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
<Divider className="my-1">
|
||||||
|
<Typography.Text className="text-xs font-normal" type="secondary">
|
||||||
|
{t("workflow_node.deploy.form.strategy_config.label")}
|
||||||
|
</Typography.Text>
|
||||||
|
</Divider>
|
||||||
|
|
||||||
|
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
|
||||||
|
<Form.Item label={t("workflow_node.deploy.form.skip_on_last_succeeded.label")}>
|
||||||
|
<Flex align="center" gap={8} wrap="wrap">
|
||||||
|
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.prefix")}</div>
|
||||||
|
<Form.Item name="skipOnLastSucceeded" noStyle rules={[formRule]}>
|
||||||
|
<Switch
|
||||||
|
checkedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.enabled.on")}
|
||||||
|
unCheckedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.enabled.off")}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.suffix")}</div>
|
||||||
|
</Flex>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
</Form.Provider>
|
</Form.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,7 @@ export type WorkflowNodeConfigForDeploy = {
|
|||||||
provider: string;
|
provider: string;
|
||||||
providerAccessId: string;
|
providerAccessId: string;
|
||||||
providerConfig: Record<string, unknown>;
|
providerConfig: Record<string, unknown>;
|
||||||
|
skipOnLastSucceeded: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WorkflowNodeConfigForNotify = {
|
export type WorkflowNodeConfigForNotify = {
|
||||||
|
@ -67,8 +67,8 @@
|
|||||||
"workflow_node.apply.form.strategy_config.label": "Strategy settings",
|
"workflow_node.apply.form.strategy_config.label": "Strategy settings",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.label": "Renewal interval",
|
"workflow_node.apply.form.skip_before_expiry_days.label": "Renewal interval",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.placeholder": "Please enter renewal interval",
|
"workflow_node.apply.form.skip_before_expiry_days.placeholder": "Please enter renewal interval",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.prefix": "Skip when the certificate expiration time exceeds",
|
"workflow_node.apply.form.skip_before_expiry_days.prefix": "If the certificate expiration time exceeds",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.suffix": "",
|
"workflow_node.apply.form.skip_before_expiry_days.suffix": ", skip to re-apply.",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.unit": "days",
|
"workflow_node.apply.form.skip_before_expiry_days.unit": "days",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "Be careful not to exceed the validity period limit of the CA, otherwise the certificate may never be renewed.",
|
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "Be careful not to exceed the validity period limit of the CA, otherwise the certificate may never be renewed.",
|
||||||
|
|
||||||
@ -359,6 +359,12 @@
|
|||||||
"workflow_node.deploy.form.webhook_data.guide": "Tips: The Webhook data should be a key-value pair in JSON format. The values in JSON support template variables, which will be replaced by actual values when sent to the Webhook URL. <br><br>Supported variables: <br><strong>${DOMAIN}</strong>: The primary domain of the certificate (<i>CommonName</i>).<br><strong>${DOMAINS}</strong>: The domain list of the certificate (<i>SubjectAltNames</i>).<br><strong>${CERTIFICATE}</strong>: The PEM format content of the certificate file.<br><strong>${PRIVATE_KEY}</strong>: The PEM format content of the private key file.",
|
"workflow_node.deploy.form.webhook_data.guide": "Tips: The Webhook data should be a key-value pair in JSON format. The values in JSON support template variables, which will be replaced by actual values when sent to the Webhook URL. <br><br>Supported variables: <br><strong>${DOMAIN}</strong>: The primary domain of the certificate (<i>CommonName</i>).<br><strong>${DOMAINS}</strong>: The domain list of the certificate (<i>SubjectAltNames</i>).<br><strong>${CERTIFICATE}</strong>: The PEM format content of the certificate file.<br><strong>${PRIVATE_KEY}</strong>: The PEM format content of the private key file.",
|
||||||
"workflow_node.deploy.form.webhook_data.errmsg.json_invalid": "Please enter a valiod JSON string",
|
"workflow_node.deploy.form.webhook_data.errmsg.json_invalid": "Please enter a valiod JSON string",
|
||||||
"workflow_node.deploy.form.webhook_data_preset.button": "Use preset template",
|
"workflow_node.deploy.form.webhook_data_preset.button": "Use preset template",
|
||||||
|
"workflow_node.deploy.form.strategy_config.label": "Strategy settings",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.label": "Repeated deployment",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.prefix": "If the last deployment was successful, ",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.suffix": " to re-deploy.",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.on": "skip",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.off": "not skip",
|
||||||
|
|
||||||
"workflow_node.notify.label": "Notification",
|
"workflow_node.notify.label": "Notification",
|
||||||
"workflow_node.notify.form.subject.label": "Subject",
|
"workflow_node.notify.form.subject.label": "Subject",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"settings.notification.template.form.message.extra": "支持的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)",
|
"settings.notification.template.form.message.extra": "支持的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)",
|
||||||
"settings.notification.channels.card.title": "通知渠道",
|
"settings.notification.channels.card.title": "通知渠道",
|
||||||
"settings.notification.channel.enabled.on": "启用",
|
"settings.notification.channel.enabled.on": "启用",
|
||||||
"settings.notification.channel.enabled.off": "未启用",
|
"settings.notification.channel.enabled.off": "停用",
|
||||||
"settings.notification.push_test.button": "推送测试消息",
|
"settings.notification.push_test.button": "推送测试消息",
|
||||||
"settings.notification.push_test.pushed": "已推送",
|
"settings.notification.push_test.pushed": "已推送",
|
||||||
"settings.notification.channel.form.bark_server_url.label": "服务器地址",
|
"settings.notification.channel.form.bark_server_url.label": "服务器地址",
|
||||||
|
@ -67,8 +67,8 @@
|
|||||||
"workflow_node.apply.form.strategy_config.label": "执行策略",
|
"workflow_node.apply.form.strategy_config.label": "执行策略",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.label": "续期间隔",
|
"workflow_node.apply.form.skip_before_expiry_days.label": "续期间隔",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.placeholder": "请输入续期间隔",
|
"workflow_node.apply.form.skip_before_expiry_days.placeholder": "请输入续期间隔",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.prefix": "当距上次申请的证书到期时间前",
|
"workflow_node.apply.form.skip_before_expiry_days.prefix": "当上次签发的证书到期时间超过",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.suffix": "时跳过执行",
|
"workflow_node.apply.form.skip_before_expiry_days.suffix": "时,跳过重新申请。",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.unit": "天",
|
"workflow_node.apply.form.skip_before_expiry_days.unit": "天",
|
||||||
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "注意不要超过 CA 的证书有效期限制,否则证书可能永远不会续期。",
|
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "注意不要超过 CA 的证书有效期限制,否则证书可能永远不会续期。",
|
||||||
|
|
||||||
@ -359,6 +359,12 @@
|
|||||||
"workflow_node.deploy.form.webhook_data.guide": "小贴士:回调数据是一个 JSON 格式的键值对。其中值支持模板变量,将在被发送到指定的 Webhook URL 时被替换为实际值;其他内容将保持原样。<br><br>支持的变量:<br><strong>${DOMAIN}</strong>:证书的主域名(即 <i>CommonName</i>)<br><strong>${DOMAINS}</strong>:证书的多域名列表(即 <i>SubjectAltNames</i>)<br><strong>${CERTIFICATE}</strong>:证书文件 PEM 格式内容<br><strong>${PRIVATE_KEY}</strong>:私钥文件 PEM 格式内容",
|
"workflow_node.deploy.form.webhook_data.guide": "小贴士:回调数据是一个 JSON 格式的键值对。其中值支持模板变量,将在被发送到指定的 Webhook URL 时被替换为实际值;其他内容将保持原样。<br><br>支持的变量:<br><strong>${DOMAIN}</strong>:证书的主域名(即 <i>CommonName</i>)<br><strong>${DOMAINS}</strong>:证书的多域名列表(即 <i>SubjectAltNames</i>)<br><strong>${CERTIFICATE}</strong>:证书文件 PEM 格式内容<br><strong>${PRIVATE_KEY}</strong>:私钥文件 PEM 格式内容",
|
||||||
"workflow_node.deploy.form.webhook_data.errmsg.json_invalid": "请输入有效的 JSON 格式字符串",
|
"workflow_node.deploy.form.webhook_data.errmsg.json_invalid": "请输入有效的 JSON 格式字符串",
|
||||||
"workflow_node.deploy.form.webhook_data_preset.button": "使用预设模板",
|
"workflow_node.deploy.form.webhook_data_preset.button": "使用预设模板",
|
||||||
|
"workflow_node.deploy.form.strategy_config.label": "执行策略",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.label": "重复部署",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.prefix": "当上次部署已成功时",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.suffix": "重新部署。",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.on": "跳过",
|
||||||
|
"workflow_node.deploy.form.skip_on_last_succeeded.enabled.off": "不跳过",
|
||||||
|
|
||||||
"workflow_node.notify.label": "通知",
|
"workflow_node.notify.label": "通知",
|
||||||
"workflow_node.notify.form.subject.label": "通知主题",
|
"workflow_node.notify.form.subject.label": "通知主题",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user