mirror of
https://github.com/appleboy/drone-jenkins.git
synced 2026-06-04 10:15:02 +08:00
feat: add debug mode with enhanced logging and token masking (#41)
* feat: add debug mode with enhanced logging and token masking - Add godump library dependency for improved debug output - Introduce a debug mode flag to the Jenkins and Plugin structs - Update NewJenkins constructor and all usages to support the debug flag - Mask sensitive tokens in debug output for security - Log detailed parameter and configuration information when debug mode is enabled - Add CLI flag to enable debug mode via environment variables Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * fix: add error handling and logging for godump.Dump failures - Add error handling for godump.Dump calls, logging a warning if dumping fails Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> --------- Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ require (
|
|||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/urfave/cli/v2 v2.27.5
|
github.com/urfave/cli/v2 v2.27.5
|
||||||
|
github.com/yassinebenaid/godump v0.11.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
|
|||||||
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
|
github.com/yassinebenaid/godump v0.11.1 h1:SPujx/XaYqGDfmNh7JI3dOyCUVrG0bG2duhO3Eh2EhI=
|
||||||
|
github.com/yassinebenaid/godump v0.11.1/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
+41
-1
@@ -11,6 +11,8 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/yassinebenaid/godump"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -26,6 +28,7 @@ type (
|
|||||||
BaseURL string
|
BaseURL string
|
||||||
Token string // Remote trigger token
|
Token string // Remote trigger token
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
|
Debug bool // Enable debug mode to show detailed information
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueueItem represents a Jenkins queue item response
|
// QueueItem represents a Jenkins queue item response
|
||||||
@@ -53,7 +56,7 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewJenkins is initial Jenkins object
|
// NewJenkins is initial Jenkins object
|
||||||
func NewJenkins(auth *Auth, url string, token string, insecure bool) *Jenkins {
|
func NewJenkins(auth *Auth, url string, token string, insecure bool, debug bool) *Jenkins {
|
||||||
url = strings.TrimRight(url, "/")
|
url = strings.TrimRight(url, "/")
|
||||||
|
|
||||||
client := http.DefaultClient
|
client := http.DefaultClient
|
||||||
@@ -71,6 +74,7 @@ func NewJenkins(auth *Auth, url string, token string, insecure bool) *Jenkins {
|
|||||||
BaseURL: url,
|
BaseURL: url,
|
||||||
Token: token,
|
Token: token,
|
||||||
Client: client,
|
Client: client,
|
||||||
|
Debug: debug,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +325,42 @@ func (jenkins *Jenkins) trigger(job string, params url.Values) (int, error) {
|
|||||||
urlPath = jenkins.parseJobPath(job) + "/build"
|
urlPath = jenkins.parseJobPath(job) + "/build"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug: Display parameters being sent
|
||||||
|
if jenkins.Debug {
|
||||||
|
log.Println("=== Debug Mode: Jenkins Job Trigger ===")
|
||||||
|
log.Printf("Job: %s", job)
|
||||||
|
log.Printf("URL Path: %s", urlPath)
|
||||||
|
|
||||||
|
// Build the full URL for display
|
||||||
|
fullURL := jenkins.buildURL(urlPath, params)
|
||||||
|
// Mask token in URL for display
|
||||||
|
if jenkins.Token != "" {
|
||||||
|
fullURL = strings.Replace(fullURL, "token="+jenkins.Token, "token=***MASKED***", 1)
|
||||||
|
}
|
||||||
|
log.Printf("Full URL: %s", fullURL)
|
||||||
|
|
||||||
|
if len(params) > 0 {
|
||||||
|
// Create a copy of params with masked token for display
|
||||||
|
displayParams := url.Values{}
|
||||||
|
for key, values := range params {
|
||||||
|
if key == "token" {
|
||||||
|
// Mask token values for security
|
||||||
|
displayParams[key] = []string{"***MASKED***"}
|
||||||
|
} else {
|
||||||
|
displayParams[key] = values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Parameters:")
|
||||||
|
if err := godump.Dump(displayParams); err != nil {
|
||||||
|
log.Printf("warning: failed to dump parameters: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("Parameters: (none)")
|
||||||
|
}
|
||||||
|
log.Println("======================================")
|
||||||
|
}
|
||||||
|
|
||||||
// All params (including token) are passed as query parameters
|
// All params (including token) are passed as query parameters
|
||||||
// Returns the queue item ID for tracking
|
// Returns the queue item ID for tracking
|
||||||
return jenkins.postAndGetLocation(urlPath, params)
|
return jenkins.postAndGetLocation(urlPath, params)
|
||||||
|
|||||||
+10
-10
@@ -16,7 +16,7 @@ func TestParseJobPath(t *testing.T) {
|
|||||||
Username: "appleboy",
|
Username: "appleboy",
|
||||||
Token: "1234",
|
Token: "1234",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, "http://example.com", "", false)
|
jenkins := NewJenkins(auth, "http://example.com", "", false, false)
|
||||||
|
|
||||||
assert.Equal(t, "/job/foo", jenkins.parseJobPath("/foo/"))
|
assert.Equal(t, "/job/foo", jenkins.parseJobPath("/foo/"))
|
||||||
assert.Equal(t, "/job/foo", jenkins.parseJobPath("foo/"))
|
assert.Equal(t, "/job/foo", jenkins.parseJobPath("foo/"))
|
||||||
@@ -29,7 +29,7 @@ func TestUnSupportProtocol(t *testing.T) {
|
|||||||
Username: "foo",
|
Username: "foo",
|
||||||
Token: "bar",
|
Token: "bar",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, "example.com", "", false)
|
jenkins := NewJenkins(auth, "example.com", "", false, false)
|
||||||
|
|
||||||
queueID, err := jenkins.trigger("drone-jenkins", nil)
|
queueID, err := jenkins.trigger("drone-jenkins", nil)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
@@ -50,7 +50,7 @@ func TestTriggerBuild(t *testing.T) {
|
|||||||
Username: "foo",
|
Username: "foo",
|
||||||
Token: "bar",
|
Token: "bar",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "remote-token", false)
|
jenkins := NewJenkins(auth, server.URL, "remote-token", false, false)
|
||||||
|
|
||||||
params := url.Values{"param": []string{"value"}}
|
params := url.Values{"param": []string{"value"}}
|
||||||
queueID, err := jenkins.trigger("drone-jenkins", params)
|
queueID, err := jenkins.trigger("drone-jenkins", params)
|
||||||
@@ -110,7 +110,7 @@ func TestPostAndGetLocation(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
queueID, err := jenkins.postAndGetLocation("/test", nil)
|
queueID, err := jenkins.postAndGetLocation("/test", nil)
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ func TestGetQueueItem(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
queueItem, err := jenkins.getQueueItem(tt.queueID)
|
queueItem, err := jenkins.getQueueItem(tt.queueID)
|
||||||
|
|
||||||
@@ -274,7 +274,7 @@ func TestGetBuildInfo(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
buildInfo, err := jenkins.getBuildInfo(tt.jobName, tt.buildNumber)
|
buildInfo, err := jenkins.getBuildInfo(tt.jobName, tt.buildNumber)
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ func TestWaitForCompletion(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
buildInfo, err := jenkins.waitForCompletion(
|
buildInfo, err := jenkins.waitForCompletion(
|
||||||
"test-job",
|
"test-job",
|
||||||
@@ -364,7 +364,7 @@ func TestWaitForCompletion(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
buildInfo, err := jenkins.waitForCompletion(
|
buildInfo, err := jenkins.waitForCompletion(
|
||||||
"test-job",
|
"test-job",
|
||||||
@@ -404,7 +404,7 @@ func TestWaitForCompletion(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
buildInfo, err := jenkins.waitForCompletion(
|
buildInfo, err := jenkins.waitForCompletion(
|
||||||
"test-job",
|
"test-job",
|
||||||
@@ -449,7 +449,7 @@ func TestWaitForCompletion(t *testing.T) {
|
|||||||
Username: "test",
|
Username: "test",
|
||||||
Token: "test",
|
Token: "test",
|
||||||
}
|
}
|
||||||
jenkins := NewJenkins(auth, server.URL, "", false)
|
jenkins := NewJenkins(auth, server.URL, "", false, false)
|
||||||
|
|
||||||
buildInfo, err := jenkins.waitForCompletion(
|
buildInfo, err := jenkins.waitForCompletion(
|
||||||
"test-job",
|
"test-job",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"github.com/yassinebenaid/godump"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version set at compile-time
|
// Version set at compile-time
|
||||||
@@ -23,6 +24,14 @@ ________ ____. __ .__
|
|||||||
version: {{.Version}}
|
version: {{.Version}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// maskToken masks a token string for secure display
|
||||||
|
func maskToken(token string) string {
|
||||||
|
if token == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "***MASKED***"
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Load env-file if it exists first
|
// Load env-file if it exists first
|
||||||
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
|
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
|
||||||
@@ -110,6 +119,11 @@ func main() {
|
|||||||
Value: 30 * time.Minute,
|
Value: 30 * time.Minute,
|
||||||
EnvVars: []string{"PLUGIN_TIMEOUT", "JENKINS_TIMEOUT", "INPUT_TIMEOUT"},
|
EnvVars: []string{"PLUGIN_TIMEOUT", "JENKINS_TIMEOUT", "INPUT_TIMEOUT"},
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "debug",
|
||||||
|
Usage: "enable debug mode to show detailed parameter information",
|
||||||
|
EnvVars: []string{"PLUGIN_DEBUG", "JENKINS_DEBUG", "INPUT_DEBUG"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override a template
|
// Override a template
|
||||||
@@ -174,6 +188,44 @@ func run(c *cli.Context) error {
|
|||||||
Wait: c.Bool("wait"),
|
Wait: c.Bool("wait"),
|
||||||
PollInterval: c.Duration("poll-interval"),
|
PollInterval: c.Duration("poll-interval"),
|
||||||
Timeout: c.Duration("timeout"),
|
Timeout: c.Duration("timeout"),
|
||||||
|
Debug: c.Bool("debug"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display plugin configuration in debug mode
|
||||||
|
if plugin.Debug {
|
||||||
|
log.Println("=== Debug Mode: Plugin Configuration ===")
|
||||||
|
|
||||||
|
// Create a display copy with masked sensitive data
|
||||||
|
displayPlugin := struct {
|
||||||
|
BaseURL string
|
||||||
|
Username string
|
||||||
|
Token string
|
||||||
|
RemoteToken string
|
||||||
|
Job []string
|
||||||
|
Insecure bool
|
||||||
|
Parameters []string
|
||||||
|
Wait bool
|
||||||
|
PollInterval time.Duration
|
||||||
|
Timeout time.Duration
|
||||||
|
Debug bool
|
||||||
|
}{
|
||||||
|
BaseURL: plugin.BaseURL,
|
||||||
|
Username: plugin.Username,
|
||||||
|
Token: maskToken(plugin.Token),
|
||||||
|
RemoteToken: maskToken(plugin.RemoteToken),
|
||||||
|
Job: plugin.Job,
|
||||||
|
Insecure: plugin.Insecure,
|
||||||
|
Parameters: plugin.Parameters,
|
||||||
|
Wait: plugin.Wait,
|
||||||
|
PollInterval: plugin.PollInterval,
|
||||||
|
Timeout: plugin.Timeout,
|
||||||
|
Debug: plugin.Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := godump.Dump(displayPlugin); err != nil {
|
||||||
|
log.Printf("warning: failed to dump plugin configuration: %v", err)
|
||||||
|
}
|
||||||
|
log.Println("========================================")
|
||||||
}
|
}
|
||||||
|
|
||||||
return plugin.Exec()
|
return plugin.Exec()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type (
|
|||||||
Wait bool // Whether to wait for job completion
|
Wait bool // Whether to wait for job completion
|
||||||
PollInterval time.Duration // Interval between status checks (default: 10s)
|
PollInterval time.Duration // Interval between status checks (default: 10s)
|
||||||
Timeout time.Duration // Maximum time to wait for job completion (default: 30m)
|
Timeout time.Duration // Maximum time to wait for job completion (default: 30m)
|
||||||
|
Debug bool // Enable debug mode to show detailed parameter information
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ func (p Plugin) Exec() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Jenkins client
|
// Initialize Jenkins client
|
||||||
jenkins := NewJenkins(auth, p.BaseURL, p.RemoteToken, p.Insecure)
|
jenkins := NewJenkins(auth, p.BaseURL, p.RemoteToken, p.Insecure, p.Debug)
|
||||||
|
|
||||||
// Parse job parameters
|
// Parse job parameters
|
||||||
params := parseParameters(p.Parameters)
|
params := parseParameters(p.Parameters)
|
||||||
|
|||||||
Reference in New Issue
Block a user