From b79ebf354e0ae31c62072e5a994554413e7fb332 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Sat, 13 Nov 2021 09:46:59 -0800 Subject: [PATCH] improve behavior when no arguments are provided Signed-off-by: Alex Goodman --- README.md | 10 ++- cmd/create_github_worker.go | 43 ++++++---- internal/git/head.go | 36 +++++++++ internal/git/head_test.go | 78 ++++++++++++++++++- internal/git/test-fixtures/Makefile | 7 +- .../test-fixtures/create-commit-in-repo.sh | 21 +++++ 6 files changed, 175 insertions(+), 20 deletions(-) create mode 100755 internal/git/test-fixtures/create-commit-in-repo.sh diff --git a/README.md b/README.md index 2f74b7e..feddc2d 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,16 @@ A fast changelog generator that sources changes from GitHub PRs and issues, organized by labels. ```bash +# create a changelog from the last GitHib release until the current git HEAD tag/commit +# for the git repo in the current directory +chronicle + +# create a changelog with all changes from v0.16.0 until current git HEAD tag/commit +# for the git repo in the current directory chronicle --since-tag v0.16.0 -chronicle --since-tag v0.16.0 --until-tag v0.18.0 + +# create a changelog between two specific tags for a repo at the given path +chronicle --since-tag v0.16.0 --until-tag v0.18.0 ./path/to/git/repo ``` ## Installation diff --git a/cmd/create_github_worker.go b/cmd/create_github_worker.go index ec10cab..c819466 100644 --- a/cmd/create_github_worker.go +++ b/cmd/create_github_worker.go @@ -32,24 +32,14 @@ func createChangelogFromGithub() (*release.Description, error) { } log.Infof("since ref=%q date=%q", lastRelease.Version, lastRelease.Date) - releaseVersion := appConfig.UntilTag - releaseDisplayVersion := releaseVersion - if releaseVersion == "" { - releaseVersion = "(Unreleased)" - releaseDisplayVersion = releaseVersion - // check if the current commit is tagged, then use that - releaseTag, err := git.HeadTagOrCommit(appConfig.CliOptions.RepoPath) - if err != nil { - return nil, fmt.Errorf("problem while attempting to find head tag: %w", err) - } - if releaseTag != "" { - releaseVersion = releaseTag - } + releaseVersion, releaseDisplayVersion, err := getCurrentReleaseInfo(appConfig.UntilTag, appConfig.CliOptions.RepoPath) + if err != nil { + return nil, err } log.Infof("until ref=%q", releaseVersion) - changes, err := summer.Changes(lastRelease.Version, appConfig.UntilTag) + changes, err := summer.Changes(lastRelease.Version, releaseVersion) if err != nil { return nil, fmt.Errorf("unable to summarize changes: %w", err) } @@ -70,9 +60,32 @@ func createChangelogFromGithub() (*release.Description, error) { Date: time.Now(), }, VCSTagURL: summer.TagURL(lastRelease.Version), - VCSChangesURL: summer.ChangesURL(lastRelease.Version, appConfig.UntilTag), + VCSChangesURL: summer.ChangesURL(lastRelease.Version, releaseVersion), Changes: changes, SupportedChanges: supportedChanges, Notice: "", // TODO... }, nil } + +func getCurrentReleaseInfo(explicitReleaseVersion, repoPath string) (string, string, error) { + if explicitReleaseVersion != "" { + return explicitReleaseVersion, explicitReleaseVersion, nil + } + + // check if the current commit is tagged, then use that + releaseTag, err := git.HeadTag(repoPath) + if err != nil { + return "", "", fmt.Errorf("problem while attempting to find head tag: %w", err) + } + if releaseTag != "" { + return releaseTag, releaseTag, nil + } + + // fallback to referencing the commit directly + commitRef, err := git.HeadCommit(repoPath) + if err != nil { + return "", "", fmt.Errorf("problem while attempting to find head ref: %w", err) + } + + return commitRef, "(Unreleased)", nil +} diff --git a/internal/git/head.go b/internal/git/head.go index 7a35f71..7606e3e 100644 --- a/internal/git/head.go +++ b/internal/git/head.go @@ -33,3 +33,39 @@ func HeadTagOrCommit(repoPath string) (string, error) { return ref.Hash().String(), nil } + +func HeadTag(repoPath string) (string, error) { + r, err := git.PlainOpen(repoPath) + if err != nil { + return "", fmt.Errorf("unable to open repo: %w", err) + } + ref, err := r.Head() + if err != nil { + return "", fmt.Errorf("unable fetch head: %w", err) + } + tagRefs, _ := r.Tags() + var tagName string + + _ = tagRefs.ForEach(func(t *plumbing.Reference) error { + if t.Hash().String() == ref.Hash().String() { + tagName = t.Name().Short() + return fmt.Errorf("found") + } + return nil + }) + + // note: if there is no tag, then an empty value is returned + return tagName, nil +} + +func HeadCommit(repoPath string) (string, error) { + r, err := git.PlainOpen(repoPath) + if err != nil { + return "", fmt.Errorf("unable to open repo: %w", err) + } + ref, err := r.Head() + if err != nil { + return "", fmt.Errorf("unable fetch head: %w", err) + } + return ref.Hash().String(), nil +} diff --git a/internal/git/head_test.go b/internal/git/head_test.go index a4e49b1..6e7c1f5 100644 --- a/internal/git/head_test.go +++ b/internal/git/head_test.go @@ -6,6 +6,40 @@ import ( "github.com/stretchr/testify/assert" ) +func TestHeadTagOrCommit(t *testing.T) { + tests := []struct { + name string + path string + expects string + expectsLength int + }{ + { + name: "head has tag", + path: "test-fixtures/repos/tagged-repo", + expects: "v0.1.0", + }, + { + name: "head has no tag", + path: "test-fixtures/repos/commit-in-repo", + // since we don't commit the exact fixture, we don't know what the value will be (but the length + // of a commit string is fixed and is a good proxy here) + expectsLength: 40, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := HeadTagOrCommit(test.path) + assert.NoError(t, err) + if test.expects != "" { + assert.Equal(t, test.expects, actual) + } + if test.expectsLength != 0 { + assert.Len(t, actual, test.expectsLength) + } + }) + } +} + func TestHeadTag(t *testing.T) { tests := []struct { name string @@ -13,16 +47,56 @@ func TestHeadTag(t *testing.T) { expects string }{ { - name: "go case", + name: "head has tag", path: "test-fixtures/repos/tagged-repo", expects: "v0.1.0", }, + { + name: "head has no tag", + path: "test-fixtures/repos/commit-in-repo", + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - actual, err := HeadTagOrCommit(test.path) + actual, err := HeadTag(test.path) assert.NoError(t, err) assert.Equal(t, test.expects, actual) }) } } + +func TestHeadCommit(t *testing.T) { + tests := []struct { + name string + path string + expects string + expectsLength int + }{ + { + name: "head has tag", + path: "test-fixtures/repos/tagged-repo", + // since we don't commit the exact fixture, we don't know what the value will be (but the length + // of a commit string is fixed and is a good proxy here) + expectsLength: 40, + }, + { + name: "head has no tag", + path: "test-fixtures/repos/commit-in-repo", + // since we don't commit the exact fixture, we don't know what the value will be (but the length + // of a commit string is fixed and is a good proxy here) + expectsLength: 40, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := HeadCommit(test.path) + assert.NoError(t, err) + if test.expects != "" { + assert.Equal(t, test.expects, actual) + } + if test.expectsLength != 0 { + assert.Len(t, actual, test.expectsLength) + } + }) + } +} diff --git a/internal/git/test-fixtures/Makefile b/internal/git/test-fixtures/Makefile index e6e7105..ad27795 100644 --- a/internal/git/test-fixtures/Makefile +++ b/internal/git/test-fixtures/Makefile @@ -1,9 +1,12 @@ .PHONY: all -all: repos/remote-repo repos/tagged-repo +all: repos/remote-repo repos/tagged-repo repos/commit-in-repo repos/remote-repo: ./create-remote-repo.sh repos/tagged-repo: - ./create-tagged-repo.sh \ No newline at end of file + ./create-tagged-repo.sh + +repos/commit-in-repo: + ./create-commit-in-repo.sh \ No newline at end of file diff --git a/internal/git/test-fixtures/create-commit-in-repo.sh b/internal/git/test-fixtures/create-commit-in-repo.sh new file mode 100755 index 0000000..d68ad4d --- /dev/null +++ b/internal/git/test-fixtures/create-commit-in-repo.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eux -o pipefail + +if [ -d "/path/to/dir" ] +then + echo "fixture already exists!" + exit 0 +else + echo "creating fixture..." +fi + +git init repos/commit-in-repo + +pushd repos/commit-in-repo + +git config --local user.email "nope@nope.com" +git config --local user.name "nope" + +trap 'popd' EXIT + +git commit -m 'something' --allow-empty \ No newline at end of file