refactor: improve CLI robustness and Jenkins integration

- Add missing .PHONY targets to the Makefile for better build reliability
- Ensure HTTP response bodies are always read and closed in Jenkins post requests
- Replace custom response parsing with direct JSON unmarshalling in Jenkins post
- Set a default value for the Version variable
- Move ASCII art to a constant and reuse for CLI help template
- Improve dotenv loading error handling and logging in main
- Update repository link in CLI help output
- Add validation for required CLI parameters and authentication in run function

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Bo-Yi Wu
2025-12-01 17:23:52 +08:00
parent 3dd86f956c
commit 52abef124e
3 changed files with 52 additions and 13 deletions
+4
View File
@@ -39,14 +39,18 @@ endif
TAGS ?=
LDFLAGS ?= -X 'main.Version=$(VERSION)'
.PHONY: all
all: build
.PHONY: test
test:
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
.PHONY: install
install: $(GOFILES)
$(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)'
.PHONY: build
build: $(EXECUTABLE)
$(EXECUTABLE): $(GOFILES)
+11 -1
View File
@@ -96,11 +96,21 @@ func (jenkins *Jenkins) post(path string, params url.Values, body interface{}) (
return
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected response code: %d, body: %s", resp.StatusCode, string(data))
}
return jenkins.parseResponse(resp, body)
if body == nil {
return nil
}
return json.Unmarshal(data, body)
}
func (jenkins *Jenkins) parseJobPath(job string) string {
+37 -12
View File
@@ -1,6 +1,7 @@
package main
import (
"fmt"
"log"
"os"
@@ -9,16 +10,30 @@ import (
)
// Version set at compile-time
var Version string
var Version = "dev"
const asciiArt = `
________ ____. __ .__
\______ \_______ ____ ____ ____ | | ____ ____ | | _|__| ____ ______
| | \_ __ \/ _ \ / \_/ __ \ ______ | |/ __ \ / \| |/ / |/ \ / ___/
| | \ | \( <_> ) | \ ___/ /_____/ /\__| \ ___/| | \ <| | | \\___ \
/_______ /__| \____/|___| /\___ > \________|___ >___| /__|_ \__|___| /____ >
\/ \/ \/ \/ \/ \/ \/ \/
version: {{.Version}}
`
func main() {
// Load env-file if it exists first
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
_ = godotenv.Load(filename)
if err := godotenv.Load(filename); err != nil && !os.IsNotExist(err) {
log.Printf("Warning: failed to load env file %s: %v", filename, err)
}
}
if _, err := os.Stat("/run/drone/env"); err == nil {
_ = godotenv.Overload("/run/drone/env")
if err := godotenv.Overload("/run/drone/env"); err != nil {
log.Printf("Warning: failed to load /run/drone/env: %v", err)
}
}
app := cli.NewApp()
@@ -76,14 +91,7 @@ func main() {
}
// Override a template
cli.AppHelpTemplate = `
________ ____. __ .__
\______ \_______ ____ ____ ____ | | ____ ____ | | _|__| ____ ______
| | \_ __ \/ _ \ / \_/ __ \ ______ | |/ __ \ / \| |/ / |/ \ / ___/
| | \ | \( <_> ) | \ ___/ /_____/ /\__| \ ___/| | \ <| | | \\___ \
/_______ /__| \____/|___| /\___ > \________|\___ >___| /__|_ \__|___| /____ >
\/ \/ \/ \/ \/ \/ \/ \/
version: {{.Version}}
cli.AppHelpTemplate = asciiArt + `
NAME:
{{.Name}} - {{.Usage}}
@@ -107,7 +115,7 @@ VERSION:
{{.Version}}
{{end}}
REPOSITORY:
Github: https://github.com/appleboy/drone-line
Github: https://github.com/appleboy/drone-jenkins
`
if err := app.Run(os.Args); err != nil {
@@ -116,6 +124,23 @@ REPOSITORY:
}
func run(c *cli.Context) error {
// Validate required parameters
if c.String("host") == "" {
return fmt.Errorf("host is required")
}
if len(c.StringSlice("job")) == 0 {
return fmt.Errorf("at least one job is required")
}
// Validate authentication: either (user + token) or remote-token must be provided
hasUserAuth := c.String("user") != "" && c.String("token") != ""
hasRemoteToken := c.String("remote-token") != ""
if !hasUserAuth && !hasRemoteToken {
return fmt.Errorf("authentication required: provide either (user + token) or remote-token")
}
plugin := Plugin{
BaseURL: c.String("host"),
Username: c.String("user"),