mirror of https://github.com/openspug/spug
				
				
				
			fix issue
							parent
							
								
									1897739512
								
							
						
					
					
						commit
						0dd2ef3df8
					
				| 
						 | 
				
			
			@ -202,30 +202,45 @@ class RequestDetailView(View):
 | 
			
		|||
def post_request_ext1(request):
 | 
			
		||||
    form, error = JsonParser(
 | 
			
		||||
        Argument('id', type=int, required=False),
 | 
			
		||||
        Argument('deploy_id', type=int, help='参数错误'),
 | 
			
		||||
        Argument('name', help='请输入申请标题'),
 | 
			
		||||
        Argument('repository_id', type=int, help='请选择发布版本'),
 | 
			
		||||
        Argument('extra', type=list, help='请选择发布版本'),
 | 
			
		||||
        Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择要部署的主机'),
 | 
			
		||||
        Argument('type', default='1'),
 | 
			
		||||
        Argument('plan', required=False),
 | 
			
		||||
        Argument('desc', required=False),
 | 
			
		||||
    ).parse(request.body)
 | 
			
		||||
    if error is None:
 | 
			
		||||
        repository = Repository.objects.filter(pk=form.repository_id).first()
 | 
			
		||||
        if not repository:
 | 
			
		||||
            return json_response(error='未找到指定构建版本记录')
 | 
			
		||||
        form.name = form.name.replace("'", '')
 | 
			
		||||
        form.status = '0' if repository.deploy.is_audit else '1'
 | 
			
		||||
        form.version = repository.version
 | 
			
		||||
        form.spug_version = repository.spug_version
 | 
			
		||||
        form.deploy_id = repository.deploy_id
 | 
			
		||||
        deploy = Deploy.objects.get(pk=form.deploy_id)
 | 
			
		||||
        form.spug_version = Repository.make_spug_version(deploy.id)
 | 
			
		||||
        if form.extra[0] == 'tag':
 | 
			
		||||
            if not form.extra[1]:
 | 
			
		||||
                return json_response(error='请选择要发布的版本')
 | 
			
		||||
            form.version = form.extra[1]
 | 
			
		||||
        elif form.extra[0] == 'branch':
 | 
			
		||||
            if not form.extra[2]:
 | 
			
		||||
                return json_response(error='请选择要发布的分支及Commit ID')
 | 
			
		||||
            form.version = f'{form.extra[1]}#{form.extra[2][:6]}'
 | 
			
		||||
        elif form.extra[0] == 'repository':
 | 
			
		||||
            if not form.extra[1]:
 | 
			
		||||
                return json_response(error='请选择要发布的版本')
 | 
			
		||||
            repository = Repository.objects.get(pk=form.extra[1])
 | 
			
		||||
            form.repository_id = repository.id
 | 
			
		||||
            form.version = repository.version
 | 
			
		||||
            form.spug_version = repository.spug_version
 | 
			
		||||
        else:
 | 
			
		||||
            return json_response(error='参数错误')
 | 
			
		||||
 | 
			
		||||
        form.extra = json.dumps(form.extra)
 | 
			
		||||
        form.status = '0' if deploy.is_audit else '1'
 | 
			
		||||
        form.host_ids = json.dumps(sorted(form.host_ids))
 | 
			
		||||
        if form.id:
 | 
			
		||||
            req = DeployRequest.objects.get(pk=form.id)
 | 
			
		||||
            is_required_notify = repository.deploy.is_audit and req.status == '-1'
 | 
			
		||||
            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 = repository.deploy.is_audit
 | 
			
		||||
            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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,7 @@ export default observer(function () {
 | 
			
		|||
      setExtra2(commit)
 | 
			
		||||
    } else {
 | 
			
		||||
      setExtra1(lds.get(Object.keys(tags), 0))
 | 
			
		||||
      setExtra2(null)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
import React, { useState, useEffect } from 'react';
 | 
			
		||||
import { observer } from 'mobx-react';
 | 
			
		||||
import { Modal, Form, Input, Select, DatePicker, Button, message } from 'antd';
 | 
			
		||||
import { LoadingOutlined, SyncOutlined } from '@ant-design/icons';
 | 
			
		||||
import HostSelector from './HostSelector';
 | 
			
		||||
import hostStore from 'pages/host/store';
 | 
			
		||||
import { http, history } from 'libs';
 | 
			
		||||
| 
						 | 
				
			
			@ -30,18 +31,38 @@ export default observer(function () {
 | 
			
		|||
  const [form] = Form.useForm();
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const [loading, setLoading] = useState(false);
 | 
			
		||||
  const [versions, setVersions] = useState([]);
 | 
			
		||||
  const [repositories, setRepositories] = useState([]);
 | 
			
		||||
  const [host_ids, setHostIds] = useState([]);
 | 
			
		||||
  const [plan, setPlan] = useState(store.record.plan);
 | 
			
		||||
  const [fetching, setFetching] = useState(false);
 | 
			
		||||
  const [git_type, setGitType] = useState();
 | 
			
		||||
  const [extra, setExtra] = useState([]);
 | 
			
		||||
  const [extra1, setExtra1] = useState();
 | 
			
		||||
  const [extra2, setExtra2] = useState();
 | 
			
		||||
  const [versions, setVersions] = useState({});
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const {deploy_id, app_host_ids, host_ids} = store.record;
 | 
			
		||||
    const {app_host_ids, host_ids} = store.record;
 | 
			
		||||
    setHostIds(lds.clone(host_ids || app_host_ids));
 | 
			
		||||
    http.get('/api/repository/', {params: {deploy_id}})
 | 
			
		||||
      .then(res => setVersions(res))
 | 
			
		||||
    if (!hostStore.records || hostStore.records.length === 0) hostStore.fetchRecords()
 | 
			
		||||
    fetchVersions()
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [])
 | 
			
		||||
 | 
			
		||||
  function fetchVersions() {
 | 
			
		||||
    setFetching(true);
 | 
			
		||||
    const deploy_id = store.record.deploy_id
 | 
			
		||||
    const p1 = http.get(`/api/app/deploy/${deploy_id}/versions/`, {timeout: 120000})
 | 
			
		||||
    const p2 = http.get('/api/repository/', {params: {deploy_id}})
 | 
			
		||||
    Promise.all([p1, p2])
 | 
			
		||||
      .then(([res1, res2]) => {
 | 
			
		||||
        if (!versions.branches) _initial(res1, res2)
 | 
			
		||||
        setVersions(res1)
 | 
			
		||||
        setRepositories(res2)
 | 
			
		||||
      })
 | 
			
		||||
      .finally(() => setFetching(false))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function handleSubmit() {
 | 
			
		||||
    if (host_ids.length === 0) {
 | 
			
		||||
      return message.error('请至少选择一个要发布的主机')
 | 
			
		||||
| 
						 | 
				
			
			@ -49,9 +70,10 @@ export default observer(function () {
 | 
			
		|||
    setLoading(true);
 | 
			
		||||
    const formData = form.getFieldsValue();
 | 
			
		||||
    formData['id'] = store.record.id;
 | 
			
		||||
    formData['deploy_id'] = store.record.deploy_id;
 | 
			
		||||
    formData['host_ids'] = host_ids;
 | 
			
		||||
    formData['type'] = store.record.type;
 | 
			
		||||
    formData['deploy_id'] = store.record.deploy_id;
 | 
			
		||||
    formData['extra'] = [git_type, extra1, extra2];
 | 
			
		||||
    if (plan) formData.plan = plan.format('YYYY-MM-DD HH:mm:00');
 | 
			
		||||
    http.post('/api/deploy/request/ext1/', formData)
 | 
			
		||||
      .then(res => {
 | 
			
		||||
| 
						 | 
				
			
			@ -61,32 +83,148 @@ export default observer(function () {
 | 
			
		|||
      }, () => setLoading(false))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _setDefault(type, new_extra, new_versions, new_repositories) {
 | 
			
		||||
    const now_extra = new_extra || extra;
 | 
			
		||||
    const now_versions = new_versions || versions;
 | 
			
		||||
    const now_repositories = new_repositories || repositories;
 | 
			
		||||
    const {branches, tags} = now_versions;
 | 
			
		||||
    if (type === 'branch') {
 | 
			
		||||
      let [branch, commit] = [now_extra[1], null];
 | 
			
		||||
      if (branches[branch]) {
 | 
			
		||||
        commit = lds.get(branches[branch], '0.id')
 | 
			
		||||
      } else {
 | 
			
		||||
        branch = lds.get(Object.keys(branches), 0)
 | 
			
		||||
        commit = lds.get(branches, [branch, 0, 'id'])
 | 
			
		||||
      }
 | 
			
		||||
      setExtra1(branch)
 | 
			
		||||
      setExtra2(commit)
 | 
			
		||||
    } else if (type === 'tag') {
 | 
			
		||||
      setExtra1(lds.get(Object.keys(tags), 0))
 | 
			
		||||
      setExtra2(null)
 | 
			
		||||
    } else {
 | 
			
		||||
      setExtra1(lds.get(now_repositories, '0.id'))
 | 
			
		||||
      setExtra2(null)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _initial(versions, repositories) {
 | 
			
		||||
    const {branches, tags} = versions;
 | 
			
		||||
    if (branches && tags) {
 | 
			
		||||
      for (let item of store.records) {
 | 
			
		||||
        if (item.extra && item.deploy_id === store.record.deploy_id) {
 | 
			
		||||
          const type = item.extra[0];
 | 
			
		||||
          setExtra(item.extra);
 | 
			
		||||
          setGitType(type);
 | 
			
		||||
          return _setDefault(type, item.extra, versions, repositories);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      setGitType('branch');
 | 
			
		||||
      const branch = lds.get(Object.keys(branches), 0);
 | 
			
		||||
      const commit = lds.get(branches, [branch, 0, 'id'])
 | 
			
		||||
      setExtra1(branch);
 | 
			
		||||
      setExtra2(commit)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function switchType(v) {
 | 
			
		||||
    setGitType(v);
 | 
			
		||||
    _setDefault(v)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function switchExtra1(v) {
 | 
			
		||||
    setExtra1(v)
 | 
			
		||||
    if (git_type === 'branch') {
 | 
			
		||||
      setExtra2(lds.get(versions.branches[v], '0.id'))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const {app_host_ids, type, rb_id} = store.record;
 | 
			
		||||
  const {branches, tags} = versions;
 | 
			
		||||
  return (
 | 
			
		||||
    <Modal
 | 
			
		||||
      visible
 | 
			
		||||
      width={700}
 | 
			
		||||
      width={800}
 | 
			
		||||
      maskClosable={false}
 | 
			
		||||
      title={`${store.record.id ? '编辑' : '新建'}发布申请`}
 | 
			
		||||
      onCancel={() => store.ext1Visible = false}
 | 
			
		||||
      confirmLoading={loading}
 | 
			
		||||
      onOk={handleSubmit}>
 | 
			
		||||
      <Form form={form} initialValues={store.record} labelCol={{span: 6}} wrapperCol={{span: 16}}>
 | 
			
		||||
      <Form form={form} initialValues={store.record} labelCol={{span: 5}} wrapperCol={{span: 17}}>
 | 
			
		||||
        <Form.Item required name="name" label="申请标题">
 | 
			
		||||
          <Input placeholder="请输入申请标题"/>
 | 
			
		||||
        </Form.Item>
 | 
			
		||||
        <Form.Item required name="repository_id" label={type === '2' ? '回滚版本' : '发布版本'}>
 | 
			
		||||
          <Select placeholder="请选择" notFoundContent={<NoVersions/>}>
 | 
			
		||||
            {versions.map(item => (
 | 
			
		||||
              <Select.Option key={item.id} value={item.id} disabled={type === '2' && item.id >= rb_id}>
 | 
			
		||||
                <div style={{display: 'flex', justifyContent: 'space-between'}}>
 | 
			
		||||
                  <span>{item.remarks ? `${item.version} (${item.remarks})` : item.version}</span>
 | 
			
		||||
                  <span style={{color: '#999', fontSize: 12}}>构建于 {moment(item.created_at).fromNow()}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
              </Select.Option>
 | 
			
		||||
            ))}
 | 
			
		||||
          </Select>
 | 
			
		||||
        <Form.Item required label="选择分支/标签/版本" style={{marginBottom: 12}} extra={<span>
 | 
			
		||||
            根据网络情况,首次刷新可能会很慢,请耐心等待。
 | 
			
		||||
            <a target="_blank" rel="noopener noreferrer"
 | 
			
		||||
               href="https://spug.cc/docs/install-error/#%E6%96%B0%E5%BB%BA%E5%B8%B8%E8%A7%84%E5%8F%91%E5%B8%83%E7%94%B3%E8%AF%B7-git-clone-%E9%94%99%E8%AF%AF">clone 失败?</a>
 | 
			
		||||
          </span>}>
 | 
			
		||||
          <Form.Item style={{display: 'inline-block', marginBottom: 0, width: '450px'}}>
 | 
			
		||||
            <Input.Group compact>
 | 
			
		||||
              <Select value={git_type} onChange={switchType} style={{width: 100}}>
 | 
			
		||||
                <Select.Option value="branch">Branch</Select.Option>
 | 
			
		||||
                <Select.Option value="tag">Tag</Select.Option>
 | 
			
		||||
                <Select.Option value="repository">构建仓库</Select.Option>
 | 
			
		||||
              </Select>
 | 
			
		||||
              <Select
 | 
			
		||||
                showSearch
 | 
			
		||||
                style={{width: 350}}
 | 
			
		||||
                value={extra1}
 | 
			
		||||
                placeholder="请稍等"
 | 
			
		||||
                onChange={switchExtra1}
 | 
			
		||||
                notFoundContent={git_type === 'repository' ? <NoVersions/> : undefined}
 | 
			
		||||
                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
 | 
			
		||||
                {git_type === 'branch' ? (
 | 
			
		||||
                  Object.keys(branches || {}).map(b => <Select.Option key={b} value={b}>{b}</Select.Option>)
 | 
			
		||||
                ) : git_type === 'tag' ? (
 | 
			
		||||
                  Object.entries(tags || {}).map(([tag, info]) => (
 | 
			
		||||
                    <Select.Option key={tag} value={tag}>
 | 
			
		||||
                      <div style={{display: 'flex', justifyContent: 'space-between'}}>
 | 
			
		||||
                        <span style={{
 | 
			
		||||
                          width: 200,
 | 
			
		||||
                          overflow: 'hidden',
 | 
			
		||||
                          textOverflow: 'ellipsis'
 | 
			
		||||
                        }}>{`${tag} ${info.author} ${info.message}`}</span>
 | 
			
		||||
                        <span style={{color: '#999', fontSize: 12}}>{info['date']} </span>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </Select.Option>
 | 
			
		||||
                  ))
 | 
			
		||||
                ) : (
 | 
			
		||||
                  repositories.map(item => (
 | 
			
		||||
                    <Select.Option key={item.id} value={item.id} disabled={type === '2' && item.id >= rb_id}>
 | 
			
		||||
                      <div style={{display: 'flex', justifyContent: 'space-between'}}>
 | 
			
		||||
                        <span>{item.remarks ? `${item.version} (${item.remarks})` : item.version}</span>
 | 
			
		||||
                        <span style={{color: '#999', fontSize: 12}}>构建于 {moment(item.created_at).fromNow()}</span>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </Select.Option>
 | 
			
		||||
                  ))
 | 
			
		||||
                )}
 | 
			
		||||
              </Select>
 | 
			
		||||
            </Input.Group>
 | 
			
		||||
          </Form.Item>
 | 
			
		||||
          <Form.Item style={{display: 'inline-block', width: 82, textAlign: 'center', marginBottom: 0}}>
 | 
			
		||||
            {fetching ? <LoadingOutlined style={{fontSize: 18, color: '#1890ff'}}/> :
 | 
			
		||||
              <Button type="link" icon={<SyncOutlined/>} disabled={fetching} onClick={fetchVersions}>刷新</Button>
 | 
			
		||||
            }
 | 
			
		||||
          </Form.Item>
 | 
			
		||||
        </Form.Item>
 | 
			
		||||
        {git_type === 'branch' && (
 | 
			
		||||
          <Form.Item required label="选择Commit ID">
 | 
			
		||||
            <Select value={extra2} placeholder="请选择" onChange={v => setExtra2(v)}>
 | 
			
		||||
              {extra1 && branches ? branches[extra1].map(item => (
 | 
			
		||||
                <Select.Option key={item.id}>
 | 
			
		||||
                  <div style={{display: 'flex', justifyContent: 'space-between'}}>
 | 
			
		||||
                    <span style={{
 | 
			
		||||
                      width: 400,
 | 
			
		||||
                      overflow: 'hidden',
 | 
			
		||||
                      textOverflow: 'ellipsis'
 | 
			
		||||
                    }}>{item.id.substr(0, 6)} {item['author']} {item['message']}</span>
 | 
			
		||||
                    <span style={{color: '#999', fontSize: 12}}>{item['date']} </span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </Select.Option>
 | 
			
		||||
              )) : null}
 | 
			
		||||
            </Select>
 | 
			
		||||
          </Form.Item>
 | 
			
		||||
        )}
 | 
			
		||||
        <Form.Item required label="目标主机" tooltip="可以通过创建多个发布申请单,选择主机分批发布。">
 | 
			
		||||
          {host_ids.length > 0 && `已选择 ${host_ids.length} 台(可选${app_host_ids.length})`}
 | 
			
		||||
          <Button type="link" onClick={() => setVisible(true)}>选择主机</Button>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
 */
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { observer } from 'mobx-react';
 | 
			
		||||
import { BranchesOutlined, BuildOutlined, TagOutlined, PlusOutlined } from '@ant-design/icons';
 | 
			
		||||
import { BranchesOutlined, BuildOutlined, TagOutlined, PlusOutlined, TagsOutlined } from '@ant-design/icons';
 | 
			
		||||
import { Radio, Modal, Popover, Tag, Popconfirm, Tooltip, message } from 'antd';
 | 
			
		||||
import { http, hasPermission } from 'libs';
 | 
			
		||||
import { Action, AuthButton, TableCard } from 'components';
 | 
			
		||||
| 
						 | 
				
			
			@ -33,17 +33,18 @@ function ComTable() {
 | 
			
		|||
    title: '版本',
 | 
			
		||||
    render: info => {
 | 
			
		||||
      if (info['app_extend'] === '1') {
 | 
			
		||||
        const [ext1] = info.rep_extra;
 | 
			
		||||
        return (
 | 
			
		||||
          <React.Fragment>
 | 
			
		||||
            {ext1 === 'branch' ? <BranchesOutlined/> : <TagOutlined/>} {info.version}
 | 
			
		||||
          </React.Fragment>
 | 
			
		||||
        )
 | 
			
		||||
        const [ext1] = info.extra || info.rep_extra;
 | 
			
		||||
        switch (ext1) {
 | 
			
		||||
          case 'branch':
 | 
			
		||||
            return <div><BranchesOutlined/> {info.version}</div>
 | 
			
		||||
          case 'tag':
 | 
			
		||||
            return <div><TagOutlined/> {info.version}</div>
 | 
			
		||||
          default:
 | 
			
		||||
            return <div><TagsOutlined/> {info.version}</div>
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        return (
 | 
			
		||||
          <React.Fragment>
 | 
			
		||||
            <BuildOutlined/> {info.version}
 | 
			
		||||
          </React.Fragment>
 | 
			
		||||
          <div><BuildOutlined/> {info.version}</div>
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue