New route to run gradation tests
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
nemunaire 2023-01-01 21:11:20 +01:00
parent 7340e10a7a
commit 0cc0ae3c7d
3 changed files with 125 additions and 6 deletions

View File

@ -8,10 +8,13 @@ import (
"log"
"net/http"
"net/url"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/drone/drone-go/drone"
"github.com/gin-gonic/gin"
"golang.org/x/oauth2"
@ -291,6 +294,29 @@ func declareAPIAuthRepositoriesRoutes(router *gin.RouterGroup) {
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 {
@ -465,6 +491,79 @@ func TriggerTagUpdate(c *gin.Context, work *Work, repo *Repository, u *User, tag
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 {
Id int64 `json:"id"`
IdUser int64 `json:"id_user"`
@ -474,7 +573,7 @@ type Repository struct {
LastCheck *time.Time `json:"last_check"`
DroneRef string `json:"drone_ref,omitempty"`
LastTests *time.Time `json:"last_tests"`
TestsRef string `json:"drone_ref,omitempty"`
TestsRef string `json:"tests_ref,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 {
return nil, err
} 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
}
}

View File

@ -115,6 +115,18 @@ export class Work {
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() {

View File

@ -61,8 +61,8 @@
<tbody>
{#each users as user (user.id)}
<tr>
<td><a href="users/{user.login}">{user.login}</a></td>
<td>
<td><a href="users/{user.login}" class="text-truncate">{user.login}</a></td>
<td class="text-center">
<SubmissionStatus work={w} user={user} on:done={() => { nb_rendus += 1; show_dl_btn[user.id] = true; }} />
</td>
<td>
@ -74,7 +74,7 @@
<code class="text-truncate mx-1">
{repo.uri}
</code>
<div class="mx-1">
<div class="mx-1" style="white-space: nowrap">
{#if repo.last_check}
<DateFormat date={new Date(repo.last_check)} dateStyle="medium" timeStyle="medium" />
<BuildState
@ -118,7 +118,7 @@
{/await}
{/if}
</td>
<td>
<td class="d-flex gap-1">
<a
href="/api/users/{user.id}/works/{w.id}/download"
class="btn btn-sm btn-dark"
@ -127,6 +127,14 @@
>
<i class="bi bi-download"></i>
</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>
</tr>
{/each}