diff --git a/go.mod b/go.mod index 465fd7f..db73e58 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/joho/godotenv v1.5.1 github.com/stretchr/testify v1.10.0 github.com/urfave/cli/v2 v2.27.5 + github.com/yassinebenaid/godump v0.11.1 ) require ( diff --git a/go.sum b/go.sum index 81a1f32..89e6597 100644 --- a/go.sum +++ b/go.sum @@ -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/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/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/jenkins.go b/jenkins.go index 3b18a59..11f0cb9 100644 --- a/jenkins.go +++ b/jenkins.go @@ -11,6 +11,8 @@ import ( "net/url" "strings" "time" + + "github.com/yassinebenaid/godump" ) type ( @@ -26,6 +28,7 @@ type ( BaseURL string Token string // Remote trigger token Client *http.Client + Debug bool // Enable debug mode to show detailed information } // QueueItem represents a Jenkins queue item response @@ -53,7 +56,7 @@ type ( ) // 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, "/") client := http.DefaultClient @@ -71,6 +74,7 @@ func NewJenkins(auth *Auth, url string, token string, insecure bool) *Jenkins { BaseURL: url, Token: token, Client: client, + Debug: debug, } } @@ -321,6 +325,42 @@ func (jenkins *Jenkins) trigger(job string, params url.Values) (int, error) { 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 // Returns the queue item ID for tracking return jenkins.postAndGetLocation(urlPath, params) diff --git a/jenkins_test.go b/jenkins_test.go index 942b9e2..2c01933 100644 --- a/jenkins_test.go +++ b/jenkins_test.go @@ -16,7 +16,7 @@ func TestParseJobPath(t *testing.T) { Username: "appleboy", 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/")) @@ -29,7 +29,7 @@ func TestUnSupportProtocol(t *testing.T) { Username: "foo", Token: "bar", } - jenkins := NewJenkins(auth, "example.com", "", false) + jenkins := NewJenkins(auth, "example.com", "", false, false) queueID, err := jenkins.trigger("drone-jenkins", nil) assert.NotNil(t, err) @@ -50,7 +50,7 @@ func TestTriggerBuild(t *testing.T) { Username: "foo", 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"}} queueID, err := jenkins.trigger("drone-jenkins", params) @@ -110,7 +110,7 @@ func TestPostAndGetLocation(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) queueID, err := jenkins.postAndGetLocation("/test", nil) @@ -186,7 +186,7 @@ func TestGetQueueItem(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) queueItem, err := jenkins.getQueueItem(tt.queueID) @@ -274,7 +274,7 @@ func TestGetBuildInfo(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) buildInfo, err := jenkins.getBuildInfo(tt.jobName, tt.buildNumber) @@ -332,7 +332,7 @@ func TestWaitForCompletion(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) buildInfo, err := jenkins.waitForCompletion( "test-job", @@ -364,7 +364,7 @@ func TestWaitForCompletion(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) buildInfo, err := jenkins.waitForCompletion( "test-job", @@ -404,7 +404,7 @@ func TestWaitForCompletion(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) buildInfo, err := jenkins.waitForCompletion( "test-job", @@ -449,7 +449,7 @@ func TestWaitForCompletion(t *testing.T) { Username: "test", Token: "test", } - jenkins := NewJenkins(auth, server.URL, "", false) + jenkins := NewJenkins(auth, server.URL, "", false, false) buildInfo, err := jenkins.waitForCompletion( "test-job", diff --git a/main.go b/main.go index 1f76392..d216527 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "github.com/joho/godotenv" "github.com/urfave/cli/v2" + "github.com/yassinebenaid/godump" ) // Version set at compile-time @@ -23,6 +24,14 @@ ________ ____. __ .__ version: {{.Version}} ` +// maskToken masks a token string for secure display +func maskToken(token string) string { + if token == "" { + return "" + } + return "***MASKED***" +} + func main() { // Load env-file if it exists first if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found { @@ -110,6 +119,11 @@ func main() { Value: 30 * time.Minute, 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 @@ -174,6 +188,44 @@ func run(c *cli.Context) error { Wait: c.Bool("wait"), PollInterval: c.Duration("poll-interval"), 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() diff --git a/plugin.go b/plugin.go index 146236b..36fd0b4 100644 --- a/plugin.go +++ b/plugin.go @@ -23,6 +23,7 @@ type ( Wait bool // Whether to wait for job completion PollInterval time.Duration // Interval between status checks (default: 10s) 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 - jenkins := NewJenkins(auth, p.BaseURL, p.RemoteToken, p.Insecure) + jenkins := NewJenkins(auth, p.BaseURL, p.RemoteToken, p.Insecure, p.Debug) // Parse job parameters params := parseParameters(p.Parameters)