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 }