diff --git a/.gitignore b/.gitignore index a175dc1..ca0304d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ drone-jira NOTES* output.json .vscode/ +.idea/ \ No newline at end of file diff --git a/plugin/plugin.go b/plugin/plugin.go index ccd24fb..24c6d7b 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -14,6 +14,7 @@ import ( "net/http" "net/http/httputil" "strconv" + "strings" "time" "github.com/sirupsen/logrus" @@ -101,18 +102,20 @@ func Exec(ctx context.Context, args Args) error { WithField("environment Type", environmentType). WithField("environment ID", environmentID) - //check if PLUGIN_ISSUEKEYS is provided + // check if PLUGIN_ISSUEKEYS is provided if len(args.IssueKeys) > 0 { + logger.Debugln("Provided issue keys are :", args.IssueKeys) issues = args.IssueKeys } else { // fallback to extracting from commit if no issue keys are passed - var issue string = extractIssue(args) - if issue == "" { + issues = extractIssues(args) + if len(issues) == 0 { logger.Debugln("cannot find issue number") return errors.New("failed to extract issue number") } - issues = []string{issue} // add the single issue here for consistency } + logger = logger.WithField("issues", strings.Join(issues, ",")) + logger.Debugln("successfully extracted all issues") commitMessage := args.Commit.Message if len(commitMessage) > 255 { @@ -433,7 +436,7 @@ func getCloudID(instance, cloudID string) (string, error) { return tenant.ID, nil } if cloudID == "" { - return "", fmt.Errorf("cloud id is empty. specify the cloud id or instance name") + return "", fmt.Errorf("Cloud id is empty. Specify the cloud id or instance name") } return cloudID, nil } diff --git a/plugin/util.go b/plugin/util.go index 6fc878e..dd46507 100644 --- a/plugin/util.go +++ b/plugin/util.go @@ -16,16 +16,18 @@ import ( // helper function to extract the issue number from // the commit details, including the commit message, // branch and pull request title. -func extractIssue(args Args) string { - return regexp.MustCompile(args.Project + "\\-\\d+").FindString( - fmt.Sprintln( - args.Commit.Message, - args.PullRequest.Title, - args.Commit.Source, - args.Commit.Target, - args.Commit.Branch, - ), - ) +func extractIssues(args Args) []string { + + regex := regexp.MustCompile(args.Project + "\\-\\d+") + matches := regex.FindAllString(fmt.Sprintln( + args.Commit.Message, + args.PullRequest.Title, + args.Commit.Source, + args.Commit.Target, + args.Commit.Branch, + ), -1) + + return removeDuplicates(matches) } // helper function determines the pipeline state. @@ -153,3 +155,21 @@ func toStateEnum(s string) string { return "unknown" } } + +func removeDuplicates(list []string) []string { + // Create an empty map to store seen elements + seen := make(map[string]bool) + + // Initialize a new list to store unique elements + uniqueList := []string{} + + for _, element := range list { + // Check if the element is already seen + if !seen[element] { + seen[element] = true + uniqueList = append(uniqueList, element) + } + } + + return uniqueList +} diff --git a/plugin/util_test.go b/plugin/util_test.go index c4e6c0c..79d1ba9 100644 --- a/plugin/util_test.go +++ b/plugin/util_test.go @@ -6,43 +6,94 @@ package plugin import "testing" -func TestExtractIssue(t *testing.T) { +// compareSlices checks if s2 is a subset of s1 +func compareSlices(s1, s2 []string) bool { + // Special case: if both slices are empty, they're equal + if len(s1) == 0 && len(s2) == 0 { + return true + } + + // If s2 is empty but s1 isn't, or s1 is shorter than s2, they can't match + if len(s2) == 0 || len(s1) < len(s2) { + return false + } + + // For each possible starting position in s1 + for i := 0; i <= len(s1)-len(s2); i++ { + allMatch := true + // Try to match all elements of s2 starting at position i + for j := 0; j < len(s2); j++ { + if s1[i+j] != s2[j] { + allMatch = false + break + } + } + if allMatch { + return true + } + } + return false +} + +func TestExtractIssues(t *testing.T) { tests := []struct { + name string text string - want string + want []string }{ { + name: "Single issue", text: "TEST-1 this is a test", - want: "TEST-1", + want: []string{"TEST-1"}, }, { - text: "suffix [TEST-123]", - want: "TEST-123", + name: "Two issues in brackets", + text: "suffix [TEST-123] [TEST-234]", + want: []string{"TEST-123", "TEST-234"}, }, { - text: "[TEST-123] prefix", - want: "TEST-123", + name: "Two issues, one in prefix", + text: "[TEST-123] prefix [TEST-456]", + want: []string{"TEST-123", "TEST-456"}, }, { - text: "TEST-123 prefix", - want: "TEST-123", + name: "Multiple comma-separated issues", + text: "Multiple issues: TEST-123, TEST-234, TEST-456", + want: []string{"TEST-123", "TEST-234", "TEST-456"}, }, { - text: "feature/TEST-123", - want: "TEST-123", + name: "Mixed format issues", + text: "feature/TEST-123 [TEST-456] and [TEST-789]", + want: []string{"TEST-123", "TEST-456", "TEST-789"}, }, { + name: "Space-separated issues", + text: "TEST-123 TEST-456 TEST-789", + want: []string{"TEST-123", "TEST-456", "TEST-789"}, + }, + { + name: "No issues", text: "no issue", - want: "", + want: []string{}, }, } - for _, test := range tests { - var args Args - args.Commit.Message = test.text - args.Project = "TEST" - if got, want := extractIssue(args), test.want; got != want { - t.Errorf("Got issue number %v, want %v", got, want) - } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var args Args + args.Commit.Message = tt.text + args.Project = "TEST" + + got := extractIssues(args) + + if !compareSlices(got, tt.want) { + t.Logf("\n Test case '%s' FAILED", tt.name) + t.Errorf("\ngot: %v\nwant: %v", got, tt.want) + } else { + t.Logf("\n Test case '%s' PASSED", tt.name) + t.Logf("\ngot: %v\nwant: %v", got, tt.want) + } + }) } } @@ -89,7 +140,7 @@ func TestToEnvironmentId(t *testing.T) { { name: "Empty EnvironmentId", args: Args{EnvironmentId: ""}, - expectedOutput: "production", // Updated to match the default value of "production" + expectedOutput: "production", // Updated to match the default value of "production" }, } @@ -118,7 +169,7 @@ func TestToEnvironmentType(t *testing.T) { { name: "Empty EnvironmentType", args: Args{EnvironmentType: ""}, - expectedOutput: "production", // Updated to match the default value of "production" + expectedOutput: "production", // Updated to match the default value of "production" }, }