grafana-backuper/pkg/git/commit.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)
}