/
http_changelog.go
139 lines (122 loc) · 3.94 KB
/
http_changelog.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/openshift/release-controller/pkg/rhcos"
"github.com/russross/blackfriday"
"net/http"
"regexp"
"time"
releasecontroller "github.com/openshift/release-controller/pkg/release-controller"
)
var (
reInternalLink = regexp.MustCompile(`<a href="[^"]+">`)
)
type renderResult struct {
out string
err error
}
func (c *Controller) getChangeLog(ch chan renderResult, fromPull string, fromTag string, toPull string, toTag string, format string) {
fromImage, err := releasecontroller.GetImageInfo(c.releaseInfo, c.architecture, fromPull)
if err != nil {
ch <- renderResult{err: err}
return
}
toImage, err := releasecontroller.GetImageInfo(c.releaseInfo, c.architecture, toPull)
if err != nil {
ch <- renderResult{err: err}
return
}
isJson := false
switch format {
case "json":
isJson = true
}
// Generate the change log from image digests
out, err := c.releaseInfo.ChangeLog(fromImage.GenerateDigestPullSpec(), toImage.GenerateDigestPullSpec(), isJson)
if err != nil {
ch <- renderResult{err: err}
return
}
// There is an inconsistency with what is returned from ReleaseInfo (amd64) and what
// needs to be passed into the RHCOS diff engine (x86_64).
var architecture, archExtension string
if toImage.Config.Architecture == "amd64" {
architecture = "x86_64"
} else if toImage.Config.Architecture == "arm64" {
architecture = "aarch64"
archExtension = fmt.Sprintf("-%s", architecture)
} else {
architecture = toImage.Config.Architecture
archExtension = fmt.Sprintf("-%s", architecture)
}
if isJson {
out, err = rhcos.TransformJsonOutput(out, architecture, archExtension)
if err != nil {
ch <- renderResult{err: err}
return
}
ch <- renderResult{out: out}
}
out, err = rhcos.TransformMarkDownOutput(out, fromTag, toTag, architecture, archExtension)
if err != nil {
ch <- renderResult{err: err}
return
}
ch <- renderResult{out: out}
}
func (c *Controller) renderChangeLog(w http.ResponseWriter, fromPull string, fromTag string, toPull string, toTag string, format string) {
flusher, ok := w.(http.Flusher)
if !ok {
flusher = nopFlusher{}
}
flusher.Flush()
ch := make(chan renderResult)
// run the changelog in a goroutine because it may take significant time
go c.getChangeLog(ch, fromPull, fromTag, toPull, toTag, format)
var render renderResult
select {
case render = <-ch:
case <-time.After(500 * time.Millisecond):
fmt.Fprintf(w, `<p id="loading" class="alert alert-info">Loading changelog, this may take a while ...</p>`)
flusher.Flush()
select {
case render = <-ch:
case <-time.After(15 * time.Second):
render.err = fmt.Errorf("the changelog is still loading, if this is the first access it may take several minutes to clone all repositories")
}
fmt.Fprintf(w, `<style>#loading{display: none;}</style>`)
flusher.Flush()
}
if render.err == nil {
switch format {
case "json":
var changeLog releasecontroller.ChangeLog
err := json.Unmarshal([]byte(render.out), &changeLog)
if err != nil {
fmt.Fprintf(w, `<p class="alert alert-danger">%s</p>`, fmt.Sprintf("Unable to show full changelog: %s", err))
return
}
data, err := json.MarshalIndent(&changeLog, "", " ")
if err != nil {
fmt.Fprintf(w, `<p class="alert alert-danger">%s</p>`, fmt.Sprintf("Unable to show full changelog: %s", err))
return
}
fmt.Fprintf(w, "<pre><code>")
w.Write(data)
fmt.Fprintf(w, "</pre></code>")
default:
result := blackfriday.Run([]byte(render.out))
// make our links targets
result = reInternalLink.ReplaceAllFunc(result, func(s []byte) []byte {
return []byte(`<a target="_blank" ` + string(bytes.TrimPrefix(s, []byte("<a "))))
})
w.Write(result)
}
fmt.Fprintln(w, "<hr>")
} else {
// if we don't get a valid result within limits, just show the simpler informational view
fmt.Fprintf(w, `<p class="alert alert-danger">%s</p>`, fmt.Sprintf("Unable to show full changelog: %s", render.err))
}
}