diff --git a/README.md b/README.md index c2c61c78e..50b0d7cc0 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ ## What is KubeSphere +> English | [中文](README_zh.md) + [KubeSphere](https://kubesphere.io/) is an enterprise-grade multi-tenant container management platform that built on [Kubernetes](https://kubernetes.io). It provides an easy-to-use UI for users to manage computing resources with a few clicks, which reduces the learning curve and empowers the DevOps teams. It greatly reduces the complexity of the daily work of development, testing, operation and maintenance, aiming to alleviate the pain points of Kubernetes' storage, network, security and ease of use, etc. > See this [document](https://docs.kubesphere.io/advanced-v2.0/zh-CN/introduction/intro/) that describes the KubeSphere landscape and details. @@ -54,7 +56,11 @@ KubeSphere Advanced Edition 2.0.2 was released on **July 9th, 2019**. See the [R ## Installation -### Minimum Requirements +### Deploy On Kubernetes + +You can deploy KubeSphere on any Kubernetes cluster,please refer to [KubeSphere on Kubernetes](https://github.com/kubesphere/ks-installer). + +### Deploy on Linux - Operating Systems - CentOS 7.5 (64 bit) @@ -69,18 +75,16 @@ KubeSphere Advanced Edition 2.0.2 was released on **July 9th, 2019**. See the [R [All-in-One](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/all-in-one/): For those who are new to KubeSphere and looking for the fastest way to install and experience the dashboard. Execute following commands to download and install KubeSphere in a single node. ```bash -$ curl -L https://kubesphere.io/download/stable/advanced-2.0.2 > advanced-2.0.2.tar.gz && tar -zxf advanced-2.0.2.tar.gz && cd kubesphere-all-advanced-2.0.2/scripts +$ curl -L https://kubesphere.io/download/stable/advanced-2.0.2 > advanced-2.0.2.tar.gz \ +&& tar -zxf advanced-2.0.2.tar.gz && cd kubesphere-all-advanced-2.0.2/conf $ ./install.sh ``` Choose `"1) All-in-one"` to trigger the installation. Generally, you can install it directly without any configuration. For details please reference [All-in-One](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/all-in-one/). -> Click [here](https://asciinema.org/~lilin) to preview the installation demo. - -### Multi-Node - -[Multi-Node](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/multi-node/) is used for installing KubeSphere on multiple instances, supports for installing a highly available cluster in a mission-critical environment. Multi-node installation requires pre-configuration steps, see [Multi-Node Guide](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/multi-node/). - +> Note: +> - In a formal environment, it's highly recommended to install KubeSphere with [Multi-Node Installation](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/multi-node/). +> - Click [here](https://asciinema.org/~lilin) to preview the installation demo. ## To start using KubeSphere @@ -110,7 +114,7 @@ Currently, KubeSphere has released the following 4 major editions. The future re ## Support, Discussion, and Community -If you need any help with KubeSphere, please join us at [Slack channel](http://kubesphere.slack.com/). +If you need any help with KubeSphere, please join us at [Slack Channel](https://join.slack.com/t/kubesphere/shared_invite/enQtNTE3MDIxNzUxNzQ0LTZkNTdkYWNiYTVkMTM5ZThhODY1MjAyZmVlYWEwZmQ3ODQ1NmM1MGVkNWEzZTRhNzk0MzM5MmY4NDc3ZWVhMjE). Please submit any KubeSphere bugs, issues, and feature requests to [KubeSphere GitHub Issue](https://github.com/kubesphere/kubesphere/issues). diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 000000000..81a9acf41 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,127 @@ +# KubeSphere +[![License](http://img.shields.io/badge/license-apache%20v2-blue.svg)](https://github.com/KubeSphere/KubeSphere/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/kubesphere/kubesphere.svg?branch=master)](https://travis-ci.org/kubesphere/kubesphere) +[![KubeSphere release](https://img.shields.io/github/release/kubesphere/kubesphere.svg?color=release&label=release&logo=release&logoColor=release)](https://github.com/kubesphere/kubesphere/releases/tag/advanced-2.0.2) + +![logo](docs/images/kubesphere-logo.png) + +---- + +## KubeSphere 是什么 + +> [English](README.md) | 中文 + +[KubeSphere](https://kubesphere.io/) 是在 [Kubernetes](https://kubernetes.io) 之上构建的以**应用为中心的**多租户**容器管理平台**,支持部署和运行在**任何基础设施之上**,提供**简单易用的操作界面**以及**向导式操作**方式,在降低用户使用容器调度平台学习成本的同时,极大减轻开发、测试、运维的日常工作的复杂度,旨在解决 Kubernetes 本身存在的存储、网络、安全和易用性等痛点。帮助企业轻松应对**敏捷开发、自动化运维、应用快速交付、微服务治理、多租户管理、监控日志告警、服务与网络管理、镜像仓库**等业务场景。 + +KubeSphere 已大规模服务于社区用户,广泛地应用在以容器为中心的开发测试及生产环境,大量服务平稳地运行在 KubeSphere 之上。 + +> 说明:KubeSphere 目前最新的版本为高级版 2.0.2,并且所有版本 100% 开源,关于 KubeSphere 更详细的介绍与说明请参阅 [产品介绍](https://docs.kubesphere.io/advanced-v2.0/zh-CN/introduction/intro/)。 + +![Dashboard](docs/images/dashboard-zh.png) + +## 核心功能 + +- Kubernetes 资源管理:纳管多种类型的 K8s 资源,提供易用友好的向导式 UI +- 应用编排与管理:包括**一键部署应用**、**Helm Chart 可视化管理**、**应用生命周期管理**,后续将支持计量计费 +- 微服务治理:基于 Istio 提供可视化无代码侵入的**灰度发布、熔断、流量管控、Tracing**,兼容**Spring Cloud & Dubbo** +- 容器化 DevOps:提供**可视化编辑 CI/CD 流水线**,包括从开发测试到持续部署上线的**全流程管理**,提供 [S2i](https://kubesphere.io/docs/advanced-v2.0/zh-CN/quick-start/source-to-image/) +- 多租户管理:提供基于角色的细粒度**多租户统一认证**,支持**对接企业 LDAP/AD**,提供多层级的权限管理满足多组织架构的企业用户 +- 日志查询与收集:提供基于多租户和多维度的日志查询,并支持快速对接多种日志收集平台 +- 多维度监控:提供集群与应用级别多项监控指标,提供按节点、企业空间、项目等资源用量的排行 +- 多租户告警系统:支持基于多租户、多维度的告警,提供丰富的监控告警指标,可自定义告警策略,支持邮件通知 +- 基础设施管理:提供主机管理、存储类型管理、CPU 与内存等资源配额管理 +- 支持多种网络方案:支持 Calico、Flannel,提供面向物理部署 Kubernetes 的 LB 插件 [Porter](https://github.com/kubesphere/porter) 和云上[负载均衡器插件](https://github.com/yunify/qingcloud-cloud-controller-manager) +- 支持多种存储:支持 GlusterFS、CephRBD、NFS,支持 [企业级分布式存储 NeonSAN](https://www.qingcloud.com/products/qingstor-neonsan/) 和 [QingCloud 云平台块存储](https://docs.qingcloud.com/product/storage/volume/) +- 支持 GPU 节点 + + +> 说明 +> - 点击 [KubeSphere 快览](docs/screenshots.md) 快速查看 KubeSphere UI; +> - 更多详细的功能解读与说明,请查阅 [产品功能](https://docs.kubesphere.io/advanced-v2.0/zh-CN/introduction/features/)。 + +---- + +## 架构 + +KubeSphere 采用了前后端分离的架构设计,后端的各个功能组件可通过 REST API 对接外部系统,KubeSphere 可以运行在任何 Kubernetes、私有云、公有云、VM 或物理环境之上。 + +![](docs/images/architecture-zh.png) + +## 最新发布 + +KubeSphere 高级版 (Advanced Edition 2.0.2) 已于 2019 年 7 月 9 日 正式发布,点击 [Release Notes For 2.0.2](https://docs.kubesphere.io/advanced-v2.0/zh-CN/release/release-v202/) 查看 2.0.2 版本的更新详情。 + +## 快速安装 + +### 部署在 Linux + +- 操作系统 + - CentOS 7.5 (64 bit) + - Ubuntu 16.04/18.04 LTS (64 bit) + - Red Hat Enterprise Linux Server 7.4 (64 bit) + - Debian Stretch 9.5 (64 bit) +- 配置规格(最低) + - CPU:8 Core, 内存:16 G, 硬盘:100 G + +#### All-in-One + +[All-in-One](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/all-in-one/): 对于首次接触 KubeSphere 高级版的用户,想寻找一个最快安装和体验 KubeSphere 高级版核心功能的方式,All-in-one 模式支持一键安装 KubeSphere 至一台目标机器。 + +```bash +$ curl -L https://kubesphere.io/download/stable/advanced-2.0.2 > advanced-2.0.2.tar.gz \ +&& tar -zxf advanced-2.0.2.tar.gz && cd kubesphere-all-advanced-2.0.2/conf +$ ./install.sh +``` + +直接选择 `"1) All-in-one"` 即可开始快速安装,可点击 [安装 Demo](https://asciinema.org/~lilin) 预览 All-in-one 安装。 + +> 注意:All-in-One 仅适用于**测试体验**,**正式环境**安装和使用请参考 [Multi-Node 安装指南](https://docs.kubesphere.io/advanced-v2.0/zh-CN/installation/multi-node/) 安装多节点环境。 + +### 部署在 Kubernetes + +KubeSphere 支持部署在现有的 Kubernetes 集群之上,请参考 [KubeSphere on Kubernetes](https://github.com/kubesphere/ks-installer)。 + + +## 开始使用 KubeSphere + +### 快速入门 + +[KubeSphere 快速入门](https://docs.kubesphere.io/advanced-v2.0/quick-start/admin-quick-start/) 通过 13 个 Step-by-Step 的快速入门的示例教程帮助您了解 KubeSphere 容器平台的基本使用流程,带您快速上手 KubeSphere。 + +### 文档 + +- [KubeSphere 文档中心 (En/中) ](https://docs.kubesphere.io/) +- [KubeSphere 文档 (PDF)](https://docs.kubesphere.io/KubeSphere-advanced-v2.0.pdf) +- [API 文档](https://kubesphere.io/docs/advanced-v2.0/zh-CN/api-reference/api-docs/) + + +## 开发 KubeSphere + +[开发指南](CONTRIBUTING.md) 详细说明了如何从源码编译、KubeSphere 的 GitHub 工作流、如何贡献代码以及如何测试等。 + + +## 路线图 + +目前,KubeSphere 已发布了 4 个大版本和 3 个小版本,所有版本都是完全开源的,为 KubeSphere 社区用户提供服务。下一个版本 KubeSphere 将对各个功能组件的依赖进行解耦,各模块都设计成可插拔式,并将支持多集群、大数据、AI 平台以及 SDN 等应用场景。 + +**Community Edition** => **Express Edition** => **Advanced Edition 1.0.0** => **Advanced Edition 2.0.x** + +![Roadmap](docs/images/roadmap-2.0.2-zh.png) + + +## 技术社区 + +- [Slack Channel](https://join.slack.com/t/kubesphere/shared_invite/enQtNTE3MDIxNzUxNzQ0LTZkNTdkYWNiYTVkMTM5ZThhODY1MjAyZmVlYWEwZmQ3ODQ1NmM1MGVkNWEzZTRhNzk0MzM5MmY4NDc3ZWVhMjE) + +- 微信群 (与工程师和用户们交流云原生技术,请备注 “公司 - 名字”) + + + + +## Bug 与建议反馈 + +KubeSphere 的日益完善与快速发展离不开社区用户的支持,KubeSphere 也一直在反哺社区,为开源用户提供更多的支持。若您安装使用时有任何建议问题、反馈或发现的 Bug,欢迎在 [GitHub Issue](https://github.com/kubesphere/kubesphere/issues) 提交 Issue。 + + + + diff --git a/docs/images/architecture-zh.png b/docs/images/architecture-zh.png new file mode 100644 index 000000000..910663b2f Binary files /dev/null and b/docs/images/architecture-zh.png differ diff --git a/docs/images/dashboard-zh.png b/docs/images/dashboard-zh.png new file mode 100644 index 000000000..5302af6fd Binary files /dev/null and b/docs/images/dashboard-zh.png differ diff --git a/docs/images/roadmap-2.0.2-en.png b/docs/images/roadmap-2.0.2-en.png index 7e09e64fc..2b2aca1de 100644 Binary files a/docs/images/roadmap-2.0.2-en.png and b/docs/images/roadmap-2.0.2-en.png differ diff --git a/docs/images/roadmap-2.0.2-zh.png b/docs/images/roadmap-2.0.2-zh.png new file mode 100644 index 000000000..601256746 Binary files /dev/null and b/docs/images/roadmap-2.0.2-zh.png differ diff --git a/go.mod b/go.mod index e41c23d81..95a59f6db 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( github.com/knative/pkg v0.0.0-20190314204845-cd278f2d3394 github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/kubernetes-sigs/application v0.0.0-20190404151855-67ae7f915d4e - github.com/kubesphere/s2ioperator v0.0.12 + github.com/kubesphere/s2ioperator v0.0.13 github.com/kubesphere/sonargo v0.0.2 github.com/leodido/go-urn v1.1.0 // indirect github.com/lib/pq v1.2.0 // indirect diff --git a/go.sum b/go.sum index 5324008a3..2069d4fb1 100644 --- a/go.sum +++ b/go.sum @@ -271,6 +271,8 @@ github.com/kubesphere/kiali v0.15.1-0.20190407071308-6b5b818211c3 h1:5IASnVaVqZF github.com/kubesphere/kiali v0.15.1-0.20190407071308-6b5b818211c3/go.mod h1:Y1EqeixoXkKkU8I+yvOfhdh21+8+etFE6wYOVT2XFdI= github.com/kubesphere/s2ioperator v0.0.12 h1:gEDDjKw7q7gQUuy5qtBIV/adZEwk5liJUBL4CqyOOOY= github.com/kubesphere/s2ioperator v0.0.12/go.mod h1:dv9L+zRYDlHvnKPp0j6VHRtlGB1BU+lloltW9SAWqVU= +github.com/kubesphere/s2ioperator v0.0.13 h1:K6RdjaFluhn/GterbnIykORrueAZcwR/Qj3MsVI4qQs= +github.com/kubesphere/s2ioperator v0.0.13/go.mod h1:dv9L+zRYDlHvnKPp0j6VHRtlGB1BU+lloltW9SAWqVU= github.com/kubesphere/sonargo v0.0.2 h1:hsSRE3sv3mkPcUAeSABdp7rtfcNW2zzeHXzFa01CTkU= github.com/kubesphere/sonargo v0.0.2/go.mod h1:ww8n9ANlDXhX5PBZ18iaRnCgEkXN0GMml3/KZXOZ11w= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= diff --git a/pkg/apis/devops/v1alpha2/register.go b/pkg/apis/devops/v1alpha2/register.go index 0622b2f2a..ceafb729d 100644 --- a/pkg/apis/devops/v1alpha2/register.go +++ b/pkg/apis/devops/v1alpha2/register.go @@ -351,6 +351,25 @@ The last one is encrypted info, such as the password of the username-password ty Returns(http.StatusOK, RespOK, []devops.SCMOrg{}). Writes([]devops.SCMOrg{})) + // match "/blue/rest/organizations/jenkins/scm/%s/servers/" + webservice.Route(webservice.GET("/scms/{scm}/servers"). + To(devopsapi.GetSCMServers). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsScmTag}). + Doc("List all servers in the jenkins."). + Param(webservice.PathParameter("scm", "The ID of the source configuration management (SCM).")). + Returns(http.StatusOK, RespOK, []devops.SCMServer{}). + Writes([]devops.SCMServer{})) + + // match "/blue/rest/organizations/jenkins/scm/%s/servers/" + webservice.Route(webservice.POST("/scms/{scm}/servers"). + To(devopsapi.CreateSCMServers). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsScmTag}). + Doc("Create scm server in the jenkins."). + Param(webservice.PathParameter("scm", "The ID of the source configuration management (SCM).")). + Reads(devops.CreateScmServerReq{}). + Returns(http.StatusOK, RespOK, devops.SCMServer{}). + Writes(devops.SCMServer{})) + // match "/blue/rest/organizations/jenkins/scm/{scm}/organizations/{organization}/repositories/?credentialId=&pageNumber&pageSize=" webservice.Route(webservice.GET("/scms/{scm}/organizations/{organization}/repositories"). To(devopsapi.GetOrgRepo). diff --git a/pkg/apis/tenant/v1alpha2/register.go b/pkg/apis/tenant/v1alpha2/register.go index 7e148b30e..379897c56 100644 --- a/pkg/apis/tenant/v1alpha2/register.go +++ b/pkg/apis/tenant/v1alpha2/register.go @@ -134,6 +134,13 @@ func addWebService(c *restful.Container) error { Returns(http.StatusOK, ok, models.PageableResponse{}). Doc("List the devops projects for the workspace member"). Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) + ws.Route(ws.GET("/devopscount"). + To(tenant.GetDevOpsProjectsCount). + Returns(http.StatusOK, ok, struct { + Count uint32 `json:"count"` + }{}). + Doc("Get the devops projects count for the member"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) ws.Route(ws.POST("/workspaces/{workspace}/devops"). To(tenant.CreateDevopsProject). Param(ws.PathParameter("workspace", "workspace name")). diff --git a/pkg/apiserver/devops/devops.go b/pkg/apiserver/devops/devops.go index 8e41d9fd2..e4b892ee9 100644 --- a/pkg/apiserver/devops/devops.go +++ b/pkg/apiserver/devops/devops.go @@ -141,6 +141,32 @@ func GetStepLog(req *restful.Request, resp *restful.Response) { resp.Write(res) } +func GetSCMServers(req *restful.Request, resp *restful.Response) { + scmId := req.PathParameter("scm") + + res, err := devops.GetSCMServers(scmId, req.Request) + if err != nil { + parseErr(err, resp) + return + } + + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) + resp.Write(res) +} + +func CreateSCMServers(req *restful.Request, resp *restful.Response) { + scmId := req.PathParameter("scm") + + res, err := devops.CreateSCMServers(scmId, req.Request) + if err != nil { + parseErr(err, resp) + return + } + + resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON) + resp.Write(res) +} + func Validate(req *restful.Request, resp *restful.Response) { scmId := req.PathParameter("scm") diff --git a/pkg/apiserver/tenant/tenant.go b/pkg/apiserver/tenant/tenant.go index 4e7e52d7f..23557d075 100644 --- a/pkg/apiserver/tenant/tenant.go +++ b/pkg/apiserver/tenant/tenant.go @@ -24,6 +24,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" k8serr "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/net" + "k8s.io/klog" "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" "kubesphere.io/kubesphere/pkg/apiserver/logging" "kubesphere.io/kubesphere/pkg/constants" @@ -244,6 +245,19 @@ func ListDevopsProjects(req *restful.Request, resp *restful.Response) { resp.WriteAsJson(result) } +func GetDevOpsProjectsCount(req *restful.Request, resp *restful.Response) { + username := req.HeaderParameter(constants.UserNameHeader) + + result, err := tenant.GetDevOpsProjectsCount(username) + if err != nil { + klog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + resp.WriteAsJson(struct { + Count uint32 `json:"count"` + }{Count: result}) +} func DeleteDevopsProject(req *restful.Request, resp *restful.Response) { projectId := req.PathParameter("devops") workspaceName := req.PathParameter("workspace") diff --git a/pkg/models/devops/devops.go b/pkg/models/devops/devops.go index 824752463..663ee31a2 100644 --- a/pkg/models/devops/devops.go +++ b/pkg/models/devops/devops.go @@ -135,6 +135,55 @@ func GetStepLog(projectName, pipelineName, runId, nodeId, stepId string, req *ht } +func GetSCMServers(scmId string, req *http.Request) ([]byte, error) { + baseUrl := fmt.Sprintf(jenkins.Server+GetSCMServersUrl, scmId) + log.Info("Jenkins-url: " + baseUrl) + req.Method = http.MethodGet + resBody, err := sendJenkinsRequest(baseUrl, req) + if err != nil { + log.Error(err) + return nil, err + } + return resBody, err +} + +func CreateSCMServers(scmId string, req *http.Request) ([]byte, error) { + requestBody, err := ioutil.ReadAll(req.Body) + if err != nil { + log.Error(err) + return nil, err + } + createReq := &CreateScmServerReq{} + err = json.Unmarshal(requestBody, createReq) + if err != nil { + log.Error(err) + return nil, err + } + req.Body = nil + byteServers, err := GetSCMServers(scmId, req) + if err != nil { + log.Error(err) + return nil, err + } + var servers []*SCMServer + _ = json.Unmarshal(byteServers, &servers) + for _, server := range servers { + if server.ApiURL == createReq.ApiURL { + return json.Marshal(server) + } + } + req.Body = ioutil.NopCloser(bytes.NewReader(requestBody)) + baseUrl := fmt.Sprintf(jenkins.Server+CreateSCMServersUrl, scmId) + log.Info("Jenkins-url: " + baseUrl) + req.Method = http.MethodPost + resBody, err := sendJenkinsRequest(baseUrl, req) + if err != nil { + log.Error(err) + return nil, err + } + return resBody, err +} + func Validate(scmId string, req *http.Request) ([]byte, error) { baseUrl := fmt.Sprintf(jenkins.Server+ValidateUrl, scmId) log.Info("Jenkins-url: " + baseUrl) @@ -731,7 +780,7 @@ func jenkinsClient(baseUrl string, req *http.Request) ([]byte, http.Header, erro log.Errorf("%+v", string(resBody)) jkerr := new(JkError) jkerr.Code = resp.StatusCode - jkerr.Message = http.StatusText(resp.StatusCode) + jkerr.Message = string(resBody) return nil, nil, jkerr } diff --git a/pkg/models/devops/json.go b/pkg/models/devops/json.go index bebb6f49e..ab0520eaf 100644 --- a/pkg/models/devops/json.go +++ b/pkg/models/devops/json.go @@ -260,6 +260,19 @@ type SCMOrg struct { Name string `json:"name,omitempty" description:"organization name"` } +type SCMServer struct { + Class string `json:"_class,omitempty" description:"It’s a fully qualified name and is an identifier of the producer of this resource's capability."` + Links struct { + Self struct { + Class string `json:"_class,omitempty" description:"It’s a fully qualified name and is an identifier of the producer of this resource's capability."` + Href string `json:"href,omitempty" description:"self url in api"` + } `json:"self,omitempty" description:"scm server self info"` + } `json:"_links,omitempty" description:"references the reachable path to this resource"` + ID string `json:"id,omitempty" description:"server id of scm server"` + Name string `json:"name,omitempty" description:"name of scm server"` + ApiURL string `json:"apiUrl,omitempty" description:"url of scm server"` +} + // GetOrgRepo type OrgRepo struct { Class string `json:"_class,omitempty" description:"It’s a fully qualified name and is an identifier of the producer of this resource's capability."` @@ -721,6 +734,11 @@ type CheckPlayload struct { Abort bool `json:"abort,omitempty" description:"abort or not"` } +type CreateScmServerReq struct { + Name string `json:"name,omitempty" description:"name of scm server"` + ApiURL string `json:"apiUrl,omitempty" description:"url of scm server"` +} + type CheckPlayloadParameters struct { Name string `json:"name,omitempty" description:"name"` Value string `json:"value,omitempty" description:"value"` diff --git a/pkg/models/devops/project_pipeline.go b/pkg/models/devops/project_pipeline.go index ad876ebac..9cac73b13 100644 --- a/pkg/models/devops/project_pipeline.go +++ b/pkg/models/devops/project_pipeline.go @@ -30,6 +30,8 @@ const ( MultiBranchPipelineType = "multi-branch-pipeline" ) +type Parameters []*Parameter + var ParameterTypeMap = map[string]string{ "hudson.model.StringParameterDefinition": "string", "hudson.model.ChoiceParameterDefinition": "choice", @@ -62,7 +64,7 @@ type NoScmPipeline struct { Name string `json:"name" description:"name of pipeline"` Description string `json:"descriptio,omitempty" description:"description of pipeline"` Discarder *DiscarderProperty `json:"discarder,omitempty" description:"Discarder of pipeline, managing when to drop a pipeline"` - Parameters []*Parameter `json:"parameters,omitempty" description:"Parameters define of pipeline,user could pass param when run pipeline"` + Parameters *Parameters `json:"parameters,omitempty" description:"Parameters define of pipeline,user could pass param when run pipeline"` DisableConcurrent bool `json:"disable_concurrent,omitempty" mapstructure:"disable_concurrent" description:"Whether to prohibit the pipeline from running in parallel"` TimerTrigger *TimerTrigger `json:"timer_trigger,omitempty" mapstructure:"timer_trigger" description:"Timer to trigger pipeline run"` RemoteTrigger *RemoteTrigger `json:"remote_trigger,omitempty" mapstructure:"remote_trigger" description:"Remote api define to trigger pipeline run"` @@ -70,19 +72,21 @@ type NoScmPipeline struct { } type MultiBranchPipeline struct { - Name string `json:"name" description:"name of pipeline"` - Description string `json:"descriptio,omitempty" description:"description of pipeline"` - Discarder *DiscarderProperty `json:"discarder,omitempty" description:"Discarder of pipeline, managing when to drop a pipeline"` - TimerTrigger *TimerTrigger `json:"timer_trigger,omitempty" mapstructure:"timer_trigger" description:"Timer to trigger pipeline run"` - SourceType string `json:"source_type" description:"type of scm, such as github/git/svn"` - GitSource *GitSource `json:"git_source,omitempty" description:"git scm define"` - GitHubSource *GithubSource `json:"github_source,omitempty" description:"github scm define"` - SvnSource *SvnSource `json:"svn_source,omitempty" description:"multi branch svn scm define"` - SingleSvnSource *SingleSvnSource `json:"single_svn_source,omitempty" description:"single branch svn scm define"` - ScriptPath string `json:"script_path" mapstructure:"script_path" description:"script path in scm"` + Name string `json:"name" description:"name of pipeline"` + Description string `json:"descriptio,omitempty" description:"description of pipeline"` + Discarder *DiscarderProperty `json:"discarder,omitempty" description:"Discarder of pipeline, managing when to drop a pipeline"` + TimerTrigger *TimerTrigger `json:"timer_trigger,omitempty" mapstructure:"timer_trigger" description:"Timer to trigger pipeline run"` + SourceType string `json:"source_type" description:"type of scm, such as github/git/svn"` + GitSource *GitSource `json:"git_source,omitempty" description:"git scm define"` + GitHubSource *GithubSource `json:"github_source,omitempty" description:"github scm define"` + SvnSource *SvnSource `json:"svn_source,omitempty" description:"multi branch svn scm define"` + SingleSvnSource *SingleSvnSource `json:"single_svn_source,omitempty" description:"single branch svn scm define"` + BitbucketServerSource *BitbucketServerSource `json:"bitbucket_server_source,omitempty" description:"bitbucket server scm defile"` + ScriptPath string `json:"script_path" mapstructure:"script_path" description:"script path in scm"` } type GitSource struct { + ScmId string `json:"scm_id,omitempty" description:"uid of scm"` Url string `json:"url,omitempty" mapstructure:"url" description:"url of git source"` CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access git source"` DiscoverBranches bool `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Whether to discover a branch"` @@ -91,15 +95,29 @@ type GitSource struct { } type GithubSource struct { - Owner string `json:"owner,omitempty" mapstructure:"owner" description:"owner of github repo"` - Repo string `json:"repo,omitempty" mapstructure:"repo" description:"repo name of github repo"` - CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access github source"` - ApiUri string `json:"api_uri,omitempty" mapstructure:"api_uri" description:"The api url can specify the location of the github apiserver.For private cloud configuration"` - DiscoverBranches int `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Discover branch configuration"` - DiscoverPRFromOrigin int `json:"discover_pr_from_origin,omitempty" mapstructure:"discover_pr_from_origin" description:"Discover origin PR configuration"` - DiscoverPRFromForks *GithubDiscoverPRFromForks `json:"discover_pr_from_forks,omitempty" mapstructure:"discover_pr_from_forks" description:"Discover fork PR configuration"` - CloneOption *GitCloneOption `json:"git_clone_option,omitempty" mapstructure:"git_clone_option" description:"advavced git clone options"` - RegexFilter string `json:"regex_filter,omitempty" mapstructure:"regex_filter" description:"Regex used to match the name of the branch that needs to be run"` + ScmId string `json:"scm_id,omitempty" description:"uid of scm"` + Owner string `json:"owner,omitempty" mapstructure:"owner" description:"owner of github repo"` + Repo string `json:"repo,omitempty" mapstructure:"repo" description:"repo name of github repo"` + CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access github source"` + ApiUri string `json:"api_uri,omitempty" mapstructure:"api_uri" description:"The api url can specify the location of the github apiserver.For private cloud configuration"` + DiscoverBranches int `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Discover branch configuration"` + DiscoverPRFromOrigin int `json:"discover_pr_from_origin,omitempty" mapstructure:"discover_pr_from_origin" description:"Discover origin PR configuration"` + DiscoverPRFromForks *DiscoverPRFromForks `json:"discover_pr_from_forks,omitempty" mapstructure:"discover_pr_from_forks" description:"Discover fork PR configuration"` + CloneOption *GitCloneOption `json:"git_clone_option,omitempty" mapstructure:"git_clone_option" description:"advavced git clone options"` + RegexFilter string `json:"regex_filter,omitempty" mapstructure:"regex_filter" description:"Regex used to match the name of the branch that needs to be run"` +} + +type BitbucketServerSource struct { + ScmId string `json:"scm_id,omitempty" description:"uid of scm"` + Owner string `json:"owner,omitempty" mapstructure:"owner" description:"owner of github repo"` + Repo string `json:"repo,omitempty" mapstructure:"repo" description:"repo name of github repo"` + CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access github source"` + ApiUri string `json:"api_uri,omitempty" mapstructure:"api_uri" description:"The api url can specify the location of the github apiserver.For private cloud configuration"` + DiscoverBranches int `json:"discover_branches,omitempty" mapstructure:"discover_branches" description:"Discover branch configuration"` + DiscoverPRFromOrigin int `json:"discover_pr_from_origin,omitempty" mapstructure:"discover_pr_from_origin" description:"Discover origin PR configuration"` + DiscoverPRFromForks *DiscoverPRFromForks `json:"discover_pr_from_forks,omitempty" mapstructure:"discover_pr_from_forks" description:"Discover fork PR configuration"` + CloneOption *GitCloneOption `json:"git_clone_option,omitempty" mapstructure:"git_clone_option" description:"advavced git clone options"` + RegexFilter string `json:"regex_filter,omitempty" mapstructure:"regex_filter" description:"Regex used to match the name of the branch that needs to be run"` } type GitCloneOption struct { @@ -109,17 +127,19 @@ type GitCloneOption struct { } type SvnSource struct { + ScmId string `json:"scm_id,omitempty" description:"uid of scm"` Remote string `json:"remote,omitempty" description:"remote address url"` CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access svn source"` Includes string `json:"includes,omitempty" description:"branches to run pipeline"` Excludes string `json:"excludes,omitempty" description:"branches do not run pipeline"` } type SingleSvnSource struct { + ScmId string `json:"scm_id,omitempty" description:"uid of scm"` Remote string `json:"remote,omitempty" description:"remote address url"` CredentialId string `json:"credential_id,omitempty" mapstructure:"credential_id" description:"credential id to access svn source"` } -type GithubDiscoverPRFromForks struct { +type DiscoverPRFromForks struct { Strategy int `json:"strategy,omitempty" mapstructure:"strategy" description:"github discover startegy"` Trust int `json:"trust,omitempty" mapstructure:"trust" description:"trust user type"` } @@ -189,32 +209,7 @@ func createPipelineConfigXml(pipeline *NoScmPipeline) (string, error) { strategy.CreateElement("artifactNumToKeep").SetText("-1") } if pipeline.Parameters != nil { - parameterDefinitions := properties.CreateElement("hudson.model.ParametersDefinitionProperty"). - CreateElement("parameterDefinitions") - for _, parameter := range pipeline.Parameters { - for className, typeName := range ParameterTypeMap { - if typeName == parameter.Type { - paramDefine := parameterDefinitions.CreateElement(className) - paramDefine.CreateElement("name").SetText(parameter.Name) - paramDefine.CreateElement("description").SetText(parameter.Description) - switch parameter.Type { - case "choice": - choices := paramDefine.CreateElement("choices") - choices.CreateAttr("class", "java.util.Arrays$ArrayList") - a := choices.CreateElement("a") - a.CreateAttr("class", "string-array") - choiceValues := strings.Split(parameter.DefaultValue, "\n") - for _, choiceValue := range choiceValues { - a.CreateElement("string").SetText(choiceValue) - } - case "file": - break - default: - paramDefine.CreateElement("defaultValue").SetText(parameter.DefaultValue) - } - } - } - } + pipeline.Parameters.appendToEtree(properties) } if pipeline.TimerTrigger != nil { @@ -275,65 +270,10 @@ func parsePipelineConfigXml(config string) (*NoScmPipeline, error) { NumToKeep: strategy.SelectElement("numToKeep").Text(), } } - if parametersProperty := properties.SelectElement("hudson.model.ParametersDefinitionProperty"); parametersProperty != nil { - params := parametersProperty.SelectElement("parameterDefinitions").ChildElements() - for _, param := range params { - switch param.Tag { - case "hudson.model.StringParameterDefinition": - pipeline.Parameters = append(pipeline.Parameters, &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - DefaultValue: param.SelectElement("defaultValue").Text(), - Type: ParameterTypeMap["hudson.model.StringParameterDefinition"], - }) - case "hudson.model.BooleanParameterDefinition": - pipeline.Parameters = append(pipeline.Parameters, &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - DefaultValue: param.SelectElement("defaultValue").Text(), - Type: ParameterTypeMap["hudson.model.BooleanParameterDefinition"], - }) - case "hudson.model.TextParameterDefinition": - pipeline.Parameters = append(pipeline.Parameters, &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - DefaultValue: param.SelectElement("defaultValue").Text(), - Type: ParameterTypeMap["hudson.model.TextParameterDefinition"], - }) - case "hudson.model.FileParameterDefinition": - pipeline.Parameters = append(pipeline.Parameters, &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - Type: ParameterTypeMap["hudson.model.FileParameterDefinition"], - }) - case "hudson.model.PasswordParameterDefinition": - pipeline.Parameters = append(pipeline.Parameters, &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - DefaultValue: param.SelectElement("name").Text(), - Type: ParameterTypeMap["hudson.model.PasswordParameterDefinition"], - }) - case "hudson.model.ChoiceParameterDefinition": - choiceParameter := &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - Type: ParameterTypeMap["hudson.model.ChoiceParameterDefinition"], - } - choices := param.SelectElement("choices").SelectElement("a").SelectElements("string") - for _, choice := range choices { - choiceParameter.DefaultValue += fmt.Sprintf("%s\n", choice.Text()) - } - choiceParameter.DefaultValue = strings.TrimSpace(choiceParameter.DefaultValue) - pipeline.Parameters = append(pipeline.Parameters, choiceParameter) - default: - pipeline.Parameters = append(pipeline.Parameters, &Parameter{ - Name: param.SelectElement("name").Text(), - Description: param.SelectElement("description").Text(), - DefaultValue: "unknown", - Type: param.Tag, - }) - } - } + pipeline.Parameters = &Parameters{} + pipeline.Parameters = pipeline.Parameters.fromEtree(properties) + if len(*pipeline.Parameters) == 0 { + pipeline.Parameters = nil } if triggerProperty := properties. @@ -359,6 +299,544 @@ func parsePipelineConfigXml(config string) (*NoScmPipeline, error) { return pipeline, nil } +func (s *Parameters) appendToEtree(properties *etree.Element) *Parameters { + parameterDefinitions := properties.CreateElement("hudson.model.ParametersDefinitionProperty"). + CreateElement("parameterDefinitions") + for _, parameter := range *s { + for className, typeName := range ParameterTypeMap { + if typeName == parameter.Type { + paramDefine := parameterDefinitions.CreateElement(className) + paramDefine.CreateElement("name").SetText(parameter.Name) + paramDefine.CreateElement("description").SetText(parameter.Description) + switch parameter.Type { + case "choice": + choices := paramDefine.CreateElement("choices") + choices.CreateAttr("class", "java.util.Arrays$ArrayList") + a := choices.CreateElement("a") + a.CreateAttr("class", "string-array") + choiceValues := strings.Split(parameter.DefaultValue, "\n") + for _, choiceValue := range choiceValues { + a.CreateElement("string").SetText(choiceValue) + } + case "file": + break + default: + paramDefine.CreateElement("defaultValue").SetText(parameter.DefaultValue) + } + } + } + } + return s +} + +func (s *Parameters) fromEtree(properties *etree.Element) *Parameters { + + if parametersProperty := properties.SelectElement("hudson.model.ParametersDefinitionProperty"); parametersProperty != nil { + params := parametersProperty.SelectElement("parameterDefinitions").ChildElements() + if *s == nil { + *s = make([]*Parameter, 0) + } + for _, param := range params { + switch param.Tag { + case "hudson.model.StringParameterDefinition": + *s = append(*s, &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + DefaultValue: param.SelectElement("defaultValue").Text(), + Type: ParameterTypeMap["hudson.model.StringParameterDefinition"], + }) + case "hudson.model.BooleanParameterDefinition": + *s = append(*s, &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + DefaultValue: param.SelectElement("defaultValue").Text(), + Type: ParameterTypeMap["hudson.model.BooleanParameterDefinition"], + }) + case "hudson.model.TextParameterDefinition": + *s = append(*s, &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + DefaultValue: param.SelectElement("defaultValue").Text(), + Type: ParameterTypeMap["hudson.model.TextParameterDefinition"], + }) + case "hudson.model.FileParameterDefinition": + *s = append(*s, &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + Type: ParameterTypeMap["hudson.model.FileParameterDefinition"], + }) + case "hudson.model.PasswordParameterDefinition": + *s = append(*s, &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + DefaultValue: param.SelectElement("name").Text(), + Type: ParameterTypeMap["hudson.model.PasswordParameterDefinition"], + }) + case "hudson.model.ChoiceParameterDefinition": + choiceParameter := &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + Type: ParameterTypeMap["hudson.model.ChoiceParameterDefinition"], + } + choices := param.SelectElement("choices").SelectElement("a").SelectElements("string") + for _, choice := range choices { + choiceParameter.DefaultValue += fmt.Sprintf("%s\n", choice.Text()) + } + choiceParameter.DefaultValue = strings.TrimSpace(choiceParameter.DefaultValue) + *s = append(*s, choiceParameter) + default: + *s = append(*s, &Parameter{ + Name: param.SelectElement("name").Text(), + Description: param.SelectElement("description").Text(), + DefaultValue: "unknown", + Type: param.Tag, + }) + } + } + } + return s +} + +func (s *GitSource) appendToEtree(source *etree.Element) *GitSource { + source.CreateAttr("class", "jenkins.plugins.git.GitSCMSource") + source.CreateAttr("plugin", "git") + source.CreateElement("id").SetText(s.ScmId) + source.CreateElement("remote").SetText(s.Url) + if s.CredentialId != "" { + source.CreateElement("credentialsId").SetText(s.CredentialId) + } + traits := source.CreateElement("traits") + if s.DiscoverBranches { + traits.CreateElement("jenkins.plugins.git.traits.BranchDiscoveryTrait") + } + if s.CloneOption != nil { + cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension") + cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption") + cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(s.CloneOption.Shallow)) + cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false)) + cloneExtension.CreateElement("reference") + if s.CloneOption.Timeout >= 0 { + cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(s.CloneOption.Timeout)) + } else { + cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10)) + } + + if s.CloneOption.Depth >= 0 { + cloneExtension.CreateElement("depth").SetText(strconv.Itoa(s.CloneOption.Depth)) + } else { + cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1)) + } + } + + if s.RegexFilter != "" { + regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait") + regexTraits.CreateAttr("plugin", "scm-api@2.4.0") + regexTraits.CreateElement("regex").SetText(s.RegexFilter) + } + return s +} + +func (s *GitSource) fromEtree(source *etree.Element) *GitSource { + if credential := source.SelectElement("credentialsId"); credential != nil { + s.CredentialId = credential.Text() + } + if remote := source.SelectElement("remote"); remote != nil { + s.Url = remote.Text() + } + + traits := source.SelectElement("traits") + if branchDiscoverTrait := traits.SelectElement( + "jenkins.plugins.git.traits.BranchDiscoveryTrait"); branchDiscoverTrait != nil { + s.DiscoverBranches = true + } + if cloneTrait := traits.SelectElement( + "jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil { + if cloneExtension := cloneTrait.SelectElement( + "extension"); cloneExtension != nil { + s.CloneOption = &GitCloneOption{} + if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil { + s.CloneOption.Shallow = value + } + if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil { + s.CloneOption.Timeout = int(value) + } + if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil { + s.CloneOption.Depth = int(value) + } + } + } + if regexTrait := traits.SelectElement( + "jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil { + if regex := regexTrait.SelectElement("regex"); regex != nil { + s.RegexFilter = regex.Text() + } + } + return s +} + +func (s *GithubSource) fromEtree(source *etree.Element) *GithubSource { + if credential := source.SelectElement("credentialsId"); credential != nil { + s.CredentialId = credential.Text() + } + if repoOwner := source.SelectElement("repoOwner"); repoOwner != nil { + s.Owner = repoOwner.Text() + } + if repository := source.SelectElement("repository"); repository != nil { + s.Repo = repository.Text() + } + if apiUri := source.SelectElement("apiUri"); apiUri != nil { + s.ApiUri = apiUri.Text() + } + traits := source.SelectElement("traits") + if branchDiscoverTrait := traits.SelectElement( + "org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait"); branchDiscoverTrait != nil { + strategyId, _ := strconv.Atoi(branchDiscoverTrait.SelectElement("strategyId").Text()) + s.DiscoverBranches = strategyId + } + if originPRDiscoverTrait := traits.SelectElement( + "org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait"); originPRDiscoverTrait != nil { + strategyId, _ := strconv.Atoi(originPRDiscoverTrait.SelectElement("strategyId").Text()) + s.DiscoverPRFromOrigin = strategyId + } + if forkPRDiscoverTrait := traits.SelectElement( + "org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil { + strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text()) + trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value + trust := strings.Split(trustClass, "$") + switch trust[1] { + case "TrustContributors": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 1, + } + case "TrustEveryone": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 2, + } + case "TrustPermission": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 3, + } + case "TrustNobody": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 4, + } + } + if cloneTrait := traits.SelectElement( + "jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil { + if cloneExtension := cloneTrait.SelectElement( + "extension"); cloneExtension != nil { + s.CloneOption = &GitCloneOption{} + if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil { + s.CloneOption.Shallow = value + } + if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil { + s.CloneOption.Timeout = int(value) + } + if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil { + s.CloneOption.Depth = int(value) + } + } + } + + if regexTrait := traits.SelectElement( + "jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil { + if regex := regexTrait.SelectElement("regex"); regex != nil { + s.RegexFilter = regex.Text() + } + } + } + return s +} + +func (s *GithubSource) appendToEtree(source *etree.Element) *GithubSource { + source.CreateAttr("class", "org.jenkinsci.plugins.github_branch_source.GitHubSCMSource") + source.CreateAttr("plugin", "github-branch-source") + source.CreateElement("id").SetText(s.ScmId) + source.CreateElement("credentialsId").SetText(s.CredentialId) + source.CreateElement("repoOwner").SetText(s.Owner) + source.CreateElement("repository").SetText(s.Repo) + if s.ApiUri != "" { + source.CreateElement("apiUri").SetText(s.ApiUri) + } + traits := source.CreateElement("traits") + if s.DiscoverBranches != 0 { + traits.CreateElement("org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait"). + CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverBranches)) + } + if s.DiscoverPRFromOrigin != 0 { + traits.CreateElement("org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait"). + CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverPRFromOrigin)) + } + if s.DiscoverPRFromForks != nil { + forkTrait := traits.CreateElement("org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait") + forkTrait.CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverPRFromForks.Strategy)) + trustClass := "org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$" + switch s.DiscoverPRFromForks.Trust { + case 1: + trustClass += "TrustContributors" + case 2: + trustClass += "TrustEveryone" + case 3: + trustClass += "TrustPermission" + case 4: + trustClass += "TrustNobody" + default: + } + forkTrait.CreateElement("trust").CreateAttr("class", trustClass) + } + if s.CloneOption != nil { + cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension") + cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption") + cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(s.CloneOption.Shallow)) + cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false)) + cloneExtension.CreateElement("reference") + if s.CloneOption.Timeout >= 0 { + cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(s.CloneOption.Timeout)) + } else { + cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10)) + } + + if s.CloneOption.Depth >= 0 { + cloneExtension.CreateElement("depth").SetText(strconv.Itoa(s.CloneOption.Depth)) + } else { + cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1)) + } + } + if s.RegexFilter != "" { + regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait") + regexTraits.CreateAttr("plugin", "scm-api@2.4.0") + regexTraits.CreateElement("regex").SetText(s.RegexFilter) + } + return s +} + +func (s *BitbucketServerSource) fromEtree(source *etree.Element) *BitbucketServerSource { + if credential := source.SelectElement("credentialsId"); credential != nil { + s.CredentialId = credential.Text() + } + if repoOwner := source.SelectElement("repoOwner"); repoOwner != nil { + s.Owner = repoOwner.Text() + } + if repository := source.SelectElement("repository"); repository != nil { + s.Repo = repository.Text() + } + if apiUri := source.SelectElement("serverUrl"); apiUri != nil { + s.ApiUri = apiUri.Text() + } + traits := source.SelectElement("traits") + if branchDiscoverTrait := traits.SelectElement( + "com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait"); branchDiscoverTrait != nil { + strategyId, _ := strconv.Atoi(branchDiscoverTrait.SelectElement("strategyId").Text()) + s.DiscoverBranches = strategyId + } + if originPRDiscoverTrait := traits.SelectElement( + "com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait"); originPRDiscoverTrait != nil { + strategyId, _ := strconv.Atoi(originPRDiscoverTrait.SelectElement("strategyId").Text()) + s.DiscoverPRFromOrigin = strategyId + } + if forkPRDiscoverTrait := traits.SelectElement( + "com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil { + strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text()) + trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value + trust := strings.Split(trustClass, "$") + switch trust[1] { + case "TrustEveryone": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 1, + } + case "TrustTeamForks": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 2, + } + case "TrustNobody": + s.DiscoverPRFromForks = &DiscoverPRFromForks{ + Strategy: strategyId, + Trust: 3, + } + } + if cloneTrait := traits.SelectElement( + "jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil { + if cloneExtension := cloneTrait.SelectElement( + "extension"); cloneExtension != nil { + s.CloneOption = &GitCloneOption{} + if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil { + s.CloneOption.Shallow = value + } + if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil { + s.CloneOption.Timeout = int(value) + } + if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil { + s.CloneOption.Depth = int(value) + } + } + } + + if regexTrait := traits.SelectElement( + "jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil { + if regex := regexTrait.SelectElement("regex"); regex != nil { + s.RegexFilter = regex.Text() + } + } + } + return s +} + +func (s *BitbucketServerSource) appendToEtree(source *etree.Element) *BitbucketServerSource { + source.CreateAttr("class", "com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource") + source.CreateAttr("plugin", "cloudbees-bitbucket-branch-source") + source.CreateElement("id").SetText(s.ScmId) + source.CreateElement("credentialsId").SetText(s.CredentialId) + source.CreateElement("repoOwner").SetText(s.Owner) + source.CreateElement("repository").SetText(s.Repo) + source.CreateElement("serverUrl").SetText(s.ApiUri) + + traits := source.CreateElement("traits") + if s.DiscoverBranches != 0 { + traits.CreateElement("com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait>"). + CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverBranches)) + } + if s.DiscoverPRFromOrigin != 0 { + traits.CreateElement("com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait"). + CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverPRFromOrigin)) + } + if s.DiscoverPRFromForks != nil { + forkTrait := traits.CreateElement("com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait") + forkTrait.CreateElement("strategyId").SetText(strconv.Itoa(s.DiscoverPRFromForks.Strategy)) + trustClass := "com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait$" + switch s.DiscoverPRFromForks.Trust { + case 1: + trustClass += "TrustEveryone" + case 2: + trustClass += "TrustTeamForks" + case 3: + trustClass += "TrustNobody" + default: + trustClass += "TrustEveryone" + } + forkTrait.CreateElement("trust").CreateAttr("class", trustClass) + } + if s.CloneOption != nil { + cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension") + cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption") + cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(s.CloneOption.Shallow)) + cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false)) + cloneExtension.CreateElement("reference") + if s.CloneOption.Timeout >= 0 { + cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(s.CloneOption.Timeout)) + } else { + cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10)) + } + + if s.CloneOption.Depth >= 0 { + cloneExtension.CreateElement("depth").SetText(strconv.Itoa(s.CloneOption.Depth)) + } else { + cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1)) + } + } + if s.RegexFilter != "" { + regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait") + regexTraits.CreateAttr("plugin", "scm-api@2.4.0") + regexTraits.CreateElement("regex").SetText(s.RegexFilter) + } + return s +} + +func (s *SvnSource) fromEtree(source *etree.Element) *SvnSource { + if remote := source.SelectElement("remoteBase"); remote != nil { + s.Remote = remote.Text() + } + + if credentialsId := source.SelectElement("credentialsId"); credentialsId != nil { + s.CredentialId = credentialsId.Text() + } + + if includes := source.SelectElement("includes"); includes != nil { + s.Includes = includes.Text() + } + + if excludes := source.SelectElement("excludes"); excludes != nil { + s.Excludes = excludes.Text() + } + return s +} + +func (s *SvnSource) appendToEtree(source *etree.Element) *SvnSource { + source.CreateAttr("class", "jenkins.scm.impl.subversion.SubversionSCMSource") + source.CreateAttr("plugin", "subversion") + source.CreateElement("id").SetText(s.ScmId) + if s.CredentialId != "" { + source.CreateElement("credentialsId").SetText(s.CredentialId) + } + if s.Remote != "" { + source.CreateElement("remoteBase").SetText(s.Remote) + } + if s.Includes != "" { + source.CreateElement("includes").SetText(s.Includes) + } + if s.Excludes != "" { + source.CreateElement("excludes").SetText(s.Excludes) + } + return nil +} + +func (s *SingleSvnSource) fromEtree(source *etree.Element) *SingleSvnSource { + if scm := source.SelectElement("scm"); scm != nil { + if locations := scm.SelectElement("locations"); locations != nil { + if moduleLocations := locations.SelectElement("hudson.scm.SubversionSCM_-ModuleLocation"); moduleLocations != nil { + if remote := moduleLocations.SelectElement("remote"); remote != nil { + s.Remote = remote.Text() + } + if credentialId := moduleLocations.SelectElement("credentialsId"); credentialId != nil { + s.CredentialId = credentialId.Text() + } + } + } + } + return s +} + +func (s *SingleSvnSource) appendToEtree(source *etree.Element) *SingleSvnSource { + + source.CreateAttr("class", "jenkins.scm.impl.SingleSCMSource") + source.CreateAttr("plugin", "scm-api") + source.CreateElement("id").SetText(s.ScmId) + source.CreateElement("name").SetText("master") + + scm := source.CreateElement("scm") + scm.CreateAttr("class", "hudson.scm.SubversionSCM") + scm.CreateAttr("plugin", "subversion") + + location := scm.CreateElement("locations").CreateElement("hudson.scm.SubversionSCM_-ModuleLocation") + if s.Remote != "" { + location.CreateElement("remote").SetText(s.Remote) + } + if s.CredentialId != "" { + location.CreateElement("credentialsId").SetText(s.CredentialId) + } + location.CreateElement("local").SetText(".") + location.CreateElement("depthOption").SetText("infinity") + location.CreateElement("ignoreExternalsOption").SetText("true") + location.CreateElement("cancelProcessOnExternalsFail").SetText("true") + + source.CreateElement("excludedRegions") + source.CreateElement("includedRegions") + source.CreateElement("excludedUsers") + source.CreateElement("excludedRevprop") + source.CreateElement("excludedCommitMessages") + source.CreateElement("workspaceUpdater").CreateAttr("class", "hudson.scm.subversion.UpdateUpdater") + source.CreateElement("ignoreDirPropChanges").SetText("false") + source.CreateElement("filterChangelog").SetText("false") + source.CreateElement("quietOperation").SetText("true") + + return s +} + func createMultiBranchPipelineConfigXml(projectName string, pipeline *MultiBranchPipeline) (string, error) { doc := etree.NewDocument() xmlString := ` @@ -427,175 +905,38 @@ func createMultiBranchPipelineConfigXml(projectName string, pipeline *MultiBranc branchSourceStrategy.CreateAttr("class", "jenkins.branch.NamedExceptionsBranchPropertyStrategy") branchSourceStrategy.CreateElement("defaultProperties").CreateAttr("class", "empty-list") branchSourceStrategy.CreateElement("namedExceptions").CreateAttr("class", "empty-list") + source := branchSource.CreateElement("source") switch pipeline.SourceType { case "git": gitDefine := pipeline.GitSource - - gitSource := branchSource.CreateElement("source") - gitSource.CreateAttr("class", "jenkins.plugins.git.GitSCMSource") - gitSource.CreateAttr("plugin", "git") - gitSource.CreateElement("id").SetText(projectName + pipeline.Name) - gitSource.CreateElement("remote").SetText(gitDefine.Url) - if gitDefine.CredentialId != "" { - gitSource.CreateElement("credentialsId").SetText(gitDefine.CredentialId) - } - traits := gitSource.CreateElement("traits") - if gitDefine.DiscoverBranches { - traits.CreateElement("jenkins.plugins.git.traits.BranchDiscoveryTrait") - } - if gitDefine.CloneOption != nil { - cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension") - cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption") - cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(gitDefine.CloneOption.Shallow)) - cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false)) - cloneExtension.CreateElement("reference") - if gitDefine.CloneOption.Timeout >= 0 { - cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(gitDefine.CloneOption.Timeout)) - } else { - cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10)) - } - - if gitDefine.CloneOption.Depth >= 0 { - cloneExtension.CreateElement("depth").SetText(strconv.Itoa(gitDefine.CloneOption.Depth)) - } else { - cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1)) - } - } - - if gitDefine.RegexFilter != "" { - regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait") - regexTraits.CreateAttr("plugin", "scm-api@2.4.0") - regexTraits.CreateElement("regex").SetText(gitDefine.RegexFilter) - } - + gitDefine.ScmId = projectName + pipeline.Name + gitDefine.appendToEtree(source) case "github": githubDefine := pipeline.GitHubSource - - githubSource := branchSource.CreateElement("source") - githubSource.CreateAttr("class", "org.jenkinsci.plugins.github_branch_source.GitHubSCMSource") - githubSource.CreateAttr("plugin", "github-branch-source") - githubSource.CreateElement("id").SetText(projectName + pipeline.Name) - githubSource.CreateElement("credentialsId").SetText(githubDefine.CredentialId) - githubSource.CreateElement("repoOwner").SetText(githubDefine.Owner) - githubSource.CreateElement("repository").SetText(githubDefine.Repo) - if githubDefine.ApiUri != "" { - githubSource.CreateElement("apiUri").SetText(githubDefine.ApiUri) - } - traits := githubSource.CreateElement("traits") - if githubDefine.DiscoverBranches != 0 { - traits.CreateElement("org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait"). - CreateElement("strategyId").SetText(strconv.Itoa(githubDefine.DiscoverBranches)) - } - if githubDefine.DiscoverPRFromOrigin != 0 { - traits.CreateElement("org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait"). - CreateElement("strategyId").SetText(strconv.Itoa(githubDefine.DiscoverPRFromOrigin)) - } - if githubDefine.DiscoverPRFromForks != nil { - forkTrait := traits.CreateElement("org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait") - forkTrait.CreateElement("strategyId").SetText(strconv.Itoa(githubDefine.DiscoverPRFromForks.Strategy)) - trustClass := "org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$" - switch githubDefine.DiscoverPRFromForks.Trust { - case 1: - trustClass += "TrustContributors" - case 2: - trustClass += "TrustEveryone" - case 3: - trustClass += "TrustPermission" - case 4: - trustClass += "TrustNobody" - default: - return "", fmt.Errorf("unsupport trust choice") - } - forkTrait.CreateElement("trust").CreateAttr("class", trustClass) - } - if githubDefine.CloneOption != nil { - cloneExtension := traits.CreateElement("jenkins.plugins.git.traits.CloneOptionTrait").CreateElement("extension") - cloneExtension.CreateAttr("class", "hudson.plugins.git.extensions.impl.CloneOption") - cloneExtension.CreateElement("shallow").SetText(strconv.FormatBool(githubDefine.CloneOption.Shallow)) - cloneExtension.CreateElement("noTags").SetText(strconv.FormatBool(false)) - cloneExtension.CreateElement("reference") - if githubDefine.CloneOption.Timeout >= 0 { - cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(githubDefine.CloneOption.Timeout)) - } else { - cloneExtension.CreateElement("timeout").SetText(strconv.Itoa(10)) - } - - if githubDefine.CloneOption.Depth >= 0 { - cloneExtension.CreateElement("depth").SetText(strconv.Itoa(githubDefine.CloneOption.Depth)) - } else { - cloneExtension.CreateElement("depth").SetText(strconv.Itoa(1)) - } - } - if githubDefine.RegexFilter != "" { - regexTraits := traits.CreateElement("jenkins.scm.impl.trait.RegexSCMHeadFilterTrait") - regexTraits.CreateAttr("plugin", "scm-api@2.4.0") - regexTraits.CreateElement("regex").SetText(githubDefine.RegexFilter) - } - + githubDefine.ScmId = projectName + pipeline.Name + githubDefine.appendToEtree(source) case "svn": svnDefine := pipeline.SvnSource - svnSource := branchSource.CreateElement("source") - svnSource.CreateAttr("class", "jenkins.scm.impl.subversion.SubversionSCMSource") - svnSource.CreateAttr("plugin", "subversion") - svnSource.CreateElement("id").SetText(projectName + pipeline.Name) - if svnDefine.CredentialId != "" { - svnSource.CreateElement("credentialsId").SetText(svnDefine.CredentialId) - } - if svnDefine.Remote != "" { - svnSource.CreateElement("remoteBase").SetText(svnDefine.Remote) - } - if svnDefine.Includes != "" { - svnSource.CreateElement("includes").SetText(svnDefine.Includes) - } - if svnDefine.Excludes != "" { - svnSource.CreateElement("excludes").SetText(svnDefine.Excludes) - } + svnDefine.ScmId = projectName + pipeline.Name + svnDefine.appendToEtree(source) case "single_svn": - singleSvnDefine := pipeline.SingleSvnSource - if err != nil { - return "", err - } - svnSource := branchSource.CreateElement("source") - svnSource.CreateAttr("class", "jenkins.scm.impl.SingleSCMSource") - svnSource.CreateAttr("plugin", "scm-api") + singSvnDefine := pipeline.SingleSvnSource + singSvnDefine.ScmId = projectName + pipeline.Name + singSvnDefine.appendToEtree(source) - svnSource.CreateElement("id").SetText(projectName + pipeline.Name) - svnSource.CreateElement("name").SetText("master") - - scm := svnSource.CreateElement("scm") - scm.CreateAttr("class", "hudson.scm.SubversionSCM") - scm.CreateAttr("plugin", "subversion") - - location := scm.CreateElement("locations").CreateElement("hudson.scm.SubversionSCM_-ModuleLocation") - if singleSvnDefine.Remote != "" { - location.CreateElement("remote").SetText(singleSvnDefine.Remote) - } - if singleSvnDefine.CredentialId != "" { - location.CreateElement("credentialsId").SetText(singleSvnDefine.CredentialId) - } - location.CreateElement("local").SetText(".") - location.CreateElement("depthOption").SetText("infinity") - location.CreateElement("ignoreExternalsOption").SetText("true") - location.CreateElement("cancelProcessOnExternalsFail").SetText("true") - - svnSource.CreateElement("excludedRegions") - svnSource.CreateElement("includedRegions") - svnSource.CreateElement("excludedUsers") - svnSource.CreateElement("excludedRevprop") - svnSource.CreateElement("excludedCommitMessages") - svnSource.CreateElement("workspaceUpdater").CreateAttr("class", "hudson.scm.subversion.UpdateUpdater") - svnSource.CreateElement("ignoreDirPropChanges").SetText("false") - svnSource.CreateElement("filterChangelog").SetText("false") - svnSource.CreateElement("quietOperation").SetText("true") + case "bitbucket_server": + bitbucketServerDefine := pipeline.BitbucketServerSource + bitbucketServerDefine.ScmId = projectName + pipeline.Name + bitbucketServerDefine.appendToEtree(source) default: return "", fmt.Errorf("unsupport source type") } + factory := project.CreateElement("factory") factory.CreateAttr("class", "org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory") - factoryOwner := factory.CreateElement("owner") factoryOwner.CreateAttr("class", "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject") factoryOwner.CreateAttr("reference", "../..") @@ -642,171 +983,31 @@ func parseMultiBranchPipelineConfigXml(config string) (*MultiBranchPipeline, err switch source.SelectAttr("class").Value { case "org.jenkinsci.plugins.github_branch_source.GitHubSCMSource": githubSource := &GithubSource{} - if credential := source.SelectElement("credentialsId"); credential != nil { - githubSource.CredentialId = credential.Text() - } - if repoOwner := source.SelectElement("repoOwner"); repoOwner != nil { - githubSource.Owner = repoOwner.Text() - } - if repository := source.SelectElement("repository"); repository != nil { - githubSource.Repo = repository.Text() - } - if apiUri := source.SelectElement("apiUri"); apiUri != nil { - githubSource.ApiUri = apiUri.Text() - } - traits := source.SelectElement("traits") - if branchDiscoverTrait := traits.SelectElement( - "org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait"); branchDiscoverTrait != nil { - strategyId, err := strconv.Atoi(branchDiscoverTrait.SelectElement("strategyId").Text()) - if err != nil { - return nil, err - } - githubSource.DiscoverBranches = strategyId - } - if originPRDiscoverTrait := traits.SelectElement( - "org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait"); originPRDiscoverTrait != nil { - strategyId, err := strconv.Atoi(originPRDiscoverTrait.SelectElement("strategyId").Text()) - if err != nil { - return nil, err - } - githubSource.DiscoverPRFromOrigin = strategyId - } - if forkPRDiscoverTrait := traits.SelectElement( - "org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil { - strategyId, err := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text()) - if err != nil { - return nil, err - } - trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value - trust := strings.Split(trustClass, "$") - switch trust[1] { - case "TrustContributors": - githubSource.DiscoverPRFromForks = &GithubDiscoverPRFromForks{ - Strategy: strategyId, - Trust: 1, - } - case "TrustEveryone": - githubSource.DiscoverPRFromForks = &GithubDiscoverPRFromForks{ - Strategy: strategyId, - Trust: 2, - } - case "TrustPermission": - githubSource.DiscoverPRFromForks = &GithubDiscoverPRFromForks{ - Strategy: strategyId, - Trust: 3, - } - case "TrustNobody": - githubSource.DiscoverPRFromForks = &GithubDiscoverPRFromForks{ - Strategy: strategyId, - Trust: 4, - } - } - if cloneTrait := traits.SelectElement( - "jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil { - if cloneExtension := cloneTrait.SelectElement( - "extension"); cloneExtension != nil { - githubSource.CloneOption = &GitCloneOption{} - if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil { - githubSource.CloneOption.Shallow = value - } - if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil { - githubSource.CloneOption.Timeout = int(value) - } - if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil { - githubSource.CloneOption.Depth = int(value) - } - } - } - - if regexTrait := traits.SelectElement( - "jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil { - if regex := regexTrait.SelectElement("regex"); regex != nil { - githubSource.RegexFilter = regex.Text() - } - } - } - + githubSource.fromEtree(source) pipeline.GitHubSource = githubSource pipeline.SourceType = "github" + case "com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource": + bitbucketServerSource := &BitbucketServerSource{} + bitbucketServerSource.fromEtree(source) + pipeline.BitbucketServerSource = bitbucketServerSource + pipeline.SourceType = "bitbucket_server" + case "jenkins.plugins.git.GitSCMSource": gitSource := &GitSource{} - if credential := source.SelectElement("credentialsId"); credential != nil { - gitSource.CredentialId = credential.Text() - } - if remote := source.SelectElement("remote"); remote != nil { - gitSource.Url = remote.Text() - } - - traits := source.SelectElement("traits") - if branchDiscoverTrait := traits.SelectElement( - "jenkins.plugins.git.traits.BranchDiscoveryTrait"); branchDiscoverTrait != nil { - gitSource.DiscoverBranches = true - } - if cloneTrait := traits.SelectElement( - "jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil { - if cloneExtension := cloneTrait.SelectElement( - "extension"); cloneExtension != nil { - gitSource.CloneOption = &GitCloneOption{} - if value, err := strconv.ParseBool(cloneExtension.SelectElement("shallow").Text()); err == nil { - gitSource.CloneOption.Shallow = value - } - if value, err := strconv.ParseInt(cloneExtension.SelectElement("timeout").Text(), 10, 32); err == nil { - gitSource.CloneOption.Timeout = int(value) - } - if value, err := strconv.ParseInt(cloneExtension.SelectElement("depth").Text(), 10, 32); err == nil { - gitSource.CloneOption.Depth = int(value) - } - } - } - if regexTrait := traits.SelectElement( - "jenkins.scm.impl.trait.RegexSCMHeadFilterTrait"); regexTrait != nil { - if regex := regexTrait.SelectElement("regex"); regex != nil { - gitSource.RegexFilter = regex.Text() - } - } - + gitSource.fromEtree(source) pipeline.SourceType = "git" pipeline.GitSource = gitSource + case "jenkins.scm.impl.SingleSCMSource": singleSvnSource := &SingleSvnSource{} - - if scm := source.SelectElement("scm"); scm != nil { - if locations := scm.SelectElement("locations"); locations != nil { - if moduleLocations := locations.SelectElement("hudson.scm.SubversionSCM_-ModuleLocation"); moduleLocations != nil { - if remote := moduleLocations.SelectElement("remote"); remote != nil { - singleSvnSource.Remote = remote.Text() - } - if credentialId := moduleLocations.SelectElement("credentialsId"); credentialId != nil { - singleSvnSource.CredentialId = credentialId.Text() - } - } - } - } + singleSvnSource.fromEtree(source) pipeline.SourceType = "single_svn" - pipeline.SingleSvnSource = singleSvnSource case "jenkins.scm.impl.subversion.SubversionSCMSource": svnSource := &SvnSource{} - - if remote := source.SelectElement("remoteBase"); remote != nil { - svnSource.Remote = remote.Text() - } - - if credentialsId := source.SelectElement("credentialsId"); credentialsId != nil { - svnSource.CredentialId = credentialsId.Text() - } - - if includes := source.SelectElement("includes"); includes != nil { - svnSource.Includes = includes.Text() - } - - if excludes := source.SelectElement("excludes"); excludes != nil { - svnSource.Excludes = excludes.Text() - } - + svnSource.fromEtree(source) pipeline.SourceType = "svn" - pipeline.SvnSource = svnSource } } diff --git a/pkg/models/devops/project_pipeline_test.go b/pkg/models/devops/project_pipeline_test.go index 0af6d9e67..38646881c 100644 --- a/pkg/models/devops/project_pipeline_test.go +++ b/pkg/models/devops/project_pipeline_test.go @@ -110,7 +110,7 @@ func Test_NoScmPipelineConfig_Param(t *testing.T) { Name: "", Description: "for test", Jenkinsfile: "node{echo 'hello'}", - Parameters: []*Parameter{ + Parameters: &Parameters{ &Parameter{ Name: "d", DefaultValue: "a\nb", @@ -123,7 +123,7 @@ func Test_NoScmPipelineConfig_Param(t *testing.T) { Name: "", Description: "for test", Jenkinsfile: "node{echo 'hello'}", - Parameters: []*Parameter{ + Parameters: &Parameters{ &Parameter{ Name: "a", DefaultValue: "abc", @@ -355,7 +355,28 @@ func Test_MultiBranchPipelineConfig_Source(t *testing.T) { ApiUri: "https://api.github.com", DiscoverBranches: 1, DiscoverPRFromOrigin: 2, - DiscoverPRFromForks: &GithubDiscoverPRFromForks{ + DiscoverPRFromForks: &DiscoverPRFromForks{ + Strategy: 1, + Trust: 1, + }, + }, + }, + &MultiBranchPipeline{ + Name: "", + Description: "for test", + ScriptPath: "Jenkinsfile", + SourceType: "bitbucket_server", + TimerTrigger: &TimerTrigger{ + Interval: "12345566", + }, + BitbucketServerSource: &BitbucketServerSource{ + Owner: "kubesphere", + Repo: "devops", + CredentialId: "github", + ApiUri: "https://api.github.com", + DiscoverBranches: 1, + DiscoverPRFromOrigin: 2, + DiscoverPRFromForks: &DiscoverPRFromForks{ Strategy: 1, Trust: 1, }, @@ -439,7 +460,7 @@ func Test_MultiBranchPipelineCloneConfig(t *testing.T) { ApiUri: "https://api.github.com", DiscoverBranches: 1, DiscoverPRFromOrigin: 2, - DiscoverPRFromForks: &GithubDiscoverPRFromForks{ + DiscoverPRFromForks: &DiscoverPRFromForks{ Strategy: 1, Trust: 1, }, @@ -496,7 +517,7 @@ func Test_MultiBranchPipelineRegexFilter(t *testing.T) { ApiUri: "https://api.github.com", DiscoverBranches: 1, DiscoverPRFromOrigin: 2, - DiscoverPRFromForks: &GithubDiscoverPRFromForks{ + DiscoverPRFromForks: &DiscoverPRFromForks{ Strategy: 1, Trust: 1, }, diff --git a/pkg/models/devops/urlconfig.go b/pkg/models/devops/urlconfig.go index 511667187..a42a05648 100644 --- a/pkg/models/devops/urlconfig.go +++ b/pkg/models/devops/urlconfig.go @@ -44,6 +44,8 @@ const ( CheckPipelineUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/%s/" GetBranchNodeStepsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/branches/%s/runs/%s/nodes/%s/steps/?" GetNodeStepsUrl = "/blue/rest/organizations/jenkins/pipelines/%s/pipelines/%s/runs/%s/nodes/%s/steps/?" + GetSCMServersUrl = "/blue/rest/organizations/jenkins/scm/%s/servers/" + CreateSCMServersUrl = "/blue/rest/organizations/jenkins/scm/%s/servers/" ValidateUrl = "/blue/rest/organizations/jenkins/scm/%s/validate" GetSCMOrgUrl = "/blue/rest/organizations/jenkins/scm/%s/organizations/?" GetOrgRepoUrl = "/blue/rest/organizations/jenkins/scm/%s/organizations/%s/repositories/?" diff --git a/pkg/models/tenant/devops.go b/pkg/models/tenant/devops.go index bd2927405..ba287e326 100644 --- a/pkg/models/tenant/devops.go +++ b/pkg/models/tenant/devops.go @@ -22,6 +22,7 @@ import ( "github.com/emicklei/go-restful" "github.com/gocraft/dbr" "github.com/golang/glog" + "k8s.io/klog" "kubesphere.io/kubesphere/pkg/db" "kubesphere.io/kubesphere/pkg/gojenkins" "kubesphere.io/kubesphere/pkg/gojenkins/utils" @@ -105,6 +106,34 @@ func ListDevopsProjects(workspace, username string, conditions *params.Condition return &models.PageableResponse{Items: result, TotalCount: int(count)}, nil } +func GetDevOpsProjectsCount(username string) (uint32, error) { + dbconn := devops_mysql.OpenDatabase() + + query := dbconn.Select(devops.GetColumnsFromStructWithPrefix(devops.DevOpsProjectTableName, devops.DevOpsProject{})...). + From(devops.DevOpsProjectTableName) + var sqconditions []dbr.Builder + + if username != devops.KS_ADMIN { + onCondition := fmt.Sprintf("%s = %s", devops.DevOpsProjectMembershipProjectIdColumn, devops.DevOpsProjectIdColumn) + query.Join(devops.DevOpsProjectMembershipTableName, onCondition) + sqconditions = append(sqconditions, db.Eq(devops.DevOpsProjectMembershipUsernameColumn, username)) + sqconditions = append(sqconditions, db.Eq( + devops.DevOpsProjectMembershipTableName+"."+devops.StatusColumn, devops.StatusActive)) + } + + sqconditions = append(sqconditions, db.Eq( + devops.DevOpsProjectTableName+"."+devops.StatusColumn, devops.StatusActive)) + if len(sqconditions) > 0 { + query.Where(db.And(sqconditions...)) + } + count, err := query.Count() + if err != nil { + klog.Errorf("%+v", err) + return 0, restful.NewError(http.StatusInternalServerError, err.Error()) + } + return count, nil +} + func DeleteDevOpsProject(projectId, username string) error { err := devops.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) if err != nil { diff --git a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/openapi_generated.go b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/openapi_generated.go index 386062fd2..96133f39d 100644 --- a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/openapi_generated.go +++ b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/openapi_generated.go @@ -42,6 +42,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.Parameter": schema_pkg_apis_devops_v1alpha1_Parameter(ref), "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.ProxyConfig": schema_pkg_apis_devops_v1alpha1_ProxyConfig(ref), "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iAutoScale": schema_pkg_apis_devops_v1alpha1_S2iAutoScale(ref), + "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuildResult": schema_pkg_apis_devops_v1alpha1_S2iBuildResult(ref), + "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuildSource": schema_pkg_apis_devops_v1alpha1_S2iBuildSource(ref), "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuilder": schema_pkg_apis_devops_v1alpha1_S2iBuilder(ref), "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuilderList": schema_pkg_apis_devops_v1alpha1_S2iBuilderList(ref), "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuilderSpec": schema_pkg_apis_devops_v1alpha1_S2iBuilderSpec(ref), @@ -772,6 +774,144 @@ func schema_pkg_apis_devops_v1alpha1_S2iAutoScale(ref common.ReferenceCallback) } } +func schema_pkg_apis_devops_v1alpha1_S2iBuildResult(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "imageName": { + SchemaProps: spec.SchemaProps{ + Description: "ImageName is the name of artifact", + Type: []string{"string"}, + Format: "", + }, + }, + "imageSize": { + SchemaProps: spec.SchemaProps{ + Description: "The size in bytes of the image", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "imageID": { + SchemaProps: spec.SchemaProps{ + Description: "Image ID.", + Type: []string{"string"}, + Format: "", + }, + }, + "imageCreated": { + SchemaProps: spec.SchemaProps{ + Description: "Image created time.", + Type: []string{"string"}, + Format: "", + }, + }, + "imageRepoTags": { + SchemaProps: spec.SchemaProps{ + Description: "image tags.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "commandPull": { + SchemaProps: spec.SchemaProps{ + Description: "Command for pull image.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + Dependencies: []string{}, + } +} + +func schema_pkg_apis_devops_v1alpha1_S2iBuildSource(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "sourceUrl": { + SchemaProps: spec.SchemaProps{ + Description: "SourceURL is url of the codes such as https://github.com/a/b.git", + Type: []string{"string"}, + Format: "", + }, + }, + "revisionId": { + SchemaProps: spec.SchemaProps{ + Description: "The RevisionId is a branch name or a SHA-1 hash of every important thing about the commit", + Type: []string{"string"}, + Format: "", + }, + }, + "binaryName": { + SchemaProps: spec.SchemaProps{ + Description: "Binary file Name", + Type: []string{"string"}, + Format: "", + }, + }, + "binarySize": { + SchemaProps: spec.SchemaProps{ + Description: "Binary file Size", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "builderImage": { + SchemaProps: spec.SchemaProps{ + Description: "// BuilderImage describes which image is used for building the result images.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "Description is a result image description label. The default is no description.", + Type: []string{"string"}, + Format: "", + }, + }, + "commitID": { + SchemaProps: spec.SchemaProps{ + Description: "CommitID represents an arbitrary extended object reference in Git as SHA-1", + Type: []string{"string"}, + Format: "", + }, + }, + "committerName": { + SchemaProps: spec.SchemaProps{ + Description: "CommitterName contains the name of the committer", + Type: []string{"string"}, + Format: "", + }, + }, + "committerEmail": { + SchemaProps: spec.SchemaProps{ + Description: "CommitterEmail contains the e-mail of the committer", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + Dependencies: []string{}, + } +} + func schema_pkg_apis_devops_v1alpha1_S2iBuilder(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1577,6 +1717,13 @@ func schema_pkg_apis_devops_v1alpha1_S2iConfig(ref common.ReferenceCallback) com }, }, }, + "outputBuildResult": { + SchemaProps: spec.SchemaProps{ + Description: "Whether output build result to status.", + Type: []string{"boolean"}, + Format: "", + }, + }, }, Required: []string{"imageName", "sourceUrl"}, }, @@ -1774,18 +1921,23 @@ func schema_pkg_apis_devops_v1alpha1_S2iRunStatus(ref common.ReferenceCallback) Format: "", }, }, - "imageName": { + "s2iBuildResult": { SchemaProps: spec.SchemaProps{ - Description: "ImageName is the name of artifact", - Type: []string{"string"}, - Format: "", + Description: "S2i build result info.", + Ref: ref("github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuildResult"), + }, + }, + "s2iBuildSource": { + SchemaProps: spec.SchemaProps{ + Description: "S2i build source info.", + Ref: ref("github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuildSource"), }, }, }, }, }, Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuildResult", "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1.S2iBuildSource", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } diff --git a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2ibuilder_types.go b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2ibuilder_types.go index 98a8d1bfb..75fecb7d1 100644 --- a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2ibuilder_types.go +++ b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2ibuilder_types.go @@ -419,6 +419,9 @@ type S2iConfig struct { // The values of Node Affinity. NodeAffinityValues []string `json:"nodeAffinityValues,omitempty"` + + // Whether output build result to status. + OutputBuildResult bool `json:"outputBuildResult,omitempty"` } type UserDefineTemplate struct { diff --git a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2irun_types.go b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2irun_types.go index ac5101c51..7adb396b6 100644 --- a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2irun_types.go +++ b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/s2irun_types.go @@ -61,8 +61,50 @@ type S2iRunStatus struct { LogURL string `json:"logURL,omitempty"` //KubernetesJobName is the job name in k8s KubernetesJobName string `json:"kubernetesJobName,omitempty"` + + // S2i build result info. + S2iBuildResult *S2iBuildResult `json:"s2iBuildResult,omitempty"` + // S2i build source info. + S2iBuildSource *S2iBuildSource `json:"s2iBuildSource,omitempty"` +} + +type S2iBuildResult struct { //ImageName is the name of artifact ImageName string `json:"imageName,omitempty"` + //The size in bytes of the image + ImageSize int64 `json:"imageSize,omitempty"` + // Image ID. + ImageID string `json:"imageID,omitempty"` + // Image created time. + ImageCreated string `json:"imageCreated,omitempty"` + // image tags. + ImageRepoTags []string `json:"imageRepoTags,omitempty"` + // Command for pull image. + CommandPull string `json:"commandPull,omitempty"` +} + +type S2iBuildSource struct { + // SourceURL is url of the codes such as https://github.com/a/b.git + SourceUrl string `json:"sourceUrl,omitempty"` + // The RevisionId is a branch name or a SHA-1 hash of every important thing about the commit + RevisionId string `json:"revisionId,omitempty"` + // Binary file Name + BinaryName string `json:"binaryName,omitempty"` + // Binary file Size + BinarySize uint64 `json:"binarySize,omitempty"` + + // // BuilderImage describes which image is used for building the result images. + BuilderImage string `json:"builderImage,omitempty"` + // Description is a result image description label. The default is no + // description. + Description string `json:"description,omitempty"` + + // CommitID represents an arbitrary extended object reference in Git as SHA-1 + CommitID string `json:"commitID,omitempty"` + // CommitterName contains the name of the committer + CommitterName string `json:"committerName,omitempty"` + // CommitterEmail contains the e-mail of the committer + CommitterEmail string `json:"committerEmail,omitempty"` } // +genclient @@ -76,7 +118,7 @@ type S2iRunStatus struct { // +kubebuilder:printcolumn:name="K8sJobName",type="string",JSONPath=".status.kubernetesJobName" // +kubebuilder:printcolumn:name="StartTime",type="date",JSONPath=".status.startTime" // +kubebuilder:printcolumn:name="CompletionTime",type="date",JSONPath=".status.completionTime" -// +kubebuilder:printcolumn:name="ImageName",type="string",JSONPath=".status.imageName" +// +kubebuilder:printcolumn:name="ImageName",type="string",JSONPath=".status.s2iBuildResult.imageName" type S2iRun struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go index 2f926f6e5..4383eed30 100644 --- a/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go @@ -271,6 +271,43 @@ func (in *S2iAutoScale) DeepCopy() *S2iAutoScale { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *S2iBuildResult) DeepCopyInto(out *S2iBuildResult) { + *out = *in + if in.ImageRepoTags != nil { + in, out := &in.ImageRepoTags, &out.ImageRepoTags + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuildResult. +func (in *S2iBuildResult) DeepCopy() *S2iBuildResult { + if in == nil { + return nil + } + out := new(S2iBuildResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *S2iBuildSource) DeepCopyInto(out *S2iBuildSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuildSource. +func (in *S2iBuildSource) DeepCopy() *S2iBuildSource { + if in == nil { + return nil + } + out := new(S2iBuildSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S2iBuilder) DeepCopyInto(out *S2iBuilder) { *out = *in @@ -681,6 +718,16 @@ func (in *S2iRunStatus) DeepCopyInto(out *S2iRunStatus) { in, out := &in.CompletionTime, &out.CompletionTime *out = (*in).DeepCopy() } + if in.S2iBuildResult != nil { + in, out := &in.S2iBuildResult, &out.S2iBuildResult + *out = new(S2iBuildResult) + (*in).DeepCopyInto(*out) + } + if in.S2iBuildSource != nil { + in, out := &in.S2iBuildSource, &out.S2iBuildSource + *out = new(S2iBuildSource) + **out = **in + } return } diff --git a/vendor/modules.txt b/vendor/modules.txt index 1bba91297..5843c82a7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -367,7 +367,7 @@ github.com/kubernetes-sigs/application/pkg/resource github.com/kubernetes-sigs/application/pkg/genericreconciler github.com/kubernetes-sigs/application/pkg/kbcontroller github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/scheme -# github.com/kubesphere/s2ioperator v0.0.12 +# github.com/kubesphere/s2ioperator v0.0.13 github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1