未验证 提交 4d136021 编写于 作者: LinuxSuRen's avatar LinuxSuRen 提交者: GitHub

Add support to output installed plugins as json format (#137)

* Add support to output installed plugins as json format

* Fix the wrong filter of plugin list

* Adjust the test data

* Adjust the test data
上级 dae8ec17
...@@ -4,8 +4,8 @@ import ( ...@@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
...@@ -36,8 +36,9 @@ func (o *OutputOption) Output(obj interface{}) (data []byte, err error) { ...@@ -36,8 +36,9 @@ func (o *OutputOption) Output(obj interface{}) (data []byte, err error) {
return nil, fmt.Errorf("not support format %s", o.Format) return nil, fmt.Errorf("not support format %s", o.Format)
} }
// SetFlag set flag of output format
func (o *OutputOption) SetFlag(cmd *cobra.Command) { func (o *OutputOption) SetFlag(cmd *cobra.Command) {
cmd.Flags().StringVarP(&o.Format, "output", "o", "table", "Format the output (default 'json')") cmd.Flags().StringVarP(&o.Format, "output", "o", "table", "Format the output, supported formats: table, json, yaml")
} }
func Format(obj interface{}, format string) (data []byte, err error) { func Format(obj interface{}, format string) (data []byte, err error) {
......
package cmd package cmd
import ( import (
"bytes"
"fmt" "fmt"
"log" "log"
"os" "net/http"
"strings" "strings"
"github.com/jenkins-zh/jenkins-cli/client" "github.com/jenkins-zh/jenkins-cli/client"
...@@ -11,10 +12,13 @@ import ( ...@@ -11,10 +12,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// PluginListOption option for plugin list command
type PluginListOption struct { type PluginListOption struct {
OutputOption OutputOption
Filter []string Filter []string
RoundTripper http.RoundTripper
} }
var pluginListOption PluginListOption var pluginListOption PluginListOption
...@@ -22,6 +26,7 @@ var pluginListOption PluginListOption ...@@ -22,6 +26,7 @@ var pluginListOption PluginListOption
func init() { func init() {
pluginCmd.AddCommand(pluginListCmd) pluginCmd.AddCommand(pluginListCmd)
pluginListCmd.Flags().StringArrayVarP(&pluginListOption.Filter, "filter", "", []string{}, "Filter for the list, like: active, hasUpdate, downgradable, enable, name=foo") pluginListCmd.Flags().StringArrayVarP(&pluginListOption.Filter, "filter", "", []string{}, "Filter for the list, like: active, hasUpdate, downgradable, enable, name=foo")
pluginListOption.SetFlag(pluginListCmd)
} }
var pluginListCmd = &cobra.Command{ var pluginListCmd = &cobra.Command{
...@@ -30,14 +35,13 @@ var pluginListCmd = &cobra.Command{ ...@@ -30,14 +35,13 @@ var pluginListCmd = &cobra.Command{
Long: `Print all the plugins which are installed`, Long: `Print all the plugins which are installed`,
Example: ` jcli plugin list --filter name=github Example: ` jcli plugin list --filter name=github
jcli plugin list --filter hasUpdate`, jcli plugin list --filter hasUpdate`,
Run: func(_ *cobra.Command, _ []string) { Run: func(cmd *cobra.Command, _ []string) {
jenkins := getCurrentJenkinsFromOptionsOrDie() jclient := &client.PluginManager{
jclient := &client.PluginManager{} JenkinsCore: client.JenkinsCore{
jclient.URL = jenkins.URL RoundTripper: pluginListOption.RoundTripper,
jclient.UserName = jenkins.UserName },
jclient.Token = jenkins.Token }
jclient.Proxy = jenkins.Proxy getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
jclient.ProxyAuth = jenkins.ProxyAuth
var ( var (
filter bool filter bool
...@@ -59,8 +63,6 @@ var pluginListCmd = &cobra.Command{ ...@@ -59,8 +63,6 @@ var pluginListCmd = &cobra.Command{
enable = true enable = true
case "active": case "active":
active = true active = true
case "name":
downgradable = true
} }
if strings.HasPrefix(f, "name=") { if strings.HasPrefix(f, "name=") {
...@@ -99,7 +101,7 @@ var pluginListCmd = &cobra.Command{ ...@@ -99,7 +101,7 @@ var pluginListCmd = &cobra.Command{
if data, err := pluginListOption.Output(filteredPlugins); err == nil { if data, err := pluginListOption.Output(filteredPlugins); err == nil {
if len(data) > 0 { if len(data) > 0 {
fmt.Println(string(data)) cmd.Print(string(data))
} }
} else { } else {
log.Fatal(err) log.Fatal(err)
...@@ -110,17 +112,20 @@ var pluginListCmd = &cobra.Command{ ...@@ -110,17 +112,20 @@ var pluginListCmd = &cobra.Command{
}, },
} }
// Output render data into byte array as a table format
func (o *PluginListOption) Output(obj interface{}) (data []byte, err error) { func (o *PluginListOption) Output(obj interface{}) (data []byte, err error) {
if data, err = o.OutputOption.Output(obj); err != nil { if data, err = o.OutputOption.Output(obj); err != nil {
buf := new(bytes.Buffer)
pluginList := obj.([]client.InstalledPlugin) pluginList := obj.([]client.InstalledPlugin)
table := util.CreateTable(os.Stdout) table := util.CreateTable(buf)
table.AddRow("number", "name", "version", "update") table.AddRow("number", "name", "version", "update")
for i, plugin := range pluginList { for i, plugin := range pluginList {
table.AddRow(fmt.Sprintf("%d", i), plugin.ShortName, plugin.Version, fmt.Sprintf("%v", plugin.HasUpdate)) table.AddRow(fmt.Sprintf("%d", i), plugin.ShortName, plugin.Version, fmt.Sprintf("%v", plugin.HasUpdate))
} }
table.Render() table.Render()
err = nil err = nil
data = []byte{} data = buf.Bytes()
} }
return return
} }
package cmd
import (
"bytes"
"io/ioutil"
"os"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
)
var _ = Describe("plugin list command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
pluginListOption.RoundTripper = roundTripper
rootCmd.SetArgs([]string{})
rootOptions.Jenkins = ""
rootOptions.ConfigFile = "test.yaml"
})
AfterEach(func() {
rootCmd.SetArgs([]string{})
os.Remove(rootOptions.ConfigFile)
rootOptions.ConfigFile = ""
ctrl.Finish()
})
Context("basic cases", func() {
It("no plugin in the list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForEmptyInstalledPluginList(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "list"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal("number name version update\n"))
})
It("one plugin in the list", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForOneInstalledPlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "list", "fake"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(`number name version update
0 fake 1.0 true
`))
})
It("one plugin output with json format", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
request, _ := client.PrepareForOneInstalledPlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "list", "fake", "--output", "json", "--filter", "hasUpdate", "--filter", "name=fake", "--filter", "enable", "--filter", "active"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(pluginsJSON()))
})
})
})
func pluginsJSON() string {
return `[
{
"Active": true,
"Enabled": false,
"Bundled": false,
"Downgradable": false,
"Deleted": false,
"Enable": true,
"ShortName": "fake",
"LongName": "",
"Version": "1.0",
"URL": "",
"HasUpdate": true,
"Pinned": false,
"RequiredCoreVesion": "",
"MinimumJavaVersion": "",
"SupportDynamicLoad": "",
"BackVersion": ""
}
]`
}
...@@ -84,26 +84,8 @@ var _ = Describe("PluginManager test", func() { ...@@ -84,26 +84,8 @@ var _ = Describe("PluginManager test", func() {
}) })
Context("GetPlugins", func() { Context("GetPlugins", func() {
var (
api string
)
BeforeEach(func() {
api = fmt.Sprintf("%s/pluginManager/api/json?depth=1", pluginMgr.URL)
})
It("no plugin in the list", func() { It("no plugin in the list", func() {
request, _ := http.NewRequest("GET", api, nil) PrepareForEmptyInstalledPluginList(roundTripper, pluginMgr.URL)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": []
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
pluginList, err := pluginMgr.GetPlugins() pluginList, err := pluginMgr.GetPlugins()
Expect(err).To(BeNil()) Expect(err).To(BeNil())
...@@ -112,19 +94,7 @@ var _ = Describe("PluginManager test", func() { ...@@ -112,19 +94,7 @@ var _ = Describe("PluginManager test", func() {
}) })
It("one plugin in the list", func() { It("one plugin in the list", func() {
request, _ := http.NewRequest("GET", api, nil) PrepareForOneInstalledPlugin(roundTripper, pluginMgr.URL)
response := &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": [{
"shortName": "fake"
}]
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
pluginList, err := pluginMgr.GetPlugins() pluginList, err := pluginMgr.GetPlugins()
Expect(err).To(BeNil()) Expect(err).To(BeNil())
...@@ -134,15 +104,7 @@ var _ = Describe("PluginManager test", func() { ...@@ -134,15 +104,7 @@ var _ = Describe("PluginManager test", func() {
}) })
It("response with 500", func() { It("response with 500", func() {
request, _ := http.NewRequest("GET", api, nil) PrepareFor500InstalledPluginList(roundTripper, pluginMgr.URL)
response := &http.Response{
StatusCode: 500,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
_, err := pluginMgr.GetPlugins() _, err := pluginMgr.GetPlugins()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
......
...@@ -47,3 +47,44 @@ func PrepareForOneAvaiablePlugin(roundTripper *mhttp.MockRoundTripper, rootURL s ...@@ -47,3 +47,44 @@ func PrepareForOneAvaiablePlugin(roundTripper *mhttp.MockRoundTripper, rootURL s
RoundTrip(request).Return(response, nil) RoundTrip(request).Return(response, nil)
return return
} }
// PrepareForEmptyInstalledPluginList only for test
func PrepareForEmptyInstalledPluginList(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response) {
request, _ = http.NewRequest("GET", fmt.Sprintf("%s/pluginManager/api/json?depth=1", rootURL), nil)
response = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(`{
"plugins": []
}`)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
return
}
// PrepareForOneInstalledPlugin only for test
func PrepareForOneInstalledPlugin(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",
"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) {
request, response = PrepareForEmptyInstalledPluginList(roundTripper, rootURL)
response.StatusCode = 500
return
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册