未验证 提交 1e740305 编写于 作者: 徐超越 提交者: GitHub

Merge branch 'go-atomci:v1.5.0-feat-app-refactor' into issue-90-unittest

## 模板配置,承载完整最新的配置内容
[default]
appname = atomci
# 默认监听端口
httpport = 8080
runmode = dev
copyrequestbody = true
[log]
logfile = "log/atomci.log"
## log level
# 0: LevelEmergency = iota
# 1: LevelAlert
# 2: LevelCritical
# 3: LevelError
# 4: LevelWarning
# 5: LevelNotice
# 6: LevelInformational
# 7: LevelDebug
level = 7
separate = ["error"]
[DB]
# 数据库相关配置,目前仅支持mysql5.7+
url = root:root@tcp(127.0.0.1:3306)/atomci?charset=utf8mb4&loc=Local
debug = false
rowsLimit = 5000
maxIdelConns = 100
maxOpenConns = 200
[ldap]
# 支持配置LDAP
host = ldap.xxx.com
port = 389
bindDN = ldap@xx.com
bindPassword = Xxx..,
userFilter = (samaccountname=%s)
baseDN = OU=Xxx,DC=xx,DC=com
[jwt]
secret = changemeforsecurity
[k8s]
# k8s相关配置文件默认保存地址,一般请不要修改
configPath = ./conf/k8sconfig
[atomci]
# atomci后端服务地址,用于k8s/jenkins进行回调,因此请确保地址是可以被k8s集群(jenkins agent)访问到
url = http://localhost:8080
# 通知配置
[notification]
# 钉钉通知
dingEnable = 1
ding = "https://oapi.dingtalk.com/robot/send?access_token=faketoken"
# 邮件通知
mailEnable = 1
smtpHost = "smtp.host"
smtpPort = 465
smtpAccount = "fake@mail.com"
smtpPassword = "pwd"
\ No newline at end of file
......@@ -54,3 +54,17 @@ const (
// HelmDeployType helm 部署
HelmDeployType = "helm"
)
// integrate type
const (
SCMGitlab = "gitlab"
SCMGithub = "github"
SCMGitea = "gitea"
SCMGitee = "gitee"
IntegrateKubernetes = "kubernetes"
IntegrateJenkins = "jenkins"
IntegrateRegistry = "registry"
)
var Integratetypes = []string{IntegrateKubernetes, IntegrateJenkins, IntegrateRegistry}
var ScmIntegratetypes = []string{SCMGitlab, SCMGithub, SCMGitea, SCMGitee}
......@@ -17,6 +17,8 @@ limitations under the License.
package api
import (
"github.com/go-atomci/atomci/constant"
"github.com/go-atomci/atomci/internal/core/settings"
"github.com/go-atomci/atomci/internal/middleware/log"
)
......@@ -28,7 +30,7 @@ type IntegrateController struct {
func (p *IntegrateController) GetClusterIntegrateSettings() {
pm := settings.NewSettingManager()
rsp, err := pm.GetIntegrateSettings("kubernetes")
rsp, err := pm.GetIntegrateSettings([]string{constant.IntegrateKubernetes})
if err != nil {
p.HandleInternalServerError(err.Error())
log.Log.Error("Get integrate settings occur error: %s", err.Error())
......@@ -41,7 +43,7 @@ func (p *IntegrateController) GetClusterIntegrateSettings() {
// GetIntegrateSettings ..
func (p *IntegrateController) GetIntegrateSettings() {
pm := settings.NewSettingManager()
rsp, err := pm.GetIntegrateSettings("")
rsp, err := pm.GetIntegrateSettings(constant.Integratetypes)
if err != nil {
p.HandleInternalServerError(err.Error())
log.Log.Error("Get integrate settings occur error: %s", err.Error())
......@@ -55,7 +57,21 @@ func (p *IntegrateController) GetIntegrateSettings() {
func (p *IntegrateController) GetIntegrateSettingsByPagination() {
filterQuery := p.GetFilterQuery()
pm := settings.NewSettingManager()
rsp, err := pm.GetIntegrateSettingsByPagination(filterQuery)
rsp, err := pm.GetIntegrateSettingsByPagination(filterQuery, constant.Integratetypes)
if err != nil {
p.HandleInternalServerError(err.Error())
log.Log.Error("Get integrate settings occur error: %s", err.Error())
return
}
p.Data["json"] = NewResult(true, rsp, "")
p.ServeJSON()
}
// GetSCMIntegrateSettingsByPagination ..
func (p *IntegrateController) GetSCMIntegrateSettingsByPagination() {
filterQuery := p.GetFilterQuery()
pm := settings.NewSettingManager()
rsp, err := pm.GetIntegrateSettingsByPagination(filterQuery, constant.ScmIntegratetypes)
if err != nil {
p.HandleInternalServerError(err.Error())
log.Log.Error("Get integrate settings occur error: %s", err.Error())
......
......@@ -89,6 +89,16 @@ type RegistryConfig struct {
IsHttps bool `json:"isHttps,omitempty"`
}
type ScmBaseConfig struct {
URL string `json:"url,omitempty"`
Token string `json:"token,omitempty"`
}
type ScmGitlabConfig struct {
ScmBaseConfig
User string `json:"user,omitempty"`
}
type JenkinsConfig struct {
BaseConfig
Token string `json:"token,omitempty"`
......@@ -116,6 +126,14 @@ func (config *Config) Struct(sc string, settingType string) (interface{}, error)
registry := &RegistryConfig{}
err := json.Unmarshal([]byte(sc), registry)
return registry, err
case "gitlab":
scmConf := &ScmGitlabConfig{}
err := json.Unmarshal([]byte(sc), scmConf)
return scmConf, err
case "gitea", "gitee", "github":
scmConf := &ScmBaseConfig{}
err := json.Unmarshal([]byte(sc), scmConf)
return scmConf, err
default:
log.Log.Warn("this settings type %s is not support, return origin string", settingType)
return sc, nil
......@@ -130,8 +148,8 @@ func NewSettingManager() *SettingManager {
}
// GetIntegrateSettings ..
func (pm *SettingManager) GetIntegrateSettings(integrateType string) ([]*IntegrateSettingResponse, error) {
items, err := pm.model.GetIntegrateSettings(integrateType)
func (pm *SettingManager) GetIntegrateSettings(integrateTypes []string) ([]*IntegrateSettingResponse, error) {
items, err := pm.model.GetIntegrateSettings(integrateTypes)
if err != nil {
log.Log.Error("get interate settings error: %s", err.Error())
return nil, err
......@@ -152,8 +170,8 @@ func (pm *SettingManager) GetIntegrateSettingByID(id int64) (*IntegrateSettingRe
}
// GetIntegrateSettingsByPagination ..
func (pm *SettingManager) GetIntegrateSettingsByPagination(filter *query.FilterQuery) (*query.QueryResult, error) {
queryResult, settingsList, err := pm.model.GetIntegrateSettingsByPagination(filter)
func (pm *SettingManager) GetIntegrateSettingsByPagination(filter *query.FilterQuery, intergrateTypes []string) (*query.QueryResult, error) {
queryResult, settingsList, err := pm.model.GetIntegrateSettingsByPagination(filter, intergrateTypes)
if err != nil {
return nil, err
}
......
......@@ -50,11 +50,11 @@ func (model *SysSettingModel) GetIntegrateSettingByID(integrateSettingID int64)
}
// GetIntegrateSettings ...
func (model *SysSettingModel) GetIntegrateSettings(integrateType string) ([]*models.IntegrateSetting, error) {
func (model *SysSettingModel) GetIntegrateSettings(integrateTypes []string) ([]*models.IntegrateSetting, error) {
integrateSettings := []*models.IntegrateSetting{}
qs := model.ormer.QueryTable(model.IntegrateSettingTableName).Filter("deleted", false)
if integrateType != "" {
qs = qs.Filter("type", integrateType)
if len(integrateTypes) > 0 {
qs = qs.Filter("type__in", integrateTypes)
}
_, err := qs.All(&integrateSettings)
if err != nil {
......@@ -64,7 +64,7 @@ func (model *SysSettingModel) GetIntegrateSettings(integrateType string) ([]*mod
}
// GetIntegrateSettingsByPagination ..
func (model *SysSettingModel) GetIntegrateSettingsByPagination(filter *query.FilterQuery) (*query.QueryResult, []*models.IntegrateSetting, error) {
func (model *SysSettingModel) GetIntegrateSettingsByPagination(filter *query.FilterQuery, intergrateTypes []string) (*query.QueryResult, []*models.IntegrateSetting, error) {
rst := &query.QueryResult{Item: []*models.IntegrateSetting{}}
queryCond := orm.NewCondition().AndCond(orm.NewCondition().And("deleted", false))
......@@ -72,6 +72,9 @@ func (model *SysSettingModel) GetIntegrateSettingsByPagination(filter *query.Fil
queryCond = queryCond.AndCond(filterCond)
}
qs := model.ormer.QueryTable(model.IntegrateSettingTableName).OrderBy("-create_at").SetCond(queryCond)
if len(intergrateTypes) > 0 {
qs = qs.Filter("type__in", intergrateTypes)
}
count, err := qs.Count()
if err != nil {
return nil, nil, err
......
......@@ -81,6 +81,7 @@ func RegisterRoutes() {
// Integrate Settings
beego.NSRouter("/integrate/settings", &api.IntegrateController{}, "get:GetIntegrateSettings;post:GetIntegrateSettingsByPagination"),
beego.NSRouter("/integrate/settings/create", &api.IntegrateController{}, "post:CreateIntegrateSetting"),
beego.NSRouter("/integrate/settings/scms", &api.IntegrateController{}, "post:GetSCMIntegrateSettingsByPagination"),
beego.NSRouter("/integrate/settings/:id", &api.IntegrateController{}, "put:UpdateIntegrateSetting;delete:DeleteIntegrateSetting"),
beego.NSRouter("/integrate/settings/verify", &api.IntegrateController{}, "post:VerifyIntegrateSetting"),
beego.NSRouter("/integrate/clusters", &api.IntegrateController{}, "get:GetClusterIntegrateSettings"),
......
......@@ -713,8 +713,8 @@ const backendAPI = {
getIntegrateSettings(body, cb) {
Package.httpMethods('post', '/atomci/api/v1/integrate/settings', cb, body);
},
getStagesAll(cb) {
Package.httpMethods('get', '/atomci/api/v1/integrate/settings', cb);
getSCMIntegrateSettings(body, cb) {
Package.httpMethods('post', '/atomci/api/v1/integrate/settings/scms', cb, body);
},
AddIntegrateSetting(body,cb) {
Package.httpMethods('post', '/atomci/api/v1/integrate/settings/create', cb, body);
......
......@@ -80,6 +80,12 @@ export const asyncRoutes = [
name: 'serviceIntegrate',
meta: { title: '服务集成', noCache: true }
},
{
path: '/settings/smcintegrate',
component: () => import('@/views/setting/ScmIntegrate.vue'),
name: 'scmIntegrate',
meta: { title: '代码源集成', noCache: true }
},
{
path: '/settings/task',
component: () => import('@/views/setting/Node.vue'),
......
......@@ -125,8 +125,6 @@ export default {
case 'registry':
this.registryList.push(element)
break;
default:
console.log("this type not support", element.type)
}
});
}
......
<template>
<div class="portlet-body">
<template>
<div class="table-toolbar">
<el-row>
<el-col :span="10">
<refresh v-on:getlist="getList"></refresh>
<el-button :plain="true" type="primary" @click="$refs.create.doCreate(false)">
<i class='icon-plus' /> 新建</el-button>
</el-col>
<el-col :span="6">
&nbsp;
</el-col>
<el-col :span="8">
<list-search ref="userSh" :searchList="searchList" v-on:changeFilterTxt="changeFilterTxt"></list-search>
</el-col>
</el-row>
</div>
<template>
<el-table stripe :data="dataList">
<span slot="empty">
{{loading?$t('bm.add.dataLoading'):noDataTxt}}
</span>
<el-table-column prop="name" label="名称" sortable min-width="15%" :show-overflow-tooltip=true />
<el-table-column prop="type" label="类型" sortable min-width="20%" :show-overflow-tooltip=true>
<template slot-scope="scope">
<div v-if="scope.row.type === 'gitee'">
<el-tag type="danger">{{scope.row.type}}</el-tag>
</div>
<div v-else-if="scope.row.type === 'gitea'">
<el-tag type="success">{{scope.row.type}}</el-tag>
</div>
<div v-else>
<el-tag>{{scope.row.type}}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="description" label="描述信息" min-width="20%" :show-overflow-tooltip=true />
<el-table-column prop="creator" :label="$t('bm.serviceM.creator')" sortable min-width="10%" :show-overflow-tooltip=true />
<el-table-column prop="create_at" :label="$t('bm.serviceM.creationTime')" sortable min-width="15%" :show-overflow-tooltip=true />
<el-table-column :label="$t('bm.deployCenter.operation')" min-width="15%">
<template slot-scope="scope">
<el-button type="text" size="small" @click="$refs.create.doCreate(true, scope.row)">{{$t('bm.infrast.edit')}}
</el-button>
<el-button @click="$refs.commonDelete.doDelete('delIntegrateSetting',scope.row.id)" type="text" size="small">{{$t('bm.other.delete')}}
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<page-nav ref="pages"
:list="curList"
v-on:getlist="getList"></page-nav>
</template>
<common-delete ref="commonDelete" v-on:getlist="getList"></common-delete>
<scm-integrate-create ref="create" v-on:getlist="getList"></scm-integrate-create>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import backend from '@/api/backend';
import ListSearch from '@/components/utils/ListSearch';
import PageNav from '@/components/utils/PageList';
import CommonDelete from '@/components/utils/Delete';
import Refresh from '@/components/utils/Refresh';
import listTemplate from '@/common/listTemplate';
import Utils from '@/common/utils';
import ScmIntegrateCreate from './components/ScmIntegrateCreate';
export default {
mixins: [listTemplate],
data() {
return {
curList: [],
searchList: [
{ key: 'type', txt: '配置类型'},
{ key: 'creator', txt: this.$t('bm.serviceM.creator') },
],
filterTxt: '',
detailInfo: [],
param: {},
searchVal: '',
searchType: '',
};
},
components: {
ListSearch,
PageNav,
Refresh,
ScmIntegrateCreate,
CommonDelete,
},
mounted() {
// this.getList();
},
mounted() {
this.getList(true);
},
computed: {
...mapGetters({
loading: 'getLoading',
}),
dataList() {
// 强制替换dataList替代listtemplate中的方法
return this.curList;
},
},
methods: {
goEdit(user) {
this.$refs.create.doCreate(true, user);
},
getList(isRefresh) {
if (isRefresh) {
this.$refs.pages.currentPage = 1;
}
if (isRefresh === 'clear') {
this.$refs.userSh.searchSelectChange();
this.$refs.pages.currentPage = 1;
}
this.curList = [];
backend.getSCMIntegrateSettings(
JSON.stringify({
page_size: this.$refs.pages.pageSize,
page_index: this.$refs.pages.currentPage,
filter_key: this.searchType,
filter_val: this.searchVal,
}),
data => {
this.$refs.pages.total = data.total;
this.curList = data.item;
this.curList = data.item.map(i => {
i.create_at = Utils.format(new Date(i.create_at), 'yyyy-MM-dd hh:mm');
return i;
});
}
);
},
changeFilterTxt(val, type) {
this.searchVal = val;
this.searchType = type;
this.getList(false);
},
},
};
</script>
<style>
.createDialog .el-dialog__body .el-form-item .el-form-item__content {
display: flex;
flex-direction: column;
}
.form-item {
margin-left: 22px;
margin-right: 22px;
}
.el-drawer__body {
overflow-y: scroll;
margin-bottom: 20px;
}
</style>
<template>
<el-drawer :title="title" :visible.sync="dialogFormVisible" :direction="direction" :before-close="handleClose">
<div style="overflow-y: scroll">
<el-form :model="form" ref="ruleForm" :rules="rules">
<el-form-item label="名称" prop="name" class="form-item">
<el-input v-model.trim="form.name" auto-complete="off" maxlength="60" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="配置类型" prop="type" class="form-item">
<el-select v-model="form.type" placeholder="请选择" filterable :disabled="isEdit" @change="setDefaultSCMURL()">
<el-option v-for="(item, index) in settingTypeList" :key="index" :label="item.name" :value="item.name">
</el-option>
</el-select>
</el-form-item>
<div v-if="form.type ==='gitlab'">
<el-form-item label="地址" prop="config.url" class="form-item">
<el-input v-model.trim="form.config.url" auto-complete="off" placeholder="请输入gitlab地址,eg: https://gitlab.com"></el-input>
</el-form-item>
<el-form-item label="用户名" prop="config.user" class="form-item">
<el-input v-model.trim="form.config.user" auto-complete="off" placeholder="请输入gitlab用户名"></el-input>
</el-form-item>
<el-form-item label="Token" prop="config.token" class="form-item">
<el-input v-model.trim="form.config.token" placeholder="请输入gitlab用户名对应token"></el-input>
</el-form-item>
</div>
<div v-else-if="form.type ==='github' || form.type ==='gitee' || form.type ==='gitea'">
<el-form-item label="地址" prop="config.url" class="form-item" >
<el-input v-model.trim="form.config.url" auto-complete="off" :disabled="disabledEditURL" placeholder="请输入代码源地址"></el-input>
</el-form-item>
<el-form-item label="Token" prop="config.token" class="form-item">
<el-input v-model.trim="form.config.token" auto-complete="off" maxlength="120" placeholder="请输入代码源Token"></el-input>
</el-form-item>
</div >
<el-form-item label="描述" prop="description" class="form-item">
<el-input v-model="form.description" auto-complete="off" maxlength="80" placeholder="请输入描述" ></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="success" @click="doTestConnection" :loading="loading">测试连接</el-button>
<el-button type="primary" @click="doSubmit" :loading="loading">{{$t('bm.other.confirm')}}</el-button>
</div>
</div>
</el-drawer>
</template>
<script>
import { mapGetters } from 'vuex';
import { Message } from 'element-ui';
import backend from '@/api/backend';
import createTemplate from '@/common/createTemplate';
import validate from '@/common/validate';
const formData = {
name: '',
type: '',
config: {},
description: '',
};
export default {
mixins: [createTemplate, validate],
data() {
return {
name: '',
disabledEditURL: false,
groupRoleList: [],
settingTypeList: [
{"name": "gitlab"},
{"name": "github"},
{"name": "gitee"},
{"name": "gitea"},
],
direction: 'rtl',
// 是否属于编辑状态
isEdit: false,
dialogFormVisible: false,
form: JSON.parse(JSON.stringify(formData)),
title: '新增',
rules: {
name: [
{ required: true, message: '请输入名称', trigger: 'blur' },
],
type: [
{ required: true, message: '请选择集成服务的类型', trigger: 'blur' },
],
'config.url': [
{ required: true, message: '请输入url信息', trigger: 'blur' },
],
'config.user': [
{ required: true, message: '请输入用户名', trigger: 'blur' },
],
'config.conf': [
{ required: true, message: '请输入kubernetes conf', trigger: 'blur' },
],
'config.token': [
{ required: true, message: '请输入token信息', trigger: 'blur' },
],
description: [
{ required: false, message: '描述信息不能为空', trigger: 'blur' },
],
},
rowId: '',
};
},
computed: {
...mapGetters({
loading: 'getPopLoading',
}),
},
created() {
},
methods: {
setDefaultSCMURL() {
switch (this.form.type) {
case 'gitee':
this.form.config.url = 'https://gitee.com'
this.disabledEditURL = true
break;
case 'github':
this.form.config.url = 'https://github.com'
this.disabledEditURL = true
break;
default:
this.form.config.url = ''
this.disabledEditURL = false
}
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
doCreate(flag, item) {
this.isEdit = flag;
if (flag) {
this.title = '编辑配置';
this.form = {
name: item.name || '',
type: item.type || '',
config: item.config || {},
description: item.description || '',
};
switch (item.type) {
case 'gitee':
this.disabledEditURL = true
break;
case 'github':
this.disabledEditURL = true
break;
default:
}
this.rowId = item.id;
} else {
this.title = '新增配置';
this.form = {
name: '',
type: '',
config: {},
description: '',
};
this.rowId = '';
}
this.dialogFormVisible = true
this.isEdit = flag;
},
doTestConnection() {
Message.info('comming soon');
},
doSubmit() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
const successCallBack = () => {
this.$emit('getlist');
Message.success(this.$t('bm.add.optionSuc'));
this.dialogFormVisible = false;
};
const cl = {
name: this.form.name,
config: this.form.config,
type: this.form.type,
description: this.form.description,
};
if (this.isEdit) {
backend.editIntegrateSetting(this.rowId, cl, () => {
successCallBack();
});
} else {
backend.AddIntegrateSetting(cl, () => {
successCallBack();
});
}
}
});
},
},
};
</script>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册