-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/relui: add relui webserver for releases
This commit introduces relui, a prototype for running releases in a persistent server environment. The primary goals of using a long-running service for release management is to improve observability, scheduling, and testing of our release process. This change introduces a very basic webserver, and minimal styling. For golang/go#40279 Change-Id: I5958e5dc19e62df92b36c64583058cbcef8dd75c Reviewed-on: https://go-review.googlesource.com/c/build/+/243338 Run-TryBot: Alexander Rakoczy <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Andrew Bonventre <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
- Loading branch information
Showing
7 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#golang.org/x/build/cmd/relui | ||
|
||
``` | ||
▀▀█ ▀ | ||
▄ ▄▄ ▄▄▄ █ ▄ ▄ ▄▄▄ | ||
█▀ ▀ █▀ █ █ █ █ █ | ||
█ █▀▀▀▀ █ █ █ █ | ||
█ ▀█▄▄▀ ▀▄▄ ▀▄▄▀█ ▄▄█▄▄ | ||
``` | ||
|
||
relui is a web interface for managing the release process of Go. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<!-- | ||
Copyright 2020 The Go Authors. All rights reserved. | ||
Use of this source code is governed by a BSD-style | ||
license that can be found in the LICENSE file. | ||
--> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<title>Go Releases</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<link rel="stylesheet" href="/styles.css" /> | ||
<body class="Site"> | ||
<header class="Site-header"> | ||
<div class="Header"> | ||
<h1 class="Header-title">Go Releases</h1> | ||
</div> | ||
</header> | ||
<main class="Site-content"> | ||
<section class="Workflows"> | ||
<h2>Workflows</h2> | ||
<ul class="WorkflowList"> | ||
<li class="WorkflowList-item"> | ||
<h3>Local Release - 20a838ab</h3> | ||
<form> </form> | ||
<ul class="TaskList"> | ||
<li class="TaskList-item"> | ||
<h4>Fetch blob - 20a838ab</h4> | ||
Status: created | ||
</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
</section> | ||
</main> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright 2020 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"os" | ||
) | ||
|
||
func main() { | ||
http.Handle("/", fileServerHandler(relativeFile("./static"), http.HandlerFunc(homeHandler))) | ||
port := os.Getenv("PORT") | ||
if port == "" { | ||
port = "8080" | ||
} | ||
|
||
log.Printf("Listening on :" + port) | ||
log.Fatal(http.ListenAndServe(":"+port, http.DefaultServeMux)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright 2020 The Go Authors. All rights reserved. | ||
* Use of this source code is governed by a BSD-style | ||
* license that can be found in the LICENSE file. | ||
*/ | ||
*, | ||
:before, | ||
:after { | ||
box-sizing: border-box; | ||
} | ||
html, | ||
.Site { | ||
height: 100%; | ||
} | ||
.Site { | ||
display: flex; | ||
flex-direction: column; | ||
font-family: sans-serif; | ||
margin: 0; | ||
} | ||
h1, | ||
h2 { | ||
font-weight: 600; | ||
letter-spacing: 0.03rem; | ||
} | ||
|
||
h3, | ||
h4 { | ||
font-weight: 600; | ||
letter-spacing: 0.08rem; | ||
} | ||
h5, | ||
h6 { | ||
font-weight: 500; | ||
letter-spacing: 0.08rem; | ||
} | ||
.Site-content { | ||
flex: 1 0 auto; | ||
padding: 0.625rem; | ||
width: 100%; | ||
} | ||
.Site-header { | ||
flex: none; | ||
} | ||
.Header { | ||
background: #e0ebf5; | ||
color: #375eab; | ||
padding: 0.625rem; | ||
} | ||
.Header-title { | ||
font-size: 1.5rem; | ||
margin: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.Header { font-size: 10rem; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2020 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"html/template" | ||
"log" | ||
"mime" | ||
"net/http" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
) | ||
|
||
func fileServerHandler(root string, next http.Handler) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
if r.URL.Path == "/" { | ||
next.ServeHTTP(w, r) | ||
return | ||
} | ||
if _, err := os.Stat(path.Join(root, r.URL.Path)); os.IsNotExist(err) { | ||
http.NotFound(w, r) | ||
return | ||
} | ||
w.Header().Set("Content-Type", mime.TypeByExtension(path.Ext(r.URL.Path))) | ||
w.Header().Set("Cache-Control", "no-cache, private, max-age=0") | ||
|
||
fs := http.FileServer(http.Dir(root)) | ||
fs.ServeHTTP(w, r) | ||
}) | ||
} | ||
|
||
var homeTemplate = template.Must(template.ParseFiles(relativeFile("index.html"))) | ||
|
||
func homeHandler(w http.ResponseWriter, _ *http.Request) { | ||
if err := homeTemplate.Execute(w, nil); err != nil { | ||
log.Printf("homeHandlerFunc: %v", err) | ||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
// relativeFile returns the path to the provided file or directory, | ||
// conditionally prepending a relative path depending on the environment. | ||
// | ||
// In tests the current directory is ".", but the command may be running from the module root. | ||
func relativeFile(base string) string { | ||
// Check to see if it is in "." first. | ||
if _, err := os.Stat(base); err == nil { | ||
return base | ||
} | ||
return filepath.Join("cmd/relui", base) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright 2020 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"io/ioutil" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
) | ||
|
||
func TestHomeHandler(t *testing.T) { | ||
req := httptest.NewRequest("GET", "/", nil) | ||
w := httptest.NewRecorder() | ||
|
||
homeHandler(w, req) | ||
resp := w.Result() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
t.Errorf("rep.StatusCode = %d, wanted %d", resp.StatusCode, http.StatusOK) | ||
} | ||
} | ||
|
||
func TestFileServerHandler(t *testing.T) { | ||
h := fileServerHandler("./testing", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
w.Write([]byte("Home")) | ||
})) | ||
|
||
cases := []struct { | ||
desc string | ||
path string | ||
wantCode int | ||
wantBody string | ||
wantHeaders map[string]string | ||
}{ | ||
{ | ||
desc: "fallback to next handler", | ||
path: "/", | ||
wantCode: http.StatusOK, | ||
wantBody: "Home", | ||
}, | ||
{ | ||
desc: "sets headers and returns file", | ||
path: "/test.css", | ||
wantCode: http.StatusOK, | ||
wantBody: ".Header { font-size: 10rem; }\n", | ||
wantHeaders: map[string]string{ | ||
"Content-Type": "text/css; charset=utf-8", | ||
"Cache-Control": "no-cache, private, max-age=0", | ||
}, | ||
}, | ||
{ | ||
desc: "handles missing file", | ||
path: "/foo.js", | ||
wantCode: http.StatusNotFound, | ||
wantBody: "404 page not found\n", | ||
}, | ||
} | ||
for _, c := range cases { | ||
t.Run(c.desc, func(t *testing.T) { | ||
req := httptest.NewRequest("GET", c.path, nil) | ||
w := httptest.NewRecorder() | ||
|
||
h.ServeHTTP(w, req) | ||
resp := w.Result() | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != c.wantCode { | ||
t.Errorf("rep.StatusCode = %d, wanted %d", resp.StatusCode, c.wantCode) | ||
} | ||
b, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
t.Errorf("resp.Body = _, %v, wanted no error", err) | ||
} | ||
if string(b) != c.wantBody { | ||
t.Errorf("resp.Body = %q, %v, wanted %q, %v", b, err, c.wantBody, nil) | ||
} | ||
for k, v := range c.wantHeaders { | ||
if resp.Header.Get(k) != v { | ||
t.Errorf("resp.Header.Get(%q) = %q, wanted %q", k, resp.Header.Get(k), v) | ||
} | ||
} | ||
}) | ||
} | ||
} |