admin: New routes to expose git repositories status
This commit is contained in:
parent
598b34eb4f
commit
b08039c997
45
admin/api/repositories.go
Normal file
45
admin/api/repositories.go
Normal file
@ -0,0 +1,45 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"srs.epita.fr/fic-server/admin/sync"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func declareRepositoriesRoutes(router *gin.RouterGroup) {
|
||||
if gi, ok := sync.GlobalImporter.(sync.GitImporter); ok {
|
||||
router.GET("/repositories", func(c *gin.Context) {
|
||||
mod, err := gi.GetSubmodules()
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"repositories": mod})
|
||||
})
|
||||
|
||||
router.GET("/repositories/*repopath", func(c *gin.Context) {
|
||||
repopath := strings.TrimPrefix(c.Param("repopath"), "/")
|
||||
|
||||
mod, err := gi.GetSubmodule(repopath)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, mod)
|
||||
})
|
||||
|
||||
router.POST("/repositories/*repopath", func(c *gin.Context) {
|
||||
repopath := strings.TrimPrefix(c.Param("repopath"), "/")
|
||||
|
||||
mod, err := gi.IsRepositoryUptodate(repopath)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, mod)
|
||||
})
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ func DeclareRoutes(router *gin.RouterGroup) {
|
||||
declarePasswordRoutes(apiRoutes)
|
||||
declarePublicRoutes(apiRoutes)
|
||||
declareQARoutes(apiRoutes)
|
||||
declareRepositoriesRoutes(apiRoutes)
|
||||
declareTeamsRoutes(apiRoutes)
|
||||
declareThemesRoutes(apiRoutes)
|
||||
declareSettingsRoutes(apiRoutes)
|
||||
|
@ -68,6 +68,9 @@ func declareStaticRoutes(router *gin.RouterGroup, cfg *settings.Settings, baseUR
|
||||
router.GET("/pki/*_", func(c *gin.Context) {
|
||||
serveIndex(c)
|
||||
})
|
||||
router.GET("/repositories", func(c *gin.Context) {
|
||||
serveIndex(c)
|
||||
})
|
||||
router.GET("/settings", func(c *gin.Context) {
|
||||
serveIndex(c)
|
||||
})
|
||||
|
@ -13,6 +13,10 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
|
||||
controller: "ExerciceController",
|
||||
templateUrl: "views/exercice.html"
|
||||
})
|
||||
.when("/repositories", {
|
||||
controller: "RepositoriesController",
|
||||
templateUrl: "views/repositories.html"
|
||||
})
|
||||
.when("/sync", {
|
||||
controller: "SyncController",
|
||||
templateUrl: "views/sync.html"
|
||||
@ -719,6 +723,12 @@ angular.module("FICApp")
|
||||
};
|
||||
})
|
||||
|
||||
.controller("RepositoriesController", function($scope, $http) {
|
||||
$http.get("api/repositories").then(function(response) {
|
||||
$scope.repositories = response.data.repositories;
|
||||
});
|
||||
})
|
||||
|
||||
.controller("SyncController", function($scope, $rootScope, ROSettings, $location, $http, $interval) {
|
||||
$scope.displayDangerousActions = false;
|
||||
$scope.configro = ROSettings.get();
|
||||
|
25
admin/static/views/repositories.html
Normal file
25
admin/static/views/repositories.html
Normal file
@ -0,0 +1,25 @@
|
||||
<div class="card mt-3 mb-5">
|
||||
<div class="card-header bg-secondary text-light">
|
||||
<h3 class="mb-0">
|
||||
Repositories
|
||||
</h3>
|
||||
</div>
|
||||
<table class="table table-hover table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Chemin</th>
|
||||
<th>Branche</th>
|
||||
<th>Commit</th>
|
||||
<th>Plus récent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="repository in repositories">
|
||||
<td>{{ repository.path }}</td>
|
||||
<td>{{ repository.branch }}</td>
|
||||
<td>{{ repository.hash }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
@ -131,3 +132,83 @@ func (i GitImporter) Sync() error {
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (i GitImporter) GetSubmodules() ([]GitSubmoduleStatus, error) {
|
||||
oneGitPull.Lock()
|
||||
defer oneGitPull.Unlock()
|
||||
|
||||
r, err := git.PlainOpen(i.li.Base)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w, err := r.Worktree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modules, err := w.Submodules()
|
||||
|
||||
var ret []GitSubmoduleStatus
|
||||
for _, mod := range modules {
|
||||
st, err := mod.Status()
|
||||
if err == nil {
|
||||
ret = append(ret, GitSubmoduleStatus{
|
||||
Hash: st.Expected.String(),
|
||||
Path: st.Path,
|
||||
Branch: strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(st.Branch.String(), "("), "refs/"), "heads/"), ")"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (i GitImporter) GetSubmodule(repopath string) (*GitSubmoduleStatus, error) {
|
||||
oneGitPull.Lock()
|
||||
defer oneGitPull.Unlock()
|
||||
|
||||
r, err := git.PlainOpen(path.Join(i.li.Base, repopath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
st, err := r.Head()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GitSubmoduleStatus{
|
||||
Hash: st.Hash().String(),
|
||||
Path: repopath,
|
||||
Branch: st.Name().Short(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i GitImporter) IsRepositoryUptodate(repopath string) (*GitSubmoduleStatus, error) {
|
||||
oneGitPull.Lock()
|
||||
defer oneGitPull.Unlock()
|
||||
|
||||
r, err := git.PlainOpen(path.Join(i.li.Base, repopath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Perform a git pull --rebase origin/master
|
||||
err = r.Fetch(&git.FetchOptions{
|
||||
RemoteName: "origin",
|
||||
RefSpecs: []config.RefSpec{config.RefSpec("+refs/heads/" + i.Branch + ":refs/remotes/origin/" + i.Branch)},
|
||||
Auth: i.Auth,
|
||||
})
|
||||
|
||||
st, err := r.Reference(plumbing.ReferenceName("origin/"+i.Branch), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GitSubmoduleStatus{
|
||||
Hash: st.Hash().String(),
|
||||
Path: repopath,
|
||||
Branch: st.Name().Short(),
|
||||
}, nil
|
||||
}
|
||||
|
@ -64,3 +64,10 @@ func getForgeBaseLink(remote string) (u *url.URL, err error) {
|
||||
u.Host = res[1]
|
||||
return
|
||||
}
|
||||
|
||||
type GitSubmoduleStatus struct {
|
||||
Hash string `json:"hash"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Path string `json:"path"`
|
||||
Branch string `json:"branch"`
|
||||
}
|
||||
|
@ -245,3 +245,96 @@ func (i GitImporter) GetExerciceLink(e *fic.Exercice) (u *url.URL, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (i GitImporter) GetSubmodules() ([]GitSubmoduleStatus, error) {
|
||||
oneGitPull.Lock()
|
||||
defer oneGitPull.Unlock()
|
||||
|
||||
cmdsubmodule := exec.Command("git", "-C", i.li.Base, "submodule", "status")
|
||||
stdout, err := cmdsubmodule.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("Git repository submodule failed: %s\n%s", err, stdout)
|
||||
return nil, fmt.Errorf("%w:\n%s", err, stdout)
|
||||
}
|
||||
|
||||
var ret []GitSubmoduleStatus
|
||||
for _, line := range strings.Split(string(stdout), "\n") {
|
||||
flds := strings.Fields(line)
|
||||
if len(flds) == 3 {
|
||||
ret = append(ret, GitSubmoduleStatus{
|
||||
Hash: flds[0],
|
||||
Path: flds[1],
|
||||
Branch: strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(flds[2], "("), "refs/"), "remotes/"), "heads/"), "origin/"), ")"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (i GitImporter) GetSubmodule(repopath string) (*GitSubmoduleStatus, error) {
|
||||
oneGitPull.Lock()
|
||||
defer oneGitPull.Unlock()
|
||||
|
||||
if repopath == "" {
|
||||
cmdsubmodule := exec.Command("git", "-C", i.li.Base, "show", "-q", "--oneline")
|
||||
stdout, err := cmdsubmodule.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("Git repository show failed: %s\n%s", err, stdout)
|
||||
return nil, fmt.Errorf("%w:\n%s", err, stdout)
|
||||
}
|
||||
|
||||
flds := strings.SplitN(string(stdout), " ", 2)
|
||||
return &GitSubmoduleStatus{
|
||||
Hash: flds[0],
|
||||
Text: strings.TrimSpace(flds[1]),
|
||||
Path: "",
|
||||
Branch: i.Branch,
|
||||
}, nil
|
||||
} else {
|
||||
cmdsubmodule := exec.Command("git", "-C", i.li.Base, "submodule", "status", repopath)
|
||||
stdout, err := cmdsubmodule.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("Git repository submodule failed: %s\n%s", err, stdout)
|
||||
return nil, fmt.Errorf("%w:\n%s", err, stdout)
|
||||
}
|
||||
|
||||
flds := strings.Fields(strings.TrimSpace(string(stdout)))
|
||||
if len(flds) == 3 {
|
||||
return &GitSubmoduleStatus{
|
||||
Hash: flds[0],
|
||||
Path: flds[1],
|
||||
Branch: strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(flds[2], "("), "refs/"), "remotes/"), "heads/"), "origin/"), ")"),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unable to parse")
|
||||
}
|
||||
|
||||
func (i GitImporter) IsRepositoryUptodate(repopath string) (*GitSubmoduleStatus, error) {
|
||||
oneGitPull.Lock()
|
||||
defer oneGitPull.Unlock()
|
||||
|
||||
cmdsubmodule := exec.Command("git", "-C", path.Join(i.li.Base, repopath), "fetch", "origin", i.Branch)
|
||||
stdout, err := cmdsubmodule.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("Git repository submodule fetch failed: %s\n%s", err, stdout)
|
||||
return nil, fmt.Errorf("%w:\n%s", err, stdout)
|
||||
}
|
||||
|
||||
cmdsubmodule = exec.Command("git", "-C", path.Join(i.li.Base, repopath), "show", "-q", "--oneline", "origin/"+i.Branch)
|
||||
stdout, err = cmdsubmodule.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("Git repository submodule status failed: %s\n%s", err, stdout)
|
||||
return nil, fmt.Errorf("%w:\n%s", err, stdout)
|
||||
}
|
||||
|
||||
flds := strings.SplitN(string(stdout), " ", 2)
|
||||
return &GitSubmoduleStatus{
|
||||
Hash: flds[0],
|
||||
Text: strings.TrimSpace(flds[1]),
|
||||
Path: repopath,
|
||||
Branch: i.Branch,
|
||||
}, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user