diff --git a/app/cmd/common.go b/app/cmd/common.go index e6d010ea203557294228b317f5d1a3e0c5cd0cc4..99beba814002fba7afdd766a6bf74f489b2f4d6a 100644 --- a/app/cmd/common.go +++ b/app/cmd/common.go @@ -66,7 +66,7 @@ type BatchOption struct { Batch bool } -// Confirm prompte user if they really want to do this +// Confirm promote user if they really want to do this func (b *BatchOption) Confirm(message string) bool { if !b.Batch { confirm := false diff --git a/app/cmd/credential.go b/app/cmd/credential.go new file mode 100644 index 0000000000000000000000000000000000000000..727d6620dfd1a2964f68fb63226730215cabb4de --- /dev/null +++ b/app/cmd/credential.go @@ -0,0 +1,17 @@ +package cmd + +import ( + "github.com/jenkins-zh/jenkins-cli/app/i18n" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(credentialCmd) +} + +var credentialCmd = &cobra.Command{ + Use: "credential", + Aliases: []string{"secret", "cred"}, + Short: i18n.T("Manage the credentials of your Jenkins"), + Long: i18n.T(`Manage the credentials of your Jenkins`), +} diff --git a/app/cmd/credential_create.go b/app/cmd/credential_create.go new file mode 100644 index 0000000000000000000000000000000000000000..40d5fa6791c201a890d14c24a6fab3d5cbc27e61 --- /dev/null +++ b/app/cmd/credential_create.go @@ -0,0 +1,93 @@ +package cmd + +import ( + "fmt" + "github.com/jenkins-zh/jenkins-cli/app/i18n" + "github.com/jenkins-zh/jenkins-cli/client" + "github.com/spf13/cobra" + "net/http" +) + +// CredentialCreateOption option for credential delete command +type CredentialCreateOption struct { + Description string + ID string + Store string + + Username string + Password string + + Secret string + + Type string + + RoundTripper http.RoundTripper +} + +var credentialCreateOption CredentialCreateOption + +func init() { + credentialCmd.AddCommand(credentialCreateCmd) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.Store, "store", "", "system", + i18n.T("The store name of Jenkins credentials")) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.Type, "type", "", "basic", + i18n.T("The type of Jenkins credentials which could be: basic, secret")) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.ID, "id", "", "", + i18n.T("The ID of Jenkins credentials")) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.Username, "username", "", "", + i18n.T("The Username of Jenkins credentials")) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.Password, "password", "", "", + i18n.T("The Password of Jenkins credentials")) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.Description, "desc", "", "", + i18n.T("The Description of Jenkins credentials")) + credentialCreateCmd.Flags().StringVarP(&credentialCreateOption.Secret, "secret", "", "", + i18n.T("The Secret of Jenkins credentials")) +} + +var credentialCreateCmd = &cobra.Command{ + Use: "create [store] [id]", + Short: i18n.T("Create a credential from Jenkins"), + Long: i18n.T("Create a credential from Jenkins"), + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) >= 1 { + credentialCreateOption.Store = args[0] + } + + if credentialCreateOption.Store == "" { + err = fmt.Errorf("the store or id of target credential is empty") + } + return + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + jClient := &client.CredentialsManager{ + JenkinsCore: client.JenkinsCore{ + RoundTripper: credentialCreateOption.RoundTripper, + Debug: true, + }, + } + getCurrentJenkinsAndClient(&(jClient.JenkinsCore)) + + switch credentialCreateOption.Type { + case "basic": + err = jClient.CreateUsernamePassword(credentialCreateOption.Store, client.UsernamePasswordCredential{ + Username: credentialCreateOption.Username, + Password: credentialCreateOption.Password, + Credential: client.Credential{ + ID: credentialCreateOption.ID, + Description: credentialCreateOption.Description, + }, + }) + case "secret": + err = jClient.CreateSecret(credentialCreateOption.Store, client.StringCredentials{ + Secret: credentialCreateOption.Secret, + Credential: client.Credential{ + ID: credentialCreateOption.ID, + Description: credentialCreateOption.Description, + }, + }) + default: + err = fmt.Errorf("unknow credential type: %s", credentialCreateOption.Type) + } + return + }, +} diff --git a/app/cmd/credential_create_test.go b/app/cmd/credential_create_test.go new file mode 100644 index 0000000000000000000000000000000000000000..175ebbb1514b3755172e486d11668f91c3c14104 --- /dev/null +++ b/app/cmd/credential_create_test.go @@ -0,0 +1,94 @@ +package cmd + +import ( + "bytes" + "github.com/jenkins-zh/jenkins-cli/client" + "io/ioutil" + "os" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/jenkins-zh/jenkins-cli/mock/mhttp" +) + +var _ = Describe("credential create command", func() { + var ( + ctrl *gomock.Controller + roundTripper *mhttp.MockRoundTripper + buf *bytes.Buffer + store string + id string + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + roundTripper = mhttp.NewMockRoundTripper(ctrl) + rootCmd.SetArgs([]string{}) + buf = new(bytes.Buffer) + rootCmd.SetOutput(buf) + rootOptions.Jenkins = "" + rootOptions.ConfigFile = "test.yaml" + + credentialCreateOption.RoundTripper = roundTripper + + store = "system" + id = "fake-id" + }) + + AfterEach(func() { + rootCmd.SetArgs([]string{}) + os.Remove(rootOptions.ConfigFile) + rootOptions.ConfigFile = "" + ctrl.Finish() + }) + + Context("basic cases", func() { + var ( + err error + ) + + BeforeEach(func() { + var data []byte + data, err = generateSampleConfig() + Expect(err).To(BeNil()) + err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664) + Expect(err).To(BeNil()) + }) + + It("lack of the necessary parameters", func() { + rootCmd.SetArgs([]string{"credential", "create", "--store="}) + _, err = rootCmd.ExecuteC() + Expect(err).To(HaveOccurred()) + }) + + It("unknown type", func() { + rootCmd.SetArgs([]string{"credential", "create", "--type", "fake-type", "--store", store}) + _, err = rootCmd.ExecuteC() + Expect(err).To(HaveOccurred()) + }) + + It("should success with user name and password", func() { + credential := client.UsernamePasswordCredential{} + + client.PrepareForCreateUsernamePasswordCredential(roundTripper, "http://localhost:8080/jenkins", + "admin", "111e3a2f0231198855dceaff96f20540a9", store, credential) + + rootCmd.SetArgs([]string{"credential", "create", "--type", "basic", store, id}) + _, err = rootCmd.ExecuteC() + Expect(err).NotTo(HaveOccurred()) + }) + + It("should success with secret", func() { + credential := client.StringCredentials{} + + client.PrepareForCreateSecretCredential(roundTripper, "http://localhost:8080/jenkins", + "admin", "111e3a2f0231198855dceaff96f20540a9", store, credential) + + rootCmd.SetArgs([]string{"credential", "create", "--type", "secret", store, id}) + _, err = rootCmd.ExecuteC() + Expect(err).NotTo(HaveOccurred()) + }) + }) +}) diff --git a/app/cmd/credential_delete.go b/app/cmd/credential_delete.go new file mode 100644 index 0000000000000000000000000000000000000000..94a9baf52350f2c72f88a5f5bd416d737c7391f7 --- /dev/null +++ b/app/cmd/credential_delete.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "fmt" + "github.com/jenkins-zh/jenkins-cli/app/i18n" + "github.com/jenkins-zh/jenkins-cli/client" + "github.com/spf13/cobra" + "net/http" +) + +// CredentialDeleteOption option for credential delete command +type CredentialDeleteOption struct { + BatchOption + + ID string + Store string + + RoundTripper http.RoundTripper +} + +var credentialDeleteOption CredentialDeleteOption + +func init() { + credentialCmd.AddCommand(credentialDeleteCmd) + credentialDeleteCmd.Flags().StringVarP(&credentialDeleteOption.Store, "store", "", "system", + i18n.T("The store name of Jenkins credentials")) + credentialDeleteCmd.Flags().StringVarP(&credentialDeleteOption.ID, "id", "", "", + i18n.T("The ID of Jenkins credentials")) + credentialDeleteOption.SetFlag(credentialDeleteCmd) +} + +var credentialDeleteCmd = &cobra.Command{ + Use: "delete [store] [id]", + Aliases: []string{"remove", "del"}, + Short: i18n.T("Delete a credential from Jenkins"), + Long: i18n.T("Delete a credential from Jenkins"), + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) >= 1 { + credentialDeleteOption.Store = args[0] + } + + if len(args) >= 2 { + credentialDeleteOption.ID = args[1] + } + + if credentialDeleteOption.Store == "" || credentialDeleteOption.ID == "" { + err = fmt.Errorf("the store or id of target credential is empty") + } + return + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + if !credentialDeleteOption.Confirm(fmt.Sprintf("Are you sure to delete credential %s", credentialDeleteOption.ID)) { + return + } + + jClient := &client.CredentialsManager{ + JenkinsCore: client.JenkinsCore{ + RoundTripper: credentialDeleteOption.RoundTripper, + }, + } + getCurrentJenkinsAndClient(&(jClient.JenkinsCore)) + + err = jClient.Delete(credentialDeleteOption.Store, credentialDeleteOption.ID) + return + }, +} diff --git a/app/cmd/credential_delete_test.go b/app/cmd/credential_delete_test.go new file mode 100644 index 0000000000000000000000000000000000000000..96d3cdbb5e3c65df2f0ae3e55af2c127d87282ab --- /dev/null +++ b/app/cmd/credential_delete_test.go @@ -0,0 +1,76 @@ +package cmd + +import ( + "bytes" + "io/ioutil" + "os" + + "github.com/jenkins-zh/jenkins-cli/client" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/jenkins-zh/jenkins-cli/mock/mhttp" +) + +var _ = Describe("credential delete command", func() { + var ( + ctrl *gomock.Controller + roundTripper *mhttp.MockRoundTripper + buf *bytes.Buffer + store string + id string + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + roundTripper = mhttp.NewMockRoundTripper(ctrl) + rootCmd.SetArgs([]string{}) + buf = new(bytes.Buffer) + rootCmd.SetOutput(buf) + rootOptions.Jenkins = "" + rootOptions.ConfigFile = "test.yaml" + + credentialDeleteOption.RoundTripper = roundTripper + + store = "system" + id = "fake-id" + }) + + AfterEach(func() { + rootCmd.SetArgs([]string{}) + os.Remove(rootOptions.ConfigFile) + rootOptions.ConfigFile = "" + ctrl.Finish() + }) + + Context("basic cases", func() { + var ( + err error + ) + + BeforeEach(func() { + var data []byte + data, err = generateSampleConfig() + Expect(err).To(BeNil()) + err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664) + Expect(err).To(BeNil()) + }) + + It("lack of the necessary parameters", func() { + rootCmd.SetArgs([]string{"credential", "delete"}) + _, err = rootCmd.ExecuteC() + Expect(err).To(HaveOccurred()) + }) + + It("should success", func() { + client.PrepareForDeleteCredential(roundTripper, "http://localhost:8080/jenkins", + "admin", "111e3a2f0231198855dceaff96f20540a9", store, id) + + rootCmd.SetArgs([]string{"credential", "delete", store, id, "-b"}) + _, err = rootCmd.ExecuteC() + Expect(err).To(BeNil()) + }) + }) +}) diff --git a/app/cmd/credential_list.go b/app/cmd/credential_list.go new file mode 100644 index 0000000000000000000000000000000000000000..3c83746a3f881f46f135ec6eb86c05a41913b5a1 --- /dev/null +++ b/app/cmd/credential_list.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/jenkins-zh/jenkins-cli/client" + "net/http" + + "github.com/jenkins-zh/jenkins-cli/app/i18n" + + "github.com/jenkins-zh/jenkins-cli/util" + "github.com/spf13/cobra" +) + +// CredentialListOption option for credential list command +type CredentialListOption struct { + OutputOption + + Store string + + RoundTripper http.RoundTripper +} + +var credentialListOption CredentialListOption + +func init() { + credentialCmd.AddCommand(credentialListCmd) + credentialListCmd.Flags().StringVarP(&credentialListOption.Store, "store", "", "system", + i18n.T("The store name of Jenkins credentials")) + credentialListOption.SetFlag(credentialListCmd) +} + +var credentialListCmd = &cobra.Command{ + Use: "list", + Short: i18n.T("List all credentials of Jenkins"), + Long: i18n.T("List all credentials of Jenkins"), + RunE: func(cmd *cobra.Command, _ []string) (err error) { + jClient := &client.CredentialsManager{ + JenkinsCore: client.JenkinsCore{ + RoundTripper: credentialListOption.RoundTripper, + }, + } + getCurrentJenkinsAndClient(&(jClient.JenkinsCore)) + + var credentialList client.CredentialList + var data []byte + if credentialList, err = jClient.GetList(credentialListOption.Store); err == nil { + if data, err = credentialListOption.Output(credentialList); err == nil { + cmd.Print(string(data)) + } + } + return + }, +} + +// Output render data into byte array as a table format +func (o *CredentialListOption) Output(obj interface{}) (data []byte, err error) { + if data, err = o.OutputOption.Output(obj); err != nil && o.Format == TableOutputFormat { + credentialList := obj.(client.CredentialList) + + buf := new(bytes.Buffer) + table := util.CreateTableWithHeader(buf, o.WithoutHeaders) + table.AddHeader("number", "displayName", "id", "type", "description") + for i, cred := range credentialList.Credentials { + table.AddRow(fmt.Sprintf("%d", i), cred.DisplayName, cred.ID, cred.TypeName, cred.Description) + } + table.Render() + err = nil + data = buf.Bytes() + } + return +} diff --git a/app/cmd/credential_list_test.go b/app/cmd/credential_list_test.go new file mode 100644 index 0000000000000000000000000000000000000000..4182be3e9e5f786b5c54b2f8fbda903ca767b835 --- /dev/null +++ b/app/cmd/credential_list_test.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "bytes" + "io/ioutil" + "os" + + "github.com/jenkins-zh/jenkins-cli/client" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/jenkins-zh/jenkins-cli/mock/mhttp" +) + +var _ = Describe("credential list command", func() { + var ( + ctrl *gomock.Controller + roundTripper *mhttp.MockRoundTripper + buf *bytes.Buffer + store string + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + roundTripper = mhttp.NewMockRoundTripper(ctrl) + rootCmd.SetArgs([]string{}) + buf = new(bytes.Buffer) + rootCmd.SetOutput(buf) + rootOptions.Jenkins = "" + rootOptions.ConfigFile = "test.yaml" + + credentialListOption.RoundTripper = roundTripper + + store = "system" + }) + + AfterEach(func() { + rootCmd.SetArgs([]string{}) + os.Remove(rootOptions.ConfigFile) + rootOptions.ConfigFile = "" + ctrl.Finish() + }) + + Context("basic cases", func() { + var ( + err error + ) + + BeforeEach(func() { + var data []byte + data, err = generateSampleConfig() + Expect(err).To(BeNil()) + err = ioutil.WriteFile(rootOptions.ConfigFile, data, 0664) + Expect(err).To(BeNil()) + }) + + It("should success", func() { + client.PrepareForGetCredentialList(roundTripper, "http://localhost:8080/jenkins", + "admin", "111e3a2f0231198855dceaff96f20540a9", store) + + rootCmd.SetArgs([]string{"credential", "list"}) + _, err = rootCmd.ExecuteC() + Expect(err).To(BeNil()) + Expect(buf.String()).To(Equal(`number displayName id type description +0 displayName 19c27487-acca-4a39-9889-9ddd500388f3 Username with password +`)) + }) + }) +}) diff --git a/client/credentials.go b/client/credentials.go new file mode 100644 index 0000000000000000000000000000000000000000..342024ba4dee9f5805ac14c038e68c2630ab3b7a --- /dev/null +++ b/client/credentials.go @@ -0,0 +1,99 @@ +package client + +import ( + "encoding/json" + "fmt" + "net/url" + "strings" + + "github.com/jenkins-zh/jenkins-cli/util" +) + +// CredentialsManager hold the info of credentials client +type CredentialsManager struct { + JenkinsCore +} + +// GetList returns the credential list +func (c *CredentialsManager) GetList(store string) (credentialList CredentialList, err error) { + api := fmt.Sprintf("/credentials/store/%s/domain/_/api/json?pretty=true&depth=1", store) + err = c.RequestWithData("GET", api, nil, nil, 200, &credentialList) + return +} + +// Delete removes a credential by id from a store +func (c *CredentialsManager) Delete(store, id string) (err error) { + api := fmt.Sprintf("/credentials/store/%s/domain/_/credential/%s/doDelete", store, id) + _, err = c.RequestWithoutData("POST", api, nil, nil, 200) + return +} + +// Create create a credential in Jenkins +func (c *CredentialsManager) Create(store, credential string) (err error) { + api := fmt.Sprintf("/credentials/store/%s/domain/_/createCredentials", store) + + formData := url.Values{} + formData.Add("json", fmt.Sprintf(`{"credentials": %s}`, credential)) + payload := strings.NewReader(formData.Encode()) + + _, err = c.RequestWithoutData("POST", api, + map[string]string{util.ContentType: util.ApplicationForm}, payload, 200) + return +} + +// CreateUsernamePassword create username and password credential in Jenkins +func (c *CredentialsManager) CreateUsernamePassword(store string, cred UsernamePasswordCredential) (err error) { + var payload []byte + cred.Class = "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl" + if payload, err = json.Marshal(cred); err == nil { + err = c.Create(store, string(payload)) + } + return +} + +// CreateSecret create token credential in Jenkins +func (c *CredentialsManager) CreateSecret(store string, cred StringCredentials) (err error) { + var payload []byte + cred.Class = "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl" + cred.Scope = "GLOBAL" + if payload, err = json.Marshal(cred); err == nil { + err = c.Create(store, string(payload)) + } + return +} + +// Credential of Jenkins +type Credential struct { + Description string `json:"description"` + DisplayName string + Fingerprint interface{} + FullName string + ID string `json:"id"` + TypeName string + Class string `json:"$class"` + Scope string `json:"scope"` +} + +// UsernamePasswordCredential hold the username and password +type UsernamePasswordCredential struct { + Credential `json:",inline"` + Username string `json:"username"` + Password string `json:"password"` +} + +// StringCredentials hold a token +type StringCredentials struct { + Credential `json:",inline"` + Secret string `json:"secret"` +} + +// CredentialList contains many credentials +type CredentialList struct { + Description string + DisplayName string + FullDisplayName string + FullName string + Global bool + URLName string + Credentials []Credential +} diff --git a/client/credentials_test.go b/client/credentials_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f624d3d78c3ac1fd77520fcd96a8139845e20a81 --- /dev/null +++ b/client/credentials_test.go @@ -0,0 +1,80 @@ +package client_test + +import ( + "github.com/golang/mock/gomock" + "github.com/jenkins-zh/jenkins-cli/client" + "github.com/jenkins-zh/jenkins-cli/mock/mhttp" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("job test", func() { + var ( + ctrl *gomock.Controller + credentialsManager client.CredentialsManager + roundTripper *mhttp.MockRoundTripper + store string + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + credentialsManager = client.CredentialsManager{} + roundTripper = mhttp.NewMockRoundTripper(ctrl) + credentialsManager.RoundTripper = roundTripper + credentialsManager.URL = "http://localhost" + + store = "system" + }) + + AfterEach(func() { + ctrl.Finish() + }) + + Context("GetList", func() { + It("should success", func() { + client.PrepareForGetCredentialList(roundTripper, credentialsManager.URL, "", "", store) + + list, err := credentialsManager.GetList(store) + Expect(err).NotTo(HaveOccurred()) + Expect(list).NotTo(BeNil()) + Expect(len(list.Credentials)).To(Equal(1)) + }) + }) + + Context("Delete", func() { + var ( + id = "fake-id" + ) + + It("should success", func() { + client.PrepareForDeleteCredential(roundTripper, credentialsManager.URL, "", "", store, id) + + err := credentialsManager.Delete(store, id) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("CreateUsernamePassword", func() { + It("should success", func() { + cred := client.UsernamePasswordCredential{} + + client.PrepareForCreateUsernamePasswordCredential(roundTripper, credentialsManager.URL, + "", "", store, cred) + + err := credentialsManager.CreateUsernamePassword(store, cred) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("CreateSecret", func() { + It("should success", func() { + cred := client.StringCredentials{} + + client.PrepareForCreateSecretCredential(roundTripper, credentialsManager.URL, + "", "", store, cred) + + err := credentialsManager.CreateSecret(store, cred) + Expect(err).NotTo(HaveOccurred()) + }) + }) +}) diff --git a/client/credentials_test_common.go b/client/credentials_test_common.go new file mode 100644 index 0000000000000000000000000000000000000000..7f9a7eee50e9cfed25d8cae3337f7184d806c65a --- /dev/null +++ b/client/credentials_test_common.go @@ -0,0 +1,93 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/jenkins-zh/jenkins-cli/mock/mhttp" + "github.com/jenkins-zh/jenkins-cli/util" +) + +// PrepareForGetCredentialList only for test +func PrepareForGetCredentialList(roundTripper *mhttp.MockRoundTripper, rootURL, user, password, store string) { + api := fmt.Sprintf("%s/credentials/store/%s/domain/_/api/json?pretty=true&depth=1", rootURL, store) + request, _ := http.NewRequest("GET", api, nil) + response := &http.Response{ + StatusCode: 200, + Request: request, + Body: ioutil.NopCloser(bytes.NewBufferString(PrepareForCredentialListJSON())), + } + roundTripper.EXPECT(). + RoundTrip(request).Return(response, nil) + if user != "" && password != "" { + request.SetBasicAuth(user, password) + } +} + +// PrepareForDeleteCredential only for test +func PrepareForDeleteCredential(roundTripper *mhttp.MockRoundTripper, rootURL, user, password, store, id string) { + api := fmt.Sprintf("%s/credentials/store/%s/domain/_/credential/%s/doDelete", rootURL, store, id) + request, _ := http.NewRequest("POST", api, nil) + PrepareCommonPost(request, "", roundTripper, user, password, rootURL) +} + +// PrepareForCreateCredential only for test +func PrepareForCreateCredential(roundTripper *mhttp.MockRoundTripper, rootURL, user, password, store, credential string) { + api := fmt.Sprintf("%s/credentials/store/%s/domain/_/createCredentials", rootURL, store) + + formData := url.Values{} + formData.Add("json", fmt.Sprintf(`{"credentials": %s}`, credential)) + payload := strings.NewReader(formData.Encode()) + + request, _ := http.NewRequest("POST", api, payload) + request.Header.Add(util.ContentType, util.ApplicationForm) + PrepareCommonPost(request, "", roundTripper, user, password, rootURL) +} + +// PrepareForCreateUsernamePasswordCredential only for test +func PrepareForCreateUsernamePasswordCredential(roundTripper *mhttp.MockRoundTripper, rootURL, user, password, + store string, cred UsernamePasswordCredential) { + cred.Class = "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl" + if payload, err := json.Marshal(cred); err == nil { + PrepareForCreateCredential(roundTripper, rootURL, user, password, store, string(payload)) + } +} + +// PrepareForCreateSecretCredential only for test +func PrepareForCreateSecretCredential(roundTripper *mhttp.MockRoundTripper, rootURL, user, password, + store string, cred StringCredentials) { + cred.Class = "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl" + cred.Scope = "GLOBAL" + if payload, err := json.Marshal(cred); err == nil { + PrepareForCreateCredential(roundTripper, rootURL, user, password, store, string(payload)) + } +} + +// PrepareForCredentialListJSON only for test +func PrepareForCredentialListJSON() string { + return `{ + "_class" : "com.cloudbees.plugins.credentials.CredentialsStoreAction$DomainWrapper", + "credentials" : [ + { + "description" : "", + "displayName" : "displayName", + "fingerprint" : { + }, + "fullName" : "system/_/19c27487-acca-4a39-9889-9ddd500388f3", + "id" : "19c27487-acca-4a39-9889-9ddd500388f3", + "typeName" : "Username with password" + } + ], + "description" : "Credentials that should be available irrespective of domain specification to requirements matching.", + "displayName" : "全局凭据 (unrestricted)", + "fullDisplayName" : "系统 » 全局凭据 (unrestricted)", + "fullName" : "system/_", + "global" : true, + "urlName" : "_" +}` +}