github.com/windmeup/goreleaser@v1.21.95/internal/pipe/changelog/changelog_test.go (about) 1 package changelog 2 3 import ( 4 "os" 5 "path/filepath" 6 "strings" 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/windmeup/goreleaser/internal/client" 12 "github.com/windmeup/goreleaser/internal/git" 13 "github.com/windmeup/goreleaser/internal/testctx" 14 "github.com/windmeup/goreleaser/internal/testlib" 15 "github.com/windmeup/goreleaser/pkg/config" 16 "github.com/windmeup/goreleaser/pkg/context" 17 ) 18 19 func TestDescription(t *testing.T) { 20 require.NotEmpty(t, Pipe{}.String()) 21 } 22 23 func TestChangelogProvidedViaFlag(t *testing.T) { 24 ctx := testctx.New() 25 ctx.ReleaseNotesFile = "testdata/changes.md" 26 require.NoError(t, Pipe{}.Run(ctx)) 27 require.Equal(t, "c0ff33 coffeee\n", ctx.ReleaseNotes) 28 } 29 30 func TestChangelogProvidedViaFlagIsAWhitespaceOnlyFile(t *testing.T) { 31 ctx := testctx.New() 32 ctx.ReleaseNotesFile = "testdata/changes-empty.md" 33 require.NoError(t, Pipe{}.Run(ctx)) 34 require.Equal(t, "\n", ctx.ReleaseNotes) 35 } 36 37 func TestChangelogProvidedViaFlagIsReallyEmpty(t *testing.T) { 38 ctx := testctx.New() 39 ctx.ReleaseNotesFile = "testdata/changes-really-empty.md" 40 require.NoError(t, Pipe{}.Run(ctx)) 41 require.Equal(t, "", ctx.ReleaseNotes) 42 } 43 44 func TestChangelogTmplProvidedViaFlagIsReallyEmpty(t *testing.T) { 45 ctx := testctx.New() 46 ctx.ReleaseNotesTmpl = "testdata/changes-really-empty.md" 47 require.NoError(t, Pipe{}.Run(ctx)) 48 require.Equal(t, "", ctx.ReleaseNotes) 49 } 50 51 func TestTemplatedChangelogProvidedViaFlag(t *testing.T) { 52 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 53 ctx.ReleaseNotesFile = "testdata/changes.md" 54 ctx.ReleaseNotesTmpl = "testdata/changes-templated.md" 55 require.NoError(t, Pipe{}.Run(ctx)) 56 require.Equal(t, "c0ff33 coffeee v0.0.1\n", ctx.ReleaseNotes) 57 } 58 59 func TestTemplatedChangelogProvidedViaFlagResultIsEmpty(t *testing.T) { 60 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 61 ctx.ReleaseNotesTmpl = "testdata/changes-templated-empty.md" 62 require.NoError(t, Pipe{}.Run(ctx)) 63 require.Equal(t, "\n\n", ctx.ReleaseNotes) 64 } 65 66 func TestChangelogProvidedViaFlagDoesntExist(t *testing.T) { 67 ctx := testctx.New() 68 ctx.ReleaseNotesFile = "testdata/changes.nope" 69 require.ErrorIs(t, Pipe{}.Run(ctx), os.ErrNotExist) 70 } 71 72 func TestReleaseHeaderProvidedViaFlagDoesntExist(t *testing.T) { 73 ctx := testctx.New() 74 ctx.ReleaseHeaderFile = "testdata/header.nope" 75 require.ErrorIs(t, Pipe{}.Run(ctx), os.ErrNotExist) 76 } 77 78 func TestReleaseFooterProvidedViaFlagDoesntExist(t *testing.T) { 79 ctx := testctx.New() 80 ctx.ReleaseFooterFile = "testdata/footer.nope" 81 require.ErrorIs(t, Pipe{}.Run(ctx), os.ErrNotExist) 82 } 83 84 func TestChangelog(t *testing.T) { 85 folder := testlib.Mktmp(t) 86 testlib.GitInit(t) 87 testlib.GitCommit(t, "first") 88 testlib.GitTag(t, "v0.0.1") 89 testlib.GitCommit(t, "added feature 1") 90 testlib.GitCommit(t, "fixed bug 2") 91 testlib.GitCommit(t, "ignored: whatever") 92 testlib.GitCommit(t, "docs: whatever") 93 testlib.GitCommit(t, "something about cArs we dont need") 94 testlib.GitCommit(t, "feat: added that thing") 95 testlib.GitCommit(t, "Merge pull request #999 from goreleaser/some-branch") 96 testlib.GitCommit(t, "this is not a Merge pull request") 97 testlib.GitTag(t, "v0.0.2") 98 ctx := testctx.NewWithCfg(config.Project{ 99 Dist: folder, 100 Changelog: config.Changelog{ 101 Use: "git", 102 Filters: config.Filters{ 103 Exclude: []string{ 104 "docs:", 105 "ignored:", 106 "(?i)cars", 107 "^Merge pull request", 108 }, 109 }, 110 }, 111 }, testctx.WithCurrentTag("v0.0.2"), testctx.WithPreviousTag("v0.0.1")) 112 require.NoError(t, Pipe{}.Run(ctx)) 113 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 114 require.NotContains(t, ctx.ReleaseNotes, "first") 115 require.Contains(t, ctx.ReleaseNotes, "added feature 1") 116 require.Contains(t, ctx.ReleaseNotes, "fixed bug 2") 117 require.NotContains(t, ctx.ReleaseNotes, "docs") 118 require.NotContains(t, ctx.ReleaseNotes, "ignored") 119 require.NotContains(t, ctx.ReleaseNotes, "cArs") 120 require.NotContains(t, ctx.ReleaseNotes, "from goreleaser/some-branch") 121 122 for _, line := range strings.Split(ctx.ReleaseNotes, "\n")[1:] { 123 if line == "" { 124 continue 125 } 126 require.Truef(t, strings.HasPrefix(line, "* "), "%q: changelog commit must be a list item", line) 127 } 128 129 bts, err := os.ReadFile(filepath.Join(folder, "CHANGELOG.md")) 130 require.NoError(t, err) 131 require.NotEmpty(t, string(bts)) 132 } 133 134 func TestChangelogInclude(t *testing.T) { 135 folder := testlib.Mktmp(t) 136 testlib.GitInit(t) 137 testlib.GitCommit(t, "first") 138 testlib.GitTag(t, "v0.0.1") 139 testlib.GitCommit(t, "added feature 1") 140 testlib.GitCommit(t, "fixed bug 2") 141 testlib.GitCommit(t, "ignored: whatever") 142 testlib.GitCommit(t, "docs: whatever") 143 testlib.GitCommit(t, "something about cArs we dont need") 144 testlib.GitCommit(t, "feat: added that thing") 145 testlib.GitCommit(t, "Merge pull request #999 from goreleaser/some-branch") 146 testlib.GitCommit(t, "this is not a Merge pull request") 147 testlib.GitTag(t, "v0.0.2") 148 ctx := testctx.NewWithCfg(config.Project{ 149 Dist: folder, 150 Changelog: config.Changelog{ 151 Use: "git", 152 Filters: config.Filters{ 153 Include: []string{ 154 "docs:", 155 "ignored:", 156 "(?i)cars", 157 "^Merge pull request", 158 }, 159 }, 160 }, 161 }, testctx.WithCurrentTag("v0.0.2"), testctx.WithPreviousTag("v0.0.1")) 162 require.NoError(t, Pipe{}.Run(ctx)) 163 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 164 require.NotContains(t, ctx.ReleaseNotes, "first") 165 require.NotContains(t, ctx.ReleaseNotes, "added feature 1") 166 require.NotContains(t, ctx.ReleaseNotes, "fixed bug 2") 167 require.Contains(t, ctx.ReleaseNotes, "docs") 168 require.Contains(t, ctx.ReleaseNotes, "ignored") 169 require.Contains(t, ctx.ReleaseNotes, "cArs") 170 require.Contains(t, ctx.ReleaseNotes, "from goreleaser/some-branch") 171 172 for _, line := range strings.Split(ctx.ReleaseNotes, "\n")[1:] { 173 if line == "" { 174 continue 175 } 176 require.Truef(t, strings.HasPrefix(line, "* "), "%q: changelog commit must be a list item", line) 177 } 178 179 bts, err := os.ReadFile(filepath.Join(folder, "CHANGELOG.md")) 180 require.NoError(t, err) 181 require.NotEmpty(t, string(bts)) 182 } 183 184 func TestChangelogForGitlab(t *testing.T) { 185 folder := testlib.Mktmp(t) 186 testlib.GitInit(t) 187 testlib.GitCommit(t, "first") 188 testlib.GitTag(t, "v0.0.1") 189 testlib.GitCommit(t, "added feature 1") 190 testlib.GitCommit(t, "fixed bug 2") 191 testlib.GitCommit(t, "ignored: whatever") 192 testlib.GitCommit(t, "docs: whatever") 193 testlib.GitCommit(t, "something about cArs we dont need") 194 testlib.GitCommit(t, "feat: added that thing") 195 testlib.GitCommit(t, "Merge pull request #999 from goreleaser/some-branch") 196 testlib.GitCommit(t, "this is not a Merge pull request") 197 testlib.GitTag(t, "v0.0.2") 198 ctx := testctx.NewWithCfg( 199 config.Project{ 200 Dist: folder, 201 Changelog: config.Changelog{ 202 Filters: config.Filters{ 203 Exclude: []string{ 204 "docs:", 205 "ignored:", 206 "(?i)cars", 207 "^Merge pull request", 208 }, 209 }, 210 }, 211 }, 212 testctx.GitLabTokenType, 213 testctx.WithCurrentTag("v0.0.2"), 214 testctx.WithPreviousTag("v0.0.1"), 215 ) 216 require.NoError(t, Pipe{}.Run(ctx)) 217 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 218 require.NotContains(t, ctx.ReleaseNotes, "first") 219 require.Contains(t, ctx.ReleaseNotes, "added feature 1") // no whitespace because its the last entry of the changelog 220 require.Contains(t, ctx.ReleaseNotes, "fixed bug 2 ") // whitespaces are on purpose 221 require.NotContains(t, ctx.ReleaseNotes, "docs") 222 require.NotContains(t, ctx.ReleaseNotes, "ignored") 223 require.NotContains(t, ctx.ReleaseNotes, "cArs") 224 require.NotContains(t, ctx.ReleaseNotes, "from goreleaser/some-branch") 225 226 bts, err := os.ReadFile(filepath.Join(folder, "CHANGELOG.md")) 227 require.NoError(t, err) 228 require.NotEmpty(t, string(bts)) 229 } 230 231 func TestChangelogSort(t *testing.T) { 232 testlib.Mktmp(t) 233 testlib.GitInit(t) 234 testlib.GitCommit(t, "whatever") 235 testlib.GitTag(t, "v0.9.9") 236 testlib.GitCommit(t, "c: commit") 237 testlib.GitCommit(t, "a: commit") 238 testlib.GitCommit(t, "b: commit") 239 testlib.GitTag(t, "v1.0.0") 240 ctx := testctx.New( 241 242 testctx.WithCurrentTag("v1.0.0"), 243 testctx.WithPreviousTag("v0.9.9"), 244 ) 245 246 for _, cfg := range []struct { 247 Sort string 248 Entries []string 249 }{ 250 { 251 Sort: "", 252 Entries: []string{ 253 "b: commit", 254 "a: commit", 255 "c: commit", 256 }, 257 }, 258 { 259 Sort: "asc", 260 Entries: []string{ 261 "a: commit", 262 "b: commit", 263 "c: commit", 264 }, 265 }, 266 { 267 Sort: "desc", 268 Entries: []string{ 269 "c: commit", 270 "b: commit", 271 "a: commit", 272 }, 273 }, 274 } { 275 t.Run("changelog sort='"+cfg.Sort+"'", func(t *testing.T) { 276 ctx.Config.Changelog.Sort = cfg.Sort 277 entries, err := buildChangelog(ctx) 278 require.NoError(t, err) 279 require.Len(t, entries, len(cfg.Entries)) 280 var changes []string 281 for _, line := range entries { 282 changes = append(changes, extractCommitInfo(line)) 283 } 284 require.EqualValues(t, cfg.Entries, changes) 285 }) 286 } 287 } 288 289 func TestChangelogInvalidSort(t *testing.T) { 290 ctx := testctx.NewWithCfg(config.Project{ 291 Changelog: config.Changelog{ 292 Sort: "dope", 293 }, 294 }) 295 require.EqualError(t, Pipe{}.Run(ctx), ErrInvalidSortDirection.Error()) 296 } 297 298 func TestChangelogOfFirstRelease(t *testing.T) { 299 testlib.Mktmp(t) 300 testlib.GitInit(t) 301 msgs := []string{ 302 "initial commit", 303 "another one", 304 "one more", 305 "and finally this one", 306 } 307 for _, msg := range msgs { 308 testlib.GitCommit(t, msg) 309 } 310 testlib.GitTag(t, "v0.0.1") 311 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 312 require.NoError(t, Pipe{}.Run(ctx)) 313 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 314 for _, msg := range msgs { 315 require.Contains(t, ctx.ReleaseNotes, msg) 316 } 317 } 318 319 func TestChangelogFilterInvalidRegex(t *testing.T) { 320 testlib.Mktmp(t) 321 testlib.GitInit(t) 322 testlib.GitCommit(t, "commitssss") 323 testlib.GitTag(t, "v0.0.3") 324 testlib.GitCommit(t, "commitzzz") 325 testlib.GitTag(t, "v0.0.4") 326 ctx := testctx.NewWithCfg(config.Project{ 327 Changelog: config.Changelog{ 328 Filters: config.Filters{ 329 Exclude: []string{ 330 "(?iasdr4qasd)not a valid regex i guess", 331 }, 332 }, 333 }, 334 }, testctx.WithCurrentTag("v0.0.4"), testctx.WithPreviousTag("v0.0.3")) 335 require.EqualError(t, Pipe{}.Run(ctx), "error parsing regexp: invalid or unsupported Perl syntax: `(?ia`") 336 } 337 338 func TestChangelogFilterIncludeInvalidRegex(t *testing.T) { 339 testlib.Mktmp(t) 340 testlib.GitInit(t) 341 testlib.GitCommit(t, "commitssss") 342 testlib.GitTag(t, "v0.0.3") 343 testlib.GitCommit(t, "commitzzz") 344 testlib.GitTag(t, "v0.0.4") 345 ctx := testctx.NewWithCfg(config.Project{ 346 Changelog: config.Changelog{ 347 Filters: config.Filters{ 348 Include: []string{ 349 "(?iasdr4qasd)not a valid regex i guess", 350 }, 351 }, 352 }, 353 }, testctx.WithCurrentTag("v0.0.4"), testctx.WithPreviousTag("v0.0.3")) 354 require.EqualError(t, Pipe{}.Run(ctx), "error parsing regexp: invalid or unsupported Perl syntax: `(?ia`") 355 } 356 357 func TestChangelogNoTags(t *testing.T) { 358 testlib.Mktmp(t) 359 testlib.GitInit(t) 360 testlib.GitCommit(t, "first") 361 ctx := testctx.New() 362 require.Error(t, Pipe{}.Run(ctx)) 363 require.Empty(t, ctx.ReleaseNotes) 364 } 365 366 func TestChangelogOnBranchWithSameNameAsTag(t *testing.T) { 367 testlib.Mktmp(t) 368 testlib.GitInit(t) 369 msgs := []string{ 370 "initial commit", 371 "another one", 372 "one more", 373 "and finally this one", 374 } 375 for _, msg := range msgs { 376 testlib.GitCommit(t, msg) 377 } 378 testlib.GitTag(t, "v0.0.1") 379 testlib.GitCheckoutBranch(t, "v0.0.1") 380 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 381 require.NoError(t, Pipe{}.Run(ctx)) 382 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 383 for _, msg := range msgs { 384 require.Contains(t, ctx.ReleaseNotes, msg) 385 } 386 } 387 388 func TestChangeLogWithReleaseHeader(t *testing.T) { 389 current, err := os.Getwd() 390 require.NoError(t, err) 391 tmpdir := testlib.Mktmp(t) 392 require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata")) 393 testlib.GitInit(t) 394 msgs := []string{ 395 "initial commit", 396 "another one", 397 "one more", 398 "and finally this one", 399 } 400 for _, msg := range msgs { 401 testlib.GitCommit(t, msg) 402 } 403 testlib.GitTag(t, "v0.0.1") 404 testlib.GitCheckoutBranch(t, "v0.0.1") 405 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 406 ctx.ReleaseHeaderFile = "testdata/release-header.md" 407 require.NoError(t, Pipe{}.Run(ctx)) 408 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 409 require.Contains(t, ctx.ReleaseNotes, "test header") 410 } 411 412 func TestChangeLogWithTemplatedReleaseHeader(t *testing.T) { 413 current, err := os.Getwd() 414 require.NoError(t, err) 415 tmpdir := testlib.Mktmp(t) 416 require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata")) 417 testlib.GitInit(t) 418 msgs := []string{ 419 "initial commit", 420 "another one", 421 "one more", 422 "and finally this one", 423 } 424 for _, msg := range msgs { 425 testlib.GitCommit(t, msg) 426 } 427 testlib.GitTag(t, "v0.0.1") 428 testlib.GitCheckoutBranch(t, "v0.0.1") 429 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 430 ctx.ReleaseHeaderTmpl = "testdata/release-header-templated.md" 431 require.NoError(t, Pipe{}.Run(ctx)) 432 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 433 require.Contains(t, ctx.ReleaseNotes, "test header with tag v0.0.1") 434 } 435 436 func TestChangeLogWithReleaseFooter(t *testing.T) { 437 current, err := os.Getwd() 438 require.NoError(t, err) 439 tmpdir := testlib.Mktmp(t) 440 require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata")) 441 testlib.GitInit(t) 442 msgs := []string{ 443 "initial commit", 444 "another one", 445 "one more", 446 "and finally this one", 447 } 448 for _, msg := range msgs { 449 testlib.GitCommit(t, msg) 450 } 451 testlib.GitTag(t, "v0.0.1") 452 testlib.GitCheckoutBranch(t, "v0.0.1") 453 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 454 ctx.ReleaseFooterFile = "testdata/release-footer.md" 455 require.NoError(t, Pipe{}.Run(ctx)) 456 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 457 require.Contains(t, ctx.ReleaseNotes, "test footer") 458 require.Equal(t, rune(ctx.ReleaseNotes[len(ctx.ReleaseNotes)-1]), '\n') 459 } 460 461 func TestChangeLogWithTemplatedReleaseFooter(t *testing.T) { 462 current, err := os.Getwd() 463 require.NoError(t, err) 464 tmpdir := testlib.Mktmp(t) 465 require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata")) 466 testlib.GitInit(t) 467 msgs := []string{ 468 "initial commit", 469 "another one", 470 "one more", 471 "and finally this one", 472 } 473 for _, msg := range msgs { 474 testlib.GitCommit(t, msg) 475 } 476 testlib.GitTag(t, "v0.0.1") 477 testlib.GitCheckoutBranch(t, "v0.0.1") 478 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 479 ctx.ReleaseFooterTmpl = "testdata/release-footer-templated.md" 480 require.NoError(t, Pipe{}.Run(ctx)) 481 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 482 require.Contains(t, ctx.ReleaseNotes, "test footer with tag v0.0.1") 483 require.Equal(t, rune(ctx.ReleaseNotes[len(ctx.ReleaseNotes)-1]), '\n') 484 } 485 486 func TestChangeLogWithoutReleaseFooter(t *testing.T) { 487 current, err := os.Getwd() 488 require.NoError(t, err) 489 tmpdir := testlib.Mktmp(t) 490 require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata")) 491 testlib.GitInit(t) 492 msgs := []string{ 493 "initial commit", 494 "another one", 495 "one more", 496 "and finally this one", 497 } 498 for _, msg := range msgs { 499 testlib.GitCommit(t, msg) 500 } 501 testlib.GitTag(t, "v0.0.1") 502 testlib.GitCheckoutBranch(t, "v0.0.1") 503 ctx := testctx.New(testctx.WithCurrentTag("v0.0.1"), withFirstCommit(t)) 504 require.NoError(t, Pipe{}.Run(ctx)) 505 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 506 require.Equal(t, rune(ctx.ReleaseNotes[len(ctx.ReleaseNotes)-1]), '\n') 507 } 508 509 func TestGetChangelogGitHub(t *testing.T) { 510 ctx := testctx.NewWithCfg(config.Project{ 511 Changelog: config.Changelog{ 512 Use: useGitHub, 513 }, 514 }, testctx.WithCurrentTag("v0.180.2"), testctx.WithPreviousTag("v0.180.1")) 515 516 expected := "c90f1085f255d0af0b055160bfff5ee40f47af79: fix: do not skip any defaults (#2521) (@caarlos0)" 517 mock := client.NewMock() 518 mock.Changes = expected 519 l := scmChangeloger{ 520 client: mock, 521 repo: client.Repo{ 522 Owner: "goreleaser", 523 Name: "goreleaser", 524 }, 525 } 526 527 log, err := l.Log(ctx) 528 require.NoError(t, err) 529 require.Equal(t, expected, log) 530 } 531 532 func TestGetChangelogGitHubNative(t *testing.T) { 533 ctx := testctx.NewWithCfg(config.Project{ 534 Changelog: config.Changelog{ 535 Use: useGitHubNative, 536 }, 537 }, testctx.WithCurrentTag("v0.180.2"), testctx.WithPreviousTag("v0.180.1")) 538 539 expected := `## What's changed 540 541 * Foo bar test 542 543 **Full Changelog**: https://github.com/gorelease/goreleaser/compare/v0.180.1...v0.180.2 544 ` 545 mock := client.NewMock() 546 mock.ReleaseNotes = expected 547 l := githubNativeChangeloger{ 548 client: mock, 549 repo: client.Repo{ 550 Owner: "goreleaser", 551 Name: "goreleaser", 552 }, 553 } 554 log, err := l.Log(ctx) 555 require.NoError(t, err) 556 require.Equal(t, expected, log) 557 require.Equal(t, []string{"v0.180.1", "v0.180.2"}, mock.ReleaseNotesParams) 558 } 559 560 func TestGetChangelogGitHubNativeFirstRelease(t *testing.T) { 561 ctx := testctx.NewWithCfg(config.Project{ 562 Changelog: config.Changelog{ 563 Use: useGitHubNative, 564 }, 565 }, testctx.WithCurrentTag("v0.1.0")) 566 567 expected := `## What's changed 568 569 * Foo bar test 570 571 **Full Changelog**: https://github.com/gorelease/goreleaser/commits/v0.1.0 572 ` 573 mock := client.NewMock() 574 mock.ReleaseNotes = expected 575 l := githubNativeChangeloger{ 576 client: mock, 577 repo: client.Repo{ 578 Owner: "goreleaser", 579 Name: "goreleaser", 580 }, 581 } 582 log, err := l.Log(ctx) 583 require.NoError(t, err) 584 require.Equal(t, expected, log) 585 require.Equal(t, []string{"", "v0.1.0"}, mock.ReleaseNotesParams) 586 } 587 588 func TestGetChangeloger(t *testing.T) { 589 t.Run("default", func(t *testing.T) { 590 c, err := getChangeloger(testctx.New()) 591 require.NoError(t, err) 592 require.IsType(t, c, gitChangeloger{}) 593 }) 594 595 t.Run(useGit, func(t *testing.T) { 596 c, err := getChangeloger(testctx.NewWithCfg(config.Project{ 597 Changelog: config.Changelog{ 598 Use: useGit, 599 }, 600 })) 601 require.NoError(t, err) 602 require.IsType(t, c, gitChangeloger{}) 603 }) 604 605 t.Run(useGitHub, func(t *testing.T) { 606 ctx := testctx.NewWithCfg(config.Project{ 607 Changelog: config.Changelog{ 608 Use: useGitHub, 609 }, 610 }, testctx.GitHubTokenType) 611 c, err := getChangeloger(ctx) 612 require.NoError(t, err) 613 require.IsType(t, c, &scmChangeloger{}) 614 }) 615 616 t.Run(useGitHubNative, func(t *testing.T) { 617 ctx := testctx.NewWithCfg(config.Project{ 618 Changelog: config.Changelog{ 619 Use: useGitHubNative, 620 }, 621 }, testctx.GitHubTokenType) 622 c, err := getChangeloger(ctx) 623 require.NoError(t, err) 624 require.IsType(t, c, &githubNativeChangeloger{}) 625 }) 626 627 t.Run(useGitHubNative+"-invalid-repo", func(t *testing.T) { 628 testlib.Mktmp(t) 629 testlib.GitInit(t) 630 testlib.GitRemoteAdd(t, "https://gist.github.com/") 631 ctx := testctx.NewWithCfg(config.Project{ 632 Changelog: config.Changelog{ 633 Use: useGitHubNative, 634 }, 635 }, testctx.GitHubTokenType) 636 c, err := getChangeloger(ctx) 637 require.EqualError(t, err, "unsupported repository URL: https://gist.github.com/") 638 require.Nil(t, c) 639 }) 640 641 t.Run(useGitLab, func(t *testing.T) { 642 ctx := testctx.NewWithCfg(config.Project{ 643 Changelog: config.Changelog{ 644 Use: useGitLab, 645 }, 646 }, testctx.GitHubTokenType) 647 c, err := getChangeloger(ctx) 648 require.NoError(t, err) 649 require.IsType(t, c, &scmChangeloger{}) 650 }) 651 652 t.Run(useGitHub+"-invalid-repo", func(t *testing.T) { 653 testlib.Mktmp(t) 654 testlib.GitInit(t) 655 testlib.GitRemoteAdd(t, "https://gist.github.com/") 656 ctx := testctx.NewWithCfg(config.Project{ 657 Changelog: config.Changelog{ 658 Use: useGitHub, 659 }, 660 }, testctx.GitHubTokenType) 661 c, err := getChangeloger(ctx) 662 require.EqualError(t, err, "unsupported repository URL: https://gist.github.com/") 663 require.Nil(t, c) 664 }) 665 666 t.Run("invalid", func(t *testing.T) { 667 c, err := getChangeloger(testctx.NewWithCfg(config.Project{ 668 Changelog: config.Changelog{ 669 Use: "nope", 670 }, 671 })) 672 require.EqualError(t, err, `invalid changelog.use: "nope"`) 673 require.Nil(t, c) 674 }) 675 } 676 677 func TestSkip(t *testing.T) { 678 t.Run("skip", func(t *testing.T) { 679 ctx := testctx.New(testctx.Snapshot) 680 b, err := Pipe{}.Skip(ctx) 681 require.NoError(t, err) 682 require.True(t, b) 683 }) 684 685 t.Run("skip on patches", func(t *testing.T) { 686 ctx := testctx.NewWithCfg(config.Project{ 687 Changelog: config.Changelog{ 688 Skip: "{{gt .Patch 0}}", 689 }, 690 }, testctx.WithSemver(0, 0, 1, "")) 691 b, err := Pipe{}.Skip(ctx) 692 require.NoError(t, err) 693 require.True(t, b) 694 }) 695 696 t.Run("invalid template", func(t *testing.T) { 697 ctx := testctx.NewWithCfg(config.Project{ 698 Changelog: config.Changelog{ 699 Skip: "{{if eq .Patch 123}", 700 }, 701 }, testctx.WithSemver(0, 0, 1, "")) 702 _, err := Pipe{}.Skip(ctx) 703 require.Error(t, err) 704 }) 705 706 t.Run("dont skip", func(t *testing.T) { 707 b, err := Pipe{}.Skip(testctx.New()) 708 require.NoError(t, err) 709 require.False(t, b) 710 }) 711 712 t.Run("dont skip based on template", func(t *testing.T) { 713 ctx := testctx.NewWithCfg(config.Project{ 714 Changelog: config.Changelog{ 715 Skip: "{{gt .Patch 0}}", 716 }, 717 }) 718 b, err := Pipe{}.Skip(ctx) 719 require.NoError(t, err) 720 require.False(t, b) 721 }) 722 } 723 724 func TestGroup(t *testing.T) { 725 folder := testlib.Mktmp(t) 726 testlib.GitInit(t) 727 testlib.GitCommit(t, "first") 728 testlib.GitTag(t, "v0.0.1") 729 testlib.GitCommit(t, "added feature 1") 730 testlib.GitCommit(t, "fixed bug 2") 731 testlib.GitCommit(t, "ignored: whatever") 732 testlib.GitCommit(t, "feat(deps): update foobar [bot]") 733 testlib.GitCommit(t, "fix: whatever") 734 testlib.GitCommit(t, "docs: whatever") 735 testlib.GitCommit(t, "chore: something about cArs we dont need") 736 testlib.GitCommit(t, "feat: added that thing") 737 testlib.GitCommit(t, "bug: Merge pull request #999 from goreleaser/some-branch") 738 testlib.GitCommit(t, "this is not a Merge pull request") 739 testlib.GitTag(t, "v0.0.2") 740 ctx := testctx.NewWithCfg(config.Project{ 741 Dist: folder, 742 Changelog: config.Changelog{ 743 Groups: []config.ChangelogGroup{ 744 { 745 Title: "Bots", 746 Regexp: ".*bot.*", 747 Order: 900, 748 }, 749 { 750 Title: "Features", 751 Regexp: `^.*?feat(\([[:word:]]+\))??!?:.+$`, 752 Order: 0, 753 }, 754 { 755 Title: "Bug Fixes", 756 Regexp: `^.*?bug(\([[:word:]]+\))??!?:.+$`, 757 Order: 1, 758 }, 759 { 760 Title: "Catch nothing", 761 Regexp: "yada yada yada honk the planet", 762 Order: 10, 763 }, 764 { 765 Title: "Others", 766 Order: 999, 767 }, 768 }, 769 }, 770 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 771 require.NoError(t, Pipe{}.Run(ctx)) 772 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 773 require.Contains(t, ctx.ReleaseNotes, "### Bots") 774 require.Contains(t, ctx.ReleaseNotes, "### Features") 775 require.Contains(t, ctx.ReleaseNotes, "### Bug Fixes") 776 require.NotContains(t, ctx.ReleaseNotes, "### Catch nothing") 777 require.Contains(t, ctx.ReleaseNotes, "### Others") 778 } 779 780 func TestGroupBadRegex(t *testing.T) { 781 folder := testlib.Mktmp(t) 782 testlib.GitInit(t) 783 testlib.GitCommit(t, "first") 784 testlib.GitTag(t, "v0.0.1") 785 testlib.GitTag(t, "v0.0.2") 786 ctx := testctx.NewWithCfg(config.Project{ 787 Dist: folder, 788 Changelog: config.Changelog{ 789 Groups: []config.ChangelogGroup{ 790 { 791 Title: "Something", 792 Regexp: "^.*feat[a-z", // unterminated regex 793 }, 794 }, 795 }, 796 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 797 require.EqualError(t, Pipe{}.Run(ctx), "failed to group into \"Something\": error parsing regexp: missing closing ]: `[a-z`") 798 } 799 800 func TestChangelogFormat(t *testing.T) { 801 t.Run("without groups", func(t *testing.T) { 802 makeConf := func(u string) config.Project { 803 return config.Project{Changelog: config.Changelog{Use: u}} 804 } 805 806 for _, use := range []string{useGit, useGitHub, useGitLab} { 807 t.Run(use, func(t *testing.T) { 808 out, err := formatChangelog( 809 testctx.NewWithCfg(makeConf(use)), 810 []string{ 811 "aea123 foo", 812 "aef653 bar", 813 }, 814 ) 815 require.NoError(t, err) 816 require.Equal(t, `## Changelog 817 * aea123 foo 818 * aef653 bar`, out) 819 }) 820 } 821 822 t.Run(useGitHubNative, func(t *testing.T) { 823 out, err := formatChangelog( 824 testctx.NewWithCfg(makeConf(useGitHubNative)), 825 []string{ 826 "# What's changed", 827 "* aea123 foo", 828 "* aef653 bar", 829 }, 830 ) 831 require.NoError(t, err) 832 require.Equal(t, `# What's changed 833 * aea123 foo 834 * aef653 bar`, out) 835 }) 836 }) 837 838 t.Run("with groups", func(t *testing.T) { 839 makeConf := func(u string) config.Project { 840 return config.Project{ 841 Changelog: config.Changelog{ 842 Use: u, 843 Groups: []config.ChangelogGroup{ 844 {Title: "catch-all"}, 845 }, 846 }, 847 } 848 } 849 850 t.Run(useGitHubNative, func(t *testing.T) { 851 out, err := formatChangelog( 852 testctx.NewWithCfg(makeConf(useGitHubNative)), 853 []string{ 854 "# What's changed", 855 "* aea123 foo", 856 "* aef653 bar", 857 }, 858 ) 859 require.NoError(t, err) 860 require.Equal(t, `# What's changed 861 * aea123 foo 862 * aef653 bar`, out) 863 }) 864 for _, use := range []string{useGit, useGitHub, useGitLab} { 865 t.Run(use, func(t *testing.T) { 866 out, err := formatChangelog( 867 testctx.NewWithCfg(makeConf(use)), 868 []string{ 869 "aea123 foo", 870 "aef653 bar", 871 }, 872 ) 873 require.NoError(t, err) 874 require.Equal(t, `## Changelog 875 ### catch-all 876 * aea123 foo 877 * aef653 bar`, out) 878 }) 879 } 880 }) 881 } 882 883 func TestAbbrev(t *testing.T) { 884 folder := testlib.Mktmp(t) 885 testlib.GitInit(t) 886 testlib.GitCommit(t, "first") 887 testlib.GitTag(t, "v0.0.1") 888 testlib.GitCommit(t, "added feature 1") 889 testlib.GitCommit(t, "fixed bug 2") 890 testlib.GitCommit(t, "ignored: whatever") 891 testlib.GitCommit(t, "feat(deps): update foobar [bot]") 892 testlib.GitCommit(t, "fix: whatever") 893 testlib.GitCommit(t, "docs: whatever") 894 testlib.GitCommit(t, "chore: something about cArs we dont need") 895 testlib.GitCommit(t, "feat: added that thing") 896 testlib.GitCommit(t, "bug: Merge pull request #999 from goreleaser/some-branch") 897 testlib.GitCommit(t, "this is not a Merge pull request") 898 testlib.GitTag(t, "v0.0.2") 899 900 t.Run("no abbrev", func(t *testing.T) { 901 ctx := testctx.NewWithCfg(config.Project{ 902 Dist: folder, 903 Changelog: config.Changelog{}, 904 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 905 906 require.NoError(t, Pipe{}.Run(ctx)) 907 ensureCommitHashLen(t, ctx.ReleaseNotes, 7) 908 }) 909 910 t.Run("abbrev -1", func(t *testing.T) { 911 ctx := testctx.NewWithCfg(config.Project{ 912 Dist: folder, 913 Changelog: config.Changelog{ 914 Abbrev: -1, 915 }, 916 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 917 require.NoError(t, Pipe{}.Run(ctx)) 918 }) 919 920 t.Run("abbrev 3", func(t *testing.T) { 921 ctx := testctx.NewWithCfg(config.Project{ 922 Dist: folder, 923 Changelog: config.Changelog{ 924 Abbrev: 3, 925 }, 926 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 927 require.NoError(t, Pipe{}.Run(ctx)) 928 ensureCommitHashLen(t, ctx.ReleaseNotes, 3) 929 }) 930 931 t.Run("abbrev 7", func(t *testing.T) { 932 ctx := testctx.NewWithCfg(config.Project{ 933 Dist: folder, 934 Changelog: config.Changelog{ 935 Abbrev: 7, 936 }, 937 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 938 require.NoError(t, Pipe{}.Run(ctx)) 939 ensureCommitHashLen(t, ctx.ReleaseNotes, 7) 940 }) 941 942 t.Run("abbrev 40", func(t *testing.T) { 943 ctx := testctx.NewWithCfg(config.Project{ 944 Dist: folder, 945 Changelog: config.Changelog{ 946 Abbrev: 40, 947 }, 948 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 949 require.NoError(t, Pipe{}.Run(ctx)) 950 ensureCommitHashLen(t, ctx.ReleaseNotes, 7) 951 }) 952 } 953 954 func ensureCommitHashLen(tb testing.TB, log string, l int) { 955 tb.Helper() 956 for _, line := range strings.Split(log, "\n") { 957 if strings.HasPrefix(line, "#") || strings.TrimSpace(line) == "" { 958 continue 959 } 960 parts := strings.SplitN(line, " ", 3) 961 commit := strings.TrimPrefix(parts[1], "* ") 962 require.Len(tb, commit, l) 963 } 964 } 965 966 func withFirstCommit(tb testing.TB) testctx.Opt { 967 tb.Helper() 968 return func(ctx *context.Context) { 969 s, err := git.Clean(git.Run(testctx.New(), "rev-list", "--max-parents=0", "HEAD")) 970 require.NoError(tb, err) 971 ctx.Git.FirstCommit = s 972 } 973 }