241 lines
4.8 KiB
Go
241 lines
4.8 KiB
Go
|
package git
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"git.ar21.de/yolokube/grafana-backuper/pkg/grafana"
|
||
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||
|
"github.com/go-git/go-billy/v5"
|
||
|
"github.com/go-git/go-billy/v5/memfs"
|
||
|
"github.com/go-git/go-git/v5"
|
||
|
"github.com/go-git/go-git/v5/plumbing"
|
||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||
|
"github.com/go-git/go-git/v5/storage/memory"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
fs billy.Filesystem
|
||
|
storer *memory.Storage
|
||
|
)
|
||
|
|
||
|
type Payload struct {
|
||
|
Author *object.Signature
|
||
|
Committer *object.Signature
|
||
|
Content []byte
|
||
|
Dashboard grafana.FoundBoard
|
||
|
DashboardInfo grafana.BoardProperties
|
||
|
Directory string
|
||
|
KeyFile string
|
||
|
Repository *git.Repository
|
||
|
Version grafana.DashboardVersion
|
||
|
}
|
||
|
|
||
|
func NewPayload(keyFile string) *Payload {
|
||
|
fs = memfs.New()
|
||
|
storer = memory.NewStorage()
|
||
|
|
||
|
return &Payload{
|
||
|
Author: nil,
|
||
|
Committer: nil,
|
||
|
Content: []byte{},
|
||
|
Dashboard: grafana.FoundBoard{},
|
||
|
DashboardInfo: grafana.BoardProperties{},
|
||
|
Directory: "",
|
||
|
KeyFile: keyFile,
|
||
|
Repository: nil,
|
||
|
Version: grafana.DashboardVersion{},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (p *Payload) AddAuthor(name, email string) {
|
||
|
p.Author = &object.Signature{
|
||
|
Name: name,
|
||
|
Email: email,
|
||
|
When: time.Now(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (p *Payload) UpdateAuthor(timestamp time.Time) {
|
||
|
p.Author.When = timestamp
|
||
|
}
|
||
|
|
||
|
func (p *Payload) AddCommitter(name, email string) {
|
||
|
p.Committer = &object.Signature{
|
||
|
Name: name,
|
||
|
Email: email,
|
||
|
When: time.Now(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (p *Payload) UpdateCommitter() {
|
||
|
p.Committer.When = time.Now()
|
||
|
}
|
||
|
|
||
|
func (p *Payload) UpdateContent(content []byte) {
|
||
|
p.Content = content
|
||
|
}
|
||
|
|
||
|
func (p *Payload) UpdateDashboard(dashboard grafana.FoundBoard) {
|
||
|
p.Dashboard = dashboard
|
||
|
}
|
||
|
|
||
|
func (p *Payload) UpdateDashboardInfo(dashboardInfo grafana.BoardProperties) {
|
||
|
p.DashboardInfo = dashboardInfo
|
||
|
}
|
||
|
|
||
|
func (p *Payload) UpdateVersion(version grafana.DashboardVersion) {
|
||
|
p.Version = version
|
||
|
}
|
||
|
|
||
|
func (p *Payload) GetRepo(repoURL, user, password string) (err error) {
|
||
|
p.Repository, err = git.Clone(
|
||
|
storer,
|
||
|
fs,
|
||
|
&git.CloneOptions{
|
||
|
Auth: genAuth(user, password),
|
||
|
URL: repoURL,
|
||
|
Progress: os.Stdout,
|
||
|
},
|
||
|
)
|
||
|
|
||
|
p.Directory = filepath.Base(repoURL)
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (p *Payload) IsVersionCommitted(branch string) bool {
|
||
|
refName := plumbing.NewBranchReferenceName(branch)
|
||
|
ref, err := p.Repository.Reference(refName, false)
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
commitIter, err := p.Repository.Log(&git.LogOptions{From: ref.Hash()})
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
err = commitIter.ForEach(func(commit *object.Commit) error {
|
||
|
if strings.Contains(commit.Message, fmt.Sprintf("Update %s", p.Version.DashboardUID)) && strings.Contains(commit.Message, fmt.Sprintf("version %d", p.Version.ID)) {
|
||
|
return fmt.Errorf("version already committed")
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
|
||
|
return err != nil
|
||
|
}
|
||
|
|
||
|
func genAuth(user, password string) *http.BasicAuth {
|
||
|
return &http.BasicAuth{
|
||
|
Username: user,
|
||
|
Password: password,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func commitDashboard(repo *git.Repository, content []byte, commitMsg, dashboardTitle, folderTitle, gitRepoDirectory, keyFile string, author, committer *object.Signature) (err error) {
|
||
|
var (
|
||
|
file billy.File
|
||
|
signer *openpgp.Entity
|
||
|
worktree *git.Worktree
|
||
|
)
|
||
|
|
||
|
if strings.TrimSpace(keyFile) != "" {
|
||
|
signer, err = getSigner(keyFile)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
worktree, err = repo.Worktree()
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if err = fs.MkdirAll(folderTitle, 0755); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
filePath := filepath.Join(folderTitle, fmt.Sprintf("%s.json", dashboardTitle))
|
||
|
if file, err = fs.Create(filePath); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if _, err = file.Write(content); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if err = file.Close(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if _, err = worktree.Add(filePath); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
_, err = worktree.Commit(
|
||
|
commitMsg,
|
||
|
&git.CommitOptions{
|
||
|
Author: author,
|
||
|
Committer: committer,
|
||
|
SignKey: signer,
|
||
|
},
|
||
|
)
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (p *Payload) CreateCommit() error {
|
||
|
var commitmsg string
|
||
|
|
||
|
if p.Version.Message != "" {
|
||
|
commitmsg = fmt.Sprintf(
|
||
|
"%s: Update %s to version %d => %s",
|
||
|
p.Dashboard.Title,
|
||
|
p.Version.DashboardUID,
|
||
|
p.Version.ID,
|
||
|
p.Version.Message,
|
||
|
)
|
||
|
} else {
|
||
|
commitmsg = fmt.Sprintf(
|
||
|
"%s: Update %s to version %d",
|
||
|
p.Dashboard.Title,
|
||
|
p.Version.DashboardUID,
|
||
|
p.Version.ID,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
p.UpdateAuthor(p.Version.Created)
|
||
|
p.UpdateCommitter()
|
||
|
|
||
|
return commitDashboard(
|
||
|
p.Repository,
|
||
|
p.Content,
|
||
|
commitmsg,
|
||
|
p.Dashboard.Title,
|
||
|
p.DashboardInfo.FolderTitle,
|
||
|
p.Directory,
|
||
|
p.KeyFile,
|
||
|
p.Author,
|
||
|
p.Committer,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func (p *Payload) PushToRemote(user, password string) error {
|
||
|
origin, err := p.Repository.Remote("origin")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return origin.Push(
|
||
|
&git.PushOptions{
|
||
|
Auth: genAuth(user, password),
|
||
|
Progress: os.Stdout,
|
||
|
},
|
||
|
)
|
||
|
}
|