in prow/cmd/deck/main.go [952:1151]
func renderSpyglass(ctx context.Context, sg *spyglass.Spyglass, cfg config.Getter, src string, o options, csrfToken string, log *logrus.Entry) (string, error) {
renderStart := time.Now()
src = strings.TrimSuffix(src, "/")
realPath, err := sg.ResolveSymlink(src)
if err != nil {
return "", fmt.Errorf("error when resolving real path %s: %w", src, err)
}
src = realPath
artifactNames, err := sg.ListArtifacts(ctx, src)
if err != nil {
return "", fmt.Errorf("error listing artifacts: %w", err)
}
if len(artifactNames) == 0 {
log.Infof("found no artifacts for %s", src)
}
regexCache := cfg().Deck.Spyglass.RegexCache
lensCache := map[int][]string{}
var lensIndexes []int
lensesLoop:
for i, lfc := range cfg().Deck.Spyglass.Lenses {
matches := sets.String{}
for _, re := range lfc.RequiredFiles {
found := false
for _, a := range artifactNames {
if regexCache[re].MatchString(a) {
matches.Insert(a)
found = true
}
}
if !found {
continue lensesLoop
}
}
for _, re := range lfc.OptionalFiles {
for _, a := range artifactNames {
if regexCache[re].MatchString(a) {
matches.Insert(a)
}
}
}
lensCache[i] = matches.List()
lensIndexes = append(lensIndexes, i)
}
lensIndexes, ls := sg.Lenses(lensIndexes)
jobHistLink := ""
jobPath, err := sg.JobPath(src)
if err == nil {
jobHistLink = path.Join("/job-history", jobPath)
}
var prowJobLink string
prowJobName, err := sg.ProwJobName(src)
if err == nil {
if prowJobName != "" {
u, err := url.Parse("/prowjob")
if err != nil {
return "", fmt.Errorf("error parsing prowjob path: %w", err)
}
query := url.Values{}
query.Set("prowjob", prowJobName)
u.RawQuery = query.Encode()
prowJobLink = u.String()
}
} else {
log.WithError(err).Warningf("Error getting ProwJob name for source %q.", src)
}
prHistLink := ""
org, repo, number, err := sg.RunToPR(src)
if err == nil && !cfg().Deck.Spyglass.HidePRHistLink {
prHistLinkTemplate := cfg().Deck.Spyglass.PRHistLinkTemplate
if prHistLinkTemplate == "" { // Not defined globally
prHistLinkTemplate = defaultPRHistLinkTemplate
}
prHistLink, err = prHistLinkFromTemplate(prHistLinkTemplate, org, repo, number)
if err != nil {
return "", err
}
}
artifactsLink := ""
gcswebPrefix := cfg().Deck.Spyglass.GCSBrowserPrefixes.GetGCSBrowserPrefix(org, repo)
if gcswebPrefix != "" {
runPath, err := sg.RunPath(src)
if err == nil {
artifactsLink = gcswebPrefix + runPath
// gcsweb wants us to end URLs with a trailing slash
if !strings.HasSuffix(artifactsLink, "/") {
artifactsLink += "/"
}
}
}
jobName, buildID, err := common.KeyToJob(src)
if err != nil {
return "", fmt.Errorf("error determining jobName / buildID: %w", err)
}
prLink := ""
j, err := sg.JobAgent.GetProwJob(jobName, buildID)
if err == nil && j.Spec.Refs != nil && len(j.Spec.Refs.Pulls) > 0 {
prLink = j.Spec.Refs.Pulls[0].Link
}
announcement := ""
if cfg().Deck.Spyglass.Announcement != "" {
announcementTmpl, err := template.New("announcement").Parse(cfg().Deck.Spyglass.Announcement)
if err != nil {
return "", fmt.Errorf("error parsing announcement template: %w", err)
}
runPath, err := sg.RunPath(src)
if err != nil {
runPath = ""
}
var announcementBuf bytes.Buffer
err = announcementTmpl.Execute(&announcementBuf, struct {
ArtifactPath string
}{
ArtifactPath: runPath,
})
if err != nil {
return "", fmt.Errorf("error executing announcement template: %w", err)
}
announcement = announcementBuf.String()
}
tgLink, err := sg.TestGridLink(src)
if err != nil {
tgLink = ""
}
extraLinks, err := sg.ExtraLinks(ctx, src)
if err != nil {
log.WithError(err).WithField("page", src).Warn("Failed to fetch extra links")
extraLinks = nil
}
var viewBuf bytes.Buffer
type spyglassTemplate struct {
Lenses map[int]spyglass.LensConfig
LensIndexes []int
Source string
LensArtifacts map[int][]string
JobHistLink string
ProwJobLink string
ArtifactsLink string
PRHistLink string
Announcement template.HTML
TestgridLink string
JobName string
BuildID string
PRLink string
ExtraLinks []spyglass.ExtraLink
ReRunCreatesJob bool
ProwJobName string
}
sTmpl := spyglassTemplate{
Lenses: ls,
LensIndexes: lensIndexes,
Source: src,
LensArtifacts: lensCache,
JobHistLink: jobHistLink,
ProwJobLink: prowJobLink,
ArtifactsLink: artifactsLink,
PRHistLink: prHistLink,
Announcement: template.HTML(announcement),
TestgridLink: tgLink,
JobName: jobName,
BuildID: buildID,
PRLink: prLink,
ExtraLinks: extraLinks,
ReRunCreatesJob: o.rerunCreatesJob,
ProwJobName: prowJobName,
}
t := template.New("spyglass.html")
if _, err := prepareBaseTemplate(o, cfg, csrfToken, t); err != nil {
return "", fmt.Errorf("error preparing base template: %w", err)
}
t, err = t.ParseFiles(path.Join(o.templateFilesLocation, "spyglass.html"))
if err != nil {
return "", fmt.Errorf("error parsing template: %w", err)
}
if err = t.Execute(&viewBuf, sTmpl); err != nil {
return "", fmt.Errorf("error rendering template: %w", err)
}
renderElapsed := time.Since(renderStart)
log.WithFields(logrus.Fields{
"duration": renderElapsed.String(),
"source": src,
}).Info("Rendered spyglass views.")
return viewBuf.String(), nil
}