func renderSpyglass()

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
}