diff --git a/gradation.go b/gradation.go index 4acf203..8e762e9 100644 --- a/gradation.go +++ b/gradation.go @@ -1,11 +1,8 @@ package main import ( - "fmt" "log" "net/http" - "strconv" - "strings" "github.com/drone/drone-go/drone" "github.com/gin-gonic/gin" @@ -33,74 +30,3 @@ func declareAPIAdminGradationRoutes(router *gin.RouterGroup) { c.JSON(http.StatusOK, result) }) } - -type TestsWebhook struct { - Login string `json:"login"` - RepositoryId int `json:"repository_id"` - BuildNumber int `json:"build_number"` - Steps map[string]float64 `json:"steps,omitempty"` -} - -func (r *Repository) fetchRepoTests(build_number int, steps map[string]float64) error { - tmp := strings.Split(r.TestsRef, "/") - if len(tmp) < 3 { - return fmt.Errorf("This repository tests reference is not filled properly.") - } - - work, err := getWork(r.IdWork) - if err != nil { - return fmt.Errorf("Unable to retrieve the related work: %w", err) - } - - client := drone.NewClient(droneEndpoint, droneConfig) - result, err := client.Build(tmp[0], tmp[1], build_number) - if err != nil { - return fmt.Errorf("Unable to find the referenced build (%d): %w", build_number, err) - } - - if result.Finished > 0 { - return fmt.Errorf("The test phase is not finished") - } - - var grade float64 - for _, stage := range result.Stages { - for _, step := range stage.Steps { - if g, ok := steps[fmt.Sprintf("%d", step.Number)]; ok { - log.Printf("Step %q (%d) in status %q", step.Name, step.Number, step.Status) - // Give the point if it succeed - if step.Status == "success" { - grade += g - } - continue - } - - logs, err := client.Logs(tmp[0], tmp[1], build_number, stage.Number, step.Number) - if err != nil { - log.Printf("Unable to retrieve build logs %s/%s/%d/%d/%d: %s", tmp[0], tmp[1], build_number, stage.Number, step.Number, err.Error()) - continue - } - - if len(logs) < 1 { - continue - } - - line := logs[len(logs)-1] - if strings.HasPrefix(line.Message, "grade:") { - g, err := strconv.ParseFloat(strings.TrimSpace(strings.TrimPrefix(line.Message, "grade:")), 64) - if err == nil { - grade += g - } else { - log.Println("Unable to parse grade:", err.Error()) - } - } - } - } - - work.AddGrade(WorkGrade{ - IdUser: r.IdUser, - IdWork: work.Id, - Grade: grade, - }) - - return nil -} diff --git a/repositories.go b/repositories.go index d06d8fa..855397e 100644 --- a/repositories.go +++ b/repositories.go @@ -334,6 +334,12 @@ type GitLabWebhook struct { Repository GitLabRepository } +type TestsWebhook struct { + Login string `json:"login"` + RepositoryId int `json:"repository_id"` + BuildNumber int `json:"build_number"` +} + func declareCallbacksRoutes(router *gin.RouterGroup) { router.POST("/callbacks/trigger.json", func(c *gin.Context) { // Check event type @@ -440,7 +446,7 @@ func declareCallbacksRoutes(router *gin.RouterGroup) { return } - err = repo.fetchRepoTests(hook.BuildNumber, hook.Steps) + err = repo.fetchRepoTests(hook.BuildNumber) if err != nil { log.Printf("Unable to fetchRepoTests(%d): %s", hook.RepositoryId, err.Error()) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to fetch tests results."}) @@ -570,7 +576,7 @@ func TriggerTests(c *gin.Context, work *Work, repo *Repository, u *User) { Key: aws.String(filepath.Join(fmt.Sprintf("%d", work.Id), fmt.Sprintf("rendu-%s.tar.xz", login))), }) - url, err := req.Presign(SharingTime * 20) + 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."}) @@ -603,42 +609,6 @@ func TriggerTests(c *gin.Context, work *Work, repo *Repository, u *User) { c.JSON(http.StatusOK, repo) } -func (w *Work) stopTests() error { - repos, err := w.GetRepositories() - if err != nil { - return err - } - - client := drone.NewClient(droneEndpoint, droneConfig) - for _, repo := range repos { - slug := strings.Split(repo.TestsRef, "/") - if len(slug) < 3 { - continue - } - - buildn, err := strconv.ParseInt(slug[2], 10, 32) - if err != nil { - continue - } - - build, err := client.Build(slug[0], slug[1], int(buildn)) - if err != nil { - log.Println("Unable to communicate with Drone:", err.Error()) - continue - } - - if build.Status == "pending" { - err := client.BuildCancel(slug[0], slug[1], int(buildn)) - if err != nil { - log.Println("Unable to cancel the build:", err.Error()) - continue - } - } - } - - return nil -} - type Repository struct { Id int64 `json:"id"` IdUser int64 `json:"id_user"` @@ -673,27 +643,6 @@ func (u *User) GetRepositories() (repositories []*Repository, err error) { } } -func (w *Work) GetRepositories() (repositories []*Repository, err error) { - if rows, errr := DBQuery("SELECT id_repository, id_user, id_work, uri, secret, last_check, droneref, last_tests, testsref FROM user_work_repositories WHERE id_work=?", w.Id); errr != nil { - return nil, errr - } else { - defer rows.Close() - - for rows.Next() { - var repo Repository - if err = rows.Scan(&repo.Id, &repo.IdUser, &repo.IdWork, &repo.URI, &repo.Secret, &repo.LastCheck, &repo.DroneRef, &repo.LastTests, &repo.TestsRef); err != nil { - return - } - repositories = append(repositories, &repo) - } - if err = rows.Err(); err != nil { - return - } - - return - } -} - func getRepositoriesByURI(uri string) (repositories []*Repository, err error) { if rows, errr := DBQuery("SELECT id_repository, id_user, id_work, uri, secret, last_check, droneref, last_tests, testsref FROM user_work_repositories WHERE uri=?", uri); errr != nil { return nil, errr @@ -740,7 +689,7 @@ func (u *User) NewRepository(w *Work, uri string) (*Repository, error) { return nil, err } - if res, err := DBExec("INSERT INTO user_work_repositories (id_user, id_work, uri, secret, droneref, testsref) VALUES (?, ?, ?, ?, ?, '')", u.Id, w.Id, uri, secret, ""); err != nil { + if res, err := DBExec("INSERT INTO user_work_repositories (id_user, id_work, uri, secret, droneref) VALUES (?, ?, ?, ?, ?)", u.Id, w.Id, uri, secret, ""); err != nil { return nil, err } else if rid, err := res.LastInsertId(); err != nil { return nil, err @@ -767,6 +716,58 @@ func (r Repository) Delete() (int64, error) { } } +func (r *Repository) fetchRepoTests(build_number int) error { + tmp := strings.Split(r.TestsRef, "/") + if len(tmp) < 3 { + return fmt.Errorf("This repository tests reference is not filled properly.") + } + + work, err := getWork(r.IdWork) + if err != nil { + return fmt.Errorf("Unable to retrieve the related work: %w", err) + } + + client := drone.NewClient(droneEndpoint, droneConfig) + result, err := client.Build(tmp[0], tmp[1], build_number) + if err != nil { + return fmt.Errorf("Unable to find the referenced build (%d): %w", build_number, err) + } + + if result.Finished > 0 { + return fmt.Errorf("The test phase is not finished") + } + + var grade float64 + for _, stage := range result.Stages { + for _, step := range stage.Steps { + logs, err := client.Logs(tmp[0], tmp[1], build_number, stage.Number, step.Number) + if err != nil { + log.Printf("Unable to retrieve build logs %s/%s/%d/%d/%d: %s", tmp[0], tmp[1], build_number, stage.Number, step.Number, err.Error()) + continue + } + + for _, line := range logs { + if strings.HasPrefix(line.Message, "grade:") { + g, err := strconv.ParseFloat(strings.TrimSpace(strings.TrimPrefix(line.Message, "grade:")), 64) + if err == nil { + grade += g + } else { + log.Println("Unable to parse grade:", err.Error()) + } + } + } + } + } + + work.AddGrade(WorkGrade{ + IdUser: r.IdUser, + IdWork: work.Id, + Grade: grade, + }) + + return nil +} + func ClearRepositories() (int64, error) { if res, err := DBExec("DELETE FROM user_work_repositories"); err != nil { return 0, err diff --git a/submissions.go b/submissions.go index 8f7aa59..b5f0da1 100644 --- a/submissions.go +++ b/submissions.go @@ -17,7 +17,7 @@ import ( "github.com/gin-gonic/gin" ) -const SharingTime = 10 * time.Minute +const SharingTime = 15 * time.Minute var ( s3_endpoint string diff --git a/ui/src/lib/components/ScoreBadge.svelte b/ui/src/lib/components/ScoreBadge.svelte deleted file mode 100644 index f170afe..0000000 --- a/ui/src/lib/components/ScoreBadge.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -= 18} - class:bg-info={score < 18 && score >= 15} - class:bg-warning={score < 15 && score >= 9} - class:bg-danger={score < 9} - class:bg-dark={score == "N/A"} -> - {score} - diff --git a/ui/src/lib/components/SurveyList.svelte b/ui/src/lib/components/SurveyList.svelte index 5ca0c68..6b97e43 100644 --- a/ui/src/lib/components/SurveyList.svelte +++ b/ui/src/lib/components/SurveyList.svelte @@ -4,7 +4,6 @@ import { user } from '$lib/stores/user'; import DateFormat from '$lib/components/DateFormat.svelte'; import SurveyBadge from '$lib/components/SurveyBadge.svelte'; - import ScoreBadge from '$lib/components/ScoreBadge.svelte'; import SubmissionStatus from '$lib/components/SubmissionStatus.svelte'; import { getCategories } from '$lib/categories'; import { getSurveys } from '$lib/surveys'; @@ -145,7 +144,16 @@ {/if} {:else} - + = 18} + class:bg-info={score.score < 18 && score.score >= 15} + class:bg-warning={score.score < 15 && score.score >= 9} + class:bg-danger={score.score < 9} + class:bg-dark={score.score == "N/A"} + > + {score.score} + {/if} {:catch error} diff --git a/ui/src/lib/components/WorkRepository.svelte b/ui/src/lib/components/WorkRepository.svelte index 79b5069..950d827 100644 --- a/ui/src/lib/components/WorkRepository.svelte +++ b/ui/src/lib/components/WorkRepository.svelte @@ -160,7 +160,7 @@ {:then rrepos} diff --git a/ui/src/lib/works.js b/ui/src/lib/works.js index 1d5976c..9d83b98 100644 --- a/ui/src/lib/works.js +++ b/ui/src/lib/works.js @@ -95,20 +95,6 @@ export class Work { } } - async stopTests() { - if (this.id) { - const res = await fetch(`api/works/${this.id}/tests`, { - method: 'DELETE', - headers: {'Accept': 'application/json'}, - }); - if (res.status == 200) { - return true; - } else { - throw new Error((await res.json()).errmsg); - } - } - } - async getSubmission(uid) { const res = await fetch(uid?`api/users/${uid}/works/${this.id}/submission`:`api/works/${this.id}/submission`, { headers: {'Accept': 'application/json'} diff --git a/ui/src/routes/works/+page.svelte b/ui/src/routes/works/+page.svelte index d248212..722a343 100644 --- a/ui/src/routes/works/+page.svelte +++ b/ui/src/routes/works/+page.svelte @@ -3,7 +3,6 @@ import { user } from '$lib/stores/user'; import DateFormat from '$lib/components/DateFormat.svelte'; - import ScoreBadge from '$lib/components/ScoreBadge.svelte'; import SurveyBadge from '$lib/components/SurveyBadge.svelte'; import SubmissionStatus from '$lib/components/SubmissionStatus.svelte'; import { getCategories } from '$lib/categories'; @@ -121,7 +120,16 @@ {#await getScore(work)}
{:then score} - + = 18} + class:bg-info={score.score < 18 && score.score >= 15} + class:bg-warning={score.score < 15 && score.score >= 9} + class:bg-danger={score.score < 9} + class:bg-dark={score.score == "N/A"} + > + {score.score} + {:catch error} {/await} diff --git a/ui/src/routes/works/[wid]/+page.svelte b/ui/src/routes/works/[wid]/+page.svelte index d79e6bb..af8dbbc 100644 --- a/ui/src/routes/works/[wid]/+page.svelte +++ b/ui/src/routes/works/[wid]/+page.svelte @@ -3,7 +3,6 @@ import { user } from '$lib/stores/user'; import DateFormat from '$lib/components/DateFormat.svelte'; - import ScoreBadge from '$lib/components/ScoreBadge.svelte'; import SubmissionStatus from '$lib/components/SubmissionStatus.svelte'; import SurveyBadge from '$lib/components/SurveyBadge.svelte'; import WorkAdmin from '$lib/components/WorkAdmin.svelte'; @@ -61,15 +60,7 @@ {/if}
-
-

Notes

- -
+

Notes

{#await gradesP}
@@ -100,7 +91,7 @@ {grade.login} - + {grade.score} {#if grade.comment}{grade.comment}{:else}-{/if} {grade.date} diff --git a/ui/src/routes/works/[wid]/rendus/+page.svelte b/ui/src/routes/works/[wid]/rendus/+page.svelte index a7d0574..23c7597 100644 --- a/ui/src/routes/works/[wid]/rendus/+page.svelte +++ b/ui/src/routes/works/[wid]/rendus/+page.svelte @@ -32,21 +32,16 @@ repositoriesP[userid] = getRepositories(wid, userid); } - let gradation_preflight = false; async function runGradations() { - gradation_preflight = true; for (const user of await usersP) { if (repositoriesP[user.id]) { try { for (const repo of await repositoriesP[user.id]) { repo.runGradation(); } - } catch (err) { - ToastsStore.addToast({color: "danger", title: "Impossible de lancer la notation de " + user.login, msg: err}) - } + } catch {} } } - gradation_preflight = false; } let nb_rendus = 0; @@ -71,20 +66,8 @@ class="btn btn-sm btn-success mr-1" title="Relancer les tests" on:click={runGradations} - disabled={gradation_preflight} > - {#if gradation_preflight} -
- {:else} - - {/if} - -
diff --git a/works.go b/works.go index 1ce2e81..e3c4940 100644 --- a/works.go +++ b/works.go @@ -153,18 +153,6 @@ func declareAPIAdminWorksRoutes(router *gin.RouterGroup) { c.JSON(http.StatusOK, nil) }) - worksRoutes.DELETE("/tests", func(c *gin.Context) { - w := c.MustGet("work").(*Work) - - err := w.stopTests() - if err != nil { - log.Println("Unable to stop tests:", err) - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during test stop."}) - return - } - - c.JSON(http.StatusOK, true) - }) // Grades related to works worksRoutes.GET("/grades", func(c *gin.Context) {