diff --git a/README.md b/README.md index a0aafb2..09236ac 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ To use this plugin you need to include the following block in your | auth_private_key | | The path to an SSH private key file. | | git_path | . | The path to the Git repository. | | push_options | | The push options for the git tag push. | +| log_order | dfs | The log order traversal algorithm. | ### Authentication @@ -70,6 +71,17 @@ For this method you'll need to set `auth_username` and `auth_private_key`. If your private key uses a password then you'll also need to set `auth_password`. +### Log Order Options + +log_order=dfs (Default) - Ordering by depth-first search in pre-order + +log_order=dfs_post - Ordering by depth-first search in post-order (useful to traverse +history in chronological order) + +log_order=bfs - Ordering by breadth-first search + +log_order=ctime - Ordering by committer time (more compatible with `git log`) + ## Licence The [MIT License (MIT)](http://opensource.org/licenses/MIT) diff --git a/pkg/provider/git.go b/pkg/provider/git.go index c816043..d3adc04 100644 --- a/pkg/provider/git.go +++ b/pkg/provider/git.go @@ -29,8 +29,10 @@ type Repository struct { auth transport.AuthMethod repo *git.Repository pushOptions map[string]string + logOrder git.LogOrder } +//gocyclo:ignore func (repo *Repository) Init(config map[string]string) error { repo.defaultBranch = config["default_branch"] if repo.defaultBranch == "" { @@ -78,6 +80,19 @@ func (repo *Repository) Init(config map[string]string) error { } } + switch config["log_order"] { + case "ctime": + repo.logOrder = git.LogOrderCommitterTime + case "dfs": + repo.logOrder = git.LogOrderDFS + case "dfs_post": + repo.logOrder = git.LogOrderDFSPost + case "bfs": // intentionally correcting to bfs instead of the bsf typo + repo.logOrder = git.LogOrderBSF + default: + repo.logOrder = git.LogOrderDefault + } + gitPath := config["git_path"] if gitPath == "" { gitPath = "." @@ -108,7 +123,8 @@ func (repo *Repository) GetCommits(fromSha, toSha string) ([]*semrel.RawCommit, } commits, err := repo.repo.Log(&git.LogOptions{ - From: *toHash, + From: *toHash, + Order: repo.logOrder, }) if err != nil { return nil, err diff --git a/pkg/provider/git_test.go b/pkg/provider/git_test.go index 1a4a7ec..7615233 100644 --- a/pkg/provider/git_test.go +++ b/pkg/provider/git_test.go @@ -26,6 +26,9 @@ func TestGit(t *testing.T) { t.Run("GetInfo", getInfo) t.Run("GetReleases", getReleases) t.Run("GetCommits", getCommits) + t.Run("GetCommitsNoFFMergeDFS", getCommitsNoFFMergeDFS) + t.Run("GetCommitsNoFFMergeDFSPost", getCommitsNoFFMergeDFSPost) + t.Run("GetCommitsNoFFMergeCTime", getCommitsNoFFMergeCTime) t.Run("CreateRelease", createRelease) } @@ -151,6 +154,31 @@ func createRepo() (*Repository, error) { return repo, nil } +func cloneRepo(path, url string) (*Repository, error) { + _, err := git.PlainClone(path, false, &git.CloneOptions{ + Auth: &http.BasicAuth{ + Username: "test", + Password: "test", + }, + URL: url, + }) + if err != nil { + return nil, err + } + repo := &Repository{} + err = repo.Init(map[string]string{ + "git_path": path, + "auth": "basic", + "auth_username": "test", + "auth_password": "test", + }) + if err != nil { + return nil, err + } + + return repo, nil +} + func getInfo(t *testing.T) { require := require.New(t) repo, err := createRepo() @@ -179,6 +207,53 @@ func getCommits(t *testing.T) { } } +func getCommitsNoFFMergeDFS(t *testing.T) { + require := require.New(t) + dir, err := os.MkdirTemp("", "provider-git") + require.NoError(err) + repo, err := cloneRepo(dir, "http://localhost:3000/test/no_ff_merge.git") + require.NoError(err) + releases, err := repo.GetReleases("") + require.NoError(err) + require.Len(releases, 1) + initialCommitSha := releases[0].GetSHA() + commits, err := repo.GetCommits(initialCommitSha, "master") + require.NoError(err) + require.Len(commits, 1) +} + +func getCommitsNoFFMergeCTime(t *testing.T) { + require := require.New(t) + dir, err := os.MkdirTemp("", "provider-git") + require.NoError(err) + repo, err := cloneRepo(dir, "http://localhost:3000/test/no_ff_merge.git") + repo.logOrder = git.LogOrderCommitterTime + require.NoError(err) + releases, err := repo.GetReleases("") + require.NoError(err) + require.Len(releases, 1) + initialCommitSha := releases[0].GetSHA() + commits, err := repo.GetCommits(initialCommitSha, "master") + require.NoError(err) + require.Len(commits, 2) +} + +func getCommitsNoFFMergeDFSPost(t *testing.T) { + require := require.New(t) + dir, err := os.MkdirTemp("", "provider-git") + require.NoError(err) + repo, err := cloneRepo(dir, "http://localhost:3000/test/no_ff_merge.git") + repo.logOrder = git.LogOrderDFSPost + require.NoError(err) + releases, err := repo.GetReleases("") + require.NoError(err) + require.Len(releases, 1) + initialCommitSha := releases[0].GetSHA() + commits, err := repo.GetCommits(initialCommitSha, "master") + require.NoError(err) + require.Len(commits, 2) +} + func createRelease(t *testing.T) { require := require.New(t) repo, err := createRepo() @@ -211,14 +286,27 @@ func createRelease(t *testing.T) { Changelog: testCase.changelog, }) require.NoError(err) + tagName := "v" + testCase.version - tagRef, err := gRepo.Tag("v" + testCase.version) + tagRef, err := gRepo.Tag(tagName) require.NoError(err) tagObj, err := gRepo.TagObject(tagRef.Hash()) require.NoError(err) require.Equal(testCase.changelog+"\n", tagObj.Message) + + // Clean up tags so future test runs succeed + tagRefName := ":refs/tags/" + tagName + err = gRepo.Push(&git.PushOptions{ + RemoteName: "origin", + RefSpecs: []config.RefSpec{config.RefSpec(tagRefName)}, + Auth: &http.BasicAuth{ + Username: "test", + Password: "test", + }, + }) + require.NoError(err) } } diff --git a/scripts/start-gitea.sh b/scripts/start-gitea.sh index b150ec1..d9bf89a 100755 --- a/scripts/start-gitea.sh +++ b/scripts/start-gitea.sh @@ -17,3 +17,25 @@ sleep 10 echo "creating test repo..." curl -u 'test:test' -XPOST -H 'Content-Type: application/json' -d '{"name":"test"}' http://localhost:3000/api/v1/user/repos + +echo "creating no_ff_merge repo..." +curl -u 'test:test' -XPOST -H 'Content-Type: application/json' -d '{"name":"no_ff_merge"}' http://localhost:3000/api/v1/user/repos + +echo "populating no_ff_merge repo..." +tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'tmpdir') +cd $tmpdir +export GIT_COMMITTER_NAME=test +export GIT_COMMITTER_EMAIL=test@test.com +export GIT_AUTHOR_NAME=test +export GIT_AUTHOR_EMAIL=test@test.com +git init --initial-branch=master +git commit -m "feat: initial commit" --allow-empty +git tag v1.0.0 +git switch -C feature +sleep 1 +git commit -m "feat: feature" --allow-empty +git switch master +git merge --no-ff feature --no-edit +git push http://test:test@localhost:3000/test/no_ff_merge.git master --tags +cd - +rm -rf $tmpdir