cli/pkg/cmd/workflow/view/view_test.go
2021-04-02 10:16:09 -07:00

438 lines
9.9 KiB
Go

package view
import (
"bytes"
"io/ioutil"
"net/http"
"testing"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/internal/ghrepo"
runShared "github.com/cli/cli/pkg/cmd/run/shared"
"github.com/cli/cli/pkg/cmd/workflow/shared"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/pkg/httpmock"
"github.com/cli/cli/pkg/iostreams"
"github.com/cli/cli/pkg/prompt"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
)
func TestNewCmdView(t *testing.T) {
tests := []struct {
name string
cli string
tty bool
wants ViewOptions
wantsErr bool
}{
{
name: "blank tty",
tty: true,
wants: ViewOptions{
Prompt: true,
},
},
{
name: "blank nontty",
wantsErr: true,
},
{
name: "arg tty",
cli: "123",
tty: true,
wants: ViewOptions{
Selector: "123",
},
},
{
name: "arg nontty",
cli: "123",
wants: ViewOptions{
Selector: "123",
Raw: true,
},
},
{
name: "web tty",
cli: "--web",
tty: true,
wants: ViewOptions{
Prompt: true,
Web: true,
},
},
{
name: "web nontty",
cli: "-w 123",
wants: ViewOptions{
Raw: true,
Web: true,
Selector: "123",
},
},
{
name: "yaml tty",
cli: "--yaml",
tty: true,
wants: ViewOptions{
Prompt: true,
YAML: true,
},
},
{
name: "yaml nontty",
cli: "-y 123",
wants: ViewOptions{
Raw: true,
YAML: true,
Selector: "123",
},
},
{
name: "ref tty",
cli: "--ref 456",
tty: true,
wantsErr: true,
},
{
name: "ref nontty",
cli: "123 -r 456",
wantsErr: true,
},
{
name: "yaml ref tty",
cli: "--yaml --ref 456",
tty: true,
wants: ViewOptions{
Prompt: true,
YAML: true,
Ref: "456",
},
},
{
name: "yaml ref nontty",
cli: "123 -y -r 456",
wants: ViewOptions{
Raw: true,
YAML: true,
Ref: "456",
Selector: "123",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
io, _, _, _ := iostreams.Test()
io.SetStdinTTY(tt.tty)
io.SetStdoutTTY(tt.tty)
f := &cmdutil.Factory{
IOStreams: io,
}
argv, err := shlex.Split(tt.cli)
assert.NoError(t, err)
var gotOpts *ViewOptions
cmd := NewCmdView(f, func(opts *ViewOptions) error {
gotOpts = opts
return nil
})
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(ioutil.Discard)
cmd.SetErr(ioutil.Discard)
_, err = cmd.ExecuteC()
if tt.wantsErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wants.Selector, gotOpts.Selector)
assert.Equal(t, tt.wants.Ref, gotOpts.Ref)
assert.Equal(t, tt.wants.Web, gotOpts.Web)
assert.Equal(t, tt.wants.Prompt, gotOpts.Prompt)
assert.Equal(t, tt.wants.Raw, gotOpts.Raw)
assert.Equal(t, tt.wants.YAML, gotOpts.YAML)
})
}
}
func TestViewRun(t *testing.T) {
aWorkflow := shared.Workflow{
Name: "a workflow",
ID: 123,
Path: ".github/workflows/flow.yml",
State: shared.Active,
}
aWorkflowContent := `{"content":"bmFtZTogYSB3b3JrZmxvdwo="}`
aWorkflowInfo := heredoc.Doc(`
a workflow - flow.yml
ID: 123
Total runs 10
Recent runs
X cool commit timed out trunk push 1
- cool commit in progress trunk push 2
✓ cool commit successful trunk push 3
✓ cool commit cancelled trunk push 4
To see more runs for this workflow, try: gh run list --workflow flow.yml
To see the YAML for this workflow, try: gh workflow view flow.yml --yaml
`)
tests := []struct {
name string
opts *ViewOptions
httpStubs func(*httpmock.Registry)
askStubs func(*prompt.AskStubber)
tty bool
wantOut string
wantErrOut string
wantErr bool
}{
{
name: "no enabled workflows",
tty: true,
opts: &ViewOptions{
Prompt: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"),
httpmock.JSONResponse(shared.WorkflowsPayload{}))
},
wantErrOut: "could not fetch workflows for OWNER/REPO: no workflows are enabled",
wantErr: true,
},
{
name: "web",
tty: true,
opts: &ViewOptions{
Selector: "123",
Web: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
},
wantOut: "Opening github.com/OWNER/REPO/actions/workflows/flow.yml in your browser.\n",
},
{
name: "web notty",
tty: false,
opts: &ViewOptions{
Selector: "123",
Web: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
},
wantOut: "",
},
{
name: "web with yaml",
tty: true,
opts: &ViewOptions{
Selector: "123",
YAML: true,
Web: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.GraphQL(`query RepositoryInfo\b`),
httpmock.StringResponse(`{ "data": { "repository": { "defaultBranchRef": { "name": "trunk" } } } }`),
)
},
wantOut: "Opening github.com/OWNER/REPO/blob/trunk/.github/workflows/flow.yml in your browser.\n",
},
{
name: "web with yaml and ref",
tty: true,
opts: &ViewOptions{
Selector: "123",
Ref: "base",
YAML: true,
Web: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
},
wantOut: "Opening github.com/OWNER/REPO/blob/base/.github/workflows/flow.yml in your browser.\n",
},
{
name: "workflow with yaml",
tty: true,
opts: &ViewOptions{
Selector: "123",
YAML: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
httpmock.StringResponse(aWorkflowContent),
)
},
wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n",
},
{
name: "workflow with yaml notty",
tty: false,
opts: &ViewOptions{
Selector: "123",
YAML: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
httpmock.StringResponse(aWorkflowContent),
)
},
wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n",
},
{
name: "workflow with yaml not found",
tty: true,
opts: &ViewOptions{
Selector: "123",
YAML: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
httpmock.StatusStringResponse(404, "not Found"),
)
},
wantErr: true,
wantErrOut: "could not find workflow file flow.yml, try specifying a branch or tag using `--ref`",
},
{
name: "workflow with yaml and ref",
tty: true,
opts: &ViewOptions{
Selector: "123",
Ref: "456",
YAML: true,
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/flow.yml"),
httpmock.StringResponse(aWorkflowContent),
)
},
wantOut: "a workflow - flow.yml\nID: 123\n\nname: a workflow\n\n\n",
},
{
name: "workflow info",
tty: true,
opts: &ViewOptions{
Selector: "123",
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123/runs"),
httpmock.JSONResponse(runShared.RunsPayload{
TotalCount: 10,
WorkflowRuns: runShared.TestRuns[0:4],
}),
)
},
wantOut: aWorkflowInfo,
},
{
name: "workflow info notty",
tty: true,
opts: &ViewOptions{
Selector: "123",
},
httpStubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
httpmock.JSONResponse(aWorkflow),
)
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123/runs"),
httpmock.JSONResponse(runShared.RunsPayload{
TotalCount: 10,
WorkflowRuns: runShared.TestRuns[0:4],
}),
)
},
wantOut: aWorkflowInfo,
},
}
for _, tt := range tests {
reg := &httpmock.Registry{}
tt.httpStubs(reg)
tt.opts.HttpClient = func() (*http.Client, error) {
return &http.Client{Transport: reg}, nil
}
io, _, stdout, _ := iostreams.Test()
io.SetStdoutTTY(tt.tty)
io.SetStdinTTY(tt.tty)
tt.opts.IO = io
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
return ghrepo.FromFullName("OWNER/REPO")
}
browser := &cmdutil.TestBrowser{}
tt.opts.Browser = browser
as, teardown := prompt.InitAskStubber()
defer teardown()
if tt.askStubs != nil {
tt.askStubs(as)
}
t.Run(tt.name, func(t *testing.T) {
err := runView(tt.opts)
if tt.wantErr {
assert.Error(t, err)
assert.Equal(t, tt.wantErrOut, err.Error())
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wantOut, stdout.String())
reg.Verify(t)
})
}
}