Repository: cli/cli
Pull request #1164 (2020-06-11 12:00:45)

Fix error when Milestone is empty during PR create
## Summary

Replaces #1159
Fixes bug introduced in #1124

## Details
I missed the corner case in #1124. Thanks @mislav and @vilmibm for pointing it out!



Patch:
diff --git a/.github/PULL_REQUEST_TEMPLATE/bug_fix.md b/.github/PULL_REQUEST_TEMPLATE/bug_fix.md
index ca33dd34c..a8eef75e6 100644
--- a/.github/PULL_REQUEST_TEMPLATE/bug_fix.md
+++ b/.github/PULL_REQUEST_TEMPLATE/bug_fix.md
@@ -7,7 +7,7 @@ about: Fix a bug in GitHub CLI
 <!--
 Please make sure you read our contributing guidelines at
 https://github.com/cli/cli/blob/trunk/.github/CONTRIBUTING.md
-before opening a pull request. Thanks!
+before opening opening a pull request. Thanks!
 -->
 
 ## Summary
diff --git a/command/help.go b/command/help.go
deleted file mode 100644
index ad3561af2..000000000
--- a/command/help.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package command
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/cli/cli/utils"
-	"github.com/spf13/cobra"
-)
-
-func rootHelpFunc(command *cobra.Command, args []string) {
-	// Display helpful error message in case subcommand name was mistyped.
-	// This matches Cobra's behavior for root command, which Cobra
-	// confusingly doesn't apply to nested commands.
-	if command != RootCmd {
-		if command.Parent() == RootCmd && len(args) >= 2 {
-			if command.SuggestionsMinimumDistance <= 0 {
-				command.SuggestionsMinimumDistance = 2
-			}
-			candidates := command.SuggestionsFor(args[1])
-
-			errOut := command.OutOrStderr()
-			fmt.Fprintf(errOut, "unknown command %q for %q\n", args[1], "gh "+args[0])
-
-			if len(candidates) > 0 {
-				fmt.Fprint(errOut, "\nDid you mean this?\n")
-				for _, c := range candidates {
-					fmt.Fprintf(errOut, "\t%s\n", c)
-				}
-				fmt.Fprint(errOut, "\n")
-			}
-
-			oldOut := command.OutOrStdout()
-			command.SetOut(errOut)
-			defer command.SetOut(oldOut)
-		}
-	}
-
-	coreCommands := []string{}
-	additionalCommands := []string{}
-	for _, c := range command.Commands() {
-		if c.Short == "" {
-			continue
-		}
-		if c.Hidden {
-			continue
-		}
-
-		s := rpad(c.Name()+":", c.NamePadding()) + c.Short
-		if _, ok := c.Annotations["IsCore"]; ok {
-			coreCommands = append(coreCommands, s)
-		} else {
-			additionalCommands = append(additionalCommands, s)
-		}
-	}
-
-	// If there are no core commands, assume everything is a core command
-	if len(coreCommands) == 0 {
-		coreCommands = additionalCommands
-		additionalCommands = []string{}
-	}
-
-	type helpEntry struct {
-		Title string
-		Body  string
-	}
-
-	helpEntries := []helpEntry{}
-	if command.Long != "" {
-		helpEntries = append(helpEntries, helpEntry{"", command.Long})
-	} else if command.Short != "" {
-		helpEntries = append(helpEntries, helpEntry{"", command.Short})
-	}
-	helpEntries = append(helpEntries, helpEntry{"USAGE", command.UseLine()})
-	if len(coreCommands) > 0 {
-		helpEntries = append(helpEntries, helpEntry{"CORE COMMANDS", strings.Join(coreCommands, "\n")})
-	}
-	if len(additionalCommands) > 0 {
-		helpEntries = append(helpEntries, helpEntry{"ADDITIONAL COMMANDS", strings.Join(additionalCommands, "\n")})
-	}
-	if command.HasLocalFlags() {
-		helpEntries = append(helpEntries, helpEntry{"FLAGS", strings.TrimRight(command.LocalFlags().FlagUsages(), "\n")})
-	}
-	if _, ok := command.Annotations["help:arguments"]; ok {
-		helpEntries = append(helpEntries, helpEntry{"ARGUMENTS", command.Annotations["help:arguments"]})
-	}
-	if command.Example != "" {
-		helpEntries = append(helpEntries, helpEntry{"EXAMPLES", command.Example})
-	}
-	helpEntries = append(helpEntries, helpEntry{"LEARN MORE", `
-Use "gh <command> <subcommand> --help" for more information about a command.
-Read the manual at http://cli.github.com/manual`})
-	if _, ok := command.Annotations["help:feedback"]; ok {
-		helpEntries = append(helpEntries, helpEntry{"FEEDBACK", command.Annotations["help:feedback"]})
-	}
-
-	out := colorableOut(command)
-	for _, e := range helpEntries {
-		if e.Title != "" {
-			// If there is a title, add indentation to each line in the body
-			fmt.Fprintln(out, utils.Bold(e.Title))
-
-			for _, l := range strings.Split(strings.Trim(e.Body, "\n\r"), "\n") {
-				l = strings.Trim(l, " \n\r")
-				fmt.Fprintln(out, "  "+l)
-			}
-		} else {
-			// If there is no title print the body as is
-			fmt.Fprintln(out, e.Body)
-		}
-		fmt.Fprintln(out)
-	}
-}
-
-// rpad adds padding to the right of a string.
-func rpad(s string, padding int) string {
-	template := fmt.Sprintf("%%-%ds ", padding)
-	return fmt.Sprintf(template, s)
-}
diff --git a/command/issue.go b/command/issue.go
index d630b340c..9a76fcf98 100644
--- a/command/issue.go
+++ b/command/issue.go
@@ -49,17 +49,13 @@ func init() {
 }
 
 var issueCmd = &cobra.Command{
-	Use:   "issue <command>",
+	Use:   "issue",
 	Short: "Create and view issues",
-	Long:  `Work with GitHub issues`,
-	Example: `$ gh issue list
-$ gh issue create --fill
-$ gh issue view --web`,
-	Annotations: map[string]string{
-		"IsCore": "true",
-		"help:arguments": `An issue can be supplied as argument in any of the following formats:
+	Long: `Work with GitHub issues.
+
+An issue can be supplied as argument in any of the following formats:
 - by number, e.g. "123"; or
-- by URL, e.g. "https://github.com/OWNER/REPO/issues/123".`},
+- by URL, e.g. "https://github.com/OWNER/REPO/issues/123".`,
 }
 var issueCreateCmd = &cobra.Command{
 	Use:   "create",
diff --git a/command/pr.go b/command/pr.go
index dce006bf0..e92fa7cf0 100644
--- a/command/pr.go
+++ b/command/pr.go
@@ -46,27 +46,19 @@ func init() {
 }
 
 var prCmd = &cobra.Command{
-	Use:   "pr <command>",
+	Use:   "pr",
 	Short: "Create, view, and checkout pull requests",
-	Long:  `Work with GitHub pull requests`,
-	Example: `$ gh pr checkout 353
-$ gh pr checkout bug-fix-branch
-$ gh pr create --fill
-$ gh pr view --web`,
-	Annotations: map[string]string{
-		"IsCore": "true",
-		"help:arguments": `A pull request can be supplied as argument in any of the following formats:
+	Long: `Work with GitHub pull requests.
+
+A pull request can be supplied as argument in any of the following formats:
 - by number, e.g. "123";
 - by URL, e.g. "https://github.com/OWNER/REPO/pull/123"; or
-- by the name of its head branch, e.g. "patch-1" or "OWNER:patch-1".`},
+- by the name of its head branch, e.g. "patch-1" or "OWNER:patch-1".`,
 }
 var prListCmd = &cobra.Command{
 	Use:   "list",
 	Short: "List and filter pull requests in this repository",
-	Example: `$ gh pr list --limit all
-$ gh pr list --state closed
-$ gh pr list --label “priority 1” “bug”`,
-	RunE: prList,
+	RunE:  prList,
 }
 var prStatusCmd = &cobra.Command{
 	Use:   "status",
diff --git a/command/pr_review.go b/command/pr_review.go
index 37b4e09c0..642c9ac24 100644
--- a/command/pr_review.go
+++ b/command/pr_review.go
@@ -180,7 +180,7 @@ func reviewSurvey(cmd *cobra.Command) (*api.PullRequestReviewInput, error) {
 	}
 
 	bodyQs := []*survey.Question{
-		{
+		&survey.Question{
 			Name: "body",
 			Prompt: &surveyext.GhEditor{
 				BlankAllowed:  blankAllowed,
diff --git a/command/repo.go b/command/repo.go
index d62f0c715..b1a57d3a7 100644
--- a/command/repo.go
+++ b/command/repo.go
@@ -44,19 +44,13 @@ func init() {
 }
 
 var repoCmd = &cobra.Command{
-	Use:   "repo <command>",
+	Use:   "repo",
 	Short: "Create, clone, fork, and view repositories",
-	Long:  `Work with GitHub repositories`,
-	Example: `$ gh repo create
-$ gh repo clone cli/cli 
-$ gh repo view --web
-`,
-	Annotations: map[string]string{
-		"IsCore": "true",
-		"help:arguments": `
+	Long: `Work with GitHub repositories.
+
 A repository can be supplied as an argument in any of the following formats:
 - "OWNER/REPO"
-- by URL, e.g. "https://github.com/OWNER/REPO"`},
+- by URL, e.g. "https://github.com/OWNER/REPO"`,
 }
 
 var repoCloneCmd = &cobra.Command{
@@ -75,18 +69,9 @@ To pass 'git clone' flags, separate them with '--'.`,
 var repoCreateCmd = &cobra.Command{
 	Use:   "create [<name>]",
 	Short: "Create a new repository",
-	Long:  `Create a new GitHub repository`,
-	Example: utils.Bold("$ gh repo create") + `
-Will create a repository on your account using the name of your current directory
-
-` + utils.Bold("$ gh repo create my-project") + `
-Will create a repository on your account using the name 'my-project'
-
-` + utils.Bold("$ gh repo create cli/my-project") + `
-Will create a repository in the organization 'cli' using the name 'my-project'`,
-	Annotations: map[string]string{"help:arguments": `A repository can be supplied as an argument in any of the following formats:
-- <OWNER/REPO>
-- by URL, e.g. "https://github.com/OWNER/REPO"`},
+	Long: `Create a new GitHub repository.
+
+Use the "ORG/NAME" syntax to create a repository within your organization.`,
 	RunE: repoCreate,
 }
 
diff --git a/command/root.go b/command/root.go
index 12979ad5f..05e864eb7 100644
--- a/command/root.go
+++ b/command/root.go
@@ -34,6 +34,7 @@ var Version = "DEV"
 var BuildDate = "" // YYYY-MM-DD
 
 var versionOutput = ""
+var cobraDefaultHelpFunc func(*cobra.Command, []string)
 
 func init() {
 	if Version == "DEV" {
@@ -57,11 +58,9 @@ func init() {
 	// TODO:
 	// RootCmd.PersistentFlags().BoolP("verbose", "V", false, "enable verbose output")
 
+	cobraDefaultHelpFunc = RootCmd.HelpFunc()
 	RootCmd.SetHelpFunc(rootHelpFunc)
 
-	// This will silence the usage func on error
-	RootCmd.SetUsageFunc(func(_ *cobra.Command) error { return nil })
-
 	RootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
 		if err == pflag.ErrHelp {
 			return err
@@ -96,13 +95,6 @@ var RootCmd = &cobra.Command{
 
 	SilenceErrors: true,
 	SilenceUsage:  true,
-	Example: `$ gh issue create
-$ gh repo clone
-$ gh pr checkout 321`,
-	Annotations: map[string]string{
-		"help:feedback": `
-Fill out our feedback form https://forms.gle/umxd3h31c7aMQFKG7
-Open an issue using “gh issue create -R cli/cli”`},
 }
 
 var versionCmd = &cobra.Command{
@@ -328,6 +320,100 @@ func determineBaseRepo(apiClient *api.Client, cmd *cobra.Command, ctx context.Co
 	return baseRepo, nil
 }
 
+func rootHelpFunc(command *cobra.Command, args []string) {
+	if command != RootCmd {
+		// Display helpful error message in case subcommand name was mistyped.
+		// This matches Cobra's behavior for root command, which Cobra
+		// confusingly doesn't apply to nested commands.
+		if command.Parent() == RootCmd && len(args) >= 2 {
+			if command.SuggestionsMinimumDistance <= 0 {
+				command.SuggestionsMinimumDistance = 2
+			}
+			candidates := command.SuggestionsFor(args[1])
+
+			errOut := command.OutOrStderr()
+			fmt.Fprintf(errOut, "unknown command %q for %q\n", args[1], "gh "+args[0])
+
+			if len(candidates) > 0 {
+				fmt.Fprint(errOut, "\nDid you mean this?\n")
+				for _, c := range candidates {
+					fmt.Fprintf(errOut, "\t%s\n", c)
+				}
+				fmt.Fprint(errOut, "\n")
+			}
+
+			oldOut := command.OutOrStdout()
+			command.SetOut(errOut)
+			defer command.SetOut(oldOut)
+		}
+		cobraDefaultHelpFunc(command, args)
+		return
+	}
+
+	type helpEntry struct {
+		Title string
+		Body  string
+	}
+
+	coreCommandNames := []string{"issue", "pr", "repo"}
+	var coreCommands []string
+	var additionalCommands []string
+	for _, c := range command.Commands() {
+		if c.Short == "" {
+			continue
+		}
+		s := "  " + rpad(c.Name()+":", c.NamePadding()) + c.Short
+		if includes(coreCommandNames, c.Name()) {
+			coreCommands = append(coreCommands, s)
+		} else if !c.Hidden {
+			additionalCommands = append(additionalCommands, s)
+		}
+	}
+
+	helpEntries := []helpEntry{
+		{
+			"",
+			command.Long},
+		{"USAGE", command.Use},
+		{"CORE COMMANDS", strings.Join(coreCommands, "\n")},
+		{"ADDITIONAL COMMANDS", strings.Join(additionalCommands, "\n")},
+		{"FLAGS", strings.TrimRight(command.LocalFlags().FlagUsages(), "\n")},
+		{"EXAMPLES", `
+  $ gh issue create
+  $ gh repo clone
+  $ gh pr checkout 321`},
+		{"LEARN MORE", `
+  Use "gh <command> <subcommand> --help" for more information about a command.
+  Read the manual at http://cli.github.com/manual`},
+		{"FEEDBACK", `
+  Fill out our feedback form https://forms.gle/umxd3h31c7aMQFKG7
+  Open an issue using “gh issue create -R cli/cli”`},
+	}
+
+	out := colorableOut(command)
+	for _, e := range helpEntries {
+		if e.Title != "" {
+			fmt.Fprintln(out, utils.Bold(e.Title))
+		}
+		fmt.Fprintln(out, strings.TrimLeft(e.Body, "\n")+"\n")
+	}
+}
+
+// rpad adds padding to the right of a string.
+func rpad(s string, padding int) string {
+	template := fmt.Sprintf("%%-%ds ", padding)
+	return fmt.Sprintf(template, s)
+}
+
+func includes(a []string, s string) bool {
+	for _, x := range a {
+		if x == s {
+			return true
+		}
+	}
+	return false
+}
+
 func formatRemoteURL(cmd *cobra.Command, fullRepoName string) string {
 	ctx := contextForCommand(cmd)
 
diff --git a/command/title_body_survey.go b/command/title_body_survey.go
index d6fe11bbf..1dcf3c668 100644
--- a/command/title_body_survey.go
+++ b/command/title_body_survey.go
@@ -371,10 +371,8 @@ func titleBodySurvey(cmd *cobra.Command, issueState *issueMetadataState, apiClie
 		issueState.Assignees = values.Assignees
 		issueState.Labels = values.Labels
 		issueState.Projects = values.Projects
-		issueState.Milestones = []string{values.Milestone}
-
-		if len(issueState.Milestones) > 0 && issueState.Milestones[0] == noMilestone {
-			issueState.Milestones = issueState.Milestones[0:0]
+		if values.Milestone != "" && values.Milestone != noMilestone {
+			issueState.Milestones = []string{values.Milestone}
 		}
 
 		allowPreview = !issueState.HasMetadata()
diff --git a/docs/triage.md b/docs/triage.md
deleted file mode 100644
index 95e1bf852..000000000
--- a/docs/triage.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Triage role
-
-As we get more issues and pull requests opened on the GitHub CLI, we've decided on a weekly rotation
-triage role. The initial expectation is that the person in the role for the week spends no more than
-1-2 hours a day on this work; we can refine that as needed.
-
-# Incoming issues
-
-just imagine a flowchart
-
-- can this be closed outright?
-  - e.g. spam/junk
-  - close without comment
-- do we not want to do it?
-  - e.g. have already discussed not wanting to do or duplicate issue
-  - comment acknowledging receipt
-  - close
-- do we want to do it?
-  - e.g. bugs or things we have discussed before
-  - comment acknowledging it
-  - label appropriately (examples include `enhancement` or `bug`)
-  - add to project TODO column if appropriate, otherwise just leave it labeled
-- is it intriguing but needs discussion?
-  - label `needs-design` if design input is needed, ping
-  - label `needs-investigation` if engineering research is required before action can be taken
-  - ping engineers if eng needed
-  - ping product if it's about future directions/roadamp/big changes
-- does it need more info from the issue author?
-  - ask the user for that
-  - add `needs-user-input` label
-- is it a user asking for help and you have all the info you need to help?
-  - try and help
-
-# Incoming PRs
-
-just imagine a flowchart
-
-- can it be closed outright?
-  - ie spam/junk
-- do we not want to do it?
-  - ie have already discussed not wanting to do, duplicate issue
-  - comment acknowledging receipt
-  - close
-- is it intriguing but needs discussion?
-  - request an issue
-  - close
-- is it something we want to include?
-  - add `community` label
-  - add to `needs review` column
-
-# Weekly PR audit
-
-In the interest of not letting our open PR list get out of hand (20+ total PRs _or_ multiple PRs
-over a few months old), try to audit open PRs each week with the goal of getting them merged and/or
-closed. It's likely too much work to deal with every PR, but even getting a few closer to done is
-helpful.
-
-For each PR, ask:
-
-- is this too stale? close with comment
-- is this really close but author is absent? push commits to finish, request review
-- is this waiting on triage? go through the PR triage flow
diff --git a/pkg/cmd/api/api.go b/pkg/cmd/api/api.go
index b4a8dbdff..b828c607c 100644
--- a/pkg/cmd/api/api.go
+++ b/pkg/cmd/api/api.go
@@ -103,16 +103,13 @@ func apiRun(opts *ApiOptions) error {
 	}
 
 	if opts.RequestInputFile != "" {
-		file, size, err := openUserFile(opts.RequestInputFile, opts.IO.In)
+		file, err := openUserFile(opts.RequestInputFile, opts.IO.In)
 		if err != nil {
 			return err
 		}
 		defer file.Close()
 		requestPath = addQuery(requestPath, params)
 		requestBody = file
-		if size >= 0 {
-			requestHeaders = append([]string{fmt.Sprintf("Content-Length: %d", size)}, requestHeaders...)
-		}
 	}
 
 	httpClient, err := opts.HttpClient()
@@ -243,36 +240,19 @@ func magicFieldValue(v string, stdin io.ReadCloser) (interface{}, error) {
 }
 
 func readUserFile(fn string, stdin io.ReadCloser) ([]byte, error) {
-	var r io.ReadCloser
-	if fn == "-" {
-		r = stdin
-	} else {
-		var err error
-		r, err = os.Open(fn)
-		if err != nil {
-			return nil, err
-		}
+	r, err := openUserFile(fn, stdin)
+	if err != nil {
+		return nil, err
 	}
 	defer r.Close()
 	return ioutil.ReadAll(r)
 }
 
-func openUserFile(fn string, stdin io.ReadCloser) (io.ReadCloser, int64, error) {
+func openUserFile(fn string, stdin io.ReadCloser) (io.ReadCloser, error) {
 	if fn == "-" {
-		return stdin, -1, nil
+		return stdin, nil
 	}
-
-	r, err := os.Open(fn)
-	if err != nil {
-		return r, -1, err
-	}
-
-	s, err := os.Stat(fn)
-	if err != nil {
-		return r, -1, err
-	}
-
-	return r, s.Size(), nil
+	return os.Open(fn)
 }
 
 func parseErrorResponse(r io.Reader, statusCode int) (io.Reader, string, error) {
diff --git a/pkg/cmd/api/http.go b/pkg/cmd/api/http.go
index e393bb593..4db21b286 100644
--- a/pkg/cmd/api/http.go
+++ b/pkg/cmd/api/http.go
@@ -7,7 +7,6 @@ import (
 	"io"
 	"net/http"
 	"net/url"
-	"strconv"
 	"strings"
 )
 
@@ -63,16 +62,7 @@ func httpRequest(client *http.Client, method string, p string, params interface{
 		if idx == -1 {
 			return nil, fmt.Errorf("header %q requires a value separated by ':'", h)
 		}
-		name, value := h[0:idx], strings.TrimSpace(h[idx+1:])
-		if strings.EqualFold(name, "Content-Length") {
-			length, err := strconv.ParseInt(value, 10, 0)
-			if err != nil {
-				return nil, err
-			}
-			req.ContentLength = length
-		} else {
-			req.Header.Add(name, value)
-		}
+		req.Header.Add(h[0:idx], strings.TrimSpace(h[idx+1:]))
 	}
 	if bodyIsJSON && req.Header.Get("Content-Type") == "" {
 		req.Header.Set("Content-Type", "application/json; charset=utf-8")
diff --git a/utils/color.go b/utils/color.go
index 4940fe26b..b2b2add21 100644
--- a/utils/color.go
+++ b/utils/color.go
@@ -9,20 +9,10 @@ import (
 	"github.com/mgutz/ansi"
 )
 
-var (
-	_isColorEnabled                                    bool = true
-	_isStdoutTerminal, checkedTerminal, checkedNoColor bool
-
-	// Outputs ANSI color if stdout is a tty
-	Magenta = makeColorFunc("magenta")
-	Cyan    = makeColorFunc("cyan")
-	Red     = makeColorFunc("red")
-	Yellow  = makeColorFunc("yellow")
-	Blue    = makeColorFunc("blue")
-	Green   = makeColorFunc("green")
-	Gray    = makeColorFunc("black+h")
-	Bold    = makeColorFunc("default+b")
-)
+var _isColorEnabled = true
+var _isStdoutTerminal = false
+var checkedTerminal = false
+var checkedNoColor = false
 
 func isStdoutTerminal() bool {
 	if !checkedTerminal {
@@ -59,3 +49,27 @@ func isColorEnabled() bool {
 	}
 	return _isColorEnabled
 }
+
+// Magenta outputs ANSI color if stdout is a tty
+var Magenta = makeColorFunc("magenta")
+
+// Cyan outputs ANSI color if stdout is a tty
+var Cyan = makeColorFunc("cyan")
+
+// Red outputs ANSI color if stdout is a tty
+var Red = makeColorFunc("red")
+
+// Yellow outputs ANSI color if stdout is a tty
+var Yellow = makeColorFunc("yellow")
+
+// Blue outputs ANSI color if stdout is a tty
+var Blue = makeColorFunc("blue")
+
+// Green outputs ANSI color if stdout is a tty
+var Green = makeColorFunc("green")
+
+// Gray outputs ANSI color if stdout is a tty
+var Gray = makeColorFunc("black+h")
+
+// Bold outputs ANSI color if stdout is a tty
+var Bold = makeColorFunc("default+b")


Test patch:
diff --git a/command/pr_review_test.go b/command/pr_review_test.go
index 2c2673db4..612f6c574 100644
--- a/command/pr_review_test.go
+++ b/command/pr_review_test.go
@@ -213,10 +213,10 @@ func TestPRReview(t *testing.T) {
 		ExpectedBody  string
 	}
 	cases := []c{
-		{`pr review --request-changes -b"bad"`, "REQUEST_CHANGES", "bad"},
-		{`pr review --approve`, "APPROVE", ""},
-		{`pr review --approve -b"hot damn"`, "APPROVE", "hot damn"},
-		{`pr review --comment --body "i donno"`, "COMMENT", "i donno"},
+		c{`pr review --request-changes -b"bad"`, "REQUEST_CHANGES", "bad"},
+		c{`pr review --approve`, "APPROVE", ""},
+		c{`pr review --approve -b"hot damn"`, "APPROVE", "hot damn"},
+		c{`pr review --comment --body "i donno"`, "COMMENT", "i donno"},
 	}
 
 	for _, kase := range cases {
diff --git a/pkg/cmd/api/api_test.go b/pkg/cmd/api/api_test.go
index 100c1257e..c121455db 100644
--- a/pkg/cmd/api/api_test.go
+++ b/pkg/cmd/api/api_test.go
@@ -247,78 +247,41 @@ func Test_apiRun(t *testing.T) {
 }
 
 func Test_apiRun_inputFile(t *testing.T) {
-	tests := []struct {
-		name          string
-		inputFile     string
-		inputContents []byte
+	io, stdin, _, _ := iostreams.Test()
+	resp := &http.Response{StatusCode: 204}
 
-		contentLength    int64
-		expectedContents []byte
-	}{
-		{
-			name:          "stdin",
-			inputFile:     "-",
-			inputContents: []byte("I WORK OUT"),
-			contentLength: 0,
-		},
-		{
-			name:          "from file",
-			inputFile:     "gh-test-file",
-			inputContents: []byte("I WORK OUT"),
-			contentLength: 10,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			io, stdin, _, _ := iostreams.Test()
-			resp := &http.Response{StatusCode: 204}
+	options := ApiOptions{
+		RequestPath:      "hello",
+		RequestInputFile: "-",
+		RawFields:        []string{"a=b", "c=d"},
 
-			inputFile := tt.inputFile
-			if tt.inputFile == "-" {
-				_, _ = stdin.Write(tt.inputContents)
-			} else {
-				f, err := ioutil.TempFile("", tt.inputFile)
-				if err != nil {
-					t.Fatal(err)
-				}
-				_, _ = f.Write(tt.inputContents)
-				f.Close()
-				t.Cleanup(func() { os.Remove(f.Name()) })
-				inputFile = f.Name()
+		IO: io,
+		HttpClient: func() (*http.Client, error) {
+			var tr roundTripper = func(req *http.Request) (*http.Response, error) {
+				resp.Request = req
+				return resp, nil
 			}
+			return &http.Client{Transport: tr}, nil
+		},
+	}
 
-			var bodyBytes []byte
-			options := ApiOptions{
-				RequestPath:      "hello",
-				RequestInputFile: inputFile,
-				RawFields:        []string{"a=b", "c=d"},
+	fmt.Fprintln(stdin, "I WORK OUT")
 
-				IO: io,
-				HttpClient: func() (*http.Client, error) {
-					var tr roundTripper = func(req *http.Request) (*http.Response, error) {
-						var err error
-						if bodyBytes, err = ioutil.ReadAll(req.Body); err != nil {
-							return nil, err
-						}
-						resp.Request = req
-						return resp, nil
-					}
-					return &http.Client{Transport: tr}, nil
-				},
-			}
+	err := apiRun(&options)
+	if err != nil {
+		t.Errorf("got error %v", err)
+	}
 
-			err := apiRun(&options)
-			if err != nil {
-				t.Errorf("got error %v", err)
-			}
+	assert.Equal(t, "POST", resp.Request.Method)
+	assert.Equal(t, "/hello?a=b&c=d", resp.Request.URL.RequestURI())
+	assert.Equal(t, "", resp.Request.Header.Get("Content-Length"))
+	assert.Equal(t, "", resp.Request.Header.Get("Content-Type"))
 
-			assert.Equal(t, "POST", resp.Request.Method)
-			assert.Equal(t, "/hello?a=b&c=d", resp.Request.URL.RequestURI())
-			assert.Equal(t, tt.contentLength, resp.Request.ContentLength)
-			assert.Equal(t, "", resp.Request.Header.Get("Content-Type"))
-			assert.Equal(t, tt.inputContents, bodyBytes)
-		})
+	bb, err := ioutil.ReadAll(resp.Request.Body)
+	if err != nil {
+		t.Errorf("got error %v", err)
 	}
+	assert.Equal(t, "I WORK OUT\n", string(bb))
 }
 
 func Test_parseFields(t *testing.T) {
@@ -437,7 +400,7 @@ func Test_openUserFile(t *testing.T) {
 	f.Close()
 	t.Cleanup(func() { os.Remove(f.Name()) })
 
-	file, length, err := openUserFile(f.Name(), nil)
+	file, err := openUserFile(f.Name(), nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -448,6 +411,5 @@ func Test_openUserFile(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	assert.Equal(t, int64(13), length)
 	assert.Equal(t, "file contents", string(fb))
 }