Skip to content

Commit 88204a4

Browse files
committed
internal/relui: create workflows from parameters
This change updates the UI and creation endpoint to use the parameters specified for the workflow. For golang/go#47401 Change-Id: I46623a17161806c39cad98853e996f0fee5a0305 Reviewed-on: https://go-review.googlesource.com/c/build/+/352169 Trust: Alexander Rakoczy <[email protected]> Run-TryBot: Alexander Rakoczy <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent cbb5112 commit 88204a4

File tree

5 files changed

+143
-42
lines changed

5 files changed

+143
-42
lines changed

internal/relui/templates/new_workflow.html

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,35 @@
44
license that can be found in the LICENSE file.
55
-->
66
{{define "content"}}
7-
<section class="NewWorkflow">
8-
<h2>New Go Release</h2>
9-
<form action="/workflows/create" method="post">
10-
<label>
11-
Revision
12-
<input name="workflow.params.revision" value="main" />
13-
</label>
14-
<input name="workflow.create" type="submit" value="Create" />
15-
</form>
16-
</section>
7+
<section class="NewWorkflow">
8+
<h2>New Go Release</h2>
9+
<form action="/workflows/new" method="get">
10+
<label for="workflow.name">
11+
Workflow:
12+
</label>
13+
<select id="workflow.name" name="workflow.name" onchange="this.form.submit()">
14+
<option value="">Select Workflow</option>
15+
{{range $name, $definition := .Definitions}}
16+
<option value="{{$name}}" {{if eq $name $.Name}}selected="selected"{{end}}>
17+
{{$name}}
18+
</option>
19+
{{end}}
20+
</select>
21+
<noscript>
22+
<input name="workflow.new" type="submit" value="New"/>
23+
</noscript>
24+
</form>
25+
{{if .Selected}}
26+
<form action="/workflows/create" method="post">
27+
<input type="hidden" id="workflow.name" name="workflow.name" value="{{$.Name}}">
28+
{{range $name := .Selected.ParameterNames}}
29+
<div class="NewWorkflow-Parameter">
30+
<label for="workflow.params.{{$name}}">{{$name}}</label>
31+
<input id="workflow.params.{{$name}}" name="workflow.params.{{$name}}" value=""/>
32+
</div>
33+
{{end}}
34+
<input name="workflow.create" type="submit" value="Create"/>
35+
</form>
36+
{{end}}
37+
</section>
1738
{{end}}

internal/relui/web.go

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,23 @@ func (s *Server) homeHandler(w http.ResponseWriter, r *http.Request) {
109109
io.Copy(w, &out)
110110
}
111111

112+
type newWorkflowResponse struct {
113+
Definitions map[string]*workflow.Definition
114+
Name string
115+
}
116+
117+
func (n *newWorkflowResponse) Selected() *workflow.Definition {
118+
return n.Definitions[n.Name]
119+
}
120+
112121
// newWorkflowHandler presents a form for creating a new workflow.
113-
func (s *Server) newWorkflowHandler(w http.ResponseWriter, _ *http.Request) {
122+
func (s *Server) newWorkflowHandler(w http.ResponseWriter, r *http.Request) {
114123
out := bytes.Buffer{}
115-
if err := newWorkflowTmpl.Execute(&out, nil); err != nil {
124+
resp := &newWorkflowResponse{
125+
Definitions: Definitions,
126+
Name: r.FormValue("workflow.name"),
127+
}
128+
if err := newWorkflowTmpl.Execute(&out, resp); err != nil {
116129
log.Printf("newWorkflowHandler: %v", err)
117130
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
118131
return
@@ -123,17 +136,20 @@ func (s *Server) newWorkflowHandler(w http.ResponseWriter, _ *http.Request) {
123136
// createWorkflowHandler persists a new workflow in the datastore, and
124137
// starts the workflow in a goroutine.
125138
func (s *Server) createWorkflowHandler(w http.ResponseWriter, r *http.Request) {
126-
if err := r.ParseForm(); err != nil {
139+
d := Definitions[r.FormValue("workflow.name")]
140+
if d == nil {
127141
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
128142
return
129143
}
130-
ref := r.Form.Get("workflow.params.revision")
131-
if ref == "" {
132-
http.Error(w, "workflow revision is required", http.StatusBadRequest)
133-
return
144+
params := make(map[string]string)
145+
for _, n := range d.ParameterNames() {
146+
params[n] = r.FormValue(fmt.Sprintf("workflow.params.%s", n))
147+
if params[n] == "" {
148+
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
149+
return
150+
}
134151
}
135-
params := map[string]string{"greeting": ref}
136-
wf, err := workflow.Start(newEchoWorkflow(ref), params)
152+
wf, err := workflow.Start(Definitions["echo"], params)
137153
if err != nil {
138154
log.Printf("createWorkflowHandler: %v", err)
139155
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@@ -220,16 +236,3 @@ type stdoutLogger struct {
220236
func (l *stdoutLogger) Printf(format string, v ...interface{}) {
221237
log.Printf("%q(%q): %v", l.WorkflowID, l.TaskID, fmt.Sprintf(format, v...))
222238
}
223-
224-
// newEchoWorkflow returns a runnable workflow.Definition for
225-
// development.
226-
func newEchoWorkflow(greeting string) *workflow.Definition {
227-
wd := workflow.New()
228-
gt := wd.Task("echo", echo, wd.Constant(greeting))
229-
wd.Output("greeting", gt)
230-
return wd
231-
}
232-
233-
func echo(_ context.Context, arg string) (string, error) {
234-
return arg, nil
235-
}

internal/relui/web_test.go

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,40 @@ func TestServerHomeHandler(t *testing.T) {
130130
}
131131

132132
func TestServerNewWorkflowHandler(t *testing.T) {
133-
req := httptest.NewRequest(http.MethodGet, "/workflows/new", nil)
134-
w := httptest.NewRecorder()
133+
cases := []struct {
134+
desc string
135+
params url.Values
136+
wantCode int
137+
}{
138+
{
139+
desc: "No selection",
140+
wantCode: http.StatusOK,
141+
},
142+
{
143+
desc: "valid workflow",
144+
params: url.Values{"workflow.name": []string{"echo"}},
145+
wantCode: http.StatusOK,
146+
},
147+
{
148+
desc: "invalid workflow",
149+
params: url.Values{"workflow.name": []string{"this workflow does not exist"}},
150+
wantCode: http.StatusOK,
151+
},
152+
}
153+
for _, c := range cases {
154+
t.Run(c.desc, func(t *testing.T) {
155+
u := url.URL{Path: "/workflows/new", RawQuery: c.params.Encode()}
156+
req := httptest.NewRequest(http.MethodGet, u.String(), nil)
157+
w := httptest.NewRecorder()
135158

136-
s := &Server{}
137-
s.newWorkflowHandler(w, req)
138-
resp := w.Result()
159+
s := &Server{}
160+
s.newWorkflowHandler(w, req)
161+
resp := w.Result()
139162

140-
if resp.StatusCode != http.StatusOK {
141-
t.Errorf("rep.StatusCode = %d, wanted %d", resp.StatusCode, http.StatusOK)
163+
if resp.StatusCode != http.StatusOK {
164+
t.Errorf("rep.StatusCode = %d, wanted %d", resp.StatusCode, http.StatusOK)
165+
}
166+
})
142167
}
143168
}
144169

@@ -155,12 +180,25 @@ func TestServerCreateWorkflowHandler(t *testing.T) {
155180
wantTasks []db.Task
156181
}{
157182
{
158-
desc: "bad request",
183+
desc: "no params",
159184
wantCode: http.StatusBadRequest,
160185
},
161186
{
162-
desc: "successful creation",
163-
params: url.Values{"workflow.params.revision": []string{"abc"}},
187+
desc: "invalid workflow name",
188+
params: url.Values{"workflow.name": []string{"invalid"}},
189+
wantCode: http.StatusBadRequest,
190+
},
191+
{
192+
desc: "missing workflow params",
193+
params: url.Values{"workflow.name": []string{"echo"}},
194+
wantCode: http.StatusBadRequest,
195+
},
196+
{
197+
desc: "successful creation",
198+
params: url.Values{
199+
"workflow.name": []string{"echo"},
200+
"workflow.params.greeting": []string{"abc"},
201+
},
164202
wantCode: http.StatusSeeOther,
165203
wantHeaders: map[string]string{
166204
"Location": "/",

internal/relui/workflows.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package relui
6+
7+
import (
8+
"context"
9+
10+
"golang.org/x/build/internal/workflow"
11+
)
12+
13+
// Definitions is a list of all initialized Definition that can be
14+
// created.
15+
var Definitions = map[string]*workflow.Definition{
16+
"echo": newEchoWorkflow(),
17+
}
18+
19+
// newEchoWorkflow returns a runnable workflow.Definition for
20+
// development.
21+
func newEchoWorkflow() *workflow.Definition {
22+
wd := workflow.New()
23+
wd.Output("greeting", wd.Task("echo", echo, wd.Parameter("greeting")))
24+
return wd
25+
}
26+
27+
func echo(_ context.Context, arg string) (string, error) {
28+
return arg, nil
29+
}

internal/workflow/workflow.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ func (d *Definition) Parameter(name string) Value {
6767
return &workflowParameter{name: name}
6868
}
6969

70+
// ParameterNames returns the names of all parameters associated with
71+
// the Definition.
72+
func (d *Definition) ParameterNames() []string {
73+
var names []string
74+
for n := range d.parameterNames {
75+
names = append(names, n)
76+
}
77+
return names
78+
}
79+
7080
type workflowParameter struct {
7181
name string
7282
}

0 commit comments

Comments
 (0)