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

Add post command hook (#140)

* Add post command hook

* Remove commented codes

* Fix the reduandent codes
上级 a67c3949
...@@ -99,6 +99,12 @@ func (b *InteractiveOption) SetFlag(cmd *cobra.Command) { ...@@ -99,6 +99,12 @@ func (b *InteractiveOption) SetFlag(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&b.Interactive, "interactive", "i", false, "Interactive mode") cmd.Flags().BoolVarP(&b.Interactive, "interactive", "i", false, "Interactive mode")
} }
// HookOption is the option whether skip command hook
type HookOption struct {
SkipPreHook bool
SkipPostHook bool
}
func getCurrentJenkinsAndClient(jclient *client.JenkinsCore) (jenkins *JenkinsServer) { func getCurrentJenkinsAndClient(jclient *client.JenkinsCore) (jenkins *JenkinsServer) {
jenkins = getCurrentJenkinsFromOptionsOrDie() jenkins = getCurrentJenkinsFromOptionsOrDie()
jclient.URL = jenkins.URL jclient.URL = jenkins.URL
......
...@@ -50,7 +50,8 @@ type JenkinsServer struct { ...@@ -50,7 +50,8 @@ type JenkinsServer struct {
Description string `yaml:"description"` Description string `yaml:"description"`
} }
type PreHook struct { // CommndHook is a hook
type CommndHook struct {
Path string `yaml:"path"` Path string `yaml:"path"`
Command string `yaml:"cmd"` Command string `yaml:"cmd"`
} }
...@@ -62,10 +63,12 @@ type PluginSuite struct { ...@@ -62,10 +63,12 @@ type PluginSuite struct {
Description string `yaml:"description"` Description string `yaml:"description"`
} }
// Config is a global config struct
type Config struct { type Config struct {
Current string `yaml:"current"` Current string `yaml:"current"`
JenkinsServers []JenkinsServer `yaml:"jenkins_servers"` JenkinsServers []JenkinsServer `yaml:"jenkins_servers"`
PreHooks []PreHook `yaml:"preHooks"` PreHooks []CommndHook `yaml:"preHooks"`
PostHooks []CommndHook `yaml:"postHooks"`
PluginSuites []PluginSuite `yaml:"pluginSuites"` PluginSuites []PluginSuite `yaml:"pluginSuites"`
} }
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
...@@ -19,6 +20,11 @@ type PluginUploadOption struct { ...@@ -19,6 +20,11 @@ type PluginUploadOption struct {
RemoteUser string RemoteUser string
RemotePassword string RemotePassword string
RemoteJenkins string RemoteJenkins string
ShowProgress bool
RoundTripper http.RoundTripper
HookOption
pluginFilePath string pluginFilePath string
} }
...@@ -27,10 +33,14 @@ var pluginUploadOption PluginUploadOption ...@@ -27,10 +33,14 @@ var pluginUploadOption PluginUploadOption
func init() { func init() {
pluginCmd.AddCommand(pluginUploadCmd) pluginCmd.AddCommand(pluginUploadCmd)
pluginUploadCmd.Flags().BoolVarP(&pluginUploadOption.ShowProgress, "show-progress", "", true, "Whether show the upload progress")
pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.Remote, "remote", "r", "", "Remote plugin URL") pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.Remote, "remote", "r", "", "Remote plugin URL")
pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemoteUser, "remote-user", "", "", "User of remote plugin URL") pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemoteUser, "remote-user", "", "", "User of remote plugin URL")
pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemotePassword, "remote-password", "", "", "Password of remote plugin URL") pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemotePassword, "remote-password", "", "", "Password of remote plugin URL")
pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemoteJenkins, "remote-jenkins", "", "", "Remote Jenkins which will find from config list") pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemoteJenkins, "remote-jenkins", "", "", "Remote Jenkins which will find from config list")
pluginUploadCmd.Flags().BoolVarP(&pluginUploadOption.SkipPreHook, "skip-prehook", "", false, "Whether skip the previous command hook")
pluginUploadCmd.Flags().BoolVarP(&pluginUploadOption.SkipPostHook, "skip-posthook", "", false, "Whether skip the post command hook")
} }
var pluginUploadCmd = &cobra.Command{ var pluginUploadCmd = &cobra.Command{
...@@ -39,7 +49,8 @@ var pluginUploadCmd = &cobra.Command{ ...@@ -39,7 +49,8 @@ var pluginUploadCmd = &cobra.Command{
Short: "Upload a plugin to your Jenkins", Short: "Upload a plugin to your Jenkins",
Long: `Upload a plugin from local filesystem or remote URL to your Jenkins`, Long: `Upload a plugin from local filesystem or remote URL to your Jenkins`,
Example: ` jcli plugin upload --remote https://server/sample.hpi Example: ` jcli plugin upload --remote https://server/sample.hpi
jcli plugin upload sample.hpi`, jcli plugin upload sample.hpi
jcli plugin upload sample.hpi --show-progress=false`,
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
if pluginUploadOption.Remote != "" { if pluginUploadOption.Remote != "" {
file, err := ioutil.TempFile(".", "jcli-plugin") file, err := ioutil.TempFile(".", "jcli-plugin")
...@@ -70,7 +81,9 @@ var pluginUploadCmd = &cobra.Command{ ...@@ -70,7 +81,9 @@ var pluginUploadCmd = &cobra.Command{
log.Fatal(err) log.Fatal(err)
} }
} else if len(args) == 0 { } else if len(args) == 0 {
executePreCmd(cmd, args, os.Stdout) if !pluginUploadOption.SkipPreHook {
executePreCmd(cmd, args, os.Stdout)
}
path, _ := os.Getwd() path, _ := os.Getwd()
dirName := filepath.Base(path) dirName := filepath.Base(path)
...@@ -82,14 +95,22 @@ var pluginUploadCmd = &cobra.Command{ ...@@ -82,14 +95,22 @@ var pluginUploadCmd = &cobra.Command{
pluginUploadOption.pluginFilePath = args[0] pluginUploadOption.pluginFilePath = args[0]
} }
}, },
Run: func(_ *cobra.Command, _ []string) { PostRun: func(cmd *cobra.Command, args []string) {
jenkins := getCurrentJenkinsFromOptionsOrDie() if pluginUploadOption.SkipPostHook {
jclient := &client.PluginManager{} return
jclient.URL = jenkins.URL }
jclient.UserName = jenkins.UserName
jclient.Token = jenkins.Token executePostCmd(cmd, args, cmd.OutOrStdout())
jclient.Proxy = jenkins.Proxy },
jclient.ProxyAuth = jenkins.ProxyAuth Run: func(cmd *cobra.Command, _ []string) {
jclient := &client.PluginManager{
JenkinsCore: client.JenkinsCore{
RoundTripper: pluginUploadOption.RoundTripper,
Output: cmd.OutOrStdout(),
},
ShowProgress: pluginUploadOption.ShowProgress,
}
getCurrentJenkinsAndClient(&(jclient.JenkinsCore))
jclient.Debug = rootOptions.Debug jclient.Debug = rootOptions.Debug
if pluginUploadOption.Remote != "" { if pluginUploadOption.Remote != "" {
......
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 upload command", func() {
var (
ctrl *gomock.Controller
roundTripper *mhttp.MockRoundTripper
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
roundTripper = mhttp.NewMockRoundTripper(ctrl)
pluginUploadOption.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("should success", func() {
data, err := generateSampleConfig()
Expect(err).To(BeNil())
err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664)
Expect(err).To(BeNil())
tmpfile, err := ioutil.TempFile("", "example")
Expect(err).To(BeNil())
request, _, requestCrumb, _ := client.PrepareForUploadPlugin(roundTripper, "http://localhost:8080/jenkins")
request.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
requestCrumb.SetBasicAuth("admin", "111e3a2f0231198855dceaff96f20540a9")
rootCmd.SetArgs([]string{"plugin", "upload", tmpfile.Name(), "--show-progress=false"})
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
Expect(buf.String()).To(Equal(""))
})
})
})
...@@ -120,12 +120,32 @@ func executePreCmd(cmd *cobra.Command, _ []string, writer io.Writer) (err error) ...@@ -120,12 +120,32 @@ func executePreCmd(cmd *cobra.Command, _ []string, writer io.Writer) (err error)
} }
path := getCmdPath(cmd) path := getCmdPath(cmd)
for _, preHook := range config.PreHooks { for _, hook := range config.PreHooks {
if path != preHook.Path { if path != hook.Path {
continue continue
} }
if err = execute(preHook.Command, writer); err != nil { if err = execute(hook.Command, writer); err != nil {
return
}
}
return
}
func executePostCmd(cmd *cobra.Command, _ []string, writer io.Writer) (err error) {
config := getConfig()
if config == nil {
err = fmt.Errorf("Cannot find config file")
return
}
path := getCmdPath(cmd)
for _, hook := range config.PostHooks {
if path != hook.Path {
continue
}
if err = execute(hook.Command, writer); err != nil {
return return
} }
} }
......
...@@ -86,7 +86,7 @@ var _ = Describe("Root cmd test", func() { ...@@ -86,7 +86,7 @@ var _ = Describe("Root cmd test", func() {
It("basic use case with one preHook, should success", func() { It("basic use case with one preHook, should success", func() {
config = &Config{ config = &Config{
PreHooks: []PreHook{PreHook{ PreHooks: []CommndHook{CommndHook{
Path: "test", Path: "test",
Command: successCmd, Command: successCmd,
}}, }},
...@@ -106,13 +106,13 @@ var _ = Describe("Root cmd test", func() { ...@@ -106,13 +106,13 @@ var _ = Describe("Root cmd test", func() {
It("basic use case with many preHooks, should success", func() { It("basic use case with many preHooks, should success", func() {
config = &Config{ config = &Config{
PreHooks: []PreHook{PreHook{ PreHooks: []CommndHook{CommndHook{
Path: "test", Path: "test",
Command: successCmd, Command: successCmd,
}, PreHook{ }, CommndHook{
Path: "test", Path: "test",
Command: "echo 2", Command: "echo 2",
}, PreHook{ }, CommndHook{
Path: "fake", Path: "fake",
Command: successCmd, Command: successCmd,
}}, }},
...@@ -147,7 +147,7 @@ var _ = Describe("Root cmd test", func() { ...@@ -147,7 +147,7 @@ var _ = Describe("Root cmd test", func() {
It("basic use case with error command, should success", func() { It("basic use case with error command, should success", func() {
config = &Config{ config = &Config{
PreHooks: []PreHook{PreHook{ PreHooks: []CommndHook{CommndHook{
Path: "test", Path: "test",
Command: errorCmd, Command: errorCmd,
}}, }},
......
...@@ -22,6 +22,7 @@ type JenkinsCore struct { ...@@ -22,6 +22,7 @@ type JenkinsCore struct {
ProxyAuth string ProxyAuth string
Debug bool Debug bool
Output io.Writer
RoundTripper http.RoundTripper RoundTripper http.RoundTripper
} }
...@@ -112,6 +113,48 @@ func (j *JenkinsCore) GetCrumb() (crumbIssuer *JenkinsCrumb, err error) { ...@@ -112,6 +113,48 @@ func (j *JenkinsCore) GetCrumb() (crumbIssuer *JenkinsCrumb, err error) {
return return
} }
// RequestWithData requests the api and parse the data into an interface
func (j *JenkinsCore) RequestWithData(method, api string, headers map[string]string,
payload io.Reader, successCode int, obj interface{}) (err error) {
var (
statusCode int
data []byte
)
if statusCode, data, err = j.Request(method, api, headers, payload); err == nil {
if statusCode == successCode {
json.Unmarshal(data, obj)
} else {
err = j.ErrorHandle(statusCode, data)
}
}
return
}
// RequestWithoutData requests the api without handling data
func (j *JenkinsCore) RequestWithoutData(method, api string, headers map[string]string,
payload io.Reader, successCode int) (err error) {
var (
statusCode int
data []byte
)
if statusCode, data, err = j.Request(method, api, headers, payload); err == nil &&
statusCode != successCode {
err = j.ErrorHandle(statusCode, data)
}
return
}
// ErrorHandle handles the error cases
func (j *JenkinsCore) ErrorHandle(statusCode int, data []byte) (err error) {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if j.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
return
}
// Request make a common request // Request make a common request
func (j *JenkinsCore) Request(method, api string, headers map[string]string, payload io.Reader) ( func (j *JenkinsCore) Request(method, api string, headers map[string]string, payload io.Reader) (
statusCode int, data []byte, err error) { statusCode int, data []byte, err error) {
......
...@@ -20,40 +20,14 @@ type JobClient struct { ...@@ -20,40 +20,14 @@ type JobClient struct {
// Search find a set of jobs by name // Search find a set of jobs by name
func (q *JobClient) Search(keyword string) (status *SearchResult, err error) { func (q *JobClient) Search(keyword string) (status *SearchResult, err error) {
var ( err = q.RequestWithData("GET", fmt.Sprintf("/search/suggest?query=%s", keyword), nil, nil, 200, &status)
statusCode int
data []byte
)
if statusCode, data, err = q.Request("GET", fmt.Sprintf("/search/suggest?query=%s", keyword), nil, nil); err == nil {
if statusCode == 200 {
json.Unmarshal(data, &status)
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
}
}
return return
} }
// Build trigger a job // Build trigger a job
func (q *JobClient) Build(jobName string) (err error) { func (q *JobClient) Build(jobName string) (err error) {
path := parseJobPath(jobName) path := parseJobPath(jobName)
err = q.RequestWithoutData("POST", fmt.Sprintf("%s/build", path), nil, nil, 201)
var (
statusCode int
data []byte
)
if statusCode, data, err = q.Request("POST", fmt.Sprintf("%s/build", path), nil, nil); err == nil {
if statusCode == 201 {
fmt.Println("build successfully")
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
}
return return
} }
...@@ -67,22 +41,7 @@ func (q *JobClient) GetBuild(jobName string, id int) (job *JobBuild, err error) ...@@ -67,22 +41,7 @@ func (q *JobClient) GetBuild(jobName string, id int) (job *JobBuild, err error)
api = fmt.Sprintf("%s/%d/api/json", path, id) api = fmt.Sprintf("%s/%d/api/json", path, id)
} }
var ( err = q.RequestWithData("GET", api, nil, nil, 200, &job)
statusCode int
data []byte
)
if statusCode, data, err = q.Request("GET", api, nil, nil); err == nil {
if statusCode == 200 {
job = &JobBuild{}
err = json.Unmarshal(data, job)
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
}
return return
} }
...@@ -139,21 +98,8 @@ func (q *JobClient) BuildWithParams(jobName string, parameters []ParameterDefini ...@@ -139,21 +98,8 @@ func (q *JobClient) BuildWithParams(jobName string, parameters []ParameterDefini
func (q *JobClient) StopJob(jobName string, num int) (err error) { func (q *JobClient) StopJob(jobName string, num int) (err error) {
path := parseJobPath(jobName) path := parseJobPath(jobName)
api := fmt.Sprintf("%s/%d/stop", path, num) api := fmt.Sprintf("%s/%d/stop", path, num)
var (
statusCode int
data []byte
)
if statusCode, data, err = q.Request("POST", api, nil, nil); err == nil { err = q.RequestWithoutData("POST", api, nil, nil, 200)
if statusCode == 200 {
fmt.Println("stoped successfully")
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
}
return return
} }
...@@ -161,22 +107,8 @@ func (q *JobClient) StopJob(jobName string, num int) (err error) { ...@@ -161,22 +107,8 @@ func (q *JobClient) StopJob(jobName string, num int) (err error) {
func (q *JobClient) GetJob(name string) (job *Job, err error) { func (q *JobClient) GetJob(name string) (job *Job, err error) {
path := parseJobPath(name) path := parseJobPath(name)
api := fmt.Sprintf("%s/api/json", path) api := fmt.Sprintf("%s/api/json", path)
var (
statusCode int
data []byte
)
if statusCode, data, err = q.Request("GET", api, nil, nil); err == nil { err = q.RequestWithData("GET", api, nil, nil, 200, &job)
if statusCode == 200 {
job = &Job{}
err = json.Unmarshal(data, job)
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if q.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
}
return return
} }
......
...@@ -134,4 +134,15 @@ var _ = Describe("PluginManager test", func() { ...@@ -134,4 +134,15 @@ var _ = Describe("PluginManager test", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
}) })
Context("Upload", func() {
It("normal case, should success", func() {
tmpfile, err := ioutil.TempFile("", "example")
Expect(err).To(BeNil())
PrepareForUploadPlugin(roundTripper, pluginMgr.URL)
pluginMgr.Upload(tmpfile.Name())
})
})
}) })
...@@ -2,7 +2,6 @@ package client ...@@ -2,7 +2,6 @@ package client
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
...@@ -16,8 +15,11 @@ import ( ...@@ -16,8 +15,11 @@ import (
"github.com/jenkins-zh/jenkins-cli/util" "github.com/jenkins-zh/jenkins-cli/util"
) )
// PluginManager is the client of plugin manager
type PluginManager struct { type PluginManager struct {
JenkinsCore JenkinsCore
ShowProgress bool
} }
type Plugin struct { type Plugin struct {
...@@ -89,43 +91,13 @@ func (p *PluginManager) CheckUpdate(handle func(*http.Response)) { ...@@ -89,43 +91,13 @@ func (p *PluginManager) CheckUpdate(handle func(*http.Response)) {
// GetAvailablePlugins get the aviable plugins from Jenkins // GetAvailablePlugins get the aviable plugins from Jenkins
func (p *PluginManager) GetAvailablePlugins() (pluginList *AvailablePluginList, err error) { func (p *PluginManager) GetAvailablePlugins() (pluginList *AvailablePluginList, err error) {
var ( err = p.RequestWithData("GET", "/pluginManager/plugins", nil, nil, 200, &pluginList)
statusCode int
data []byte
)
if statusCode, data, err = p.Request("GET", "/pluginManager/plugins", nil, nil); err == nil {
if statusCode == 200 {
pluginList = &AvailablePluginList{}
err = json.Unmarshal(data, pluginList)
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if p.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
}
return return
} }
// GetPlugins get installed plugins // GetPlugins get installed plugins
func (p *PluginManager) GetPlugins() (pluginList *InstalledPluginList, err error) { func (p *PluginManager) GetPlugins() (pluginList *InstalledPluginList, err error) {
var ( err = p.RequestWithData("GET", "/pluginManager/api/json?depth=1", nil, nil, 200, &pluginList)
statusCode int
data []byte
)
if statusCode, data, err = p.Request("GET", "/pluginManager/api/json?depth=1", nil, nil); err == nil {
if statusCode == 200 {
pluginList = &InstalledPluginList{}
err = json.Unmarshal(data, pluginList)
} else {
err = fmt.Errorf("unexpected status code: %d", statusCode)
if p.Debug {
ioutil.WriteFile("debug.html", data, 0664)
}
}
}
return return
} }
...@@ -207,34 +179,27 @@ func (p *PluginManager) UninstallPlugin(name string) (err error) { ...@@ -207,34 +179,27 @@ func (p *PluginManager) UninstallPlugin(name string) (err error) {
} }
// Upload will upload a file from local filesystem into Jenkins // Upload will upload a file from local filesystem into Jenkins
func (p *PluginManager) Upload(pluginFile string) { func (p *PluginManager) Upload(pluginFile string) (err error) {
api := fmt.Sprintf("%s/pluginManager/uploadPlugin", p.URL) api := fmt.Sprintf("%s/pluginManager/uploadPlugin", p.URL)
extraParams := map[string]string{} extraParams := map[string]string{}
request, err := newfileUploadRequest(api, extraParams, "@name", pluginFile) var request *http.Request
if err != nil { if request, err = p.newfileUploadRequest(api, extraParams, "@name", pluginFile); err != nil {
log.Fatal(err)
}
if err == nil {
p.AuthHandle(request)
} else {
return return
} }
p.AuthHandle(request)
client := p.GetClient() client := p.GetClient()
var response *http.Response var response *http.Response
response, err = client.Do(request) if response, err = client.Do(request); err != nil {
if err != nil { return
log.Fatal(err)
} else if response.StatusCode != 200 { } else if response.StatusCode != 200 {
fmt.Println("StatusCode", response.StatusCode) err = fmt.Errorf("StatusCode: %d", response.StatusCode)
var data []byte if data, readErr := ioutil.ReadAll(response.Body); readErr == nil && p.Debug {
if data, err = ioutil.ReadAll(response.Body); err == nil && p.Debug {
ioutil.WriteFile("debug.html", data, 0664) ioutil.WriteFile("debug.html", data, 0664)
} else {
log.Fatal(err)
} }
} }
return err
} }
func (p *PluginManager) handleCheck(handle func(*http.Response)) func(*http.Response) { func (p *PluginManager) handleCheck(handle func(*http.Response)) func(*http.Response) {
...@@ -246,32 +211,28 @@ func (p *PluginManager) handleCheck(handle func(*http.Response)) func(*http.Resp ...@@ -246,32 +211,28 @@ func (p *PluginManager) handleCheck(handle func(*http.Response)) func(*http.Resp
return handle return handle
} }
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { func (p *PluginManager) newfileUploadRequest(uri string, params map[string]string, paramName, path string) (req *http.Request, err error) {
file, err := os.Open(path) var file *os.File
file, err = os.Open(path)
if err != nil { if err != nil {
return nil, err return
} }
var total float64 var total float64
if stat, err := file.Stat(); err != nil { var stat os.FileInfo
panic(err) if stat, err = file.Stat(); err != nil {
} else { return
total = float64(stat.Size())
} }
total = float64(stat.Size())
defer file.Close() defer file.Close()
bytesBuffer := &bytes.Buffer{} bytesBuffer := &bytes.Buffer{}
progressWriter := &util.ProgressIndicator{
Total: total,
Writer: bytesBuffer,
Reader: bytesBuffer,
Title: "Uploading",
}
progressWriter.Init()
writer := multipart.NewWriter(bytesBuffer) writer := multipart.NewWriter(bytesBuffer)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
var part io.Writer
part, err = writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil { if err != nil {
return nil, err return
} }
_, err = io.Copy(part, file) _, err = io.Copy(part, file)
...@@ -281,10 +242,23 @@ func newfileUploadRequest(uri string, params map[string]string, paramName, path ...@@ -281,10 +242,23 @@ func newfileUploadRequest(uri string, params map[string]string, paramName, path
} }
err = writer.Close() err = writer.Close()
if err != nil { if err != nil {
return nil, err return
}
var progressWriter *util.ProgressIndicator
if p.ShowProgress {
progressWriter = &util.ProgressIndicator{
Total: total,
Writer: bytesBuffer,
Reader: bytesBuffer,
Title: "Uploading",
}
progressWriter.Init()
req, err = http.NewRequest("POST", uri, progressWriter)
} else {
req, err = http.NewRequest("POST", uri, bytesBuffer)
} }
req, err := http.NewRequest("POST", uri, progressWriter)
req.Header.Set("Content-Type", writer.FormDataContentType()) req.Header.Set("Content-Type", writer.FormDataContentType())
return req, err return
} }
package client
import (
"fmt"
"net/http"
)
type requestMatcher struct {
request *http.Request
verbose bool
matchOptions matchOptions
}
type matchOptions struct {
withQuery bool
}
// NewRequestMatcher create a request matcher will match request method and request path
func NewRequestMatcher(request *http.Request) *requestMatcher {
return &requestMatcher{request: request}
}
// NewVerboseRequestMatcher create a verbose request matcher will match request method and request path
func NewVerboseRequestMatcher(request *http.Request) *requestMatcher {
return &requestMatcher{request: request, verbose: true}
}
func (request *requestMatcher) WithQuery() *requestMatcher {
request.matchOptions.withQuery = true
return request
}
func (request *requestMatcher) Matches(x interface{}) bool {
target := x.(*http.Request)
if request.verbose {
fmt.Printf("%s=?%s , %s=?%s, %s=?%s \n", request.request.Method, target.Method, request.request.URL.Path, target.URL.Path,
request.request.URL.Opaque, target.URL.Opaque)
}
match := request.request.Method == target.Method && (request.request.URL.Path == target.URL.Path ||
request.request.URL.Path == target.URL.Opaque) //gitlab sdk did not set request path correctly
if request.matchOptions.withQuery {
if request.verbose {
fmt.Printf("%s=?%s \n", request.request.URL.RawQuery, target.URL.RawQuery)
}
match = match && (request.request.URL.RawQuery == target.URL.RawQuery)
}
return match
}
func (*requestMatcher) String() string {
return "request matcher"
}
...@@ -3,8 +3,11 @@ package client ...@@ -3,8 +3,11 @@ package client
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"mime/multipart"
"net/http" "net/http"
"path/filepath"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp" "github.com/jenkins-zh/jenkins-cli/mock/mhttp"
) )
...@@ -89,6 +92,34 @@ func PrepareFor500InstalledPluginList(roundTripper *mhttp.MockRoundTripper, root ...@@ -89,6 +92,34 @@ func PrepareFor500InstalledPluginList(roundTripper *mhttp.MockRoundTripper, root
return return
} }
// PrepareForUploadPlugin only for test
func PrepareForUploadPlugin(roundTripper *mhttp.MockRoundTripper, rootURL string) (
request *http.Request, response *http.Response, requestCrumb *http.Request, responseCrumb *http.Response) {
tmpfile, _ := ioutil.TempFile("", "example")
bytesBuffer := &bytes.Buffer{}
writer := multipart.NewWriter(bytesBuffer)
part, _ := writer.CreateFormFile("@name", filepath.Base(tmpfile.Name()))
io.Copy(part, tmpfile)
request, _ = http.NewRequest("POST", fmt.Sprintf("%s/pluginManager/uploadPlugin", rootURL), nil)
request.Header.Add("CrumbRequestField", "Crumb")
request.Header.Set("Content-Type", writer.FormDataContentType())
response = &http.Response{
StatusCode: 200,
Proto: "HTTP/1.1",
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString("")),
}
roundTripper.EXPECT().
RoundTrip(NewRequestMatcher(request)).Return(response, nil)
// common crumb request
requestCrumb, responseCrumb = RequestCrumb(roundTripper, rootURL)
return
}
// PrepareForUninstallPlugin only for test // PrepareForUninstallPlugin only for test
func PrepareForUninstallPlugin(roundTripper *mhttp.MockRoundTripper, rootURL, pluginName string) ( func PrepareForUninstallPlugin(roundTripper *mhttp.MockRoundTripper, rootURL, pluginName string) (
request *http.Request, response *http.Response, requestCrumb *http.Request, responseCrumb *http.Response) { request *http.Request, response *http.Response, requestCrumb *http.Request, responseCrumb *http.Response) {
...@@ -101,7 +132,7 @@ func PrepareForUninstallPlugin(roundTripper *mhttp.MockRoundTripper, rootURL, pl ...@@ -101,7 +132,7 @@ func PrepareForUninstallPlugin(roundTripper *mhttp.MockRoundTripper, rootURL, pl
Body: ioutil.NopCloser(bytes.NewBufferString("")), Body: ioutil.NopCloser(bytes.NewBufferString("")),
} }
roundTripper.EXPECT(). roundTripper.EXPECT().
RoundTrip(request).Return(response, nil) RoundTrip(NewRequestMatcher(request)).Return(response, nil)
// common crumb request // common crumb request
requestCrumb, responseCrumb = RequestCrumb(roundTripper, rootURL) requestCrumb, responseCrumb = RequestCrumb(roundTripper, rootURL)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册