github.com/goreleaser/goreleaser@v1.25.1/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/goreleaser/goreleaser/internal/client" 12 "github.com/goreleaser/goreleaser/internal/git" 13 "github.com/goreleaser/goreleaser/internal/testctx" 14 "github.com/goreleaser/goreleaser/internal/testlib" 15 "github.com/goreleaser/goreleaser/pkg/config" 16 "github.com/goreleaser/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, '\n', rune(ctx.ReleaseNotes[len(ctx.ReleaseNotes)-1])) 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, '\n', rune(ctx.ReleaseNotes[len(ctx.ReleaseNotes)-1])) 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, '\n', rune(ctx.ReleaseNotes[len(ctx.ReleaseNotes)-1])) 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, gitChangeloger{}, c) 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, gitChangeloger{}, c) 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, &scmChangeloger{}, c) 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, &githubNativeChangeloger{}, c) 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, &scmChangeloger{}, c) 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/disable", 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 require.Equal(t, ctx.Config.Changelog.Skip, ctx.Config.Changelog.Disable) 695 }) 696 697 t.Run("disable on patches", func(t *testing.T) { 698 ctx := testctx.NewWithCfg(config.Project{ 699 Changelog: config.Changelog{ 700 Disable: "{{gt .Patch 0}}", 701 }, 702 }, testctx.WithSemver(0, 0, 1, "")) 703 b, err := Pipe{}.Skip(ctx) 704 require.NoError(t, err) 705 require.True(t, b) 706 }) 707 708 t.Run("invalid template", func(t *testing.T) { 709 ctx := testctx.NewWithCfg(config.Project{ 710 Changelog: config.Changelog{ 711 Disable: "{{if eq .Patch 123}", 712 }, 713 }, testctx.WithSemver(0, 0, 1, "")) 714 _, err := Pipe{}.Skip(ctx) 715 require.Error(t, err) 716 }) 717 718 t.Run("dont skip", func(t *testing.T) { 719 b, err := Pipe{}.Skip(testctx.New()) 720 require.NoError(t, err) 721 require.False(t, b) 722 }) 723 724 t.Run("dont skip based on template", func(t *testing.T) { 725 ctx := testctx.NewWithCfg(config.Project{ 726 Changelog: config.Changelog{ 727 Disable: "{{gt .Patch 0}}", 728 }, 729 }) 730 b, err := Pipe{}.Skip(ctx) 731 require.NoError(t, err) 732 require.False(t, b) 733 }) 734 } 735 736 func TestGroup(t *testing.T) { 737 folder := testlib.Mktmp(t) 738 testlib.GitInit(t) 739 testlib.GitCommit(t, "first") 740 testlib.GitTag(t, "v0.0.1") 741 testlib.GitCommit(t, "added feature 1") 742 testlib.GitCommit(t, "fixed bug 2") 743 testlib.GitCommit(t, "ignored: whatever") 744 testlib.GitCommit(t, "feat(deps): update foobar [bot]") 745 testlib.GitCommit(t, "fix: whatever") 746 testlib.GitCommit(t, "docs: whatever") 747 testlib.GitCommit(t, "chore: something about cArs we dont need") 748 testlib.GitCommit(t, "feat: added that thing") 749 testlib.GitCommit(t, "bug: Merge pull request #999 from goreleaser/some-branch") 750 testlib.GitCommit(t, "this is not a Merge pull request") 751 testlib.GitTag(t, "v0.0.2") 752 ctx := testctx.NewWithCfg(config.Project{ 753 Dist: folder, 754 Changelog: config.Changelog{ 755 Groups: []config.ChangelogGroup{ 756 { 757 Title: "Bots", 758 Regexp: ".*bot.*", 759 Order: 900, 760 }, 761 { 762 Title: "Features", 763 Regexp: `^.*?feat(\([[:word:]]+\))??!?:.+$`, 764 Order: 0, 765 }, 766 { 767 Title: "Bug Fixes", 768 Regexp: `^.*?bug(\([[:word:]]+\))??!?:.+$`, 769 Order: 1, 770 }, 771 { 772 Title: "Catch nothing", 773 Regexp: "yada yada yada honk the planet", 774 Order: 10, 775 }, 776 { 777 Title: "Others", 778 Order: 999, 779 }, 780 }, 781 }, 782 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 783 require.NoError(t, Pipe{}.Run(ctx)) 784 require.Contains(t, ctx.ReleaseNotes, "## Changelog") 785 require.Contains(t, ctx.ReleaseNotes, "### Bots") 786 require.Contains(t, ctx.ReleaseNotes, "### Features") 787 require.Contains(t, ctx.ReleaseNotes, "### Bug Fixes") 788 require.NotContains(t, ctx.ReleaseNotes, "### Catch nothing") 789 require.Contains(t, ctx.ReleaseNotes, "### Others") 790 } 791 792 func TestGroupBadRegex(t *testing.T) { 793 folder := testlib.Mktmp(t) 794 testlib.GitInit(t) 795 testlib.GitCommit(t, "first") 796 testlib.GitTag(t, "v0.0.1") 797 testlib.GitTag(t, "v0.0.2") 798 ctx := testctx.NewWithCfg(config.Project{ 799 Dist: folder, 800 Changelog: config.Changelog{ 801 Groups: []config.ChangelogGroup{ 802 { 803 Title: "Something", 804 Regexp: "^.*feat[a-z", // unterminated regex 805 }, 806 }, 807 }, 808 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 809 require.EqualError(t, Pipe{}.Run(ctx), "failed to group into \"Something\": error parsing regexp: missing closing ]: `[a-z`") 810 } 811 812 func TestChangelogFormat(t *testing.T) { 813 t.Run("without groups", func(t *testing.T) { 814 makeConf := func(u string) config.Project { 815 return config.Project{Changelog: config.Changelog{Use: u}} 816 } 817 818 for _, use := range []string{useGit, useGitHub, useGitLab} { 819 t.Run(use, func(t *testing.T) { 820 out, err := formatChangelog( 821 testctx.NewWithCfg(makeConf(use)), 822 []string{ 823 "aea123 foo", 824 "aef653 bar", 825 }, 826 ) 827 require.NoError(t, err) 828 require.Equal(t, `## Changelog 829 * aea123 foo 830 * aef653 bar`, out) 831 }) 832 } 833 834 t.Run(useGitHubNative, func(t *testing.T) { 835 out, err := formatChangelog( 836 testctx.NewWithCfg(makeConf(useGitHubNative)), 837 []string{ 838 "# What's changed", 839 "* aea123 foo", 840 "* aef653 bar", 841 }, 842 ) 843 require.NoError(t, err) 844 require.Equal(t, `# What's changed 845 * aea123 foo 846 * aef653 bar`, out) 847 }) 848 }) 849 850 t.Run("with groups", func(t *testing.T) { 851 makeConf := func(u string) config.Project { 852 return config.Project{ 853 Changelog: config.Changelog{ 854 Use: u, 855 Groups: []config.ChangelogGroup{ 856 {Title: "catch-all"}, 857 }, 858 }, 859 } 860 } 861 862 t.Run(useGitHubNative, func(t *testing.T) { 863 out, err := formatChangelog( 864 testctx.NewWithCfg(makeConf(useGitHubNative)), 865 []string{ 866 "# What's changed", 867 "* aea123 foo", 868 "* aef653 bar", 869 }, 870 ) 871 require.NoError(t, err) 872 require.Equal(t, `# What's changed 873 * aea123 foo 874 * aef653 bar`, out) 875 }) 876 for _, use := range []string{useGit, useGitHub, useGitLab} { 877 t.Run(use, func(t *testing.T) { 878 out, err := formatChangelog( 879 testctx.NewWithCfg(makeConf(use)), 880 []string{ 881 "aea123 foo", 882 "aef653 bar", 883 }, 884 ) 885 require.NoError(t, err) 886 require.Equal(t, `## Changelog 887 ### catch-all 888 * aea123 foo 889 * aef653 bar`, out) 890 }) 891 } 892 }) 893 } 894 895 func TestAbbrev(t *testing.T) { 896 folder := testlib.Mktmp(t) 897 testlib.GitInit(t) 898 testlib.GitCommit(t, "first") 899 testlib.GitTag(t, "v0.0.1") 900 testlib.GitCommit(t, "added feature 1") 901 testlib.GitCommit(t, "fixed bug 2") 902 testlib.GitCommit(t, "ignored: whatever") 903 testlib.GitCommit(t, "feat(deps): update foobar [bot]") 904 testlib.GitCommit(t, "fix: whatever") 905 testlib.GitCommit(t, "docs: whatever") 906 testlib.GitCommit(t, "chore: something about cArs we dont need") 907 testlib.GitCommit(t, "feat: added that thing") 908 testlib.GitCommit(t, "bug: Merge pull request #999 from goreleaser/some-branch") 909 testlib.GitCommit(t, "this is not a Merge pull request") 910 testlib.GitTag(t, "v0.0.2") 911 912 t.Run("no abbrev", func(t *testing.T) { 913 ctx := testctx.NewWithCfg(config.Project{ 914 Dist: folder, 915 Changelog: config.Changelog{}, 916 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 917 918 require.NoError(t, Pipe{}.Run(ctx)) 919 ensureCommitHashLen(t, ctx.ReleaseNotes, 7) 920 }) 921 922 t.Run("abbrev -1", func(t *testing.T) { 923 ctx := testctx.NewWithCfg(config.Project{ 924 Dist: folder, 925 Changelog: config.Changelog{ 926 Abbrev: -1, 927 }, 928 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 929 require.NoError(t, Pipe{}.Run(ctx)) 930 }) 931 932 t.Run("abbrev 3", func(t *testing.T) { 933 ctx := testctx.NewWithCfg(config.Project{ 934 Dist: folder, 935 Changelog: config.Changelog{ 936 Abbrev: 3, 937 }, 938 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 939 require.NoError(t, Pipe{}.Run(ctx)) 940 ensureCommitHashLen(t, ctx.ReleaseNotes, 3) 941 }) 942 943 t.Run("abbrev 7", func(t *testing.T) { 944 ctx := testctx.NewWithCfg(config.Project{ 945 Dist: folder, 946 Changelog: config.Changelog{ 947 Abbrev: 7, 948 }, 949 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 950 require.NoError(t, Pipe{}.Run(ctx)) 951 ensureCommitHashLen(t, ctx.ReleaseNotes, 7) 952 }) 953 954 t.Run("abbrev 40", func(t *testing.T) { 955 ctx := testctx.NewWithCfg(config.Project{ 956 Dist: folder, 957 Changelog: config.Changelog{ 958 Abbrev: 40, 959 }, 960 }, testctx.WithCurrentTag("v0.0.2"), withFirstCommit(t)) 961 require.NoError(t, Pipe{}.Run(ctx)) 962 ensureCommitHashLen(t, ctx.ReleaseNotes, 7) 963 }) 964 } 965 966 func ensureCommitHashLen(tb testing.TB, log string, l int) { 967 tb.Helper() 968 for _, line := range strings.Split(log, "\n") { 969 if strings.HasPrefix(line, "#") || strings.TrimSpace(line) == "" { 970 continue 971 } 972 parts := strings.SplitN(line, " ", 3) 973 commit := strings.TrimPrefix(parts[1], "* ") 974 require.Len(tb, commit, l) 975 } 976 } 977 978 func withFirstCommit(tb testing.TB) testctx.Opt { 979 tb.Helper() 980 return func(ctx *context.Context) { 981 s, err := git.Clean(git.Run(testctx.New(), "rev-list", "--max-parents=0", "HEAD")) 982 require.NoError(tb, err) 983 ctx.Git.FirstCommit = s 984 } 985 }