update-api/api/v1/handlers.go

87 lines
1.8 KiB
Go

package v1
import (
"net/http"
"strings"
"sync"
"errors"
"git.dog/xx/update-api/model"
"github.com/gin-gonic/gin"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object"
)
var (
repos = sync.Map{}
errStop = errors.New("stopped iteration")
)
func SetRepo(repo *model.Repo) error {
repos.Store(repo.Name, repo.Plumbing)
return nil
}
func RegisterHandlers(router *gin.RouterGroup) {
router.GET("/changes/:project/head/:commit", getChanges)
}
func getChanges(c *gin.Context) {
comm := c.Param("commit")
project := c.Param("project")
repoi, ok := repos.Load(project)
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "no such project"})
return
}
repo := repoi.(*git.Repository)
head, err := repo.Head()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
cIter, err := repo.Log(&git.LogOptions{From: head.Hash()})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// should probably move this logic outside of this function
// it should be called only when the repo is initialized or updated
// after that, this func should operate on a "cache"
var commits []model.Commit
err = cIter.ForEach(func(iterCommit *object.Commit) error {
commitHash := iterCommit.Hash.String()
// todo: minimum length for short hashes
if strings.HasPrefix(commitHash, comm) {
return errStop
}
// this can get very expensive if the repo is large
commits = append(commits, model.Commit{
ID: commitHash,
Description: iterCommit.Message,
})
return nil
})
if err != nil && err != errStop {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, model.Changelog{
Latest: head.Hash().String(),
Changes: &commits,
})
}