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

Add custom war packager support (#340)

* Add custom war packager wrapper support

* Create dir if it does no exists when gen doc

* Keep the same default value of temp dir

* Fix the fake exec command error

* Do not focus one test case

* Fix the cwp test fail

* Give the runner as a specific version

* Format the code
上级 5dd4de9e
......@@ -8,7 +8,7 @@ on:
jobs:
build:
name: Build
runs-on: ubuntu-latest
runs-on: ubuntu-18.04
steps:
- name: Set up Go 1.13
......
......@@ -13,6 +13,7 @@
bin/
release/
jcli
*.xml
......
......@@ -19,6 +19,7 @@ init: gen-mock
darwin: gen-data
GO111MODULE=on CGO_ENABLED=$(CGO_ENABLED) GOOS=darwin GOARCH=amd64 $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o bin/darwin/$(NAME) $(MAIN_SRC_FILE)
chmod +x bin/darwin/$(NAME)
rm -rf jcli && ln -s bin/darwin/$(NAME) jcli
linux: gen-data
CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GOARCH=amd64 $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o bin/linux/$(NAME) $(MAIN_SRC_FILE)
......
package cmd
import (
"encoding/xml"
"fmt"
"github.com/jenkins-zh/jenkins-cli/app/i18n"
"github.com/jenkins-zh/jenkins-cli/util"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"io/ioutil"
"os"
"path"
)
func init() {
rootCmd.AddCommand(cwpCmd)
cwpCmd.Flags().BoolVarP(&cwpOptions.BatchMode, "batch-mode", "", false,
i18n.T("Enables the batch mode for the build"))
cwpCmd.Flags().StringVarP(&cwpOptions.BomPath, "bom-path", "", "",
i18n.T("Path to the BOM file. If defined, it will override settings in Config YAML"))
cwpCmd.Flags().StringVarP(&cwpOptions.Environment, "environment", "", "",
i18n.T("Environment to be used"))
cwpCmd.Flags().BoolVarP(&cwpOptions.InstallArtifacts, "install-artifacts", "", false,
i18n.T("If set, the final artifacts will be automatically installed to the local repository (current version - only WAR)"))
cwpCmd.Flags().StringVarP(&cwpOptions.ConfigPath, "config-path", "", "",
i18n.T("Path to the configuration YAML. See the tool's README for format"))
cwpCmd.Flags().BoolVarP(&cwpOptions.Demo, "demo", "", false,
i18n.T("Enables demo mode with predefined config file"))
cwpCmd.Flags().StringVarP(&cwpOptions.MvnSettingsFile, "mvn-settings-file", "", "",
i18n.T("Path to a custom Maven settings file to be used within the build"))
cwpCmd.Flags().StringVarP(&cwpOptions.TmpDir, "tmp-dir", "", "",
i18n.T("Temporary directory for generated files and the output WAR."))
cwpCmd.Flags().StringVarP(&cwpOptions.Version, "version", "", "1.0-SNAPSHOT",
i18n.T("Version of WAR to be set."))
cwpCmd.Flags().BoolVarP(&cwpOptions.ShowProgress, "show-progress", "", true,
i18n.T("Show the progress of downloading files"))
cwpCmd.Flags().StringVarP(&cwpOptions.MetadataURL, "metadata-url", "",
"https://repo.jenkins-ci.org/list/releases/io/jenkins/tools/custom-war-packager/custom-war-packager-cli/maven-metadata.xml",
i18n.T("The metadata URL"))
localCache := path.Join(os.TempDir(), "/", ".jenkins-cli")
if userHome, err := homedir.Dir(); err == nil {
localCache = path.Join(userHome, "/", ".jenkins-cli")
}
cwpCmd.Flags().StringVarP(&cwpOptions.LocalCache, "local-cache", "", localCache,
i18n.T("The local cache directory"))
}
// CWPOptions is the option of custom-war-packager
// see also https://github.com/jenkinsci/custom-war-packager
type CWPOptions struct {
CommonOption
ConfigPath string
Version string
TmpDir string
Environment string
BomPath string
MvnSettingsFile string
BatchMode bool
Demo bool
InstallArtifacts bool
ShowProgress bool
MetadataURL string
LocalCache string
}
var cwpOptions CWPOptions
var cwpCmd = &cobra.Command{
Use: "cwp",
Short: i18n.T("Custom Jenkins WAR packager for Jenkins"),
Long: i18n.T(`Custom Jenkins WAR packager for Jenkins
This's a wrapper of https://github.com/jenkinsci/custom-war-packager`),
RunE: cwpOptions.Run,
Annotations: map[string]string{
since: "v0.0.27",
},
}
// Run is the main logic of cwp cmd
func (o *CWPOptions) Run(cmd *cobra.Command, args []string) (err error) {
localCWP := o.getLocalCWP()
_, err = os.Stat(localCWP)
if os.IsNotExist(err) {
if err = o.Download(); err != nil {
return
}
} else if err != nil {
return
}
var binary string
binary, err = util.LookPath("java", o.LookPathContext)
if err == nil {
env := os.Environ()
cwpArgs := []string{"java"}
cwpArgs = append(cwpArgs, "-jar", localCWP)
if o.Demo {
cwpArgs = append(cwpArgs, "-demo")
}
if o.BatchMode {
cwpArgs = append(cwpArgs, "--batch-mode")
}
if o.InstallArtifacts {
cwpArgs = append(cwpArgs, "--installArtifacts")
}
if o.ConfigPath != "" {
cwpArgs = append(cwpArgs, "-configPath", o.ConfigPath)
}
if o.TmpDir != "" {
cwpArgs = append(cwpArgs, "-tmpDir", o.TmpDir)
}
err = util.Exec(binary, cwpArgs, env, o.SystemCallExec)
}
return
}
// Download get the latest cwp from server into local
func (o *CWPOptions) Download() (err error) {
var latest string
if latest, err = o.GetLatest(); err == nil {
cwpURL := o.GetCWPURL(latest)
err = o.downloadFile(cwpURL, o.getLocalCWP())
}
return
}
// GetCWPURL returns the download URL of a specific version cwp
func (o *CWPOptions) GetCWPURL(version string) string {
return fmt.Sprintf("https://repo.jenkins-ci.org/list/releases/io/jenkins/tools/custom-war-packager/custom-war-packager-cli/%s/custom-war-packager-cli-%s-jar-with-dependencies.jar",
version, version)
}
func (o *CWPOptions) getLocalCWP() string {
return path.Join(o.LocalCache, "cwp-cli.jar")
}
// GetLatest returns the latest of cwp
func (o *CWPOptions) GetLatest() (version string, err error) {
metadataURL := o.MetadataURL
output := "metadata.xml"
if err = o.downloadFile(metadataURL, output); err == nil {
var data []byte
mavenMeta := MavenMetadata{}
if data, err = ioutil.ReadFile(output); err == nil {
err = xml.Unmarshal(data, &mavenMeta)
}
if err == nil {
version = mavenMeta.Versioning.Latest
}
}
return
}
func (o *CWPOptions) downloadFile(url, output string) (err error) {
downloader := util.HTTPDownloader{
RoundTripper: o.RoundTripper,
TargetFilePath: output,
URL: url,
ShowProgress: o.ShowProgress,
}
err = downloader.DownloadFile()
return
}
// MavenMetadata is the maven metadata xml root
type MavenMetadata struct {
XMLName xml.Name `xml:"metadata"`
Versioning MavenVersioning `xml:"versioning"`
}
// MavenVersioning is the versioning of maven
type MavenVersioning struct {
XMLName xml.Name `xml:"versioning"`
Latest string `xml:"latest"`
Release string `xml:"release"`
}
package cmd
import (
"bytes"
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-cli/mock/mhttp"
"github.com/jenkins-zh/jenkins-cli/util"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"os"
"path"
"testing"
)
var _ = Describe("cwp command test", func() {
var (
ctrl *gomock.Controller
localCache string
)
BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
localCache = os.TempDir()
roundTripper := mhttp.NewMockRoundTripper(ctrl)
cwpOptions = CWPOptions{
CommonOption: CommonOption{RoundTripper: roundTripper},
MetadataURL: "http://localhost/maven-metadata.xml",
LocalCache: localCache,
}
prepareMavenMetadataRequest(roundTripper)
fakeContent := "hello"
prepareDownloadFileRequest(cwpOptions.GetCWPURL("2.0-alpha-2"), fakeContent, roundTripper)
cwpOptions.SystemCallExec = util.FakeSystemCallExecSuccess
cwpOptions.LookPathContext = util.FakeLookPath
})
AfterEach(func() {
os.RemoveAll(localCache)
ctrl.Finish()
})
Context("basic test", func() {
It("should success", func() {
rootCmd.SetArgs([]string{"cwp"})
_, err := rootCmd.ExecuteC()
Expect(err).NotTo(HaveOccurred())
})
})
})
func TestDownload(t *testing.T) {
ctrl := gomock.NewController(t)
tmpDir := os.TempDir()
defer os.RemoveAll(tmpDir)
roundTripper := mhttp.NewMockRoundTripper(ctrl)
cwpOpts := CWPOptions{
CommonOption: CommonOption{RoundTripper: roundTripper},
MetadataURL: "http://localhost/maven-metadata.xml",
LocalCache: tmpDir,
}
prepareMavenMetadataRequest(roundTripper)
fakeContent := "hello"
prepareDownloadFileRequest(cwpOpts.GetCWPURL("2.0-alpha-2"), fakeContent, roundTripper)
err := cwpOpts.Download()
assert.Nil(t, err)
var data []byte
data, err = ioutil.ReadFile(path.Join(tmpDir, "cwp-cli.jar"))
assert.Nil(t, err)
assert.Equal(t, fakeContent, string(data))
}
func TestGetLatest(t *testing.T) {
ctrl := gomock.NewController(t)
roundTripper := mhttp.NewMockRoundTripper(ctrl)
cwpOpts := CWPOptions{
CommonOption: CommonOption{RoundTripper: roundTripper},
MetadataURL: "http://localhost/maven-metadata.xml",
}
prepareMavenMetadataRequest(roundTripper)
ver, err := cwpOpts.GetLatest()
assert.Nil(t, err)
assert.Equal(t, "2.0-alpha-2", ver)
}
func prepareDownloadFileRequest(url, content string, roundTripper *mhttp.MockRoundTripper) {
request, _ := http.NewRequest("GET", url, nil)
response := &http.Response{
StatusCode: 200,
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(content)),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
}
func prepareMavenMetadataRequest(roundTripper *mhttp.MockRoundTripper) {
request, _ := http.NewRequest("GET", "http://localhost/maven-metadata.xml", nil)
response := &http.Response{
StatusCode: 200,
Request: request,
Body: ioutil.NopCloser(bytes.NewBufferString(getMavenMetadataSample())),
}
roundTripper.EXPECT().
RoundTrip(request).Return(response, nil)
}
func getMavenMetadataSample() string {
return `<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>io.jenkins.tools.custom-war-packager</groupId>
<artifactId>custom-war-packager-cli</artifactId>
<versioning>
<latest>2.0-alpha-2</latest>
<release>2.0-alpha-2</release>
<versions>
<version>2.0-alpha-2</version>
</versions>
<lastUpdated>20190815083928</lastUpdated>
</versioning>
</metadata>`
}
......@@ -2,6 +2,7 @@ package cmd
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
......@@ -28,10 +29,11 @@ version: %s
)
var docCmd = &cobra.Command{
Use: "doc <output dir>",
Short: i18n.T("Generate document for all jcl commands"),
Long: i18n.T("Generate document for all jcl commands"),
Args: cobra.MinimumNArgs(1),
Use: "doc",
Example: "doc tmp",
Short: i18n.T("Generate document for all jcl commands"),
Long: i18n.T("Generate document for all jcl commands"),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
now := time.Now().Format(time.RFC3339)
prepender := func(filename string) string {
......@@ -48,9 +50,10 @@ var docCmd = &cobra.Command{
}
outputDir := args[0]
rootCmd.DisableAutoGenTag = true
err = doc.GenMarkdownTreeCustom(rootCmd, outputDir, prepender, linkHandler)
if err = os.MkdirAll(outputDir, os.FileMode(0755)); err == nil {
rootCmd.DisableAutoGenTag = true
err = doc.GenMarkdownTreeCustom(rootCmd, outputDir, prepender, linkHandler)
}
return
},
}
......@@ -2,12 +2,13 @@ package cmd
import (
"bytes"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"io/ioutil"
"os"
"path/filepath"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("doc command test", func() {
......@@ -37,17 +38,16 @@ var _ = Describe("doc command test", func() {
buf := new(bytes.Buffer)
rootCmd.SetOutput(buf)
tmpdir, err := ioutil.TempDir("", "test-gen-cmd-tree")
Expect(err).To(BeNil())
tmpdir := os.TempDir()
defer os.RemoveAll(tmpdir)
rootCmd.SetArgs([]string{"doc", tmpdir})
_, err = rootCmd.ExecuteC()
Expect(err).To(BeNil())
_, err := rootCmd.ExecuteC()
Expect(err).NotTo(HaveOccurred())
Expect(buf.String()).To(Equal(""))
_, err = os.Stat(filepath.Join(tmpdir, "jcli_doc.md"))
Expect(err).To(BeNil())
Expect(err).NotTo(HaveOccurred())
})
})
})
......@@ -3,13 +3,14 @@ package cmd
import (
"bytes"
"fmt"
"github.com/Netflix/go-expect"
"io/ioutil"
"net/http"
"os"
"testing"
"time"
expect "github.com/Netflix/go-expect"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/golang/mock/gomock"
"github.com/jenkins-zh/jenkins-cli/client"
......
......@@ -4,11 +4,11 @@ import (
"io/ioutil"
"os"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"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 disable command", func() {
......
......@@ -20,10 +20,10 @@ func init() {
}
var jobEnabelCmd = &cobra.Command{
Use: "enable",
Short: i18n.T("Enable a job in your Jenkins"),
Long: i18n.T("Enable a job in your Jenkins"),
Args: cobra.MinimumNArgs(1),
Use: "enable",
Short: i18n.T("Enable a job in your Jenkins"),
Long: i18n.T("Enable a job in your Jenkins"),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
jobName := args[0]
jclient := &client.JobClient{
......
......@@ -4,11 +4,11 @@ import (
"io/ioutil"
"os"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"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 enable command", func() {
......
......@@ -92,6 +92,7 @@ func needReadConfig(cmd *cobra.Command) bool {
ignoreConfigLoad := []string{
"config.generate",
"center.start",
"cwp",
"version",
}
configPath := getCmdPath(cmd)
......
package util
import (
"os"
"os/exec"
"runtime"
"syscall"
......@@ -57,7 +56,8 @@ type LookPathContext = func(file string) (string, error)
func FakeExecCommandSuccess(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestShellProcessSuccess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd := exec.Command("go", cs...)
//cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_TEST_PROCESS=1"}
return cmd
}
......
......@@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"os"
"path"
"strconv"
"github.com/gosuri/uiprogress"
......@@ -109,6 +110,11 @@ func (h *HTTPDownloader) DownloadFile() error {
}
}
}
if err := os.MkdirAll(path.Dir(filepath), os.FileMode(0755)); err != nil {
return err
}
// Create the file
out, err := os.Create(filepath)
if err != nil {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册