154 lines
2.7 KiB
Go
154 lines
2.7 KiB
Go
package git
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
|
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
|
"github.com/go-git/go-billy/v5"
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/config"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
"github.com/go-git/go-git/v5/plumbing/object"
|
|
)
|
|
|
|
type CommitOption func(*Commit)
|
|
|
|
func WithAuthor(name, email string) CommitOption {
|
|
return func(c *Commit) {
|
|
c.Author = &object.Signature{
|
|
Name: name,
|
|
Email: email,
|
|
When: time.Now(),
|
|
}
|
|
}
|
|
}
|
|
|
|
func WithCommitter(name, email string) CommitOption {
|
|
return func(c *Commit) {
|
|
c.Committer = &object.Signature{
|
|
Name: name,
|
|
Email: email,
|
|
When: time.Now(),
|
|
}
|
|
}
|
|
}
|
|
|
|
func WithFileContent(content []byte, file billy.File) CommitOption {
|
|
return func(c *Commit) {
|
|
c.Content = content
|
|
c.File = file
|
|
}
|
|
}
|
|
|
|
type Commit struct {
|
|
Author *object.Signature
|
|
Committer *object.Signature
|
|
Content []byte
|
|
File billy.File
|
|
|
|
project *Project
|
|
}
|
|
|
|
func (p *Project) NewCommit(options ...CommitOption) *Commit {
|
|
commit := &Commit{project: p}
|
|
|
|
for _, option := range options {
|
|
option(commit)
|
|
}
|
|
|
|
return commit
|
|
}
|
|
|
|
func (c *Commit) Create(msg string) error {
|
|
var (
|
|
signer *openpgp.Entity
|
|
)
|
|
|
|
if c.project.KeyFile != "" {
|
|
file, err := os.Open(c.project.KeyFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
block, err := armor.Decode(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
entityList, err := openpgp.ReadKeyRing(block.Body)
|
|
if err != nil || len(entityList) < 1 {
|
|
return err
|
|
}
|
|
|
|
signer = entityList[0]
|
|
}
|
|
|
|
worktree, err := c.project.repository.Worktree()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = c.project.repository.Branch(c.project.Branch)
|
|
if errors.Is(err, git.ErrBranchNotFound) {
|
|
err = c.project.repository.CreateBranch(
|
|
&config.Branch{Name: c.project.Branch, Remote: c.project.Branch},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = worktree.Checkout(&git.CheckoutOptions{
|
|
Branch: plumbing.ReferenceName(c.project.Branch),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err = c.File.Write(c.Content); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = c.File.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err = worktree.Add(c.File.Name()); err != nil {
|
|
return err
|
|
}
|
|
|
|
commitOpts := git.CommitOptions{Author: c.Author}
|
|
|
|
if c.Committer != nil {
|
|
commitOpts.Committer = c.Committer
|
|
}
|
|
|
|
if signer != nil {
|
|
commitOpts.SignKey = signer
|
|
}
|
|
|
|
_, err = worktree.Commit(msg, &commitOpts)
|
|
return err
|
|
}
|
|
|
|
func (c *Commit) Push() error {
|
|
origin, err := c.project.repository.Remote("origin")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pushOpts := git.PushOptions{}
|
|
|
|
if c.project.auth != nil {
|
|
pushOpts.Auth = c.project.auth
|
|
}
|
|
|
|
return origin.Push(&pushOpts)
|
|
}
|