New route to run gradation tests
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
7340e10a7a
commit
0cc0ae3c7d
103
repositories.go
103
repositories.go
@ -8,10 +8,13 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
"github.com/drone/drone-go/drone"
|
"github.com/drone/drone-go/drone"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
@ -291,6 +294,29 @@ func declareAPIAuthRepositoriesRoutes(router *gin.RouterGroup) {
|
|||||||
c.JSON(http.StatusOK, result)
|
c.JSON(http.StatusOK, result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
repositoriesRoutes.POST("/gradation", func(c *gin.Context) {
|
||||||
|
loggeduser := c.MustGet("LoggedUser").(*User)
|
||||||
|
if !loggeduser.IsAdmin {
|
||||||
|
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Permission denied."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var u *User
|
||||||
|
if user, ok := c.Get("user"); ok {
|
||||||
|
u = user.(*User)
|
||||||
|
} else {
|
||||||
|
u = loggeduser
|
||||||
|
}
|
||||||
|
repo := c.MustGet("repository").(*Repository)
|
||||||
|
work, err := getWork(int(repo.IdWork))
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to find related work."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerTests(c, work, repo, u)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitLabWebhook struct {
|
type GitLabWebhook struct {
|
||||||
@ -465,6 +491,79 @@ func TriggerTagUpdate(c *gin.Context, work *Work, repo *Repository, u *User, tag
|
|||||||
c.JSON(http.StatusOK, repo)
|
c.JSON(http.StatusOK, repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TriggerTests(c *gin.Context, work *Work, repo *Repository, u *User) {
|
||||||
|
if work.GradationRepo == nil || len(*work.GradationRepo) == 0 {
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "No tests defined for this work."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
slug := strings.SplitN(*work.GradationRepo, "/", 2)
|
||||||
|
if len(slug) != 2 {
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Graduation repository is invalid."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
login := u.Login
|
||||||
|
groups := u.Groups
|
||||||
|
if u.Id != repo.IdUser {
|
||||||
|
user, _ := getUser(int(repo.IdUser))
|
||||||
|
if user != nil {
|
||||||
|
login = user.Login
|
||||||
|
groups = user.Groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
branch := "master"
|
||||||
|
if len(work.Tag) > 0 {
|
||||||
|
branch = work.Tag
|
||||||
|
}
|
||||||
|
if branch[len(branch)-1] == '-' {
|
||||||
|
branch += "grades"
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := s3NewSession()
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Something goes wrong."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, _ := s3.New(s).GetObjectRequest(&s3.GetObjectInput{
|
||||||
|
Bucket: aws.String(s3_bucket),
|
||||||
|
Key: aws.String(filepath.Join(fmt.Sprintf("%d", work.Id), fmt.Sprintf("rendu-%s.tar.xz", u.Login))),
|
||||||
|
})
|
||||||
|
|
||||||
|
url, err := req.Presign(SharingTime)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to create presign URL:", err)
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Something goes wrong when creating the presigned URL."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
env := map[string]string{
|
||||||
|
"SUBMISSION_URL": repo.URI,
|
||||||
|
"META_URL": url,
|
||||||
|
"LOGIN": login,
|
||||||
|
"GROUPS": groups,
|
||||||
|
"DEST": fmt.Sprintf("%d", work.Id),
|
||||||
|
}
|
||||||
|
|
||||||
|
client := drone.NewClient(droneEndpoint, droneConfig)
|
||||||
|
result, err := client.BuildCreate(slug[0], slug[1], "", branch, env)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Unable to communicate with Drone:", err.Error())
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to communication with the extraction service."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
repo.TestsRef = fmt.Sprintf("%s/%d", *work.GradationRepo, result.Number)
|
||||||
|
repo.LastTests = &now
|
||||||
|
repo.Update()
|
||||||
|
|
||||||
|
repo.Secret = []byte{}
|
||||||
|
c.JSON(http.StatusOK, repo)
|
||||||
|
}
|
||||||
|
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
IdUser int64 `json:"id_user"`
|
IdUser int64 `json:"id_user"`
|
||||||
@ -474,7 +573,7 @@ type Repository struct {
|
|||||||
LastCheck *time.Time `json:"last_check"`
|
LastCheck *time.Time `json:"last_check"`
|
||||||
DroneRef string `json:"drone_ref,omitempty"`
|
DroneRef string `json:"drone_ref,omitempty"`
|
||||||
LastTests *time.Time `json:"last_tests"`
|
LastTests *time.Time `json:"last_tests"`
|
||||||
TestsRef string `json:"drone_ref,omitempty"`
|
TestsRef string `json:"tests_ref,omitempty"`
|
||||||
AlreadyUsed bool `json:"already_used,omitempty"`
|
AlreadyUsed bool `json:"already_used,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,7 +643,7 @@ func (u *User) NewRepository(w *Work, uri string) (*Repository, error) {
|
|||||||
} else if rid, err := res.LastInsertId(); err != nil {
|
} else if rid, err := res.LastInsertId(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
return &Repository{rid, u.Id, w.Id, uri, secret, nil, "", false}, nil
|
return &Repository{rid, u.Id, w.Id, uri, secret, nil, "", nil, "", false}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,18 @@ export class Work {
|
|||||||
throw new Error((await res.json()).errmsg);
|
throw new Error((await res.json()).errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async runGradation(uid) {
|
||||||
|
const res = await fetch(uid?`api/users/${uid}/works/${this.id}/gradation`:`api/works/${this.id}/gradation`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Accept': 'application/json'},
|
||||||
|
});
|
||||||
|
if (res.status == 200) {
|
||||||
|
return await res.json();
|
||||||
|
} else {
|
||||||
|
throw new Error((await res.json()).errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorks() {
|
export async function getWorks() {
|
||||||
|
@ -61,8 +61,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{#each users as user (user.id)}
|
{#each users as user (user.id)}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="users/{user.login}">{user.login}</a></td>
|
<td><a href="users/{user.login}" class="text-truncate">{user.login}</a></td>
|
||||||
<td>
|
<td class="text-center">
|
||||||
<SubmissionStatus work={w} user={user} on:done={() => { nb_rendus += 1; show_dl_btn[user.id] = true; }} />
|
<SubmissionStatus work={w} user={user} on:done={() => { nb_rendus += 1; show_dl_btn[user.id] = true; }} />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<code class="text-truncate mx-1">
|
<code class="text-truncate mx-1">
|
||||||
{repo.uri}
|
{repo.uri}
|
||||||
</code>
|
</code>
|
||||||
<div class="mx-1">
|
<div class="mx-1" style="white-space: nowrap">
|
||||||
{#if repo.last_check}
|
{#if repo.last_check}
|
||||||
<DateFormat date={new Date(repo.last_check)} dateStyle="medium" timeStyle="medium" />
|
<DateFormat date={new Date(repo.last_check)} dateStyle="medium" timeStyle="medium" />
|
||||||
<BuildState
|
<BuildState
|
||||||
@ -118,7 +118,7 @@
|
|||||||
{/await}
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="d-flex gap-1">
|
||||||
<a
|
<a
|
||||||
href="/api/users/{user.id}/works/{w.id}/download"
|
href="/api/users/{user.id}/works/{w.id}/download"
|
||||||
class="btn btn-sm btn-dark"
|
class="btn btn-sm btn-dark"
|
||||||
@ -127,6 +127,14 @@
|
|||||||
>
|
>
|
||||||
<i class="bi bi-download"></i>
|
<i class="bi bi-download"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-success mr-1"
|
||||||
|
class:disabled={!show_dl_btn[user.id]}
|
||||||
|
title="Relancer les tests"
|
||||||
|
on:click={() => { w.runGradation(user.id); }}
|
||||||
|
>
|
||||||
|
<i class="bi bi-play"></i>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
|
Reference in New Issue
Block a user