--- type: change message: |- Refactor commit type and logic to account for future commit types This commit introduces a CommitInterface which CommitChange (previously ChangeCommit) now implements. Additionally, now all commit messages will include a type field and a "---" separator. The code is written to still accept all the old commit messages used in this repo. Other than those changes, most of this is just rearranging existing code. change_hash: AHjWAUxCjXgOL0Sb+oQZc6TmuVgVHJn08zpGreYyChwx credentials: - type: pgp_signature pub_key_id: 95C46FA6A41148AC body: iQIzBAABAgAdFiEEJ6tQKp6olvZKJ0lwlcRvpqQRSKwFAl5gOuoACgkQlcRvpqQRSKxapA//bODd2IwX2D7nFBkEEd00ol1l4vaw7pgwCjqyQtyskeCZ5IH6H6PkYOSmU9DIBde+cGo35Oi5ynChmfnSatvUZ1dLRJqm8FfOGDw/IsccyYDd1iptj16Ckr6Bsht1XgFJNN10hufuAg77fRIwbGi003WCQdnrJZ1Xbtgex6a4rUqVFW+sjXAB1msmo5B5nabfm/ta0epptxhlINIY2qP5Vb+ftdb2lRUNQwkIEr5GErfAgN3sxYEfqQvLzr/007tEeVznyhdgww47awWsBaTEd6njycbWpphnNA8PbcgUGKDYsj3qLz/bCR1VQOdWgod8PLEru2O+uC2+72ssfT9NDn8HB/WrBKG4W4oykJIhXJ5um18/B9ZSxPMlTQv2Yr4nF7w+Sx3UynEdUTducbIOUq2K+JnI+Ln3gHe0yRw5UEfrzymR4f2Nfe1I13rJk2W7SVRDmOYidr0MwBlLs8tmnJFMWmWZtd1hpPOpyOyUF1jKgvMuR9ferb5niuc3Lk4trqDiaF+tjy/NmAv/7c+qiVmKKpVJVVqvT60TqBR9DTHjRGktcPFD50sc811Th+Xd9RdhzpIYM+0DT790FTf8E0hY6wm/NKTGplfqwBSNZk87SeIiFTu7sZWVpAaPz1vTmVGduC1oj3/Zlv6TzNrUAp3VwBepROBhZlHCHUr9tKg= account: mediocregophermain
parent
9bfd012221
commit
cf05b3a072
@ -0,0 +1,64 @@ |
|||||||
|
package dehub |
||||||
|
|
||||||
|
import ( |
||||||
|
"dehub/fs" |
||||||
|
"dehub/yamlutil" |
||||||
|
"errors" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"gopkg.in/src-d/go-git.v4/plumbing" |
||||||
|
"gopkg.in/src-d/go-git.v4/plumbing/object" |
||||||
|
) |
||||||
|
|
||||||
|
// CommitChange describes the structure of a change commit message.
|
||||||
|
type CommitChange struct { |
||||||
|
Message string `yaml:"message"` |
||||||
|
ChangeHash yamlutil.Blob `yaml:"change_hash"` |
||||||
|
} |
||||||
|
|
||||||
|
var _ CommitInterface = CommitChange{} |
||||||
|
|
||||||
|
// NewCommitChange constructs a Commit populated with a CommitChange
|
||||||
|
// encompassing the currently staged file changes. The Credentials of the
|
||||||
|
// returned Commit will _not_ be filled in.
|
||||||
|
func (r *Repo) NewCommitChange(msg string) (Commit, error) { |
||||||
|
_, headTree, err := r.head() |
||||||
|
if errors.Is(err, plumbing.ErrReferenceNotFound) { |
||||||
|
headTree = &object.Tree{} |
||||||
|
} else if err != nil { |
||||||
|
return Commit{}, err |
||||||
|
} |
||||||
|
|
||||||
|
_, stagedTree, err := fs.FromStagedChangesTree(r.GitRepo) |
||||||
|
if err != nil { |
||||||
|
return Commit{}, err |
||||||
|
} |
||||||
|
|
||||||
|
cc := CommitChange{Message: msg} |
||||||
|
if cc.ChangeHash, err = cc.Hash(headTree, stagedTree); err != nil { |
||||||
|
return Commit{}, err |
||||||
|
} |
||||||
|
|
||||||
|
return Commit{ |
||||||
|
Change: &cc, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// MessageHead implements the method for the CommitInterface interface.
|
||||||
|
func (cc CommitChange) MessageHead() (string, error) { |
||||||
|
i := strings.Index(cc.Message, "\n") |
||||||
|
if i > 0 { |
||||||
|
return cc.Message[:i], nil |
||||||
|
} |
||||||
|
return cc.Message, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Hash implements the method for the CommitInterface interface.
|
||||||
|
func (cc CommitChange) Hash(parent, this *object.Tree) ([]byte, error) { |
||||||
|
return genChangeHash(nil, cc.Message, parent, this), nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetHash implements the method for the CommitInterface interface.
|
||||||
|
func (cc CommitChange) GetHash() []byte { |
||||||
|
return cc.ChangeHash |
||||||
|
} |
@ -0,0 +1,105 @@ |
|||||||
|
package dehub |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"strings" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew" |
||||||
|
) |
||||||
|
|
||||||
|
func TestChangeCommitVerify(t *testing.T) { |
||||||
|
type step struct { |
||||||
|
msg string |
||||||
|
msgHead string // defaults to msg
|
||||||
|
tree map[string]string |
||||||
|
} |
||||||
|
testCases := []struct { |
||||||
|
descr string |
||||||
|
steps []step |
||||||
|
}{ |
||||||
|
{ |
||||||
|
descr: "single commit", |
||||||
|
steps: []step{ |
||||||
|
{ |
||||||
|
msg: "first commit", |
||||||
|
tree: map[string]string{"a": "0", "b": "1"}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
descr: "multiple commits", |
||||||
|
steps: []step{ |
||||||
|
{ |
||||||
|
msg: "first commit", |
||||||
|
tree: map[string]string{"a": "0", "b": "1"}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
msg: "second commit, changing a", |
||||||
|
tree: map[string]string{"a": "1"}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
msg: "third commit, empty", |
||||||
|
}, |
||||||
|
{ |
||||||
|
msg: "fourth commit, adding c, removing b", |
||||||
|
tree: map[string]string{"b": "", "c": "2"}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
descr: "big body commits", |
||||||
|
steps: []step{ |
||||||
|
{ |
||||||
|
msg: "first commit, single line but with newline\n", |
||||||
|
}, |
||||||
|
{ |
||||||
|
msg: "second commit, single line but with two newlines\n\n", |
||||||
|
msgHead: "second commit, single line but with two newlines\n\n", |
||||||
|
}, |
||||||
|
{ |
||||||
|
msg: "third commit, multi-line with one newline\nanother line!", |
||||||
|
msgHead: "third commit, multi-line with one newline\n\n", |
||||||
|
}, |
||||||
|
{ |
||||||
|
msg: "fourth commit, multi-line with two newlines\n\nanother line!", |
||||||
|
msgHead: "fourth commit, multi-line with two newlines\n\n", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
for _, test := range testCases { |
||||||
|
t.Run(test.descr, func(t *testing.T) { |
||||||
|
h := newHarness(t) |
||||||
|
for _, step := range test.steps { |
||||||
|
h.stage(step.tree) |
||||||
|
account := h.cfg.Accounts[0] |
||||||
|
|
||||||
|
commit, hash := h.changeCommit(step.msg, account.ID, h.sig) |
||||||
|
if err := h.repo.VerifyCommit(MainRefName, hash); err != nil { |
||||||
|
t.Fatalf("could not verify hash %v: %v", hash, err) |
||||||
|
} |
||||||
|
|
||||||
|
commitObj, err := h.repo.GitRepo.CommitObject(hash) |
||||||
|
if err != nil { |
||||||
|
t.Fatalf("failed to retrieve commit %v: %v", hash, err) |
||||||
|
} else if step.msgHead == "" { |
||||||
|
step.msgHead = strings.TrimSpace(step.msg) + "\n\n" |
||||||
|
} |
||||||
|
|
||||||
|
if !strings.HasPrefix(commitObj.Message, step.msgHead) { |
||||||
|
t.Fatalf("commit message %q does not start with expected head %q", commitObj.Message, step.msgHead) |
||||||
|
} |
||||||
|
|
||||||
|
var actualCommit Commit |
||||||
|
if err := actualCommit.UnmarshalText([]byte(commitObj.Message)); err != nil { |
||||||
|
t.Fatalf("error unmarshaling commit body: %v", err) |
||||||
|
} else if !reflect.DeepEqual(actualCommit, commit) { |
||||||
|
t.Fatalf("returned change commit:\n%s\ndoes not match actual one:\n%s", |
||||||
|
spew.Sdump(commit), spew.Sdump(actualCommit)) |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue