github.com/xgoffin/jenkins-library@v1.154.0/cmd/githubPublishRelease_test.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/google/go-github/v32/github"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  type ghRCMock struct {
    17  	createErr         error
    18  	latestRelease     *github.RepositoryRelease
    19  	release           *github.RepositoryRelease
    20  	delErr            error
    21  	delID             int64
    22  	delOwner          string
    23  	delRepo           string
    24  	listErr           error
    25  	listID            int64
    26  	listOwner         string
    27  	listReleaseAssets []*github.ReleaseAsset
    28  	listRepo          string
    29  	listOpts          *github.ListOptions
    30  	latestStatusCode  int
    31  	latestErr         error
    32  	preRelease        bool
    33  	uploadID          int64
    34  	uploadOpts        *github.UploadOptions
    35  	uploadOwner       string
    36  	uploadRepo        string
    37  }
    38  
    39  func (g *ghRCMock) CreateRelease(ctx context.Context, owner string, repo string, release *github.RepositoryRelease) (*github.RepositoryRelease, *github.Response, error) {
    40  	g.release = release
    41  	return release, nil, g.createErr
    42  }
    43  
    44  func (g *ghRCMock) DeleteReleaseAsset(ctx context.Context, owner string, repo string, id int64) (*github.Response, error) {
    45  	g.delOwner = owner
    46  	g.delRepo = repo
    47  	g.delID = id
    48  	return nil, g.delErr
    49  }
    50  
    51  func (g *ghRCMock) GetLatestRelease(ctx context.Context, owner string, repo string) (*github.RepositoryRelease, *github.Response, error) {
    52  	hc := http.Response{StatusCode: 200}
    53  	if g.latestStatusCode != 0 {
    54  		hc.StatusCode = g.latestStatusCode
    55  	}
    56  
    57  	if len(owner) == 0 {
    58  		return g.latestRelease, nil, g.latestErr
    59  	}
    60  
    61  	ghResp := github.Response{Response: &hc}
    62  	return g.latestRelease, &ghResp, g.latestErr
    63  }
    64  
    65  func (g *ghRCMock) ListReleaseAssets(ctx context.Context, owner string, repo string, id int64, opt *github.ListOptions) ([]*github.ReleaseAsset, *github.Response, error) {
    66  	g.listID = id
    67  	g.listOwner = owner
    68  	g.listRepo = repo
    69  	g.listOpts = opt
    70  	return g.listReleaseAssets, nil, g.listErr
    71  }
    72  
    73  func (g *ghRCMock) UploadReleaseAsset(ctx context.Context, owner string, repo string, id int64, opt *github.UploadOptions, file *os.File) (*github.ReleaseAsset, *github.Response, error) {
    74  	g.uploadID = id
    75  	g.uploadOwner = owner
    76  	g.uploadRepo = repo
    77  	g.uploadOpts = opt
    78  	return nil, nil, nil
    79  }
    80  
    81  type ghICMock struct {
    82  	issues        []*github.Issue
    83  	lastPublished time.Time
    84  	owner         string
    85  	repo          string
    86  	options       *github.IssueListByRepoOptions
    87  }
    88  
    89  func (g *ghICMock) ListByRepo(ctx context.Context, owner string, repo string, opt *github.IssueListByRepoOptions) ([]*github.Issue, *github.Response, error) {
    90  	g.owner = owner
    91  	g.repo = repo
    92  	g.options = opt
    93  	g.lastPublished = opt.Since
    94  	return g.issues, nil, nil
    95  }
    96  
    97  func TestRunGithubPublishRelease(t *testing.T) {
    98  	ctx := context.Background()
    99  
   100  	t.Run("Success - first release & no body", func(t *testing.T) {
   101  		ghIssueClient := ghICMock{}
   102  		ghRepoClient := ghRCMock{
   103  			latestStatusCode: 404,
   104  			latestErr:        fmt.Errorf("not found"),
   105  		}
   106  
   107  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   108  			AddDeltaToLastRelease: true,
   109  			Commitish:             "master",
   110  			Owner:                 "TEST",
   111  			PreRelease:            true,
   112  			Repository:            "test",
   113  			ServerURL:             "https://github.com",
   114  			ReleaseBodyHeader:     "Header",
   115  			Version:               "1.0",
   116  		}
   117  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   118  		assert.NoError(t, err, "Error occurred but none expected.")
   119  
   120  		assert.Equal(t, "Header\n", ghRepoClient.release.GetBody())
   121  		assert.Equal(t, true, ghRepoClient.release.GetPrerelease())
   122  		assert.Equal(t, "1.0", ghRepoClient.release.GetTagName())
   123  	})
   124  
   125  	t.Run("Success - first release with tag prefix set & no body", func(t *testing.T) {
   126  		ghIssueClient := ghICMock{}
   127  		ghRepoClient := ghRCMock{
   128  			latestStatusCode: 404,
   129  			latestErr:        fmt.Errorf("not found"),
   130  		}
   131  
   132  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   133  			AddDeltaToLastRelease: true,
   134  			Commitish:             "master",
   135  			Owner:                 "TEST",
   136  			PreRelease:            true,
   137  			Repository:            "test",
   138  			ServerURL:             "https://github.com",
   139  			ReleaseBodyHeader:     "Header",
   140  			Version:               "1.0",
   141  			TagPrefix:             "v",
   142  		}
   143  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   144  		assert.NoError(t, err, "Error occurred but none expected.")
   145  
   146  		assert.Equal(t, "Header\n", ghRepoClient.release.GetBody())
   147  		assert.Equal(t, true, ghRepoClient.release.GetPrerelease())
   148  		assert.Equal(t, "v1.0", ghRepoClient.release.GetTagName())
   149  	})
   150  
   151  	t.Run("Success - subsequent releases & with body", func(t *testing.T) {
   152  		lastTag := "1.0"
   153  		lastPublishedAt := github.Timestamp{Time: time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)}
   154  		ghRepoClient := ghRCMock{
   155  			createErr: nil,
   156  			latestRelease: &github.RepositoryRelease{
   157  				TagName:     &lastTag,
   158  				PublishedAt: &lastPublishedAt,
   159  			},
   160  		}
   161  		prHTMLURL := "https://github.com/TEST/test/pull/1"
   162  		prTitle := "Pull"
   163  		prNo := 1
   164  
   165  		issHTMLURL := "https://github.com/TEST/test/issues/2"
   166  		issTitle := "Issue"
   167  		issNo := 2
   168  
   169  		ghIssueClient := ghICMock{
   170  			issues: []*github.Issue{
   171  				{Number: &prNo, Title: &prTitle, HTMLURL: &prHTMLURL, PullRequestLinks: &github.PullRequestLinks{URL: &prHTMLURL}},
   172  				{Number: &issNo, Title: &issTitle, HTMLURL: &issHTMLURL},
   173  			},
   174  		}
   175  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   176  			AddClosedIssues:       true,
   177  			AddDeltaToLastRelease: true,
   178  			Commitish:             "master",
   179  			Owner:                 "TEST",
   180  			Repository:            "test",
   181  			ServerURL:             "https://github.com",
   182  			ReleaseBodyHeader:     "Header",
   183  			Version:               "1.1",
   184  		}
   185  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   186  
   187  		assert.NoError(t, err, "Error occurred but none expected.")
   188  
   189  		assert.Equal(t, "Header\n\n**List of closed pull-requests since last release**\n[#1](https://github.com/TEST/test/pull/1): Pull\n\n**List of closed issues since last release**\n[#2](https://github.com/TEST/test/issues/2): Issue\n\n**Changes**\n[1.0...1.1](https://github.com/TEST/test/compare/1.0...1.1)\n", ghRepoClient.release.GetBody())
   190  		assert.Equal(t, "1.1", ghRepoClient.release.GetName())
   191  		assert.Equal(t, "1.1", ghRepoClient.release.GetTagName())
   192  		assert.Equal(t, "master", ghRepoClient.release.GetTargetCommitish())
   193  
   194  		assert.Equal(t, lastPublishedAt.Time, ghIssueClient.lastPublished)
   195  	})
   196  
   197  	t.Run("Success - update asset", func(t *testing.T) {
   198  		var releaseID int64 = 1
   199  		ghIssueClient := ghICMock{}
   200  		ghRepoClient := ghRCMock{
   201  			latestRelease: &github.RepositoryRelease{
   202  				ID: &releaseID,
   203  			},
   204  		}
   205  
   206  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   207  			AssetPath: filepath.Join("testdata", t.Name()+"_test.txt"),
   208  			Version:   "latest",
   209  		}
   210  
   211  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   212  
   213  		assert.NoError(t, err, "Error occurred but none expected.")
   214  
   215  		assert.Nil(t, ghRepoClient.release)
   216  
   217  		assert.Equal(t, releaseID, ghRepoClient.listID)
   218  		assert.Equal(t, releaseID, ghRepoClient.uploadID)
   219  	})
   220  
   221  	t.Run("Error - get release", func(t *testing.T) {
   222  		ghIssueClient := ghICMock{}
   223  		ghRepoClient := ghRCMock{
   224  			latestErr: fmt.Errorf("Latest release error"),
   225  		}
   226  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   227  			Owner:      "TEST",
   228  			Repository: "test",
   229  		}
   230  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   231  
   232  		assert.Equal(t, "Error occurred when retrieving latest GitHub release (TEST/test): Latest release error", fmt.Sprint(err))
   233  	})
   234  
   235  	t.Run("Error - get release no response", func(t *testing.T) {
   236  		ghIssueClient := ghICMock{}
   237  		ghRepoClient := ghRCMock{
   238  			latestErr: fmt.Errorf("Latest release error, no response"),
   239  		}
   240  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   241  			Owner:      "",
   242  			Repository: "test",
   243  		}
   244  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   245  
   246  		assert.Equal(t, "Error occurred when retrieving latest GitHub release (/test): Latest release error, no response", fmt.Sprint(err))
   247  	})
   248  
   249  	t.Run("Error - create release", func(t *testing.T) {
   250  		ghIssueClient := ghICMock{}
   251  		ghRepoClient := ghRCMock{
   252  			createErr: fmt.Errorf("Create release error"),
   253  		}
   254  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   255  			Version: "1.0",
   256  		}
   257  		err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
   258  
   259  		assert.Equal(t, "Creation of release '1.0' failed: Create release error", fmt.Sprint(err))
   260  	})
   261  }
   262  
   263  func TestGetClosedIssuesText(t *testing.T) {
   264  	ctx := context.Background()
   265  	publishedAt := github.Timestamp{Time: time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)}
   266  
   267  	t.Run("No issues", func(t *testing.T) {
   268  		ghIssueClient := ghICMock{}
   269  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   270  			Version: "1.0",
   271  		}
   272  
   273  		res := getClosedIssuesText(ctx, publishedAt, &myGithubPublishReleaseOptions, &ghIssueClient)
   274  
   275  		assert.Equal(t, "", res)
   276  	})
   277  
   278  	t.Run("All issues", func(t *testing.T) {
   279  		ctx := context.Background()
   280  		publishedAt := github.Timestamp{Time: time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)}
   281  
   282  		prHTMLURL := []string{"https://github.com/TEST/test/pull/1", "https://github.com/TEST/test/pull/2"}
   283  		prTitle := []string{"Pull1", "Pull2"}
   284  		prNo := []int{1, 2}
   285  
   286  		issHTMLURL := []string{"https://github.com/TEST/test/issues/3", "https://github.com/TEST/test/issues/4"}
   287  		issTitle := []string{"Issue3", "Issue4"}
   288  		issNo := []int{3, 4}
   289  
   290  		ghIssueClient := ghICMock{
   291  			issues: []*github.Issue{
   292  				{Number: &prNo[0], Title: &prTitle[0], HTMLURL: &prHTMLURL[0], PullRequestLinks: &github.PullRequestLinks{URL: &prHTMLURL[0]}},
   293  				{Number: &prNo[1], Title: &prTitle[1], HTMLURL: &prHTMLURL[1], PullRequestLinks: &github.PullRequestLinks{URL: &prHTMLURL[1]}},
   294  				{Number: &issNo[0], Title: &issTitle[0], HTMLURL: &issHTMLURL[0]},
   295  				{Number: &issNo[1], Title: &issTitle[1], HTMLURL: &issHTMLURL[1]},
   296  			},
   297  		}
   298  
   299  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   300  			Owner:      "TEST",
   301  			Repository: "test",
   302  		}
   303  
   304  		res := getClosedIssuesText(ctx, publishedAt, &myGithubPublishReleaseOptions, &ghIssueClient)
   305  
   306  		assert.Equal(t, "\n**List of closed pull-requests since last release**\n[#1](https://github.com/TEST/test/pull/1): Pull1\n[#2](https://github.com/TEST/test/pull/2): Pull2\n\n**List of closed issues since last release**\n[#3](https://github.com/TEST/test/issues/3): Issue3\n[#4](https://github.com/TEST/test/issues/4): Issue4\n", res)
   307  		assert.Equal(t, "TEST", ghIssueClient.owner, "Owner not properly passed")
   308  		assert.Equal(t, "test", ghIssueClient.repo, "Repo not properly passed")
   309  		assert.Equal(t, "closed", ghIssueClient.options.State, "Issue state not properly passed")
   310  		assert.Equal(t, "asc", ghIssueClient.options.Direction, "Sort direction not properly passed")
   311  		assert.Equal(t, publishedAt.Time, ghIssueClient.options.Since, "PublishedAt not properly passed")
   312  	})
   313  
   314  }
   315  
   316  func TestGetReleaseDeltaText(t *testing.T) {
   317  	myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   318  		Owner:      "TEST",
   319  		Repository: "test",
   320  		ServerURL:  "https://github.com",
   321  		Version:    "1.1",
   322  	}
   323  	lastTag := "1.0"
   324  	lastRelease := github.RepositoryRelease{
   325  		TagName: &lastTag,
   326  	}
   327  
   328  	res := getReleaseDeltaText(&myGithubPublishReleaseOptions, &lastRelease)
   329  
   330  	assert.Equal(t, "\n**Changes**\n[1.0...1.1](https://github.com/TEST/test/compare/1.0...1.1)\n", res)
   331  }
   332  
   333  func TestUploadReleaseAsset(t *testing.T) {
   334  	ctx := context.Background()
   335  
   336  	t.Run("Success - existing asset", func(t *testing.T) {
   337  		var releaseID int64 = 1
   338  		assetName := "Success_-_existing_asset_test.txt"
   339  		var assetID int64 = 11
   340  		ghRepoClient := ghRCMock{
   341  			latestRelease: &github.RepositoryRelease{
   342  				ID: &releaseID,
   343  			},
   344  			listReleaseAssets: []*github.ReleaseAsset{
   345  				{Name: &assetName, ID: &assetID},
   346  			},
   347  		}
   348  
   349  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   350  			Owner:      "TEST",
   351  			Repository: "test",
   352  			AssetPath:  filepath.Join("testdata", t.Name()+"_test.txt"),
   353  		}
   354  
   355  		err := uploadReleaseAsset(ctx, releaseID, &myGithubPublishReleaseOptions, &ghRepoClient)
   356  
   357  		assert.NoError(t, err, "Error occurred but none expected.")
   358  
   359  		assert.Equal(t, "TEST", ghRepoClient.listOwner, "Owner not properly passed - list")
   360  		assert.Equal(t, "test", ghRepoClient.listRepo, "Repo not properly passed - list")
   361  		assert.Equal(t, releaseID, ghRepoClient.listID, "Relase ID not properly passed - list")
   362  
   363  		assert.Equal(t, "TEST", ghRepoClient.delOwner, "Owner not properly passed - del")
   364  		assert.Equal(t, "test", ghRepoClient.delRepo, "Repo not properly passed - del")
   365  		assert.Equal(t, assetID, ghRepoClient.delID, "Relase ID not properly passed - del")
   366  
   367  		assert.Equal(t, "TEST", ghRepoClient.uploadOwner, "Owner not properly passed - upload")
   368  		assert.Equal(t, "test", ghRepoClient.uploadRepo, "Repo not properly passed - upload")
   369  		assert.Equal(t, releaseID, ghRepoClient.uploadID, "Relase ID not properly passed - upload")
   370  		assert.Equal(t, "text/plain; charset=utf-8", ghRepoClient.uploadOpts.MediaType, "Wrong MediaType passed - upload")
   371  	})
   372  
   373  	t.Run("Success - no asset", func(t *testing.T) {
   374  		var releaseID int64 = 1
   375  		assetName := "notFound"
   376  		var assetID int64 = 11
   377  		ghRepoClient := ghRCMock{
   378  			latestRelease: &github.RepositoryRelease{
   379  				ID: &releaseID,
   380  			},
   381  			listReleaseAssets: []*github.ReleaseAsset{
   382  				{Name: &assetName, ID: &assetID},
   383  			},
   384  		}
   385  
   386  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{
   387  			Owner:      "TEST",
   388  			Repository: "test",
   389  			AssetPath:  filepath.Join("testdata", t.Name()+"_test.txt"),
   390  		}
   391  
   392  		err := uploadReleaseAsset(ctx, releaseID, &myGithubPublishReleaseOptions, &ghRepoClient)
   393  
   394  		assert.NoError(t, err, "Error occurred but none expected.")
   395  
   396  		assert.Equal(t, int64(0), ghRepoClient.delID, "Relase ID should not be populated")
   397  	})
   398  
   399  	t.Run("Error - List Assets", func(t *testing.T) {
   400  		var releaseID int64 = 1
   401  		ghRepoClient := ghRCMock{
   402  			listErr: fmt.Errorf("List Asset Error"),
   403  		}
   404  		myGithubPublishReleaseOptions := githubPublishReleaseOptions{}
   405  
   406  		err := uploadReleaseAsset(ctx, releaseID, &myGithubPublishReleaseOptions, &ghRepoClient)
   407  		assert.Equal(t, "Failed to get list of release assets.: List Asset Error", fmt.Sprint(err), "Wrong error received")
   408  	})
   409  }
   410  
   411  func TestIsExcluded(t *testing.T) {
   412  
   413  	l1 := "label1"
   414  	l2 := "label2"
   415  
   416  	tt := []struct {
   417  		issue         *github.Issue
   418  		excludeLabels []string
   419  		expected      bool
   420  	}{
   421  		{issue: nil, excludeLabels: nil, expected: false},
   422  		{issue: &github.Issue{}, excludeLabels: nil, expected: false},
   423  		{issue: &github.Issue{Labels: []*github.Label{{Name: &l1}}}, excludeLabels: nil, expected: false},
   424  		{issue: &github.Issue{Labels: []*github.Label{{Name: &l1}}}, excludeLabels: []string{"label0"}, expected: false},
   425  		{issue: &github.Issue{Labels: []*github.Label{{Name: &l1}}}, excludeLabels: []string{"label1"}, expected: true},
   426  		{issue: &github.Issue{Labels: []*github.Label{{Name: &l1}, {Name: &l2}}}, excludeLabels: []string{}, expected: false},
   427  		{issue: &github.Issue{Labels: []*github.Label{{Name: &l1}, {Name: &l2}}}, excludeLabels: []string{"label1"}, expected: true},
   428  	}
   429  
   430  	for k, v := range tt {
   431  		assert.Equal(t, v.expected, isExcluded(v.issue, v.excludeLabels), fmt.Sprintf("Run %v failed", k))
   432  	}
   433  
   434  }