github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/scripts/internal/workflow-helpers/github_test.go (about)

     1  package workflow_helpers
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/ActiveState/cli/internal/errs"
    10  	"github.com/blang/semver"
    11  	"github.com/google/go-github/v45/github"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/thoas/go-funk"
    14  )
    15  
    16  func TestParseJiraKey(t *testing.T) {
    17  	testCases := []struct {
    18  		name     string
    19  		msg      string
    20  		expected string
    21  	}{
    22  		{
    23  			name:     "empty",
    24  			msg:      "",
    25  			expected: "",
    26  		},
    27  		{
    28  			name:     "no jira",
    29  			msg:      "this is a commit message",
    30  			expected: "",
    31  		},
    32  		{
    33  			name:     "jira",
    34  			msg:      "this is a commit message with a JIRA issue ID: DX-123",
    35  			expected: "DX-123",
    36  		},
    37  		{
    38  			name:     "jira with space",
    39  			msg:      "this is a commit message with a JIRA issue ID: DX-123 and some other stuff",
    40  			expected: "DX-123",
    41  		},
    42  		{
    43  			name:     "jira with multiple",
    44  			msg:      "this is a commit message with a JIRA issue ID: DX-123 and some other stuff and another JIRA issue ID: XYZ-456",
    45  			expected: "DX-123",
    46  		},
    47  	}
    48  
    49  	for _, tc := range testCases {
    50  		t.Run(tc.name, func(t *testing.T) {
    51  			actual, err := ParseJiraKey(tc.msg)
    52  			if err != nil {
    53  				if tc.expected != "" {
    54  					t.Errorf("expected %s, got error: %s", tc.expected, errs.JoinMessage(err))
    55  				}
    56  				return
    57  			}
    58  			if actual != tc.expected {
    59  				t.Errorf("Expected %s, got %s", tc.expected, actual)
    60  			}
    61  		})
    62  	}
    63  }
    64  
    65  func TestFetchPRs(t *testing.T) {
    66  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
    67  
    68  	type args struct {
    69  		ghClient *github.Client
    70  		cutoff   time.Time
    71  		opts     *github.PullRequestListOptions
    72  	}
    73  	tests := []struct {
    74  		name        string
    75  		args        args
    76  		wantResults bool
    77  	}{
    78  		{
    79  			name: "success",
    80  			args: args{
    81  				ghClient: InitGHClient(),
    82  				cutoff:   time.Now().AddDate(0, -1, 0),
    83  				opts:     nil,
    84  			},
    85  			wantResults: true,
    86  		},
    87  		{
    88  			name: "empty",
    89  			args: args{
    90  				ghClient: InitGHClient(),
    91  				cutoff:   time.Now(),
    92  				opts:     &github.PullRequestListOptions{},
    93  			},
    94  			wantResults: false,
    95  		},
    96  	}
    97  	for _, tt := range tests {
    98  		t.Run(tt.name, func(t *testing.T) {
    99  			got, err := FetchPRs(tt.args.ghClient, tt.args.cutoff, tt.args.opts)
   100  			if err != nil {
   101  				t.Errorf("FetchPRs() error = %s", errs.JoinMessage(err))
   102  				return
   103  			}
   104  			hasResults := len(got) > 0
   105  			if hasResults != tt.wantResults {
   106  				t.Errorf("FetchPRs has %d results, but wantResults is %v", len(got), tt.wantResults)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  func TestFetchCommitsByRef(t *testing.T) {
   113  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   114  
   115  	type args struct {
   116  		ghClient *github.Client
   117  		ref      string
   118  		stop     func(commit *github.RepositoryCommit, count int) bool
   119  	}
   120  	tests := []struct {
   121  		name     string
   122  		args     args
   123  		wantSHAs []string
   124  		wantN    int
   125  	}{
   126  		{
   127  			name: "master ref",
   128  			args: args{
   129  				ghClient: InitGHClient(),
   130  				ref:      "master",
   131  				stop:     func(commit *github.RepositoryCommit, count int) bool { return count > 0 },
   132  			},
   133  			wantN: 1,
   134  		},
   135  		{
   136  			name: "sha ref",
   137  			args: args{
   138  				ghClient: InitGHClient(),
   139  				ref:      "f52d7fa6b87ca15b1f0a726c062fd6a99d92a287",
   140  				stop:     func(commit *github.RepositoryCommit, count int) bool { return count > 0 },
   141  			},
   142  			wantSHAs: []string{"f52d7fa6b87ca15b1f0a726c062fd6a99d92a287"},
   143  			wantN:    1,
   144  		},
   145  	}
   146  	for _, tt := range tests {
   147  		t.Run(tt.name, func(t *testing.T) {
   148  			count := 0
   149  			got, err := FetchCommitsByRef(tt.args.ghClient, tt.args.ref, func(commit *github.RepositoryCommit) bool {
   150  				defer func() { count++ }()
   151  				return tt.args.stop(commit, count)
   152  			})
   153  			if err != nil {
   154  				t.Errorf("FetchCommitsByRef() error = %s", errs.JoinMessage(err))
   155  				return
   156  			}
   157  			validateCommits(t, got, tt.wantSHAs, tt.wantN)
   158  		})
   159  	}
   160  }
   161  
   162  func TestSearchGithubIssues(t *testing.T) {
   163  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   164  
   165  	type args struct {
   166  		client *github.Client
   167  		term   string
   168  	}
   169  	tests := []struct {
   170  		name       string
   171  		args       args
   172  		want       []string // issue titles
   173  		maxResults int      // This guards against runaway page iterations, feel free to tweak so long as this stays relatively low
   174  	}{
   175  		{
   176  			name: "Search for Go 1.18 PR",
   177  			args: args{
   178  				client: InitGHClient(),
   179  				term:   "is:pull-request Go 1.18",
   180  			},
   181  			want:       []string{"Go 1.18 compatibility"},
   182  			maxResults: 20,
   183  		},
   184  		{
   185  			name: "Readme issue",
   186  			args: args{
   187  				client: InitGHClient(),
   188  				term:   "is:issue readme",
   189  			},
   190  			want:       []string{"README.md Development section clarifications"},
   191  			maxResults: 5,
   192  		},
   193  		{
   194  			name: "Version Prefix",
   195  			args: args{
   196  				client: InitGHClient(),
   197  				term:   "is:pr " + VersionedPRPrefix,
   198  			},
   199  			want:       []string{"Version 0.34.0-RC1"},
   200  			maxResults: 9999,
   201  		},
   202  	}
   203  	for _, tt := range tests {
   204  		t.Run(tt.name, func(t *testing.T) {
   205  			got, err := SearchGithubIssues(tt.args.client, tt.args.term)
   206  			if err != nil {
   207  				t.Errorf("SearchGithubIssues() error = %s", errs.JoinMessage(err))
   208  				return
   209  			}
   210  			for _, title := range tt.want {
   211  				found := false
   212  				for _, issue := range got {
   213  					if issue.GetTitle() == title {
   214  						found = true
   215  						break
   216  					}
   217  				}
   218  				if !found {
   219  					t.Errorf("SearchGithubIssues() did not return issue %s", title)
   220  				}
   221  			}
   222  		})
   223  	}
   224  }
   225  
   226  func TestFetchPRByTitle(t *testing.T) {
   227  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   228  
   229  	type args struct {
   230  		ghClient *github.Client
   231  		prName   string
   232  	}
   233  	tests := []struct {
   234  		name string
   235  		args args
   236  		want string
   237  	}{
   238  		{
   239  			name: "Go 1.18 compatibility",
   240  			args: args{
   241  				ghClient: InitGHClient(),
   242  				prName:   "Go 1.18 compatibility",
   243  			},
   244  			want: "Go 1.18 compatibility",
   245  		},
   246  		{
   247  			name: "Non-existant",
   248  			args: args{
   249  				ghClient: InitGHClient(),
   250  				prName:   "Non-existant",
   251  			},
   252  			want: "",
   253  		},
   254  		{
   255  			name: "Version 0.34.0-RC1",
   256  			args: args{
   257  				ghClient: InitGHClient(),
   258  				prName:   "Version 0.34.0-RC1",
   259  			},
   260  			want: "Version 0.34.0-RC1",
   261  		},
   262  		{
   263  			name: "Version 0.40.0-RC1",
   264  			args: args{
   265  				ghClient: InitGHClient(),
   266  				prName:   "Version 0.40.0-RC1",
   267  			},
   268  			want: "Version 0.40.0-RC1",
   269  		},
   270  		{
   271  			name: "Version 0.40.0-RC2",
   272  			args: args{
   273  				ghClient: InitGHClient(),
   274  				prName:   "Version 0.40.0-RC2",
   275  			},
   276  			want: "Version 0.40.0-RC2",
   277  		},
   278  		{
   279  			name: "Version 0.40.0-RC3",
   280  			args: args{
   281  				ghClient: InitGHClient(),
   282  				prName:   "Version 0.40.0-RC3",
   283  			},
   284  			want: "Version 0.40.0-RC3",
   285  		},
   286  	}
   287  	for _, tt := range tests {
   288  		t.Run(tt.name, func(t *testing.T) {
   289  			got, err := FetchPRByTitle(tt.args.ghClient, tt.args.prName)
   290  			if err != nil {
   291  				t.Errorf("FetchPRByTitle() error = %s", errs.JoinMessage(err))
   292  				return
   293  			}
   294  			if got == nil {
   295  				if tt.want != "" {
   296  					t.Errorf("FetchPRByTitle() got = nil, but want %s", tt.want)
   297  				}
   298  				return
   299  			}
   300  			if got.GetTitle() != tt.want {
   301  				t.Errorf("FetchPRByTitle() got = %s, want %v", got.GetTitle(), tt.want)
   302  			}
   303  		})
   304  	}
   305  }
   306  
   307  func TestActiveVersionsOnBranch(t *testing.T) {
   308  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   309  
   310  	jiraClient, err := InitJiraClient()
   311  	require.NoError(t, err)
   312  
   313  	versions, err := ActiveVersionsOnBranch(InitGHClient(), jiraClient, MasterBranch, time.Now().AddDate(0, -6, 0))
   314  	require.NoError(t, err, errs.JoinMessage(err))
   315  	if len(versions) < 2 {
   316  		// Realistically we should have at least 2 versions in development in the past 6 months
   317  		t.Errorf("ActiveVersionsOnBranch() returned %d versions, want at least 2", len(versions))
   318  	}
   319  }
   320  
   321  func TestFetchCommitsByShaRange(t *testing.T) {
   322  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   323  
   324  	type args struct {
   325  		ghClient *github.Client
   326  		startSha string
   327  		stopSha  string
   328  	}
   329  	tests := []struct {
   330  		name     string
   331  		args     args
   332  		wantSHAs []string
   333  		wantN    int
   334  	}{
   335  		{
   336  			name: "small range",
   337  			args: args{
   338  				ghClient: InitGHClient(),
   339  				startSha: "97cc4d358ba249493222cd2e8928015714881000",
   340  				stopSha:  "69bbdf1466135094efe0ef77108eae9953d76ac3",
   341  			},
   342  			wantSHAs: []string{"a2fe40506b564ab00b1fe46e2bd170898c46244b"},
   343  			wantN:    -1,
   344  		},
   345  		{
   346  			name: "large range",
   347  			args: args{
   348  				ghClient: InitGHClient(),
   349  				startSha: "5d6e103384849ad2cb6f604da84c4dc9f2245c31",
   350  				stopSha:  "69bbdf1466135094efe0ef77108eae9953d76ac3",
   351  			},
   352  			wantSHAs: []string{"a2fe40506b564ab00b1fe46e2bd170898c46244b"},
   353  			wantN:    -1,
   354  		},
   355  	}
   356  	for _, tt := range tests {
   357  		t.Run(tt.name, func(t *testing.T) {
   358  			got, err := FetchCommitsByShaRange(tt.args.ghClient, tt.args.startSha, tt.args.stopSha)
   359  			if err != nil {
   360  				t.Errorf("FetchCommitsByShaRange() error = %s", errs.JoinMessage(err))
   361  				return
   362  			}
   363  			validateCommits(t, got, tt.wantSHAs, tt.wantN)
   364  		})
   365  	}
   366  }
   367  
   368  func TestUpdatePRTargetBranch(t *testing.T) {
   369  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   370  
   371  	err := UpdatePRTargetBranch(InitGHClient(), 1985, "version/0-40-0-RC2")
   372  	require.NoError(t, err, errs.JoinMessage(err))
   373  }
   374  
   375  func TestCreateBranch(t *testing.T) {
   376  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   377  
   378  	prefix := funk.RandomString(10, []rune("abcdefghijklmnopqrstuvwxyz0123456789"))
   379  	name := prefix + "/" + funk.RandomString(10, []rune("abcdefghijklmnopqrstuvwxyz0123456789"))
   380  	fmt.Printf("Creating branch %s\n", name)
   381  	err := CreateBranch(InitGHClient(), name, "f8a9465c572ed7a26145c7ebf961554da9367ec7")
   382  	require.NoError(t, err, errs.JoinMessage(err))
   383  }
   384  
   385  func validateCommits(t *testing.T, commits []*github.RepositoryCommit, wantSHAs []string, wantN int) {
   386  	if wantN != -1 && len(commits) != wantN {
   387  		t.Errorf("FetchCommitsByRef() has %d results, want %d", len(commits), wantN)
   388  	}
   389  	for _, sha := range wantSHAs {
   390  		found := false
   391  		for _, commit := range commits {
   392  			if commit.GetSHA() == sha {
   393  				found = true
   394  				break
   395  			}
   396  		}
   397  		if !found {
   398  			t.Errorf("FetchCommitsByRef() did not return sha %s (got %d commits)", sha, len(commits))
   399  		}
   400  	}
   401  }
   402  
   403  func TestBehindBy(t *testing.T) {
   404  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   405  
   406  	type args struct {
   407  		client *github.Client
   408  		base   string
   409  		head   string
   410  	}
   411  	tests := []struct {
   412  		name       string
   413  		args       args
   414  		wantBehind bool
   415  		wantErr    bool
   416  	}{
   417  		{
   418  			"Should be behind",
   419  			args{
   420  				InitGHClient(),
   421  				"version/0-39-0-RC2",
   422  				"version/0-39-0-RC1",
   423  			},
   424  			true,
   425  			false,
   426  		},
   427  		{
   428  			"Should not be behind",
   429  			args{
   430  				InitGHClient(),
   431  				"version/0-39-0-RC1",
   432  				"version/0-39-0-RC2",
   433  			},
   434  			false,
   435  			false,
   436  		},
   437  	}
   438  	for _, tt := range tests {
   439  		t.Run(tt.name, func(t *testing.T) {
   440  			got, err := GetCommitsBehind(tt.args.client, tt.args.base, tt.args.head)
   441  			if (err != nil) != tt.wantErr {
   442  				t.Errorf("BehindBy() error = %v, wantErr %v", err, tt.wantErr)
   443  				return
   444  			}
   445  			if (len(got) > 0) != tt.wantBehind {
   446  				t.Errorf("BehindBy() got = %v, want %v", len(got), tt.wantBehind)
   447  			}
   448  		})
   449  	}
   450  }
   451  
   452  func TestFetchVersionPR(t *testing.T) {
   453  	t.Skip("For debugging purposes, comment this line out if you want to test this locally")
   454  
   455  	type args struct {
   456  		ghClient         *github.Client
   457  		assert           Assertion
   458  		versionToCompare semver.Version
   459  	}
   460  	tests := []struct {
   461  		name      string
   462  		args      args
   463  		wantTitle string
   464  		wantErr   bool
   465  	}{
   466  		{
   467  			"Previous Version",
   468  			args{
   469  				InitGHClient(),
   470  				AssertLT,
   471  				semver.MustParse("0.39.0-RC2"),
   472  			},
   473  			"Version 0.39.0-RC1",
   474  			false,
   475  		},
   476  		{
   477  			"Next Version",
   478  			args{
   479  				InitGHClient(),
   480  				AssertGT,
   481  				semver.MustParse("0.39.0-RC1"),
   482  			},
   483  			"Version 0.39.0-RC2",
   484  			false,
   485  		},
   486  	}
   487  	for _, tt := range tests {
   488  		t.Run(tt.name, func(t *testing.T) {
   489  			got, err := FetchVersionPR(tt.args.ghClient, tt.args.assert, tt.args.versionToCompare)
   490  			if (err != nil) != tt.wantErr {
   491  				t.Errorf("FetchVersionPR() error = %v, wantErr %v", err, tt.wantErr)
   492  				return
   493  			}
   494  			if !reflect.DeepEqual(got.GetTitle(), tt.wantTitle) {
   495  				t.Errorf("FetchVersionPR() got = %v, want %v", got.GetTitle(), tt.wantTitle)
   496  			}
   497  		})
   498  	}
   499  }