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

Add support to upload plugins from local or remote (#79)

上级 d55bde46
......@@ -22,14 +22,17 @@ func init() {
}
var configCmd = &cobra.Command{
Use: "config",
Short: "Manage the config of jcli",
Long: `Manage the config of jcli`,
Use: "config",
Aliases: []string{"cfg"},
Short: "Manage the config of jcli",
Long: `Manage the config of jcli`,
Run: func(cmd *cobra.Command, args []string) {
current := getCurrentJenkins()
fmt.Printf("Current Jenkins's name is %s, url is %s\n", current.Name, current.URL)
},
Example: "jcli config -l",
Example: ` jcli config generate
jcli config list
jcli config edit`,
}
// JenkinsServer holds the configuration of your Jenkins
......
......@@ -24,9 +24,10 @@ func init() {
}
var configGenerateCmd = &cobra.Command{
Use: "generate",
Short: "Generate a sample config file for you",
Long: `Generate a sample config file for you`,
Use: "generate",
Aliases: []string{"gen"},
Short: "Generate a sample config file for you",
Long: `Generate a sample config file for you`,
Run: func(cmd *cobra.Command, args []string) {
if data, err := generateSampleConfig(); err == nil {
configPath := configOptions.ConfigFileLocation
......
......@@ -18,6 +18,9 @@ var pluginCmd = &cobra.Command{
Use: "plugin",
Short: "Manage the plugins of Jenkins",
Long: `Manage the plugins of Jenkins`,
Example: ` jcli plugin list
jcli plugin search github
jcli plugin check`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
......
......@@ -28,6 +28,8 @@ var pluginListCmd = &cobra.Command{
Use: "list",
Short: "Print all the plugins which are installed",
Long: `Print all the plugins which are installed`,
Example: ` jcli plugin list --filter name=github
jcli plugin list --filter hasUpdate`,
Run: func(cmd *cobra.Command, args []string) {
jenkins := getCurrentJenkins()
jclient := &client.PluginManager{}
......
package cmd
import (
"github.com/jenkins-zh/jenkins-cli/client"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/jenkins-zh/jenkins-cli/util"
"github.com/jenkins-zh/jenkins-cli/client"
"github.com/spf13/cobra"
)
// PluginUploadOption will hold the options of plugin cmd
type PluginUploadOption struct {
Remote string
RemoteUser string
RemotePassword string
RemoteJenkins string
pluginFilePath string
}
var pluginUploadOption PluginUploadOption
func init() {
pluginCmd.AddCommand(pluginUploadCmd)
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.RemotePassword, "remote-password", "", "", "Password of remote plugin URL")
pluginUploadCmd.Flags().StringVarP(&pluginUploadOption.RemoteJenkins, "remote-jenkins", "", "", "Remote Jenkins which will find from config list")
}
var pluginUploadCmd = &cobra.Command{
Use: "upload",
Short: "Upload the plugin from local to your Jenkins",
Long: `Upload the plugin from local to your Jenkins`,
Use: "upload",
Aliases: []string{"up"},
Short: "Upload a plugin 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
jcli plugin upload sample.hpi`,
PreRun: func(cmd *cobra.Command, args []string) {
if pluginUploadOption.Remote != "" {
file, err := ioutil.TempFile(".", "jcli-plugin")
if err != nil {
log.Fatal(err)
}
defer os.Remove(file.Name())
if pluginUploadOption.RemoteJenkins != "" {
if jenkins := findJenkinsByName(pluginUploadOption.RemoteJenkins); jenkins != nil {
pluginUploadOption.RemoteUser = jenkins.UserName
pluginUploadOption.RemotePassword = jenkins.Token
}
}
pluginUploadOption.pluginFilePath = fmt.Sprintf("%s.hpi", file.Name())
downloader := util.HTTPDownloader{
TargetFilePath: pluginUploadOption.pluginFilePath,
URL: pluginUploadOption.Remote,
UserName: pluginUploadOption.RemoteUser,
Password: pluginUploadOption.RemotePassword,
ShowProgress: true,
Debug: rootOptions.Debug,
}
if err := downloader.DownloadFile(); err != nil {
log.Fatal(err)
}
} else if len(args) == 0 {
path, _ := os.Getwd()
dirName := filepath.Base(path)
dirName = strings.Replace(dirName, "-plugin", "", -1)
path += fmt.Sprintf("/target/%s.hpi", dirName)
pluginUploadOption.pluginFilePath = path
} else {
pluginUploadOption.pluginFilePath = args[0]
}
},
Run: func(cmd *cobra.Command, args []string) {
jenkins := getCurrentJenkins()
jclient := &client.PluginManager{}
......@@ -21,7 +88,12 @@ var pluginUploadCmd = &cobra.Command{
jclient.Token = jenkins.Token
jclient.Proxy = jenkins.Proxy
jclient.ProxyAuth = jenkins.ProxyAuth
jclient.Debug = rootOptions.Debug
if pluginUploadOption.Remote != "" {
defer os.Remove(pluginUploadOption.pluginFilePath)
}
jclient.Upload()
jclient.Upload(pluginUploadOption.pluginFilePath)
},
}
......@@ -11,6 +11,7 @@ import (
type RootOptions struct {
Version bool
Debug bool
}
var rootCmd = &cobra.Command{
......@@ -48,6 +49,7 @@ var rootOptions RootOptions
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().BoolVarP(&rootOptions.Version, "version", "v", false, "Print the version of Jenkins CLI")
rootCmd.PersistentFlags().BoolVarP(&rootOptions.Debug, "debug", "", false, "Print the output into debug.html")
}
func initConfig() {
......
......@@ -18,6 +18,8 @@ type JenkinsCore struct {
Token string
Proxy string
ProxyAuth string
Debug bool
}
type JenkinsCrumb struct {
......
......@@ -13,7 +13,7 @@ import (
"path/filepath"
"strings"
"github.com/gosuri/uiprogress"
"github.com/linuxsuren/jenkins-cli/util"
)
type PluginManager struct {
......@@ -220,15 +220,11 @@ func (p *PluginManager) UninstallPlugin(name string) (err error) {
return
}
func (p *PluginManager) Upload() {
// Upload will upload a file from local filesystem into Jenkins
func (p *PluginManager) Upload(pluginFile string) {
api := fmt.Sprintf("%s/pluginManager/uploadPlugin", p.URL)
path, _ := os.Getwd()
dirName := filepath.Base(path)
dirName = strings.Replace(dirName, "-plugin", "", -1)
path += fmt.Sprintf("/target/%s.hpi", dirName)
extraParams := map[string]string{}
request, err := newfileUploadRequest(api, extraParams, "@name", path)
request, err := newfileUploadRequest(api, extraParams, "@name", pluginFile)
if err != nil {
log.Fatal(err)
}
......@@ -245,9 +241,10 @@ func (p *PluginManager) Upload() {
if err != nil {
log.Fatal(err)
} else if response.StatusCode != 200 {
fmt.Println("StatusCode", response.StatusCode)
var data []byte
if data, err = ioutil.ReadAll(response.Body); err == nil {
fmt.Println(string(data))
if data, err = ioutil.ReadAll(response.Body); err == nil && p.Debug {
ioutil.WriteFile("debug.html", data, 0664)
} else {
log.Fatal(err)
}
......@@ -261,34 +258,6 @@ func (p *PluginManager) handleCheck(handle func(*http.Response)) func(*http.Resp
return handle
}
type ProgressIndicator struct {
bytes.Buffer
Total float64
count float64
bar *uiprogress.Bar
}
func (i *ProgressIndicator) Init() {
uiprogress.Start() // start rendering
i.bar = uiprogress.AddBar(100) // Add a new bar
// optionally, append and prepend completion and elapsed time
i.bar.AppendCompleted()
// i.bar.PrependElapsed()
}
func (i *ProgressIndicator) Write(p []byte) (n int, err error) {
n, err = i.Buffer.Write(p)
return
}
func (i *ProgressIndicator) Read(p []byte) (n int, err error) {
n, err = i.Buffer.Read(p)
i.count += float64(n)
i.bar.Set((int)(i.count * 100 / i.Total))
return
}
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
file, err := os.Open(path)
if err != nil {
......@@ -303,12 +272,15 @@ func newfileUploadRequest(uri string, params map[string]string, paramName, path
}
defer file.Close()
// body := &bytes.Buffer{}
body := &ProgressIndicator{
Total: total,
bytesBuffer := &bytes.Buffer{}
progressWriter := &util.ProgressIndicator{
Total: total,
Writer: bytesBuffer,
Reader: bytesBuffer,
Title: "Uploading",
}
body.Init()
writer := multipart.NewWriter(body)
progressWriter.Init()
writer := multipart.NewWriter(bytesBuffer)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
return nil, err
......@@ -324,7 +296,7 @@ func newfileUploadRequest(uri string, params map[string]string, paramName, path
return nil, err
}
req, err := http.NewRequest("POST", uri, body)
req, err := http.NewRequest("POST", uri, progressWriter)
req.Header.Set("Content-Type", writer.FormDataContentType())
return req, err
}
package util
import (
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strconv"
"github.com/gosuri/uiprogress"
)
type HTTPDownloader struct {
TargetFilePath string
URL string
ShowProgress bool
UserName string
Password string
Debug bool
}
// DownloadFile download a file with the progress
func (h *HTTPDownloader) DownloadFile() error {
filepath, url, showProgress := h.TargetFilePath, h.URL, h.ShowProgress
// Get the data
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
if h.UserName != "" && h.Password != "" {
req.SetBasicAuth(h.UserName, h.Password)
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
if h.Debug {
if data, err := ioutil.ReadAll(resp.Body); err == nil {
ioutil.WriteFile("debug-download.html", data, 0664)
}
}
return fmt.Errorf("Invalidate status code: %d", resp.StatusCode)
}
writer := &ProgressIndicator{
Title: "Downloading",
}
if showProgress {
if total, ok := resp.Header["Content-Length"]; ok && len(total) > 0 {
fileLength, err := strconv.ParseInt(total[0], 10, 64)
if err == nil {
writer.Total = float64(fileLength)
}
}
}
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
writer.Writer = out
writer.Init()
// Write the body to file
_, err = io.Copy(writer, resp.Body)
return err
}
// ProgressIndicator hold the progress of io operation
type ProgressIndicator struct {
Writer io.Writer
Reader io.Reader
Title string
// bytes.Buffer
Total float64
count float64
bar *uiprogress.Bar
}
// Init set the default value for progress indicator
func (i *ProgressIndicator) Init() {
uiprogress.Start() // start rendering
i.bar = uiprogress.AddBar(100) // Add a new bar
// optionally, append and prepend completion and elapsed time
i.bar.AppendCompleted()
// i.bar.PrependElapsed()
if i.Title != "" {
i.bar.PrependFunc(func(b *uiprogress.Bar) string {
return fmt.Sprintf("%s: ", i.Title)
})
}
}
func (i *ProgressIndicator) Write(p []byte) (n int, err error) {
n, err = i.Writer.Write(p)
i.setBar(n)
return
}
func (i *ProgressIndicator) Read(p []byte) (n int, err error) {
n, err = i.Reader.Read(p)
i.setBar(n)
return
}
func (i *ProgressIndicator) setBar(n int) {
i.count += float64(n)
i.bar.Set((int)(i.count * 100 / i.Total))
}
......@@ -6,12 +6,6 @@ import (
"unicode/utf8"
)
// const (
// ALIGN_LEFT = 0
// ALIGN_CENTER = 1
// ALIGN_RIGHT = 2
// )
type Table struct {
Out io.Writer
Rows [][]string
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册