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