提交 88f2284a 编写于 作者: Y Yanjun Shi 提交者: LinuxSuRen

Show the version of plugins when searching (#156)

* Add plugin search show plugin version And Update go-sum file

* Update Query plugins method And Add Unit Test

* Update Get data from PluginApi modified to get from UpdateCenter

* Add Unit Testing

* Add unit testing

* remove annotation

* update test

* fix unit test coverage

* fix some questions

* update one result name

* update some questions

* update unit test and fix some question

* fix search plugin question

* remove some comment

* update test method name

* split the method

* update some code
上级 7bdb448d
......@@ -47,8 +47,8 @@ var pluginSearchCmd = &cobra.Command{
if plugins, err := jclient.GetAvailablePlugins(); err == nil {
result := searchPlugins(plugins, keyword)
if data, err := pluginSearchOption.Output(result); err == nil {
resultData := matchPluginsData(result, jclient)
if data, err := pluginSearchOption.Output(resultData); err == nil {
if len(data) > 0 {
cmd.Print(string(data))
}
......@@ -72,19 +72,113 @@ func searchPlugins(plugins *client.AvailablePluginList, keyword string) []client
return result
}
func matchPluginsData(plugins []client.AvailablePlugin, pluginJclient *client.PluginManager) (result []client.CenterPlugin) {
if len(plugins) == 0 {
return
}
result = make([]client.CenterPlugin, 0)
jclient := &client.UpdateCenterManager{
JenkinsCore: client.JenkinsCore{
RoundTripper: pluginSearchOption.RoundTripper,
},
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
site, err := jclient.GetSite()
noSite := (err != nil || site == nil)
installedPlugins, err := pluginJclient.GetPlugins()
noInstalledPlugin := (err != nil || installedPlugins == nil)
for _, plugin := range plugins {
result = buildData(noSite, site, plugin, result, noInstalledPlugin, installedPlugins)
}
return
}
func buildData(noSite bool, site *client.CenterSite, plugin client.AvailablePlugin, result []client.CenterPlugin, noInstalledPlugin bool, installedPlugins *client.InstalledPluginList) (resultData []client.CenterPlugin) {
isMatched := false
if !noSite {
if len(site.UpdatePlugins) > 0 {
resultData, isMatched = buildUpdatePlugins(site, plugin, result)
}
if len(site.AvailablesPlugins) > 0 && !isMatched {
resultData, isMatched = buildAvailablePlugins(site, plugin, result)
}
}
if !noInstalledPlugin && len(installedPlugins.Plugins) > 0 && !isMatched {
resultData, isMatched = buildInstalledPlugins(installedPlugins, plugin, result)
}
if !isMatched {
resultData = buildNoMatchPlugins(plugin, result)
}
return
}
func buildUpdatePlugins(site *client.CenterSite, plugin client.AvailablePlugin, result []client.CenterPlugin) (resultData []client.CenterPlugin, isMatched bool) {
isMatched = false
resultData = result
for _, updatePlugin := range site.UpdatePlugins {
if plugin.Name == updatePlugin.Name {
resultData = append(result, updatePlugin)
isMatched = true
break
}
}
return
}
func buildAvailablePlugins(site *client.CenterSite, plugin client.AvailablePlugin, result []client.CenterPlugin) (resultData []client.CenterPlugin, isMatched bool) {
resultData = result
for _, availablePlugin := range site.AvailablesPlugins {
if plugin.Name == availablePlugin.Name {
resultData = append(result, availablePlugin)
isMatched = true
break
}
}
return
}
func buildInstalledPlugins(installedPlugins *client.InstalledPluginList, plugin client.AvailablePlugin, result []client.CenterPlugin) (resultData []client.CenterPlugin, isMatched bool) {
resultData = result
for _, installPlugin := range installedPlugins.Plugins {
if plugin.Name == installPlugin.ShortName {
resultPlugin := client.CenterPlugin{}
resultPlugin.CompatibleWithInstalledVersion = false
resultPlugin.Name = installPlugin.ShortName
resultPlugin.Installed.Active = true
resultPlugin.Installed.Version = installPlugin.Version
resultPlugin.Title = plugin.Title
resultData = append(result, resultPlugin)
isMatched = true
break
}
}
return
}
func buildNoMatchPlugins(plugin client.AvailablePlugin, result []client.CenterPlugin) (resultData []client.CenterPlugin) {
resultData = result
resultPlugin := client.CenterPlugin{}
resultPlugin.CompatibleWithInstalledVersion = false
resultPlugin.Name = plugin.Name
resultPlugin.Installed.Active = plugin.Installed
resultPlugin.Title = plugin.Title
resultData = append(result, resultPlugin)
return
}
// Output output the data into buffer
func (o *PluginSearchOption) Output(obj interface{}) (data []byte, err error) {
if data, err = o.OutputOption.Output(obj); err != nil {
pluginList := obj.([]client.AvailablePlugin)
pluginList := obj.([]client.CenterPlugin)
buf := new(bytes.Buffer)
if len(pluginList) != 0 {
table := util.CreateTable(buf)
table.AddRow("number", "name", "installed", "title")
table.AddRow("number", "name", "installed", "version", "installedVersion", "title")
for i, plugin := range pluginList {
table.AddRow(fmt.Sprintf("%d", i), plugin.Name,
fmt.Sprintf("%v", plugin.Installed), plugin.Title)
formatTable(&table, i, plugin)
}
table.Render()
}
......@@ -93,3 +187,14 @@ func (o *PluginSearchOption) Output(obj interface{}) (data []byte, err error) {
}
return
}
func formatTable(table *util.Table, i int, plugin client.CenterPlugin) {
installed := plugin.Installed
if installed != (client.InstalledPlugin{}) {
table.AddRow(fmt.Sprintf("%d", i), plugin.Name,
fmt.Sprintf("%t", true), plugin.Version, installed.Version, plugin.Title)
} else {
table.AddRow(fmt.Sprintf("%d", i), plugin.Name,
fmt.Sprintf("%t", false), plugin.Version, " ", plugin.Title)
}
}
......@@ -44,7 +44,6 @@ var _ = Describe("plugin search command", func() {
request, _ := client.PrepareForEmptyAvaiablePluginList(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "search", "fake"})
buf := new(bytes.Buffer)
......@@ -55,15 +54,76 @@ var _ = Describe("plugin search command", func() {
Expect(buf.String()).To(Equal(""))
})
It("one plugin in the list", func() {
It("many plugins in the list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForManyAvaiablePlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request, _ = client.PrepareForRequestUpdateCenter(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request, _ = client.PrepareForOneInstalledPlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "search", "fake"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`number name installed version installedVersion title
0 fake-ocean true 1.19.011 1.18.111 fake-ocean
1 fake-ln true 1.19.011 1.18.1 fake-ln
2 fake-is true 1.19.1 1.18.111 fake-is
3 fake-oa false 1.13.011 fake-oa
4 fake-open false 1.13.0 fake-open
5 fake true 1.0 fake
`))
})
It("should success, empty updateCenter list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForOneAvaiablePlugin(roundTripper, "http://localhost:8080/jenkins")
request, _ := client.PrepareForManyAvaiablePlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request, _ = client.PrepareForNoAvailablePlugins(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request, _ = client.PrepareForManyInstalledPlugins(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "search", "fake"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`number name installed version installedVersion title
0 fake-ocean true 1.18.111 fake-ocean
1 fake-ln true 1.18.1 fake-ln
2 fake-is true 1.18.111 fake-is
3 fake-oa false fake-oa
4 fake-open false fake-open
5 fake true 1.0 fake
`))
})
It("should success, null updateCenter and 500 installed list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForManyAvaiablePlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request, _ = client.PrepareForRequest500UpdateCenter(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
request, _ = client.PrepareFor500InstalledPluginList(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "search", "fake"})
buf := new(bytes.Buffer)
......@@ -71,8 +131,13 @@ var _ = Describe("plugin search command", func() {
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`number name installed title
0 fake false fake
Expect(buf.String()).To(Equal(`number name installed version installedVersion title
0 fake-ocean false fake-ocean
1 fake-ln false fake-ln
2 fake-is false fake-is
3 fake-oa false fake-oa
4 fake-open false fake-open
5 fake false fake
`))
})
})
......
......@@ -17,6 +17,7 @@ var _ = Describe("PluginManager test", func() {
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
pluginMgr PluginManager
updateMgr UpdateCenterManager
)
BeforeEach(func() {
......@@ -25,6 +26,9 @@ var _ = Describe("PluginManager test", func() {
pluginMgr = PluginManager{}
pluginMgr.RoundTripper = roundTripper
pluginMgr.URL = "http://localhost"
updateMgr = UpdateCenterManager{}
updateMgr.RoundTripper = roundTripper
updateMgr.URL = "http://localhost"
})
AfterEach(func() {
......@@ -67,6 +71,16 @@ var _ = Describe("PluginManager test", func() {
Expect(pluginList.Data[0].Name).To(Equal("fake"))
})
It("many plugins in the list", func() {
PrepareForManyAvaiablePlugin(roundTripper, pluginMgr.URL)
pluginList, err := pluginMgr.GetAvailablePlugins()
Expect(err).To(BeNil())
Expect(pluginList).NotTo(BeNil())
Expect(len(pluginList.Data)).To(Equal(6))
Expect(pluginList.Data[0].Name).To(Equal("fake-ocean"))
})
It("response with 500", func() {
request, _ := http.NewRequest("GET", fmt.Sprintf("%s/pluginManager/plugins", pluginMgr.URL), nil)
response := &http.Response{
......@@ -162,4 +176,47 @@ var _ = Describe("PluginManager test", func() {
pluginMgr.Upload(tmpfile.Name())
})
})
Context("UpdateCenter", func() {
It("normal case, should success", func() {
PrepareForRequestUpdateCenter(roundTripper, pluginMgr.URL)
site, err := updateMgr.GetSite()
Expect(err).To(BeNil())
Expect(site).NotTo(BeNil())
Expect(site.ID).To(Equal("default"))
})
})
Context("NullUpdateCenter", func() {
It("normal case, should success", func() {
PrepareForNoAvailablePlugins(roundTripper, pluginMgr.URL)
site, err := updateMgr.GetSite()
Expect(err).To(BeNil())
Expect(site).NotTo(BeNil())
Expect(site.ID).To(Equal("default"))
})
})
Context("ManyInstalledPlugins", func() {
It("normal case, should success", func() {
PrepareForManyInstalledPlugins(roundTripper, pluginMgr.URL)
pluginList, err := pluginMgr.GetPlugins()
Expect(err).To(BeNil())
Expect(pluginList).NotTo(BeNil())
Expect(len(pluginList.Plugins)).To(Equal(4))
Expect(pluginList.Plugins[0].ShortName).To(Equal("fake-ocean"))
})
})
Context("500UpdateCenter", func() {
It("normal case, should success", func() {
PrepareForRequest500UpdateCenter(roundTripper, pluginMgr.URL)
_, err := updateMgr.GetSite()
Expect(err).To(HaveOccurred())
})
})
})
......@@ -2,15 +2,16 @@ package client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"path/filepath"
"strings"
"net/url"
"encoding/json"
"github.com/jenkins-zh/jenkins-cli/util"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
......@@ -37,21 +38,50 @@ func PrepareForEmptyAvaiablePluginList(roundTripper *mhttp.MockRoundTripper, roo
// PrepareForOneAvaiablePlugin only for test
func PrepareForOneAvaiablePlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, _ = http.NewRequest("GET", fmt.Sprintf("%s/pluginManager/plugins", rootURL), nil)
response = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
request, response = PrepareForEmptyAvaiablePluginList(roundTripper, rootURL)
response.Body = ioutil.NopCloser(bytes.NewBufferString(`{
"status": "ok",
"data": [{
"name": "fake",
"title": "fake"
"name": "fake",
"title": "fake"
}]
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
}`))
return
}
// PrepareForManyAvaiablePlugin only for test
func PrepareForManyAvaiablePlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, response = PrepareForEmptyAvaiablePluginList(roundTripper, rootURL)
response.Body = ioutil.NopCloser(bytes.NewBufferString(`{
"status": "ok",
"data": [
{
"name": "fake-ocean",
"title": "fake-ocean"
},
{
"name": "fake-ln",
"title": "fake-ln"
},
{
"name": "fake-is",
"title": "fake-is"
},
{
"name": "fake-oa",
"title": "fake-oa"
},
{
"name": "fake-open",
"title": "fake-open"
},
{
"name": "fake",
"title": "fake"
}
]
}`))
return
}
......@@ -88,6 +118,45 @@ func PrepareForOneInstalledPlugin(roundTripper *mhttp.MockRoundTripper, rootURL
return
}
// PrepareForManyInstalledPlugins only for test
func PrepareForManyInstalledPlugins(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, response = PrepareForEmptyInstalledPluginList(roundTripper, rootURL)
response.Body = ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": [
{
"shortName": "fake-ocean",
"version": "1.18.111",
"hasUpdate": false,
"enable": true,
"active": true
},
{
"shortName": "fake-ln",
"version": "1.18.1",
"hasUpdate": true,
"enable": true,
"active": true
},
{
"shortName": "fake-is",
"version": "1.18.111",
"hasUpdate": true,
"enable": true,
"active": true
},
{
"shortName": "fake",
"version": "1.0",
"hasUpdate": true,
"enable": true,
"active": true
}
]
}`))
return
}
// PrepareFor500InstalledPluginList only for test
func PrepareFor500InstalledPluginList(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
......@@ -229,6 +298,120 @@ func RequestCrumb(roundTripper *mhttp.MockRoundTripper, rootURL string) (
return
}
// PrepareForRequestUpdateCenter only for the test case
func PrepareForRequestUpdateCenter(roundTripper *mhttp.MockRoundTripper, rootURL string) (
requestCenter *http.Request, responseCenter *http.Response) {
requestCenter, _ = http.NewRequest("GET", fmt.Sprintf("%s/updateCenter/site/default/api/json?pretty=true&depth=2", rootURL), nil)
responseCenter = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCenter,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{
"_class": "hudson.model.UpdateSite",
"connectionCheckUrl": "http://www.google.com/",
"dataTimestamp": 1567999067717,
"hasUpdates": true,
"id": "default",
"updates": [{
"name": "fake-ocean",
"sourceId": "default",
"requiredCore": "2.138.4",
"version": "1.19.011",
"title": "fake-ocean",
"sourceId": "default",
"installed": {
"active": true,
"backupVersion": "1.17.011",
"hasUpdate": true,
"version": "1.18.111"
}
},{
"name": "fake-ln",
"sourceId": "default",
"requiredCore": "2.138.4",
"version": "1.19.011",
"title": "fake-ln",
"sourceId": "default",
"installed": {
"active": true,
"hasUpdate": true,
"version": "1.18.1"
}
},{
"name": "fake-is",
"sourceId": "default",
"requiredCore": "2.138.4",
"version": "1.19.1",
"title": "fake-is",
"sourceId": "default",
"installed": {
"active": true,
"backupVersion": "1.17.011",
"hasUpdate": true,
"version": "1.18.111"
}
}
],
"availables": [{
"name": "fake-oa",
"sourceId": "default",
"requiredCore": "2.138.4",
"version": "1.13.011",
"title": "fake-oa",
"installed": null
},{
"name": "fake-open",
"sourceId": "default",
"requiredCore": "2.138.4",
"version": "1.13.0",
"title": "fake-open",
"installed": null
}
],
"url": "https://updates.jenkins.io/update-center.json"
}
`)),
}
roundTripper.EXPECT().RoundTrip(requestCenter).Return(responseCenter, nil)
return
}
// PrepareForNoAvailablePlugins only for the test case
func PrepareForNoAvailablePlugins(roundTripper *mhttp.MockRoundTripper, rootURL string) (
requestCenter *http.Request, responseCenter *http.Response) {
requestCenter, _ = http.NewRequest("GET", fmt.Sprintf("%s/updateCenter/site/default/api/json?pretty=true&depth=2", rootURL), nil)
responseCenter = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: requestCenter,
Body: ioutil.NopCloser(bytes.NewBufferString(`
{
"_class": "hudson.model.UpdateSite",
"connectionCheckUrl": "http://www.google.com/",
"dataTimestamp": 1567999067717,
"hasUpdates": true,
"id": "default",
"updates": [
],
"availables": [
],
"url": "https://updates.jenkins.io/update-center.json"
}
`)),
}
roundTripper.EXPECT().RoundTrip(requestCenter).Return(responseCenter, nil)
return
}
// PrepareForRequest500UpdateCenter only for the test case
func PrepareForRequest500UpdateCenter(roundTripper *mhttp.MockRoundTripper, rootURL string) (
requestCenter *http.Request, responseCenter *http.Response) {
requestCenter, responseCenter = PrepareForNoAvailablePlugins(roundTripper, rootURL)
responseCenter.StatusCode = 500
return
}
// PrepareForInstallPlugin only for test
func PrepareForInstallPlugin(roundTripper *mhttp.MockRoundTripper, rootURL, pluginName, user, passwd string) {
request, _ := http.NewRequest("POST", fmt.Sprintf("%s/pluginManager/install?plugin.%s=", rootURL, pluginName), nil)
......@@ -324,7 +507,7 @@ func PrepareForDeleteUser(roundTripper *mhttp.MockRoundTripper, rootURL, userNam
}
// PrepareCommonPost only for test
func PrepareCommonPost(request *http.Request,roundTripper *mhttp.MockRoundTripper, user, passwd, rootURL string) {
func PrepareCommonPost(request *http.Request, roundTripper *mhttp.MockRoundTripper, user, passwd, rootURL string) {
request.Header.Add("CrumbRequestField", "Crumb")
request.Header.Add(util.ContentType, util.ApplicationForm)
response := &http.Response{
......
package client
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
......@@ -46,10 +45,13 @@ type InstallationJobStatus struct {
// CenterSite represents the site of update center
type CenterSite struct {
ConnectionCheckURL string `json:"connectionCheckUrl"`
HasUpdates bool
ID string `json:"id"`
URL string `json:"url"`
AvailablesPlugins []CenterPlugin `json:"availables"`
ConnectionCheckURL string `json:"connectionCheckUrl"`
DataTimestamp int64 `json:"dataTimestamp"`
HasUpdates bool `json:"hasUpdates"`
ID string `json:"id"`
UpdatePlugins []CenterPlugin `json:"updates"`
URL string `json:"url"`
}
// InstallStates is the installation states
......@@ -73,37 +75,24 @@ type InstallStatesJob struct {
Version string
}
// CenterPlugin represents the all plugin from UpdateCenter
type CenterPlugin struct {
CompatibleWithInstalledVersion bool
Excerpt string
Installed InstalledPlugin
MinimumJavaVersion string
Name string
RequiredCore string
SourceID string
Title string
URL string
Version string
Wiki string
}
// Status returns the status of Jenkins
func (u *UpdateCenterManager) Status() (status *UpdateCenter, err error) {
api := fmt.Sprintf("%s/updateCenter/api/json?pretty=false&depth=1", u.URL)
var (
req *http.Request
response *http.Response
)
req, err = http.NewRequest("GET", api, nil)
if err == nil {
u.AuthHandle(req)
} else {