Skip to content

Commit bf7379f

Browse files
committed
Public variant of validator function
New function differs in cloning procedure and directory locations: - Doesn't take specific commit to validate: Only validates HEAD - Results are stored in a unique directory (UUID) - Results directory is returned to the calling function and the user is redirected to the results page
1 parent 47af56b commit bf7379f

File tree

3 files changed

+121
-4
lines changed

3 files changed

+121
-4
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
88
github.com/gogits/go-gogs-client v0.0.0-20190710002546-4c3c18947c15
99
github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15
10+
github.com/google/uuid v1.1.1
1011
github.com/gorilla/handlers v1.4.2
1112
github.com/gorilla/mux v1.7.3
1213
github.com/magiconair/properties v1.8.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
4747
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
4848
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
4949
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
50+
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
51+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5052
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
5153
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
5254
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=

internal/web/validate.go

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/G-Node/gin-valid/internal/resources/templates"
2525
gogs "github.com/gogits/go-gogs-client"
2626

27+
"github.com/google/uuid"
2728
"github.com/gorilla/mux"
2829
)
2930

@@ -460,6 +461,121 @@ func runValidator(validator, repopath, commit string, gcl *ginclient.Client) {
460461
}()
461462
}
462463

464+
func runValidatorPub(validator, repopath string, gcl *ginclient.Client) string {
465+
uuid := uuid.New()
466+
respath := filepath.Join(validator, repopath, uuid.String())
467+
go func() {
468+
log.ShowWrite("[Info] Running %s validation on repository %q (HEAD)", validator, repopath)
469+
470+
// TODO add check if a repo is currently being validated. Since the cloning
471+
// can potentially take quite some time prohibit running the same
472+
// validation at the same time. Could also move this to a mapped go
473+
// routine and if the same repo is validated twice, the first occurrence is
474+
// stopped and cleaned up while the second starts anew - to make sure its
475+
// always the latest state of the repository that is being validated.
476+
477+
srvcfg := config.Read()
478+
resdir := filepath.Join(srvcfg.Dir.Result, respath)
479+
480+
// Create results folder if necessary
481+
// CHECK: can this lead to a race condition, if a job for the same user/repo combination is started twice in short succession?
482+
err := os.MkdirAll(resdir, os.ModePerm)
483+
if err != nil {
484+
log.ShowWrite("[Error] creating %q results folder: %s", resdir, err.Error())
485+
return
486+
}
487+
488+
tmpdir, err := ioutil.TempDir(srvcfg.Dir.Temp, validator)
489+
if err != nil {
490+
log.ShowWrite("[Error] Internal error: Couldn't create temporary gin directory: %s", err.Error())
491+
writeValFailure(resdir)
492+
return
493+
}
494+
495+
repopathparts := strings.SplitN(repopath, "/", 2)
496+
_, repo := repopathparts[0], repopathparts[1]
497+
valroot := filepath.Join(tmpdir, repo)
498+
499+
// Enable cleanup once tried and tested
500+
defer os.RemoveAll(tmpdir)
501+
502+
// Add the processing badge and message to display while the validator runs
503+
procBadge := filepath.Join(resdir, srvcfg.Label.ResultsBadge)
504+
err = ioutil.WriteFile(procBadge, []byte(resources.ProcessingBadge), os.ModePerm)
505+
if err != nil {
506+
log.ShowWrite("[Error] writing results badge for %q", valroot)
507+
}
508+
509+
outFile := filepath.Join(resdir, srvcfg.Label.ResultsFile)
510+
err = ioutil.WriteFile(outFile, []byte(progressmsg), os.ModePerm)
511+
if err != nil {
512+
log.ShowWrite("[Error] writing results file for %q", valroot)
513+
}
514+
515+
// err = makeSessionKey(gcl, commit)
516+
// if err != nil {
517+
// log.ShowWrite("[error] failed to create session key: %s", err.Error())
518+
// writeValFailure(resdir)
519+
// return
520+
// }
521+
// defer deleteSessionKey(gcl, commit)
522+
523+
// TODO: if (annexed) content is not available yet, wait and retry. We
524+
// would have to set a max timeout for this. The issue is that when a user
525+
// does a 'gin upload' a push happens immediately and the hook is
526+
// triggered, but annexed content is only transferred after the push and
527+
// could take a while (hours?). The validation service should try to
528+
// download content after the transfer is complete, or should keep retrying
529+
// until it's available, with a timeout. We could also make it more
530+
// efficient by only downloading the content in the directories which are
531+
// specified in the validator config (if it exists).
532+
533+
glog.Init()
534+
clonechan := make(chan git.RepoFileStatus)
535+
os.Chdir(tmpdir)
536+
go gcl.CloneRepo(repopath, clonechan)
537+
for stat := range clonechan {
538+
if stat.Err != nil {
539+
log.ShowWrite("[Error] Failed to fetch repository data for %q: %s", repopath, stat.Err.Error())
540+
writeValFailure(resdir)
541+
return
542+
}
543+
log.ShowWrite("[Info] %s %s", stat.State, stat.Progress)
544+
}
545+
log.ShowWrite("[Info] clone complete for '%s'", repopath)
546+
547+
log.ShowWrite("[Info] Downloading content")
548+
getcontentchan := make(chan git.RepoFileStatus)
549+
// TODO: Get only the content for the files that will be validated
550+
go gcl.GetContent([]string{"."}, getcontentchan)
551+
for stat := range getcontentchan {
552+
if stat.Err != nil {
553+
log.ShowWrite("[Error] failed to get content for %q: %s", repopath, stat.Err.Error())
554+
writeValFailure(resdir)
555+
return
556+
}
557+
log.ShowWrite("[Info] %s %s %s", stat.State, stat.FileName, stat.Progress)
558+
}
559+
log.ShowWrite("[Info] get-content complete")
560+
561+
switch validator {
562+
case "bids":
563+
err = validateBIDS(valroot, resdir)
564+
case "nix":
565+
err = validateNIX(valroot, resdir)
566+
case "odml":
567+
err = validateODML(valroot, resdir)
568+
default:
569+
err = fmt.Errorf("[Error] invalid validator name: %s", validator)
570+
}
571+
572+
if err != nil {
573+
writeValFailure(resdir)
574+
}
575+
}()
576+
return respath
577+
}
578+
463579
// writeValFailure writes a badge and page content for when a hook payload is
464580
// valid, but the validator failed to run. This function does not return
465581
// anything, but logs all errors.
@@ -543,10 +659,8 @@ func PubValidatePost(w http.ResponseWriter, r *http.Request) {
543659
return
544660
}
545661

546-
runValidator(validator, repopath, "HEAD", gcl)
547-
// TODO redirect to results
548-
w.WriteHeader(http.StatusOK)
549-
w.Write([]byte("OK"))
662+
respath := runValidatorPub(validator, repopath, gcl)
663+
http.Redirect(w, r, filepath.Join("results", respath), http.StatusFound)
550664
}
551665

552666
// Validate temporarily clones a provided repository from

0 commit comments

Comments
 (0)