Repository: cli/cli
Pull request #6405 (2022-10-08 07:51:33)

Upgrade devcontainer config
<!--
  Thank you for contributing to GitHub CLI!
  To reference an open issue, please write this in your description: `Fixes #NUMBER`
-->

Upgrades this repo's devcontainer to adopt the latest and greatest devcontainer features:
- Uses an image from the new devcontainers/images repo
- Adds the GitHub CLI feature
- Adds SSH feature

Create a new codespace using this devcontainer: https://github.com/codespaces/new/?repo=543812098&ref=jungaretti%2Fnew-devcontainer

cliAutomation: Hi! Thanks for the pull request. Please ensure that this change is linked to an issue by mentioning an issue number in the description of the pull request. If this pull request would close the issue, please put the word 'Fixes' before the issue number somewhere in the pull request body. If this is a tiny change like fixing a typo, feel free to ignore this message.

Patch:
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
deleted file mode 100644
index 34448d38b..000000000
--- a/.devcontainer/Dockerfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.234.0/containers/go/.devcontainer/base.Dockerfile
-
-# VARIANT Defined in devcontainer.json
-ARG VARIANT="1.18" 
-FROM mcr.microsoft.com/vscode/devcontainers/go:0-${VARIANT}
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index cdb10785e..10bf64350 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,22 +1,24 @@
 {
-    "extensions": [
-		"golang.go"
-	],
-	"build": {
-		"dockerfile": "Dockerfile",
-		"args": {
-			"VARIANT": "1.18"
-		}
+	"image": "mcr.microsoft.com/devcontainers/go:1.18",
+	"features": {
+		"ghcr.io/devcontainers/features/sshd:1": {}
 	},
-	"settings": {
-		"go.toolsManagement.checkForUpdates": "local",
-		"go.useLanguageServer": true,
-		"go.gopath": "/go"
+	"remoteUser": "vscode",
+	"customizations": {
+		"vscode": {
+			"extensions": [
+				"golang.go"
+			],
+			"settings": {
+				"go.toolsManagement.checkForUpdates": "local",
+				"go.useLanguageServer": true,
+				"go.gopath": "/go"
+			}
+		}
 	},
 	"runArgs": [
 		"--cap-add=SYS_PTRACE",
 		"--security-opt",
 		"seccomp=unconfined"
-	],
-	"remoteUser": "vscode"
+	]
 }
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 99a52d6d6..000000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "search.exclude": {
-        "vendor/**": true
-    }
-}
\ No newline at end of file
diff --git a/pkg/cmd/search/shared/shared.go b/pkg/cmd/search/shared/shared.go
index f670548b3..d095e8769 100644
--- a/pkg/cmd/search/shared/shared.go
+++ b/pkg/cmd/search/shared/shared.go
@@ -114,12 +114,12 @@ func displayIssueResults(io *iostreams.IOStreams, now time.Time, et EntityType,
 			issueNum = "#" + issueNum
 		}
 		if issue.IsPullRequest() {
-			tp.AddField(issueNum, nil, cs.ColorFromString(colorForPRState(issue.State)))
+			tp.AddField(issueNum, nil, cs.ColorFromString(colorForPRState(issue.State())))
 		} else {
-			tp.AddField(issueNum, nil, cs.ColorFromString(colorForIssueState(issue.State, issue.StateReason)))
+			tp.AddField(issueNum, nil, cs.ColorFromString(colorForIssueState(issue.State(), issue.StateReason)))
 		}
 		if !tp.IsTTY() {
-			tp.AddField(issue.State, nil, nil)
+			tp.AddField(issue.State(), nil, nil)
 		}
 		tp.AddField(text.RemoveExcessiveWhitespace(issue.Title), nil, nil)
 		tp.AddField(listIssueLabels(&issue, cs, tp.IsTTY()), nil, nil)
diff --git a/pkg/search/result.go b/pkg/search/result.go
index 4447f48ee..6ef1b8bc0 100644
--- a/pkg/search/result.go
+++ b/pkg/search/result.go
@@ -117,28 +117,42 @@ type User struct {
 }
 
 type Issue struct {
-	Assignees         []User           `json:"assignees"`
-	Author            User             `json:"user"`
-	AuthorAssociation string           `json:"author_association"`
-	Body              string           `json:"body"`
-	ClosedAt          time.Time        `json:"closed_at"`
-	CommentsCount     int              `json:"comments"`
-	CreatedAt         time.Time        `json:"created_at"`
-	ID                string           `json:"node_id"`
-	Labels            []Label          `json:"labels"`
-	IsLocked          bool             `json:"locked"`
-	Number            int              `json:"number"`
-	PullRequestLinks  PullRequestLinks `json:"pull_request"`
-	RepositoryURL     string           `json:"repository_url"`
-	State             string           `json:"state"`
-	StateReason       string           `json:"state_reason"`
-	Title             string           `json:"title"`
-	URL               string           `json:"html_url"`
-	UpdatedAt         time.Time        `json:"updated_at"`
+	Assignees         []User      `json:"assignees"`
+	Author            User        `json:"user"`
+	AuthorAssociation string      `json:"author_association"`
+	Body              string      `json:"body"`
+	ClosedAt          time.Time   `json:"closed_at"`
+	CommentsCount     int         `json:"comments"`
+	CreatedAt         time.Time   `json:"created_at"`
+	ID                string      `json:"node_id"`
+	Labels            []Label     `json:"labels"`
+	IsLocked          bool        `json:"locked"`
+	Number            int         `json:"number"`
+	PullRequest       PullRequest `json:"pull_request"`
+	RepositoryURL     string      `json:"repository_url"`
+	// StateInternal should not be used directly. Use State() instead.
+	StateInternal string    `json:"state"`
+	StateReason   string    `json:"state_reason"`
+	Title         string    `json:"title"`
+	URL           string    `json:"html_url"`
+	UpdatedAt     time.Time `json:"updated_at"`
 }
 
-type PullRequestLinks struct {
-	URL string `json:"html_url"`
+type PullRequest struct {
+	URL      string    `json:"html_url"`
+	MergedAt time.Time `json:"merged_at"`
+}
+
+// the state of an issue or a pull request,
+// may be either open or closed.
+// for a pull request, the "merged" state is
+// inferred from a value for merged_at and
+// which we take return instead of the "closed" state.
+func (issue Issue) State() string {
+	if !issue.PullRequest.MergedAt.IsZero() {
+		return "merged"
+	}
+	return issue.StateInternal
 }
 
 type Label struct {
@@ -175,7 +189,7 @@ func (repo Repository) ExportData(fields []string) map[string]interface{} {
 }
 
 func (issue Issue) IsPullRequest() bool {
-	return issue.PullRequestLinks.URL != ""
+	return issue.PullRequest.URL != ""
 }
 
 func (issue Issue) ExportData(fields []string) map[string]interface{} {
@@ -220,6 +234,8 @@ func (issue Issue) ExportData(fields []string) map[string]interface{} {
 				"name":          name,
 				"nameWithOwner": nameWithOwner,
 			}
+		case "state":
+			data[f] = issue.State()
 		default:
 			sf := fieldByName(v, f)
 			data[f] = sf.Interface()


Test patch:
diff --git a/pkg/cmd/search/shared/shared_test.go b/pkg/cmd/search/shared/shared_test.go
index fe6c8c57b..8c4d4ca45 100644
--- a/pkg/cmd/search/shared/shared_test.go
+++ b/pkg/cmd/search/shared/shared_test.go
@@ -54,9 +54,9 @@ func TestSearchIssues(t *testing.T) {
 						return search.IssuesResult{
 							IncompleteResults: false,
 							Items: []search.Issue{
-								{RepositoryURL: "github.com/test/cli", Number: 123, State: "open", Title: "something broken", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
-								{RepositoryURL: "github.com/what/what", Number: 456, State: "closed", Title: "feature request", Labels: []search.Label{{Name: "enhancement"}}, UpdatedAt: updatedAt},
-								{RepositoryURL: "github.com/blah/test", Number: 789, State: "open", Title: "some title", UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/test/cli", Number: 123, StateInternal: "open", Title: "something broken", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/what/what", Number: 456, StateInternal: "closed", Title: "feature request", Labels: []search.Label{{Name: "enhancement"}}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/blah/test", Number: 789, StateInternal: "open", Title: "some title", UpdatedAt: updatedAt},
 							},
 							Total: 300,
 						}, nil
@@ -76,8 +76,8 @@ func TestSearchIssues(t *testing.T) {
 						return search.IssuesResult{
 							IncompleteResults: false,
 							Items: []search.Issue{
-								{RepositoryURL: "github.com/test/cli", Number: 123, State: "open", Title: "bug", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
-								{RepositoryURL: "github.com/what/what", Number: 456, State: "open", Title: "fix bug", Labels: []search.Label{{Name: "fix"}}, PullRequestLinks: search.PullRequestLinks{URL: "someurl"}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/test/cli", Number: 123, StateInternal: "open", Title: "bug", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/what/what", Number: 456, StateInternal: "open", Title: "fix bug", Labels: []search.Label{{Name: "fix"}}, PullRequest: search.PullRequest{URL: "someurl"}, UpdatedAt: updatedAt},
 							},
 							Total: 300,
 						}, nil
@@ -97,9 +97,9 @@ func TestSearchIssues(t *testing.T) {
 						return search.IssuesResult{
 							IncompleteResults: false,
 							Items: []search.Issue{
-								{RepositoryURL: "github.com/test/cli", Number: 123, State: "open", Title: "something broken", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
-								{RepositoryURL: "github.com/what/what", Number: 456, State: "closed", Title: "feature request", Labels: []search.Label{{Name: "enhancement"}}, UpdatedAt: updatedAt},
-								{RepositoryURL: "github.com/blah/test", Number: 789, State: "open", Title: "some title", UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/test/cli", Number: 123, StateInternal: "open", Title: "something broken", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/what/what", Number: 456, StateInternal: "closed", Title: "feature request", Labels: []search.Label{{Name: "enhancement"}}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/blah/test", Number: 789, StateInternal: "open", Title: "some title", UpdatedAt: updatedAt},
 							},
 							Total: 300,
 						}, nil
@@ -118,8 +118,8 @@ func TestSearchIssues(t *testing.T) {
 						return search.IssuesResult{
 							IncompleteResults: false,
 							Items: []search.Issue{
-								{RepositoryURL: "github.com/test/cli", Number: 123, State: "open", Title: "bug", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
-								{RepositoryURL: "github.com/what/what", Number: 456, State: "open", Title: "fix bug", Labels: []search.Label{{Name: "fix"}}, PullRequestLinks: search.PullRequestLinks{URL: "someurl"}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/test/cli", Number: 123, StateInternal: "open", Title: "bug", Labels: []search.Label{{Name: "bug"}, {Name: "p1"}}, UpdatedAt: updatedAt},
+								{RepositoryURL: "github.com/what/what", Number: 456, StateInternal: "open", Title: "fix bug", Labels: []search.Label{{Name: "fix"}}, PullRequest: search.PullRequest{URL: "someurl"}, UpdatedAt: updatedAt},
 							},
 							Total: 300,
 						}, nil
diff --git a/pkg/search/result_test.go b/pkg/search/result_test.go
index ba173e591..c933eb304 100644
--- a/pkg/search/result_test.go
+++ b/pkg/search/result_test.go
@@ -68,6 +68,26 @@ func TestIssueExportData(t *testing.T) {
 			},
 			output: `{"assignees":[{"id":"","login":"test","type":""}],"body":"body","commentsCount":1,"isLocked":true,"labels":[{"color":"","description":"","id":"","name":"label1"},{"color":"","description":"","id":"","name":"label2"}],"repository":{"name":"repo","nameWithOwner":"owner/repo"},"title":"title","updatedAt":"2021-02-28T12:30:00Z"}`,
 		},
+		{
+			name:   "state when issue",
+			fields: []string{"isPullRequest", "state"},
+			issue: Issue{
+				StateInternal: "closed",
+			},
+			output: `{"isPullRequest":false,"state":"closed"}`,
+		},
+		{
+			name:   "state when pull request",
+			fields: []string{"isPullRequest", "state"},
+			issue: Issue{
+				PullRequest: PullRequest{
+					MergedAt: time.Now(),
+					URL:      "a-url",
+				},
+				StateInternal: "closed",
+			},
+			output: `{"isPullRequest":true,"state":"merged"}`,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {