prow/cmd/deck/main.go
func renderSpyglass(sg *spyglass.Spyglass, cfg config.Getter, src string, o options) (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: %v", err)
	}
	src = realPath

	artifactNames, err := sg.ListArtifacts(src)
	if err != nil {
		return "", fmt.Errorf("error listing artifacts: %v", err)
	}
	if len(artifactNames) == 0 {
		return "", fmt.Errorf("found no artifacts for %s", src)
	}

	viewerCache := map[string][]string{}
	viewersRegistry := cfg().Deck.Spyglass.Viewers
	regexCache := cfg().Deck.Spyglass.RegexCache

	for re, viewerNames := range viewersRegistry {
		matches := []string{}
		for _, a := range artifactNames {
			if regexCache[re].MatchString(a) {
				matches = append(matches, a)
			}
		}
		if len(matches) > 0 {
			for _, vName := range viewerNames {
				viewerCache[vName] = matches
			}
		}
	}

	ls := sg.Lenses(viewerCache)
	lensNames := []string{}
	for _, l := range ls {
		lensNames = append(lensNames, l.Config().Name)
	}

	jobHistLink := ""
	jobPath, err := sg.JobPath(src)
	if err == nil {
		jobHistLink = path.Join("/job-history", jobPath)
	}

	artifactsLink := ""
	gcswebPrefix := cfg().Deck.Spyglass.GCSBrowserPrefix
	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 += "/"
			}
		}
	}

	prHistLink := ""
	org, repo, number, err := sg.RunToPR(src)
	if err == nil {
		prHistLink = "/pr-history?org=" + org + "&repo=" + repo + "&pr=" + strconv.Itoa(number)
	}

	jobName, buildID, err := sg.KeyToJob(src)
	if err != nil {
		return "", fmt.Errorf("error determining jobName / buildID: %v", err)
	}

	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: %v", 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: %v", err)
		}
		announcement = announcementBuf.String()
	}

	tgLink, err := sg.TestGridLink(src)
	if err != nil {
		tgLink = ""
	}

	extraLinks, err := sg.ExtraLinks(src)
	if err != nil {
		logrus.WithError(err).WithField("page", src).Warn("Failed to fetch extra links")
		extraLinks = nil
	}

	var viewBuf bytes.Buffer
	type lensesTemplate struct {
		Lenses        []lenses.Lens
		LensNames     []string
		Source        string
		LensArtifacts map[string][]string
		JobHistLink   string
		ArtifactsLink string
		PRHistLink    string
		Announcement  template.HTML
		TestgridLink  string
		JobName       string
		BuildID       string
		ExtraLinks    []spyglass.ExtraLink
	}
	lTmpl := lensesTemplate{
		Lenses:        ls,
		LensNames:     lensNames,
		Source:        src,
		LensArtifacts: viewerCache,
		JobHistLink:   jobHistLink,
		ArtifactsLink: artifactsLink,
		PRHistLink:    prHistLink,
		Announcement:  template.HTML(announcement),
		TestgridLink:  tgLink,
		JobName:       jobName,
		BuildID:       buildID,
		ExtraLinks:    extraLinks,
	}
	t := template.New("spyglass.html")

	if _, err := prepareBaseTemplate(o, cfg, t); err != nil {
		return "", fmt.Errorf("error preparing base template: %v", err)
	}
	t, err = t.ParseFiles(path.Join(o.templateFilesLocation, "spyglass.html"))
	if err != nil {
		return "", fmt.Errorf("error parsing template: %v", err)
	}

	if err = t.Execute(&viewBuf, lTmpl); err != nil {
		return "", fmt.Errorf("error rendering template: %v", err)
	}
	renderElapsed := time.Since(renderStart)
	logrus.WithFields(logrus.Fields{
		"duration": renderElapsed.String(),
		"source":   src,
	}).Info("Rendered spyglass views.")
	return viewBuf.String(), nil
}
func renderSpyglass(sg *spyglass.Spyglass, cfg config.Getter, src string, o options) (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: %v", err)
	}
	src = realPath

	artifactNames, err := sg.ListArtifacts(src)
	if err != nil {
		return "", fmt.Errorf("error listing artifacts: %v", err)
	}
	if len(artifactNames) == 0 {
		return "", fmt.Errorf("found no artifacts for %s", src)
	}

	viewerCache := map[string][]string{}
	viewersRegistry := cfg().Deck.Spyglass.Viewers
	regexCache := cfg().Deck.Spyglass.RegexCache

	for re, viewerNames := range viewersRegistry {
		matches := []string{}
		for _, a := range artifactNames {
			if regexCache[re].MatchString(a) {
				matches = append(matches, a)
			}
		}
		if len(matches) > 0 {
			for _, vName := range viewerNames {
				viewerCache[vName] = matches
			}
		}
	}

	ls := sg.Lenses(viewerCache)
	lensNames := []string{}
	for _, l := range ls {
		lensNames = append(lensNames, l.Config().Name)
	}

	jobHistLink := ""
	jobPath, err := sg.JobPath(src)
	if err == nil {
		jobHistLink = path.Join("/job-history", jobPath)
	}

	artifactsLink := ""
	gcswebPrefix := cfg().Deck.Spyglass.GCSBrowserPrefix
	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 += "/"
			}
		}
	}

	prHistLink := ""
	org, repo, number, err := sg.RunToPR(src)
	if err == nil {
		prHistLink = "/pr-history?org=" + org + "&repo=" + repo + "&pr=" + strconv.Itoa(number)
	}

	jobName, buildID, err := sg.KeyToJob(src)
	if err != nil {
		return "", fmt.Errorf("error determining jobName / buildID: %v", err)
	}

	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: %v", 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: %v", err)
		}
		announcement = announcementBuf.String()
	}

	tgLink, err := sg.TestGridLink(src)
	if err != nil {
		tgLink = ""
	}

	extraLinks, err := sg.ExtraLinks(src)
	if err != nil {
		logrus.WithError(err).WithField("page", src).Warn("Failed to fetch extra links")
		extraLinks = nil
	}

	var viewBuf bytes.Buffer
	type lensesTemplate struct {
		Lenses        []lenses.Lens
		LensNames     []string
		Source        string
		LensArtifacts map[string][]string
		JobHistLink   string
		ArtifactsLink string
		PRHistLink    string
		Announcement  template.HTML
		TestgridLink  string
		JobName       string
		BuildID       string
		ExtraLinks    []spyglass.ExtraLink
	}
	lTmpl := lensesTemplate{
		Lenses:        ls,
		LensNames:     lensNames,
		Source:        src,
		LensArtifacts: viewerCache,
		JobHistLink:   jobHistLink,
		ArtifactsLink: artifactsLink,
		PRHistLink:    prHistLink,
		Announcement:  template.HTML(announcement),
		TestgridLink:  tgLink,
		JobName:       jobName,
		BuildID:       buildID,
		ExtraLinks:    extraLinks,
	}
	t := template.New("spyglass.html")

	if _, err := prepareBaseTemplate(o, cfg, t); err != nil {
		return "", fmt.Errorf("error preparing base template: %v", err)
	}
	t, err = t.ParseFiles(path.Join(o.templateFilesLocation, "spyglass.html"))
	if err != nil {
		return "", fmt.Errorf("error parsing template: %v", err)
	}

	if err = t.Execute(&viewBuf, lTmpl); err != nil {
		return "", fmt.Errorf("error rendering template: %v", err)
	}
	renderElapsed := time.Since(renderStart)
	logrus.WithFields(logrus.Fields{
		"duration": renderElapsed.String(),
		"source":   src,
	}).Info("Rendered spyglass views.")
	return viewBuf.String(), nil
}
// renderSpyglass returns a pre-rendered Spyglass page from the given source string