From 54cb817fc4d1a520d38dfc00af3e1714ffe9470c Mon Sep 17 00:00:00 2001
From: vapao
Date: Mon, 22 Mar 2021 23:18:03 +0800
Subject: [PATCH] update
---
spug_api/apps/deploy/urls.py | 1 +
spug_api/apps/deploy/utils.py | 31 ++-
spug_api/apps/deploy/views.py | 99 +++++----
spug_web/src/pages/deploy/app/Ext2Form.js | 5 +-
spug_web/src/pages/deploy/app/Ext2Setup1.js | 13 +-
spug_web/src/pages/deploy/app/Ext2Setup2.js | 210 ++++++++++++++----
spug_web/src/pages/deploy/app/Ext2Setup3.js | 196 ----------------
.../src/pages/deploy/request/Ext1Console.js | 2 +-
spug_web/src/pages/deploy/request/Ext1Form.js | 4 +-
.../src/pages/deploy/request/Ext2Console.js | 153 +++++++++++++
spug_web/src/pages/deploy/request/Ext2Form.js | 51 ++---
spug_web/src/pages/deploy/request/Table.js | 23 +-
spug_web/src/pages/deploy/request/index.js | 7 +-
.../pages/deploy/request/index.module.less | 8 +
14 files changed, 444 insertions(+), 359 deletions(-)
delete mode 100644 spug_web/src/pages/deploy/app/Ext2Setup3.js
create mode 100644 spug_web/src/pages/deploy/request/Ext2Console.js
diff --git a/spug_api/apps/deploy/urls.py b/spug_api/apps/deploy/urls.py
index abf4245..6a63fd1 100644
--- a/spug_api/apps/deploy/urls.py
+++ b/spug_api/apps/deploy/urls.py
@@ -8,6 +8,7 @@ from .views import *
urlpatterns = [
path('request/', RequestView.as_view()),
path('request/1/', post_request_1),
+ path('request/2/', post_request_2),
path('request/upload/', do_upload),
path('request//', RequestDetailView.as_view()),
]
diff --git a/spug_api/apps/deploy/utils.py b/spug_api/apps/deploy/utils.py
index f899b58..04c1a29 100644
--- a/spug_api/apps/deploy/utils.py
+++ b/spug_api/apps/deploy/utils.py
@@ -29,7 +29,6 @@ def dispatch(req):
api_token = uuid.uuid4().hex
rds.setex(api_token, 60 * 60, f'{req.deploy.app_id},{req.deploy.env_id}')
helper = Helper(rds, rds_key)
- # helper.send_step('local', 1, f'完成\r\n{human_time()} 发布准备... ')
env = AttrDict(
SPUG_APP_NAME=req.deploy.app.name,
SPUG_APP_ID=str(req.deploy.app_id),
@@ -80,18 +79,16 @@ def _ext1_deploy(req, helper, env):
def _ext2_deploy(req, helper, env):
- extend = req.deploy.extend_obj
- extras = json.loads(req.extra)
+ helper.send_info('local', f'完成\r\n')
+ extend, step = req.deploy.extend_obj, 1
host_actions = json.loads(extend.host_actions)
server_actions = json.loads(extend.server_actions)
- if extras and extras[0]:
- env.update({'SPUG_RELEASE': extras[0]})
- step = 2
+ env.update({'SPUG_RELEASE': req.version})
for action in server_actions:
- helper.send_step('local', step, f'\r\n{human_time()} {action["title"]}...\r\n')
+ helper.send_step('local', step, f'{human_time()} {action["title"]}...\r\n')
helper.local(f'cd /tmp && {action["data"]}', env)
step += 1
- helper.send_step('local', 100, '完成\r\n' if step == 2 else '\r\n')
+ helper.send_step('local', 100, '\r\n')
tmp_transfer_file = None
for action in host_actions:
@@ -119,17 +116,18 @@ def _ext2_deploy(req, helper, env):
else:
excludes.append(f'--exclude={x}')
exclude = ' '.join(excludes)
- tar_gz_file = f'{env.SPUG_VERSION}.tar.gz'
+ tar_gz_file = f'{env.spug_version}.tar.gz'
helper.local(f'cd {sp_dir} && tar zcf {tar_gz_file} {exclude} {contain}')
helper.send_info('local', '完成\r\n')
tmp_transfer_file = os.path.join(sp_dir, tar_gz_file)
break
if host_actions:
threads, latest_exception = [], None
- with futures.ThreadPoolExecutor(max_workers=min(10, os.cpu_count() + 5)) as executor:
+ max_workers = min(10, os.cpu_count() * 4) if req.deploy.is_parallel else 1
+ with futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
for h_id in json.loads(req.host_ids):
env = AttrDict(env.items())
- t = executor.submit(_deploy_ext2_host, helper, h_id, host_actions, env)
+ t = executor.submit(_deploy_ext2_host, helper, h_id, host_actions, env, req.spug_version)
t.h_id = h_id
threads.append(t)
for t in futures.as_completed(threads):
@@ -190,23 +188,22 @@ def _deploy_ext1_host(req, helper, h_id, env):
command = f'cd {extend.dst_dir} ; {extend.hook_post_host}'
helper.remote(host.id, ssh, command, env)
- helper.send_step(h_id, 5, f'\r\n{human_time()} ** 发布成功 **')
+ helper.send_step(h_id, 100, f'\r\n{human_time()} ** 发布成功 **')
-def _deploy_ext2_host(helper, h_id, actions, env):
- helper.send_step(h_id, 1, f'{human_time()} 数据准备... ')
+def _deploy_ext2_host(helper, h_id, actions, env, spug_version):
+ helper.send_info(h_id, '就绪\r\n')
host = Host.objects.filter(pk=h_id).first()
if not host:
helper.send_error(h_id, 'no such host')
env.update({'SPUG_HOST_ID': h_id, 'SPUG_HOST_NAME': host.hostname})
ssh = host.get_ssh()
- helper.send_step(h_id, 2, '完成\r\n')
for index, action in enumerate(actions):
- helper.send_step(h_id, 2 + index, f'{human_time()} {action["title"]}...\r\n')
+ helper.send_step(h_id, 1 + index, f'{human_time()} {action["title"]}...\r\n')
if action.get('type') == 'transfer':
if action.get('src_mode') == '1':
try:
- ssh.put_file(os.path.join(REPOS_DIR, env.SPUG_DEPLOY_ID, env.SPUG_VERSION), action['dst'])
+ ssh.put_file(os.path.join(REPOS_DIR, env.SPUG_DEPLOY_ID, spug_version), action['dst'])
except Exception as e:
helper.send_error(host.id, f'exception: {e}')
helper.send_info(host.id, 'transfer completed\r\n')
diff --git a/spug_api/apps/deploy/views.py b/spug_api/apps/deploy/views.py
index 7f2a8ff..e9b3458 100644
--- a/spug_api/apps/deploy/views.py
+++ b/spug_api/apps/deploy/views.py
@@ -43,6 +43,7 @@ class RequestView(View):
tmp['app_name'] = item.app_name
tmp['app_extend'] = item.app_extend
tmp['host_ids'] = json.loads(item.host_ids)
+ tmp['extra'] = json.loads(item.extra) if item.extra else None
tmp['rep_extra'] = json.loads(item.rep_extra) if item.rep_extra else None
tmp['app_host_ids'] = json.loads(item.app_host_ids)
tmp['status_alias'] = item.get_status_display()
@@ -50,45 +51,6 @@ class RequestView(View):
data.append(tmp)
return json_response(data)
- def post(self, request):
- form, error = JsonParser(
- Argument('id', type=int, required=False),
- Argument('deploy_id', type=int, help='缺少必要参数'),
- Argument('name', help='请输申请标题'),
- Argument('extra', type=list, help='缺少必要参数'),
- Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择要部署的主机'),
- Argument('desc', required=False),
- ).parse(request.body)
- if error is None:
- deploy = Deploy.objects.filter(pk=form.deploy_id).first()
- if not deploy:
- return json_response(error='未找到该发布配置')
- if deploy.extend == '2':
- if form.extra[0]:
- form.extra[0] = form.extra[0].replace("'", '')
- if DeployExtend2.objects.filter(deploy=deploy, host_actions__contains='"src_mode": "1"').exists():
- if len(form.extra) < 2:
- return json_response(error='该应用的发布配置中使用了数据传输动作且设置为发布时上传,请上传要传输的数据')
- form.version = form.extra[1].get('path')
- form.name = form.name.replace("'", '')
- form.status = '0' if deploy.is_audit else '1'
- form.extra = json.dumps(form.extra)
- form.host_ids = json.dumps(form.host_ids)
- if form.id:
- req = DeployRequest.objects.get(pk=form.id)
- is_required_notify = deploy.is_audit and req.status == '-1'
- DeployRequest.objects.filter(pk=form.id).update(
- created_by=request.user,
- reason=None,
- **form
- )
- else:
- req = DeployRequest.objects.create(created_by=request.user, **form)
- is_required_notify = deploy.is_audit
- if is_required_notify:
- Thread(target=Helper.send_deploy_notify, args=(req, 'approve_req')).start()
- return json_response(error=error)
-
def put(self, request):
form, error = JsonParser(
Argument('id', type=int, help='缺少必要参数'),
@@ -162,11 +124,12 @@ class RequestDetailView(View):
if not req:
return json_response(error='未找到指定发布申请')
hosts = Host.objects.filter(id__in=json.loads(req.host_ids))
- server_actions, host_actions = [], []
outputs = {x.id: {'id': x.id, 'title': x.name, 'data': []} for x in hosts}
+ response = {'outputs': outputs, 'status': req.status}
if req.deploy.extend == '2':
- server_actions = json.loads(req.deploy.extend_obj.server_actions)
- host_actions = json.loads(req.deploy.extend_obj.host_actions)
+ outputs['local'] = {'id': 'local', 'data': []}
+ response['s_actions'] = json.loads(req.deploy.extend_obj.server_actions)
+ response['h_actions'] = json.loads(req.deploy.extend_obj.host_actions)
rds, key, counter = get_redis_connection(), f'{settings.REQUEST_KEY}:{r_id}', 0
data = rds.lrange(key, counter, counter + 9)
while data:
@@ -180,12 +143,7 @@ class RequestDetailView(View):
if 'status' in item:
outputs[item['key']]['status'] = item['status']
data = rds.lrange(key, counter, counter + 9)
- return json_response({
- 'server_actions': server_actions,
- 'host_actions': host_actions,
- 'outputs': outputs,
- 'status': req.status
- })
+ return json_response(response)
def post(self, request, r_id):
query = {'pk': r_id}
@@ -206,7 +164,13 @@ class RequestDetailView(View):
req.do_by = request.user
req.save()
Thread(target=dispatch, args=(req,)).start()
- return json_response({'type': req.type, 'outputs': outputs})
+ if req.deploy.extend == '2':
+ message = f'{human_time()} 建立连接... '
+ outputs['local'] = {'id': 'local', 'step': 0, 'data': [message]}
+ s_actions = json.loads(req.deploy.extend_obj.server_actions)
+ h_actions = json.loads(req.deploy.extend_obj.host_actions)
+ return json_response({'s_actions': s_actions, 'h_actions': h_actions, 'outputs': outputs})
+ return json_response({'outputs': outputs})
def patch(self, request, r_id):
form, error = JsonParser(
@@ -261,6 +225,43 @@ def post_request_1(request):
return json_response(error=error)
+def post_request_2(request):
+ form, error = JsonParser(
+ Argument('id', type=int, required=False),
+ Argument('deploy_id', type=int, help='缺少必要参数'),
+ Argument('name', help='请输申请标题'),
+ Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择要部署的主机'),
+ Argument('extra', type=dict, required=False),
+ Argument('version', required=False),
+ Argument('desc', required=False),
+ ).parse(request.body)
+ if error is None:
+ deploy = Deploy.objects.filter(pk=form.deploy_id).first()
+ if not deploy:
+ return json_response(error='未找到该发布配置')
+ extra = form.pop('extra')
+ if DeployExtend2.objects.filter(deploy=deploy, host_actions__contains='"src_mode": "1"').exists():
+ if not extra:
+ return json_response(error='该应用的发布配置中使用了数据传输动作且设置为发布时上传,请上传要传输的数据')
+ form.spug_version = extra['path']
+ form.extra = json.dumps(extra)
+ else:
+ form.spug_version = Repository.make_spug_version(deploy.id)
+ form.name = form.name.replace("'", '')
+ form.status = '0' if deploy.is_audit else '1'
+ form.host_ids = json.dumps(form.host_ids)
+ if form.id:
+ req = DeployRequest.objects.get(pk=form.id)
+ is_required_notify = deploy.is_audit and req.status == '-1'
+ DeployRequest.objects.filter(pk=form.id).update(created_by=request.user, reason=None, **form)
+ else:
+ req = DeployRequest.objects.create(created_by=request.user, **form)
+ is_required_notify = deploy.is_audit
+ if is_required_notify:
+ Thread(target=Helper.send_deploy_notify, args=(req, 'approve_req')).start()
+ return json_response(error=error)
+
+
def do_upload(request):
repos_dir = settings.REPOS_DIR
file = request.FILES['file']
diff --git a/spug_web/src/pages/deploy/app/Ext2Form.js b/spug_web/src/pages/deploy/app/Ext2Form.js
index 34db9dc..7d6d9f5 100644
--- a/spug_web/src/pages/deploy/app/Ext2Form.js
+++ b/spug_web/src/pages/deploy/app/Ext2Form.js
@@ -9,7 +9,6 @@ import { Modal, Steps } from 'antd';
import styles from './index.module.css';
import Setup1 from './Ext2Setup1';
import Setup2 from './Ext2Setup2';
-import Setup3 from './Ext2Setup3';
import store from './store';
export default observer(function Ext2From() {
@@ -30,12 +29,10 @@ export default observer(function Ext2From() {
footer={null}>
-
-
+
{store.page === 0 && }
{store.page === 1 && }
- {store.page === 2 && }
)
})
diff --git a/spug_web/src/pages/deploy/app/Ext2Setup1.js b/spug_web/src/pages/deploy/app/Ext2Setup1.js
index 8c5395c..b535184 100644
--- a/spug_web/src/pages/deploy/app/Ext2Setup1.js
+++ b/spug_web/src/pages/deploy/app/Ext2Setup1.js
@@ -6,12 +6,14 @@
import React, { useState, useEffect } from 'react';
import { observer } from 'mobx-react';
import { Link } from 'react-router-dom';
-import { Form, Switch, Select, Button, Input, Radio } from "antd";
+import { Form, Switch, Select, Button, Input, Radio } from 'antd';
import envStore from 'pages/config/environment/store';
+import Selector from 'pages/host/Selector';
import store from './store';
export default observer(function Ext2Setup1() {
const [envs, setEnvs] = useState([]);
+ const [selectorVisible, setSelectorVisible] = useState(false);
function updateEnvs() {
const ids = store.currentRecord['deploys'].map(x => x.env_id);
@@ -41,6 +43,10 @@ export default observer(function Ext2Setup1() {
新建环境
+
+ {info.host_ids.length > 0 && `已选择 ${info.host_ids.length} 台`}
+
+
info.is_parallel = e.target.value}>
并行
@@ -82,6 +88,11 @@ export default observer(function Ext2Setup1() {
disabled={!info.env_id}
onClick={() => store.page += 1}>下一步
+ setSelectorVisible(false)}
+ onOk={(_, ids) => info.host_ids = ids}/>
)
})
diff --git a/spug_web/src/pages/deploy/app/Ext2Setup2.js b/spug_web/src/pages/deploy/app/Ext2Setup2.js
index f3ffb27..909b335 100644
--- a/spug_web/src/pages/deploy/app/Ext2Setup2.js
+++ b/spug_web/src/pages/deploy/app/Ext2Setup2.js
@@ -6,56 +6,186 @@
import React from 'react';
import { observer } from 'mobx-react';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
-import { Form, Select, Button } from 'antd';
-import { hasHostPermission } from 'libs';
-import store from './store';
-import hostStore from 'pages/host/store';
+import { Form, Input, Button, message, Divider, Alert, Select } from 'antd';
+import Editor from 'react-ace';
+import 'ace-builds/src-noconflict/mode-sh';
+import 'ace-builds/src-noconflict/theme-tomorrow';
import styles from './index.module.css';
+import { http, cleanCommand } from 'libs';
+import store from './store';
+import lds from 'lodash';
@observer
class Ext2Setup2 extends React.Component {
- componentDidMount() {
- if (hostStore.records.length === 0) {
- hostStore.fetchRecords()
+ constructor(props) {
+ super(props);
+ this.helpMap = {
+ '0': null,
+ '1': '相对于输入的本地路径的文件路径,仅将匹配到文件传输至要发布的目标主机。',
+ '2': '支持模糊匹配,如果路径以 / 开头则基于输入的本地路径匹配,匹配到文件将不会被传输。'
+ }
+ this.state = {
+ loading: false,
}
}
- render() {
+ handleSubmit = () => {
+ this.setState({loading: true});
const info = store.deploy;
+ info['app_id'] = store.app_id;
+ info['extend'] = '2';
+ info['host_actions'] = info['host_actions'].filter(x => (x.title && x.data) || (x.title && (x.src || x.src_mode === '1') && x.dst));
+ info['server_actions'] = info['server_actions'].filter(x => x.title && x.data);
+ http.post('/api/app/deploy/', info)
+ .then(res => {
+ message.success('保存成功');
+ store.ext2Visible = false;
+ store.loadDeploys(store.app_id)
+ }, () => this.setState({loading: false}))
+ };
+
+ render() {
+ const server_actions = store.deploy['server_actions'];
+ const host_actions = store.deploy['host_actions'];
return (
-
- {info['host_ids'].map((id, index) => (
-
-
- {!store.isReadOnly && info['host_ids'].length > 1 && (
- store.delHost(index)} />
- )}
-
- ))}
-
+
,
+ 执行的命令内可以使用发布申请中设置的环境变量 SPUG_RELEASE,一般可用于标记一次发布的版本号或提交ID等,在执行的脚本内通过使用 $SPUG_RELEASE
+ 获取其值来执行相应操作。
+ ]}/>
+ )}
+ {server_actions.map((item, index) => (
+
+
+ item['title'] = e.target.value}
+ placeholder="请输入"/>
+
+
+
+ item['data'] = cleanCommand(v)}
+ placeholder="请输入要执行的动作"/>
+
+ {!store.isReadOnly && (
+
server_actions.splice(index, 1)}>
+ 移除
+
+ )}
+
+ ))}
+ {!store.isReadOnly && (
+
+
+
+ )}
+
+ {host_actions.map((item, index) => (
+
+ ))}
+ {!store.isReadOnly && (
+
+
+
+
+ )}
-
-
-
-
+
diff --git a/spug_web/src/pages/deploy/app/Ext2Setup3.js b/spug_web/src/pages/deploy/app/Ext2Setup3.js
deleted file mode 100644
index 0a9ec1d..0000000
--- a/spug_web/src/pages/deploy/app/Ext2Setup3.js
+++ /dev/null
@@ -1,196 +0,0 @@
-/**
- * Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
- * Copyright (c)
- * Released under the AGPL-3.0 License.
- */
-import React from 'react';
-import { observer } from 'mobx-react';
-import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
-import { Form, Input, Button, message, Divider, Alert, Select } from 'antd';
-import Editor from 'react-ace';
-import 'ace-builds/src-noconflict/mode-sh';
-import 'ace-builds/src-noconflict/theme-tomorrow';
-import styles from './index.module.css';
-import { http, cleanCommand } from 'libs';
-import store from './store';
-import lds from 'lodash';
-
-@observer
-class Ext2Setup3 extends React.Component {
- constructor(props) {
- super(props);
- this.helpMap = {
- '0': null,
- '1': '相对于输入的本地路径的文件路径,仅将匹配到文件传输至要发布的目标主机。',
- '2': '支持模糊匹配,如果路径以 / 开头则基于输入的本地路径匹配,匹配到文件将不会被传输。'
- }
- this.state = {
- loading: false,
- }
- }
-
- handleSubmit = () => {
- this.setState({loading: true});
- const info = store.deploy;
- info['app_id'] = store.app_id;
- info['extend'] = '2';
- info['host_actions'] = info['host_actions'].filter(x => (x.title && x.data) || (x.title && (x.src || x.src_mode === '1') && x.dst));
- info['server_actions'] = info['server_actions'].filter(x => x.title && x.data);
- http.post('/api/app/deploy/', info)
- .then(res => {
- message.success('保存成功');
- store.ext2Visible = false;
- store.loadDeploys(store.app_id)
- }, () => this.setState({loading: false}))
- };
-
- render() {
- const server_actions = store.deploy['server_actions'];
- const host_actions = store.deploy['host_actions'];
- return (
-
- )
- }
-}
-
-export default Ext2Setup3
diff --git a/spug_web/src/pages/deploy/request/Ext1Console.js b/spug_web/src/pages/deploy/request/Ext1Console.js
index d304d12..a233713 100644
--- a/spug_web/src/pages/deploy/request/Ext1Console.js
+++ b/spug_web/src/pages/deploy/request/Ext1Console.js
@@ -85,7 +85,7 @@ function Ext1Console(props) {
+ status={item.step === 100 ? 'success' : item.status === 'error' ? 'exception' : 'active'}/>
))}
) : (
diff --git a/spug_web/src/pages/deploy/request/Ext1Form.js b/spug_web/src/pages/deploy/request/Ext1Form.js
index c04d9fc..5fcace5 100644
--- a/spug_web/src/pages/deploy/request/Ext1Form.js
+++ b/spug_web/src/pages/deploy/request/Ext1Form.js
@@ -72,8 +72,8 @@ export default observer(function () {
))}
-
- {host_ids.length > 0 && `已选择 ${host_ids.length} 台`}
+
+ {host_ids.length > 0 && `已选择 ${host_ids.length} 台(可选${app_host_ids.length})`}
diff --git a/spug_web/src/pages/deploy/request/Ext2Console.js b/spug_web/src/pages/deploy/request/Ext2Console.js
new file mode 100644
index 0000000..651b2a7
--- /dev/null
+++ b/spug_web/src/pages/deploy/request/Ext2Console.js
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
+ * Copyright (c)
+ * Released under the AGPL-3.0 License.
+ */
+import React, { useEffect, useState } from 'react';
+import { observer, useLocalStore } from 'mobx-react';
+import { Card, Progress, Modal, Collapse, Steps } from 'antd';
+import { ShrinkOutlined, CaretRightOutlined, LoadingOutlined, CloseOutlined } from '@ant-design/icons';
+import OutView from './OutView';
+import { http, X_TOKEN } from 'libs';
+import styles from './index.module.less';
+import store from './store';
+
+function Ext2Console(props) {
+ const outputs = useLocalStore(() => ({local: {id: 'local'}}));
+ const [sActions, setSActions] = useState([]);
+ const [hActions, setHActions] = useState([]);
+
+ useEffect(props.request.mode === 'read' ? readDeploy : doDeploy, [])
+
+ function readDeploy() {
+ let socket;
+ http.get(`/api/deploy/request/${props.request.id}/`)
+ .then(res => {
+ setSActions(res.s_actions);
+ setHActions(res.h_actions);
+ Object.assign(outputs, res.outputs)
+ if (res.status === '2') {
+ socket = _makeSocket()
+ }
+ })
+ return () => socket && socket.close()
+ }
+
+ function doDeploy() {
+ let socket;
+ http.post(`/api/deploy/request/${props.request.id}/`)
+ .then(res => {
+ setSActions(res.s_actions);
+ setHActions(res.h_actions);
+ Object.assign(outputs, res.outputs)
+ socket = _makeSocket()
+ })
+ return () => socket && socket.close()
+ }
+
+ function _makeSocket() {
+ let index = 0;
+ const token = props.request.id;
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
+ const socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/request/${token}/?x-token=${X_TOKEN}`);
+ socket.onopen = () => socket.send(String(index));
+ socket.onmessage = e => {
+ if (e.data === 'pong') {
+ socket.send(String(index))
+ } else {
+ index += 1;
+ const {key, data, step, status} = JSON.parse(e.data);
+ if (data !== undefined) outputs[key].data.push(data);
+ if (step !== undefined) outputs[key].step = step;
+ if (status !== undefined) outputs[key].status = status;
+ }
+ }
+ return socket
+ }
+
+ function StepItem(props) {
+ let icon = null;
+ if (props.step === props.item.step && props.item.status !== 'error') {
+ if (props.item.id === 'local' || outputs.local.step === 100) {
+ icon =
+ }
+ }
+ return
+ }
+
+ function switchMiniMode() {
+ const value = store.tabModes[props.request.id];
+ store.tabModes[props.request.id] = !value
+ }
+
+ return store.tabModes[props.request.id] ? (
+
+
+
{props.request.name}
+
store.showConsole(props.request, true)}/>
+
+
+ {Object.values(outputs).filter(x => x.id !== 'local').map(item => (
+
+ ))}
+
+ ) : (
+ store.showConsole(props.request, true)}
+ title={[
+ {props.request.name},
+
+
+
+ ]}>
+
+
+
+ {sActions.map((item, index) => (
+
+ ))}
+
+ )}>
+
+
+
+ }>
+ {Object.values(outputs).filter(x => x.id !== 'local').map((item, index) => (
+
+ {item.title}{item.step}
+
+
+ {hActions.map((action, index) => (
+
+ ))}
+
+ }>
+
+
+ ))}
+
+
+ )
+}
+
+export default observer(Ext2Console)
\ No newline at end of file
diff --git a/spug_web/src/pages/deploy/request/Ext2Form.js b/spug_web/src/pages/deploy/request/Ext2Form.js
index ef1c8e7..1eb395a 100644
--- a/spug_web/src/pages/deploy/request/Ext2Form.js
+++ b/spug_web/src/pages/deploy/request/Ext2Form.js
@@ -8,10 +8,11 @@ import { observer } from 'mobx-react';
import { UploadOutlined } from '@ant-design/icons';
import { Modal, Form, Input, Upload, message, Button } from 'antd';
import hostStore from 'pages/host/store';
+import HostSelector from './HostSelector';
import { http, X_TOKEN } from 'libs';
+import styles from './index.module.less';
import store from './store';
import lds from 'lodash';
-import HostSelector from "./HostSelector";
export default observer(function () {
const [form] = Form.useForm();
@@ -19,17 +20,13 @@ export default observer(function () {
const [loading, setLoading] = useState(false);
const [uploading, setUploading] = useState(false);
const [fileList, setFileList] = useState([]);
- const [host_ids, setHostIds] = useState(lds.clone(store.record.app_host_ids));
+ const [host_ids, setHostIds] = useState([]);
useEffect(() => {
- if (hostStore.records.length === 0) {
- hostStore.fetchRecords()
- }
- const file = lds.get(store, 'record.extra.1');
- if (file) {
- file.uid = '0';
- setFileList([file])
- }
+ const {app_host_ids, host_ids, extra} = store.record;
+ setHostIds(lds.clone(host_ids || app_host_ids));
+ if (hostStore.records.length === 0) hostStore.fetchRecords();
+ if (store.record.extra) setFileList([{...extra, uid: '0'}])
}, [])
function handleSubmit() {
@@ -39,13 +36,10 @@ export default observer(function () {
setLoading(true);
const formData = form.getFieldsValue();
formData['id'] = store.record.id;
- formData['deploy_id'] = store.record.deploy_id;
- formData['extra'] = [formData['extra']];
- if (fileList.length > 0) {
- formData['extra'].push(lds.pick(fileList[0], ['path', 'name']))
- }
formData['host_ids'] = host_ids;
- http.post('/api/deploy/request/', formData)
+ formData['deploy_id'] = store.record.deploy_id;
+ if (fileList.length > 0) formData['extra'] = lds.pick(fileList[0], ['path', 'name']);
+ http.post('/api/deploy/request/2/', formData)
.then(res => {
message.success('操作成功');
store.ext2Visible = false;
@@ -73,6 +67,7 @@ export default observer(function () {
return false
}
+ const {app_host_ids, deploy_id} = store.record;
return (
store.ext2Visible = false}
confirmLoading={loading}
onOk={handleSubmit}>
-
+
+ name="version"
+ label="SPUG_RELEASE"
+ tooltip="可以在自定义脚本中引用该变量,用于设置本次发布相关的动态变量,在脚本中通过 $SPUG_RELEASE 来使用该值。">
-
+
+ data={{deploy_id}} onChange={handleUploadChange}>
{fileList.length === 0 ? : null}
-
- {host_ids.length > 0 && `已选择 ${host_ids.length} 台`}
+
+ {host_ids.length > 0 && `已选择 ${host_ids.length} 台(可选${app_host_ids.length})`}
+
+
+
{visible && setVisible(false)}
onOk={ids => setHostIds(ids)}/>}
diff --git a/spug_web/src/pages/deploy/request/Table.js b/spug_web/src/pages/deploy/request/Table.js
index f43e825..50b5e49 100644
--- a/spug_web/src/pages/deploy/request/Table.js
+++ b/spug_web/src/pages/deploy/request/Table.js
@@ -40,7 +40,7 @@ function ComTable() {
} else {
return (
- {info.extra[0]}
+ {info.version}
)
}
@@ -96,9 +96,7 @@ function ComTable() {
;
case '3':
return
- 查看
+ store.readConsole(info)}>查看
{
- Modal.confirm({
- title: '回滚确认',
- content: `确定要回滚至 ${res['date']} 创建的名称为【${res['name']}】的发布申请版本?`,
- onOk: () => {
- return http.put('/api/deploy/request/', {id: info.id, action: 'do'})
- .then(() => {
- message.success('回滚申请创建成功');
- store.fetchRecords()
- })
- }
- })
- })
- }
-
function handleDelete(info) {
Modal.confirm({
title: '删除确认',
diff --git a/spug_web/src/pages/deploy/request/index.js b/spug_web/src/pages/deploy/request/index.js
index 1251b07..d41bff5 100644
--- a/spug_web/src/pages/deploy/request/index.js
+++ b/spug_web/src/pages/deploy/request/index.js
@@ -13,6 +13,7 @@ import Ext2Form from './Ext2Form';
import Approve from './Approve';
import ComTable from './Table';
import Ext1Console from './Ext1Console';
+import Ext2Console from './Ext2Console';
import { http, includes } from 'libs';
import envStore from 'pages/config/environment/store';
import appStore from 'pages/config/app/store';
@@ -115,7 +116,11 @@ function Index() {
{store.tabs.map(item => (
-
+ {item.app_extend === '1' ? (
+
+ ) : (
+
+ )}
))}
diff --git a/spug_web/src/pages/deploy/request/index.module.less b/spug_web/src/pages/deploy/request/index.module.less
index d580bb2..3f8ae9a 100644
--- a/spug_web/src/pages/deploy/request/index.module.less
+++ b/spug_web/src/pages/deploy/request/index.module.less
@@ -19,6 +19,10 @@
box-shadow: 0 0 4px rgba(0, 0, 0, .3);
border-radius: 5px;
+ :global(.ant-progress-text) {
+ text-align: center;
+ }
+
.header {
display: flex;
justify-content: space-between;
@@ -100,6 +104,10 @@
padding: 0;
}
+.upload :global(.ant-upload-list-item) {
+ margin: 0;
+}
+
.floatBox {
display: none;
position: fixed;