Merge pull request #2949 from cli/edit-improvements
Change behavior of slice flags for issue edit and pr edit commands
This commit is contained in:
commit
4e5aa91fac
9 changed files with 651 additions and 407 deletions
|
|
@ -49,6 +49,14 @@ type Assignees struct {
|
|||
TotalCount int
|
||||
}
|
||||
|
||||
func (a Assignees) Logins() []string {
|
||||
logins := make([]string, len(a.Nodes))
|
||||
for i, a := range a.Nodes {
|
||||
logins[i] = a.Login
|
||||
}
|
||||
return logins
|
||||
}
|
||||
|
||||
type Labels struct {
|
||||
Nodes []struct {
|
||||
Name string
|
||||
|
|
@ -56,6 +64,14 @@ type Labels struct {
|
|||
TotalCount int
|
||||
}
|
||||
|
||||
func (l Labels) Names() []string {
|
||||
names := make([]string, len(l.Nodes))
|
||||
for i, l := range l.Nodes {
|
||||
names[i] = l.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
type ProjectCards struct {
|
||||
Nodes []struct {
|
||||
Project struct {
|
||||
|
|
@ -68,6 +84,14 @@ type ProjectCards struct {
|
|||
TotalCount int
|
||||
}
|
||||
|
||||
func (p ProjectCards) ProjectNames() []string {
|
||||
names := make([]string, len(p.Nodes))
|
||||
for i, c := range p.Nodes {
|
||||
names[i] = c.Project.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
type Milestone struct {
|
||||
Title string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,32 +80,10 @@ type PullRequest struct {
|
|||
}
|
||||
}
|
||||
}
|
||||
Assignees struct {
|
||||
Nodes []struct {
|
||||
Login string
|
||||
}
|
||||
TotalCount int
|
||||
}
|
||||
Labels struct {
|
||||
Nodes []struct {
|
||||
Name string
|
||||
}
|
||||
TotalCount int
|
||||
}
|
||||
ProjectCards struct {
|
||||
Nodes []struct {
|
||||
Project struct {
|
||||
Name string
|
||||
}
|
||||
Column struct {
|
||||
Name string
|
||||
}
|
||||
}
|
||||
TotalCount int
|
||||
}
|
||||
Milestone struct {
|
||||
Title string
|
||||
}
|
||||
Assignees Assignees
|
||||
Labels Labels
|
||||
ProjectCards ProjectCards
|
||||
Milestone Milestone
|
||||
Comments Comments
|
||||
ReactionGroups ReactionGroups
|
||||
Reviews PullRequestReviews
|
||||
|
|
@ -123,6 +101,14 @@ type ReviewRequests struct {
|
|||
TotalCount int
|
||||
}
|
||||
|
||||
func (r ReviewRequests) Logins() []string {
|
||||
logins := make([]string, len(r.Nodes))
|
||||
for i, a := range r.Nodes {
|
||||
logins[i] = a.RequestedReviewer.Login
|
||||
}
|
||||
return logins
|
||||
}
|
||||
|
||||
type NotFoundError struct {
|
||||
error
|
||||
}
|
||||
|
|
@ -816,6 +802,7 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter
|
|||
reviewParams["teamIds"] = ids
|
||||
}
|
||||
|
||||
//TODO: How much work to extract this into own method and use for create and edit?
|
||||
if len(reviewParams) > 0 {
|
||||
reviewQuery := `
|
||||
mutation PullRequestCreateRequestReviews($input: RequestReviewsInput!) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
|
@ -497,7 +496,7 @@ func (m *RepoMetadataResult) MilestoneToID(title string) (string, error) {
|
|||
return m.ID, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("not found")
|
||||
return "", fmt.Errorf("'%s' not found", title)
|
||||
}
|
||||
|
||||
func (m *RepoMetadataResult) Merge(m2 *RepoMetadataResult) {
|
||||
|
|
|
|||
|
|
@ -47,11 +47,10 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
Short: "Edit an issue",
|
||||
Example: heredoc.Doc(`
|
||||
$ gh issue edit 23 --title "I found a bug" --body "Nothing works"
|
||||
$ gh issue edit 23 --label "bug,help wanted"
|
||||
$ gh issue edit 23 --label bug --label "help wanted"
|
||||
$ gh issue edit 23 --assignee monalisa,hubot
|
||||
$ gh issue edit 23 --assignee @me
|
||||
$ gh issue edit 23 --project "Roadmap"
|
||||
$ gh issue edit 23 --add-label "bug,help wanted" --remove-label "core"
|
||||
$ gh issue edit 23 --add-assignee @me --remove-assignee monalisa,hubot
|
||||
$ gh issue edit 23 --add-project "Roadmap" --remove-project v1,v2
|
||||
$ gh issue edit 23 --milestone "Version 1"
|
||||
`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -62,22 +61,22 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
|
||||
flags := cmd.Flags()
|
||||
if flags.Changed("title") {
|
||||
opts.Editable.TitleEdited = true
|
||||
opts.Editable.Title.Edited = true
|
||||
}
|
||||
if flags.Changed("body") {
|
||||
opts.Editable.BodyEdited = true
|
||||
opts.Editable.Body.Edited = true
|
||||
}
|
||||
if flags.Changed("assignee") {
|
||||
opts.Editable.AssigneesEdited = true
|
||||
if flags.Changed("add-assignee") || flags.Changed("remove-assignee") {
|
||||
opts.Editable.Assignees.Edited = true
|
||||
}
|
||||
if flags.Changed("label") {
|
||||
opts.Editable.LabelsEdited = true
|
||||
if flags.Changed("add-label") || flags.Changed("remove-label") {
|
||||
opts.Editable.Labels.Edited = true
|
||||
}
|
||||
if flags.Changed("project") {
|
||||
opts.Editable.ProjectsEdited = true
|
||||
if flags.Changed("add-project") || flags.Changed("remove-project") {
|
||||
opts.Editable.Projects.Edited = true
|
||||
}
|
||||
if flags.Changed("milestone") {
|
||||
opts.Editable.MilestoneEdited = true
|
||||
opts.Editable.Milestone.Edited = true
|
||||
}
|
||||
|
||||
if !opts.Editable.Dirty() {
|
||||
|
|
@ -85,7 +84,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
}
|
||||
|
||||
if opts.Interactive && !opts.IO.CanPrompt() {
|
||||
return &cmdutil.FlagError{Err: errors.New("--tile, --body, --assignee, --label, --project, or --milestone required when not running interactively")}
|
||||
return &cmdutil.FlagError{Err: errors.New("field to edit flag required when not running interactively")}
|
||||
}
|
||||
|
||||
if runF != nil {
|
||||
|
|
@ -96,12 +95,15 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.Editable.Title, "title", "t", "", "Revise the issue title.")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Body, "body", "b", "", "Revise the issue body.")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Assignees, "assignee", "a", nil, "Set assigned people by their `login`. Use \"@me\" to self-assign.")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Labels, "label", "l", nil, "Set the issue labels by `name`")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Projects, "project", "p", nil, "Set the projects the issue belongs to by `name`")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Milestone, "milestone", "m", "", "Set the milestone the issue belongs to by `name`")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Title.Value, "title", "t", "", "Set the new title.")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Body.Value, "body", "b", "", "Set the new body.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Add, "add-assignee", nil, "Add assigned users by their `login`. Use \"@me\" to assign yourself.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Remove, "remove-assignee", nil, "Remove assigned users by their `login`. Use \"@me\" to unassign yourself.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Add, "add-label", nil, "Add labels by `name`")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Remove, "remove-label", nil, "Remove labels by `name`")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Add, "add-project", nil, "Add the issue to projects by `name`")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the issue from projects by `name`")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Milestone.Value, "milestone", "m", "", "Edit the milestone the issue belongs to by `name`")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -119,12 +121,12 @@ func editRun(opts *EditOptions) error {
|
|||
}
|
||||
|
||||
editable := opts.Editable
|
||||
editable.TitleDefault = issue.Title
|
||||
editable.BodyDefault = issue.Body
|
||||
editable.AssigneesDefault = issue.Assignees
|
||||
editable.LabelsDefault = issue.Labels
|
||||
editable.ProjectsDefault = issue.ProjectCards
|
||||
editable.MilestoneDefault = issue.Milestone
|
||||
editable.Title.Default = issue.Title
|
||||
editable.Body.Default = issue.Body
|
||||
editable.Assignees.Default = issue.Assignees.Logins()
|
||||
editable.Labels.Default = issue.Labels.Names()
|
||||
editable.Projects.Default = issue.ProjectCards.ProjectNames()
|
||||
editable.Milestone.Default = issue.Milestone.Title
|
||||
|
||||
if opts.Interactive {
|
||||
err = opts.FieldsToEditSurvey(&editable)
|
||||
|
|
@ -167,24 +169,59 @@ func updateIssue(client *api.Client, repo ghrepo.Interface, id string, options p
|
|||
var err error
|
||||
params := githubv4.UpdateIssueInput{
|
||||
ID: id,
|
||||
Title: options.TitleParam(),
|
||||
Body: options.BodyParam(),
|
||||
Title: ghString(options.TitleValue()),
|
||||
Body: ghString(options.BodyValue()),
|
||||
}
|
||||
params.AssigneeIDs, err = options.AssigneesParam(client, repo)
|
||||
assigneeIds, err := options.AssigneeIds(client, repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.LabelIDs, err = options.LabelsParam()
|
||||
params.AssigneeIDs = ghIds(assigneeIds)
|
||||
labelIds, err := options.LabelIds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.ProjectIDs, err = options.ProjectsParam()
|
||||
params.LabelIDs = ghIds(labelIds)
|
||||
projectIds, err := options.ProjectIds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.MilestoneID, err = options.MilestoneParam()
|
||||
params.ProjectIDs = ghIds(projectIds)
|
||||
milestoneId, err := options.MilestoneId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.MilestoneID = ghId(milestoneId)
|
||||
return api.IssueUpdate(client, repo, params)
|
||||
}
|
||||
|
||||
func ghIds(s *[]string) *[]githubv4.ID {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
ids := make([]githubv4.ID, len(*s))
|
||||
for i, v := range *s {
|
||||
ids[i] = v
|
||||
}
|
||||
return &ids
|
||||
}
|
||||
|
||||
func ghId(s *string) *githubv4.ID {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
if *s == "" {
|
||||
r := githubv4.ID(nil)
|
||||
return &r
|
||||
}
|
||||
r := githubv4.ID(*s)
|
||||
return &r
|
||||
}
|
||||
|
||||
func ghString(s *string) *githubv4.String {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
r := githubv4.String(*s)
|
||||
return &r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,10 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Title: "test",
|
||||
TitleEdited: true,
|
||||
Title: prShared.EditableString{
|
||||
Value: "test",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
|
|
@ -54,44 +56,94 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Body: "test",
|
||||
BodyEdited: true,
|
||||
Body: prShared.EditableString{
|
||||
Value: "test",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "assignee flag",
|
||||
input: "23 --assignee monalisa,hubot",
|
||||
name: "add-assignee flag",
|
||||
input: "23 --add-assignee monalisa,hubot",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Assignees: []string{"monalisa", "hubot"},
|
||||
AssigneesEdited: true,
|
||||
Assignees: prShared.EditableSlice{
|
||||
Add: []string{"monalisa", "hubot"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "label flag",
|
||||
input: "23 --label feature,TODO,bug",
|
||||
name: "remove-assignee flag",
|
||||
input: "23 --remove-assignee monalisa,hubot",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Labels: []string{"feature", "TODO", "bug"},
|
||||
LabelsEdited: true,
|
||||
Assignees: prShared.EditableSlice{
|
||||
Remove: []string{"monalisa", "hubot"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "project flag",
|
||||
input: "23 --project Cleanup,Roadmap",
|
||||
name: "add-label flag",
|
||||
input: "23 --add-label feature,TODO,bug",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Projects: []string{"Cleanup", "Roadmap"},
|
||||
ProjectsEdited: true,
|
||||
Labels: prShared.EditableSlice{
|
||||
Add: []string{"feature", "TODO", "bug"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "remove-label flag",
|
||||
input: "23 --remove-label feature,TODO,bug",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Labels: prShared.EditableSlice{
|
||||
Remove: []string{"feature", "TODO", "bug"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "add-project flag",
|
||||
input: "23 --add-project Cleanup,Roadmap",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Projects: prShared.EditableSlice{
|
||||
Add: []string{"Cleanup", "Roadmap"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "remove-project flag",
|
||||
input: "23 --remove-project Cleanup,Roadmap",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Projects: prShared.EditableSlice{
|
||||
Remove: []string{"Cleanup", "Roadmap"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
|
|
@ -102,8 +154,10 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: prShared.Editable{
|
||||
Milestone: "GA",
|
||||
MilestoneEdited: true,
|
||||
Milestone: prShared.EditableString{
|
||||
Value: "GA",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
|
|
@ -163,18 +217,33 @@ func Test_editRun(t *testing.T) {
|
|||
SelectorArg: "123",
|
||||
Interactive: false,
|
||||
Editable: prShared.Editable{
|
||||
Title: "new title",
|
||||
TitleEdited: true,
|
||||
Body: "new body",
|
||||
BodyEdited: true,
|
||||
Assignees: []string{"monalisa", "hubot"},
|
||||
AssigneesEdited: true,
|
||||
Labels: []string{"feature", "TODO", "bug"},
|
||||
LabelsEdited: true,
|
||||
Projects: []string{"Cleanup", "Roadmap"},
|
||||
ProjectsEdited: true,
|
||||
Milestone: "GA",
|
||||
MilestoneEdited: true,
|
||||
Title: prShared.EditableString{
|
||||
Value: "new title",
|
||||
Edited: true,
|
||||
},
|
||||
Body: prShared.EditableString{
|
||||
Value: "new body",
|
||||
Edited: true,
|
||||
},
|
||||
Assignees: prShared.EditableSlice{
|
||||
Add: []string{"monalisa", "hubot"},
|
||||
Remove: []string{"octocat"},
|
||||
Edited: true,
|
||||
},
|
||||
Labels: prShared.EditableSlice{
|
||||
Add: []string{"feature", "TODO", "bug"},
|
||||
Remove: []string{"docs"},
|
||||
Edited: true,
|
||||
},
|
||||
Projects: prShared.EditableSlice{
|
||||
Add: []string{"Cleanup", "Roadmap"},
|
||||
Remove: []string{"Features"},
|
||||
Edited: true,
|
||||
},
|
||||
Milestone: prShared.EditableString{
|
||||
Value: "GA",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
FetchOptions: prShared.FetchOptions,
|
||||
},
|
||||
|
|
@ -191,21 +260,21 @@ func Test_editRun(t *testing.T) {
|
|||
SelectorArg: "123",
|
||||
Interactive: true,
|
||||
FieldsToEditSurvey: func(eo *prShared.Editable) error {
|
||||
eo.TitleEdited = true
|
||||
eo.BodyEdited = true
|
||||
eo.AssigneesEdited = true
|
||||
eo.LabelsEdited = true
|
||||
eo.ProjectsEdited = true
|
||||
eo.MilestoneEdited = true
|
||||
eo.Title.Edited = true
|
||||
eo.Body.Edited = true
|
||||
eo.Assignees.Edited = true
|
||||
eo.Labels.Edited = true
|
||||
eo.Projects.Edited = true
|
||||
eo.Milestone.Edited = true
|
||||
return nil
|
||||
},
|
||||
EditFieldsSurvey: func(eo *prShared.Editable, _ string) error {
|
||||
eo.Title = "new title"
|
||||
eo.Body = "new body"
|
||||
eo.Assignees = []string{"monalisa", "hubot"}
|
||||
eo.Labels = []string{"feature", "TODO", "bug"}
|
||||
eo.Projects = []string{"Cleanup", "Roadmap"}
|
||||
eo.Milestone = "GA"
|
||||
eo.Title.Value = "new title"
|
||||
eo.Body.Value = "new body"
|
||||
eo.Assignees.Value = []string{"monalisa", "hubot"}
|
||||
eo.Labels.Value = []string{"feature", "TODO", "bug"}
|
||||
eo.Projects.Value = []string{"Cleanup", "Roadmap"}
|
||||
eo.Milestone.Value = "GA"
|
||||
return nil
|
||||
},
|
||||
FetchOptions: prShared.FetchOptions,
|
||||
|
|
|
|||
|
|
@ -50,12 +50,11 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
Short: "Edit a pull request",
|
||||
Example: heredoc.Doc(`
|
||||
$ gh pr edit 23 --title "I found a bug" --body "Nothing works"
|
||||
$ gh pr edit 23 --label "bug,help wanted"
|
||||
$ gh pr edit 23 --label bug --label "help wanted"
|
||||
$ gh pr edit 23 --reviewer monalisa,hubot --reviewer myorg/team-name
|
||||
$ gh pr edit 23 --assignee monalisa,hubot
|
||||
$ gh pr edit 23 --assignee @me
|
||||
$ gh pr edit 23 --project "Roadmap"
|
||||
$ gh pr edit 23 --add-label "bug,help wanted" --remove-label "core"
|
||||
$ gh pr edit 23 --add-reviewer monalisa,hubot --remove-reviewer myorg/team-name
|
||||
$ gh pr edit 23 --add-assignee @me --remove-assignee monalisa,hubot
|
||||
$ gh pr edit 23 --add-project "Roadmap" --remove-project v1,v2
|
||||
$ gh pr edit 23 --milestone "Version 1"
|
||||
`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -66,25 +65,25 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
|
||||
flags := cmd.Flags()
|
||||
if flags.Changed("title") {
|
||||
opts.Editable.TitleEdited = true
|
||||
opts.Editable.Title.Edited = true
|
||||
}
|
||||
if flags.Changed("body") {
|
||||
opts.Editable.BodyEdited = true
|
||||
opts.Editable.Body.Edited = true
|
||||
}
|
||||
if flags.Changed("reviewer") {
|
||||
opts.Editable.ReviewersEdited = true
|
||||
if flags.Changed("add-reviewer") || flags.Changed("remove-reviewer") {
|
||||
opts.Editable.Reviewers.Edited = true
|
||||
}
|
||||
if flags.Changed("assignee") {
|
||||
opts.Editable.AssigneesEdited = true
|
||||
if flags.Changed("add-assignee") || flags.Changed("remove-assignee") {
|
||||
opts.Editable.Assignees.Edited = true
|
||||
}
|
||||
if flags.Changed("label") {
|
||||
opts.Editable.LabelsEdited = true
|
||||
if flags.Changed("add-label") || flags.Changed("remove-label") {
|
||||
opts.Editable.Labels.Edited = true
|
||||
}
|
||||
if flags.Changed("project") {
|
||||
opts.Editable.ProjectsEdited = true
|
||||
if flags.Changed("add-project") || flags.Changed("remove-project") {
|
||||
opts.Editable.Projects.Edited = true
|
||||
}
|
||||
if flags.Changed("milestone") {
|
||||
opts.Editable.MilestoneEdited = true
|
||||
opts.Editable.Milestone.Edited = true
|
||||
}
|
||||
|
||||
if !opts.Editable.Dirty() {
|
||||
|
|
@ -103,13 +102,17 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.Editable.Title, "title", "t", "", "Revise the pr title.")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Body, "body", "b", "", "Revise the pr body.")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Reviewers, "reviewer", "r", nil, "Request reviews from people or teams by their `handle`")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Assignees, "assignee", "a", nil, "Set assigned people by their `login`. Use \"@me\" to self-assign.")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Labels, "label", "l", nil, "Set the pr labels by `name`")
|
||||
cmd.Flags().StringSliceVarP(&opts.Editable.Projects, "project", "p", nil, "Set the projects the pr belongs to by `name`")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Milestone, "milestone", "m", "", "Set the milestone the pr belongs to by `name`")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Title.Value, "title", "t", "", "Set the new title.")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Body.Value, "body", "b", "", "Set the new body.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Reviewers.Add, "add-reviewer", nil, "Add reviewers by their `login`.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Reviewers.Remove, "remove-reviewer", nil, "Remove reviewers by their `login`.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Add, "add-assignee", nil, "Add assigned users by their `login`. Use \"@me\" to assign yourself.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Remove, "remove-assignee", nil, "Remove assigned users by their `login`. Use \"@me\" to unassign yourself.")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Add, "add-label", nil, "Add labels by `name`")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Labels.Remove, "remove-label", nil, "Remove labels by `name`")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Add, "add-project", nil, "Add the pull request to projects by `name`")
|
||||
cmd.Flags().StringSliceVar(&opts.Editable.Projects.Remove, "remove-project", nil, "Remove the pull request from projects by `name`")
|
||||
cmd.Flags().StringVarP(&opts.Editable.Milestone.Value, "milestone", "m", "", "Edit the milestone the pull request belongs to by `name`")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -127,14 +130,14 @@ func editRun(opts *EditOptions) error {
|
|||
}
|
||||
|
||||
editable := opts.Editable
|
||||
editable.ReviewersAllowed = true
|
||||
editable.TitleDefault = pr.Title
|
||||
editable.BodyDefault = pr.Body
|
||||
editable.ReviewersDefault = pr.ReviewRequests
|
||||
editable.AssigneesDefault = pr.Assignees
|
||||
editable.LabelsDefault = pr.Labels
|
||||
editable.ProjectsDefault = pr.ProjectCards
|
||||
editable.MilestoneDefault = pr.Milestone
|
||||
editable.Reviewers.Allowed = true
|
||||
editable.Title.Default = pr.Title
|
||||
editable.Body.Default = pr.Body
|
||||
editable.Reviewers.Default = pr.ReviewRequests.Logins()
|
||||
editable.Assignees.Default = pr.Assignees.Logins()
|
||||
editable.Labels.Default = pr.Labels.Names()
|
||||
editable.Projects.Default = pr.ProjectCards.ProjectNames()
|
||||
editable.Milestone.Default = pr.Milestone.Title
|
||||
|
||||
if opts.Interactive {
|
||||
err = opts.Surveyor.FieldsToEdit(&editable)
|
||||
|
|
@ -177,25 +180,29 @@ func updatePullRequest(client *api.Client, repo ghrepo.Interface, id string, edi
|
|||
var err error
|
||||
params := githubv4.UpdatePullRequestInput{
|
||||
PullRequestID: id,
|
||||
Title: editable.TitleParam(),
|
||||
Body: editable.BodyParam(),
|
||||
Title: ghString(editable.TitleValue()),
|
||||
Body: ghString(editable.BodyValue()),
|
||||
}
|
||||
params.AssigneeIDs, err = editable.AssigneesParam(client, repo)
|
||||
assigneeIds, err := editable.AssigneeIds(client, repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.LabelIDs, err = editable.LabelsParam()
|
||||
params.AssigneeIDs = ghIds(assigneeIds)
|
||||
labelIds, err := editable.LabelIds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.ProjectIDs, err = editable.ProjectsParam()
|
||||
params.LabelIDs = ghIds(labelIds)
|
||||
projectIds, err := editable.ProjectIds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.MilestoneID, err = editable.MilestoneParam()
|
||||
params.ProjectIDs = ghIds(projectIds)
|
||||
milestoneId, err := editable.MilestoneId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.MilestoneID = ghId(milestoneId)
|
||||
err = api.UpdatePullRequest(client, repo, params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -204,10 +211,10 @@ func updatePullRequest(client *api.Client, repo ghrepo.Interface, id string, edi
|
|||
}
|
||||
|
||||
func updatePullRequestReviews(client *api.Client, repo ghrepo.Interface, id string, editable shared.Editable) error {
|
||||
if !editable.ReviewersEdited {
|
||||
if !editable.Reviewers.Edited {
|
||||
return nil
|
||||
}
|
||||
userIds, teamIds, err := editable.ReviewersParams()
|
||||
userIds, teamIds, err := editable.ReviewerIds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -215,8 +222,8 @@ func updatePullRequestReviews(client *api.Client, repo ghrepo.Interface, id stri
|
|||
reviewsRequestParams := githubv4.RequestReviewsInput{
|
||||
PullRequestID: id,
|
||||
Union: &union,
|
||||
UserIDs: userIds,
|
||||
TeamIDs: teamIds,
|
||||
UserIDs: ghIds(userIds),
|
||||
TeamIDs: ghIds(teamIds),
|
||||
}
|
||||
return api.UpdatePullRequestReviews(client, repo, reviewsRequestParams)
|
||||
}
|
||||
|
|
@ -257,3 +264,34 @@ type editorRetriever struct {
|
|||
func (e editorRetriever) Retrieve() (string, error) {
|
||||
return cmdutil.DetermineEditor(e.config)
|
||||
}
|
||||
|
||||
func ghIds(s *[]string) *[]githubv4.ID {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
ids := make([]githubv4.ID, len(*s))
|
||||
for i, v := range *s {
|
||||
ids[i] = v
|
||||
}
|
||||
return &ids
|
||||
}
|
||||
|
||||
func ghId(s *string) *githubv4.ID {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
if *s == "" {
|
||||
r := githubv4.ID(nil)
|
||||
return &r
|
||||
}
|
||||
r := githubv4.ID(*s)
|
||||
return &r
|
||||
}
|
||||
|
||||
func ghString(s *string) *githubv4.String {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
r := githubv4.String(*s)
|
||||
return &r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
wantsErr: true,
|
||||
},
|
||||
{
|
||||
name: "issue number argument",
|
||||
name: "pull request number argument",
|
||||
input: "23",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
|
|
@ -43,8 +43,10 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Title: "test",
|
||||
TitleEdited: true,
|
||||
Title: shared.EditableString{
|
||||
Value: "test",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
|
|
@ -55,56 +57,122 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Body: "test",
|
||||
BodyEdited: true,
|
||||
Body: shared.EditableString{
|
||||
Value: "test",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "reviewer flag",
|
||||
input: "23 --reviewer owner/team,monalisa",
|
||||
name: "add-reviewer flag",
|
||||
input: "23 --add-reviewer monalisa,owner/core",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Reviewers: []string{"owner/team", "monalisa"},
|
||||
ReviewersEdited: true,
|
||||
Reviewers: shared.EditableSlice{
|
||||
Add: []string{"monalisa", "owner/core"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "assignee flag",
|
||||
input: "23 --assignee monalisa,hubot",
|
||||
name: "remove-reviewer flag",
|
||||
input: "23 --remove-reviewer monalisa,owner/core",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Assignees: []string{"monalisa", "hubot"},
|
||||
AssigneesEdited: true,
|
||||
Reviewers: shared.EditableSlice{
|
||||
Remove: []string{"monalisa", "owner/core"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "label flag",
|
||||
input: "23 --label feature,TODO,bug",
|
||||
name: "add-assignee flag",
|
||||
input: "23 --add-assignee monalisa,hubot",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Labels: []string{"feature", "TODO", "bug"},
|
||||
LabelsEdited: true,
|
||||
Assignees: shared.EditableSlice{
|
||||
Add: []string{"monalisa", "hubot"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "project flag",
|
||||
input: "23 --project Cleanup,Roadmap",
|
||||
name: "remove-assignee flag",
|
||||
input: "23 --remove-assignee monalisa,hubot",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Projects: []string{"Cleanup", "Roadmap"},
|
||||
ProjectsEdited: true,
|
||||
Assignees: shared.EditableSlice{
|
||||
Remove: []string{"monalisa", "hubot"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "add-label flag",
|
||||
input: "23 --add-label feature,TODO,bug",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Labels: shared.EditableSlice{
|
||||
Add: []string{"feature", "TODO", "bug"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "remove-label flag",
|
||||
input: "23 --remove-label feature,TODO,bug",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Labels: shared.EditableSlice{
|
||||
Remove: []string{"feature", "TODO", "bug"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "add-project flag",
|
||||
input: "23 --add-project Cleanup,Roadmap",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Projects: shared.EditableSlice{
|
||||
Add: []string{"Cleanup", "Roadmap"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
},
|
||||
{
|
||||
name: "remove-project flag",
|
||||
input: "23 --remove-project Cleanup,Roadmap",
|
||||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Projects: shared.EditableSlice{
|
||||
Remove: []string{"Cleanup", "Roadmap"},
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
|
|
@ -115,8 +183,10 @@ func TestNewCmdEdit(t *testing.T) {
|
|||
output: EditOptions{
|
||||
SelectorArg: "23",
|
||||
Editable: shared.Editable{
|
||||
Milestone: "GA",
|
||||
MilestoneEdited: true,
|
||||
Milestone: shared.EditableString{
|
||||
Value: "GA",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantsErr: false,
|
||||
|
|
@ -176,20 +246,38 @@ func Test_editRun(t *testing.T) {
|
|||
SelectorArg: "123",
|
||||
Interactive: false,
|
||||
Editable: shared.Editable{
|
||||
Title: "new title",
|
||||
TitleEdited: true,
|
||||
Body: "new body",
|
||||
BodyEdited: true,
|
||||
Reviewers: []string{"OWNER/core", "OWNER/external", "monalisa", "hubot"},
|
||||
ReviewersEdited: true,
|
||||
Assignees: []string{"monalisa", "hubot"},
|
||||
AssigneesEdited: true,
|
||||
Labels: []string{"feature", "TODO", "bug"},
|
||||
LabelsEdited: true,
|
||||
Projects: []string{"Cleanup", "Roadmap"},
|
||||
ProjectsEdited: true,
|
||||
Milestone: "GA",
|
||||
MilestoneEdited: true,
|
||||
Title: shared.EditableString{
|
||||
Value: "new title",
|
||||
Edited: true,
|
||||
},
|
||||
Body: shared.EditableString{
|
||||
Value: "new body",
|
||||
Edited: true,
|
||||
},
|
||||
Reviewers: shared.EditableSlice{
|
||||
Add: []string{"OWNER/core", "OWNER/external", "monalisa", "hubot"},
|
||||
Remove: []string{"dependabot"},
|
||||
Edited: true,
|
||||
},
|
||||
Assignees: shared.EditableSlice{
|
||||
Add: []string{"monalisa", "hubot"},
|
||||
Remove: []string{"octocat"},
|
||||
Edited: true,
|
||||
},
|
||||
Labels: shared.EditableSlice{
|
||||
Add: []string{"feature", "TODO", "bug"},
|
||||
Remove: []string{"docs"},
|
||||
Edited: true,
|
||||
},
|
||||
Projects: shared.EditableSlice{
|
||||
Add: []string{"Cleanup", "Roadmap"},
|
||||
Remove: []string{"Features"},
|
||||
Edited: true,
|
||||
},
|
||||
Milestone: shared.EditableString{
|
||||
Value: "GA",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
Fetcher: testFetcher{},
|
||||
},
|
||||
|
|
@ -207,18 +295,33 @@ func Test_editRun(t *testing.T) {
|
|||
SelectorArg: "123",
|
||||
Interactive: false,
|
||||
Editable: shared.Editable{
|
||||
Title: "new title",
|
||||
TitleEdited: true,
|
||||
Body: "new body",
|
||||
BodyEdited: true,
|
||||
Assignees: []string{"monalisa", "hubot"},
|
||||
AssigneesEdited: true,
|
||||
Labels: []string{"feature", "TODO", "bug"},
|
||||
LabelsEdited: true,
|
||||
Projects: []string{"Cleanup", "Roadmap"},
|
||||
ProjectsEdited: true,
|
||||
Milestone: "GA",
|
||||
MilestoneEdited: true,
|
||||
Title: shared.EditableString{
|
||||
Value: "new title",
|
||||
Edited: true,
|
||||
},
|
||||
Body: shared.EditableString{
|
||||
Value: "new body",
|
||||
Edited: true,
|
||||
},
|
||||
Assignees: shared.EditableSlice{
|
||||
Add: []string{"monalisa", "hubot"},
|
||||
Remove: []string{"octocat"},
|
||||
Edited: true,
|
||||
},
|
||||
Labels: shared.EditableSlice{
|
||||
Value: []string{"feature", "TODO", "bug"},
|
||||
Remove: []string{"docs"},
|
||||
Edited: true,
|
||||
},
|
||||
Projects: shared.EditableSlice{
|
||||
Value: []string{"Cleanup", "Roadmap"},
|
||||
Remove: []string{"Features"},
|
||||
Edited: true,
|
||||
},
|
||||
Milestone: shared.EditableString{
|
||||
Value: "GA",
|
||||
Edited: true,
|
||||
},
|
||||
},
|
||||
Fetcher: testFetcher{},
|
||||
},
|
||||
|
|
@ -405,28 +508,28 @@ func (f testFetcher) EditableOptionsFetch(client *api.Client, repo ghrepo.Interf
|
|||
}
|
||||
|
||||
func (s testSurveyor) FieldsToEdit(e *shared.Editable) error {
|
||||
e.TitleEdited = true
|
||||
e.BodyEdited = true
|
||||
e.Title.Edited = true
|
||||
e.Body.Edited = true
|
||||
if !s.skipReviewers {
|
||||
e.ReviewersEdited = true
|
||||
e.Reviewers.Edited = true
|
||||
}
|
||||
e.AssigneesEdited = true
|
||||
e.LabelsEdited = true
|
||||
e.ProjectsEdited = true
|
||||
e.MilestoneEdited = true
|
||||
e.Assignees.Edited = true
|
||||
e.Labels.Edited = true
|
||||
e.Projects.Edited = true
|
||||
e.Milestone.Edited = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s testSurveyor) EditFields(e *shared.Editable, _ string) error {
|
||||
e.Title = "new title"
|
||||
e.Body = "new body"
|
||||
e.Title.Value = "new title"
|
||||
e.Body.Value = "new body"
|
||||
if !s.skipReviewers {
|
||||
e.Reviewers = []string{"monalisa", "hubot", "OWNER/core", "OWNER/external"}
|
||||
e.Reviewers.Value = []string{"monalisa", "hubot", "OWNER/core", "OWNER/external"}
|
||||
}
|
||||
e.Assignees = []string{"monalisa", "hubot"}
|
||||
e.Labels = []string{"feature", "TODO", "bug"}
|
||||
e.Projects = []string{"Cleanup", "Roadmap"}
|
||||
e.Milestone = "GA"
|
||||
e.Assignees.Value = []string{"monalisa", "hubot"}
|
||||
e.Labels.Value = []string{"feature", "TODO", "bug"}
|
||||
e.Projects.Value = []string{"Cleanup", "Roadmap"}
|
||||
e.Milestone.Value = "GA"
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,174 +7,199 @@ import (
|
|||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/cli/cli/api"
|
||||
"github.com/cli/cli/internal/ghrepo"
|
||||
"github.com/cli/cli/pkg/set"
|
||||
"github.com/cli/cli/pkg/surveyext"
|
||||
"github.com/shurcooL/githubv4"
|
||||
)
|
||||
|
||||
type Editable struct {
|
||||
Title string
|
||||
TitleDefault string
|
||||
TitleEdited bool
|
||||
Title EditableString
|
||||
Body EditableString
|
||||
Reviewers EditableSlice
|
||||
Assignees EditableSlice
|
||||
Labels EditableSlice
|
||||
Projects EditableSlice
|
||||
Milestone EditableString
|
||||
Metadata api.RepoMetadataResult
|
||||
}
|
||||
|
||||
Body string
|
||||
BodyDefault string
|
||||
BodyEdited bool
|
||||
type EditableString struct {
|
||||
Value string
|
||||
Default string
|
||||
Options []string
|
||||
Edited bool
|
||||
}
|
||||
|
||||
Reviewers []string
|
||||
ReviewersDefault api.ReviewRequests
|
||||
ReviewersOptions []string
|
||||
ReviewersEdited bool
|
||||
ReviewersAllowed bool
|
||||
|
||||
Assignees []string
|
||||
AssigneesDefault api.Assignees
|
||||
AssigneesOptions []string
|
||||
AssigneesEdited bool
|
||||
|
||||
Labels []string
|
||||
LabelsDefault api.Labels
|
||||
LabelsOptions []string
|
||||
LabelsEdited bool
|
||||
|
||||
Projects []string
|
||||
ProjectsDefault api.ProjectCards
|
||||
ProjectsOptions []string
|
||||
ProjectsEdited bool
|
||||
|
||||
Milestone string
|
||||
MilestoneDefault api.Milestone
|
||||
MilestoneOptions []string
|
||||
MilestoneEdited bool
|
||||
|
||||
Metadata api.RepoMetadataResult
|
||||
type EditableSlice struct {
|
||||
Value []string
|
||||
Add []string
|
||||
Remove []string
|
||||
Default []string
|
||||
Options []string
|
||||
Edited bool
|
||||
Allowed bool
|
||||
}
|
||||
|
||||
func (e Editable) Dirty() bool {
|
||||
return e.TitleEdited ||
|
||||
e.BodyEdited ||
|
||||
e.ReviewersEdited ||
|
||||
e.AssigneesEdited ||
|
||||
e.LabelsEdited ||
|
||||
e.ProjectsEdited ||
|
||||
e.MilestoneEdited
|
||||
return e.Title.Edited ||
|
||||
e.Body.Edited ||
|
||||
e.Reviewers.Edited ||
|
||||
e.Assignees.Edited ||
|
||||
e.Labels.Edited ||
|
||||
e.Projects.Edited ||
|
||||
e.Milestone.Edited
|
||||
}
|
||||
|
||||
func (e Editable) TitleParam() *githubv4.String {
|
||||
if !e.TitleEdited {
|
||||
func (e Editable) TitleValue() *string {
|
||||
if !e.Title.Edited {
|
||||
return nil
|
||||
}
|
||||
s := githubv4.String(e.Title)
|
||||
return &s
|
||||
return &e.Title.Value
|
||||
}
|
||||
|
||||
func (e Editable) BodyParam() *githubv4.String {
|
||||
if !e.BodyEdited {
|
||||
func (e Editable) BodyValue() *string {
|
||||
if !e.Body.Edited {
|
||||
return nil
|
||||
}
|
||||
s := githubv4.String(e.Body)
|
||||
return &s
|
||||
return &e.Body.Value
|
||||
}
|
||||
|
||||
func (e Editable) ReviewersParams() (*[]githubv4.ID, *[]githubv4.ID, error) {
|
||||
if !e.ReviewersEdited {
|
||||
func (e Editable) ReviewerIds() (*[]string, *[]string, error) {
|
||||
if !e.Reviewers.Edited {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if len(e.Reviewers.Add) != 0 || len(e.Reviewers.Remove) != 0 {
|
||||
s := set.NewStringSet()
|
||||
s.AddValues(e.Reviewers.Default)
|
||||
s.AddValues(e.Reviewers.Add)
|
||||
s.RemoveValues(e.Reviewers.Remove)
|
||||
e.Reviewers.Value = s.ToSlice()
|
||||
}
|
||||
var userReviewers []string
|
||||
var teamReviewers []string
|
||||
for _, r := range e.Reviewers {
|
||||
for _, r := range e.Reviewers.Value {
|
||||
if strings.ContainsRune(r, '/') {
|
||||
teamReviewers = append(teamReviewers, r)
|
||||
} else {
|
||||
userReviewers = append(userReviewers, r)
|
||||
}
|
||||
}
|
||||
userIds, err := toParams(userReviewers, e.Metadata.MembersToIDs)
|
||||
userIds, err := e.Metadata.MembersToIDs(userReviewers)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
teamIds, err := toParams(teamReviewers, e.Metadata.TeamsToIDs)
|
||||
teamIds, err := e.Metadata.TeamsToIDs(teamReviewers)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return userIds, teamIds, nil
|
||||
return &userIds, &teamIds, nil
|
||||
}
|
||||
|
||||
func (e Editable) AssigneesParam(client *api.Client, repo ghrepo.Interface) (*[]githubv4.ID, error) {
|
||||
if !e.AssigneesEdited {
|
||||
func (e Editable) AssigneeIds(client *api.Client, repo ghrepo.Interface) (*[]string, error) {
|
||||
if !e.Assignees.Edited {
|
||||
return nil, nil
|
||||
}
|
||||
meReplacer := NewMeReplacer(client, repo.RepoHost())
|
||||
assignees, err := meReplacer.ReplaceSlice(e.Assignees)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(e.Assignees.Add) != 0 || len(e.Assignees.Remove) != 0 {
|
||||
meReplacer := NewMeReplacer(client, repo.RepoHost())
|
||||
s := set.NewStringSet()
|
||||
s.AddValues(e.Assignees.Default)
|
||||
add, err := meReplacer.ReplaceSlice(e.Assignees.Add)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.AddValues(add)
|
||||
remove, err := meReplacer.ReplaceSlice(e.Assignees.Remove)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.RemoveValues(remove)
|
||||
e.Assignees.Value = s.ToSlice()
|
||||
}
|
||||
return toParams(assignees, e.Metadata.MembersToIDs)
|
||||
a, err := e.Metadata.MembersToIDs(e.Assignees.Value)
|
||||
return &a, err
|
||||
}
|
||||
|
||||
func (e Editable) LabelsParam() (*[]githubv4.ID, error) {
|
||||
if !e.LabelsEdited {
|
||||
func (e Editable) LabelIds() (*[]string, error) {
|
||||
if !e.Labels.Edited {
|
||||
return nil, nil
|
||||
}
|
||||
return toParams(e.Labels, e.Metadata.LabelsToIDs)
|
||||
if len(e.Labels.Add) != 0 || len(e.Labels.Remove) != 0 {
|
||||
s := set.NewStringSet()
|
||||
s.AddValues(e.Labels.Default)
|
||||
s.AddValues(e.Labels.Add)
|
||||
s.RemoveValues(e.Labels.Remove)
|
||||
e.Labels.Value = s.ToSlice()
|
||||
}
|
||||
l, err := e.Metadata.LabelsToIDs(e.Labels.Value)
|
||||
return &l, err
|
||||
}
|
||||
|
||||
func (e Editable) ProjectsParam() (*[]githubv4.ID, error) {
|
||||
if !e.ProjectsEdited {
|
||||
func (e Editable) ProjectIds() (*[]string, error) {
|
||||
if !e.Projects.Edited {
|
||||
return nil, nil
|
||||
}
|
||||
return toParams(e.Projects, e.Metadata.ProjectsToIDs)
|
||||
if len(e.Projects.Add) != 0 || len(e.Projects.Remove) != 0 {
|
||||
s := set.NewStringSet()
|
||||
s.AddValues(e.Projects.Default)
|
||||
s.AddValues(e.Projects.Add)
|
||||
s.RemoveValues(e.Projects.Remove)
|
||||
e.Projects.Value = s.ToSlice()
|
||||
}
|
||||
p, err := e.Metadata.ProjectsToIDs(e.Projects.Value)
|
||||
return &p, err
|
||||
}
|
||||
|
||||
func (e Editable) MilestoneParam() (*githubv4.ID, error) {
|
||||
if !e.MilestoneEdited {
|
||||
func (e Editable) MilestoneId() (*string, error) {
|
||||
if !e.Milestone.Edited {
|
||||
return nil, nil
|
||||
}
|
||||
if e.Milestone == noMilestone || e.Milestone == "" {
|
||||
return githubv4.NewID(nil), nil
|
||||
if e.Milestone.Value == noMilestone || e.Milestone.Value == "" {
|
||||
s := ""
|
||||
return &s, nil
|
||||
}
|
||||
return toParam(e.Milestone, e.Metadata.MilestoneToID)
|
||||
m, err := e.Metadata.MilestoneToID(e.Milestone.Value)
|
||||
return &m, err
|
||||
}
|
||||
|
||||
func EditFieldsSurvey(editable *Editable, editorCommand string) error {
|
||||
var err error
|
||||
if editable.TitleEdited {
|
||||
editable.Title, err = titleSurvey(editable.TitleDefault)
|
||||
if editable.Title.Edited {
|
||||
editable.Title.Value, err = titleSurvey(editable.Title.Default)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if editable.BodyEdited {
|
||||
editable.Body, err = bodySurvey(editable.BodyDefault, editorCommand)
|
||||
if editable.Body.Edited {
|
||||
editable.Body.Value, err = bodySurvey(editable.Body.Default, editorCommand)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if editable.ReviewersEdited {
|
||||
editable.Reviewers, err = reviewersSurvey(editable.ReviewersDefault, editable.ReviewersOptions)
|
||||
if editable.Reviewers.Edited {
|
||||
editable.Reviewers.Value, err = multiSelectSurvey("Reviewers", editable.Reviewers.Default, editable.Reviewers.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if editable.AssigneesEdited {
|
||||
editable.Assignees, err = assigneesSurvey(editable.AssigneesDefault, editable.AssigneesOptions)
|
||||
if editable.Assignees.Edited {
|
||||
editable.Assignees.Value, err = multiSelectSurvey("Assignees", editable.Assignees.Default, editable.Assignees.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if editable.LabelsEdited {
|
||||
editable.Labels, err = labelsSurvey(editable.LabelsDefault, editable.LabelsOptions)
|
||||
if editable.Labels.Edited {
|
||||
editable.Labels.Value, err = multiSelectSurvey("Labels", editable.Labels.Default, editable.Labels.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if editable.ProjectsEdited {
|
||||
editable.Projects, err = projectsSurvey(editable.ProjectsDefault, editable.ProjectsOptions)
|
||||
if editable.Projects.Edited {
|
||||
editable.Projects.Value, err = multiSelectSurvey("Projects", editable.Projects.Default, editable.Projects.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if editable.MilestoneEdited {
|
||||
editable.Milestone, err = milestoneSurvey(editable.MilestoneDefault, editable.MilestoneOptions)
|
||||
if editable.Milestone.Edited {
|
||||
editable.Milestone.Value, err = milestoneSurvey(editable.Milestone.Default, editable.Milestone.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -200,41 +225,36 @@ func FieldsToEditSurvey(editable *Editable) error {
|
|||
return false
|
||||
}
|
||||
|
||||
results := []string{}
|
||||
opts := []string{"Title", "Body"}
|
||||
if editable.ReviewersAllowed {
|
||||
if editable.Reviewers.Allowed {
|
||||
opts = append(opts, "Reviewers")
|
||||
}
|
||||
opts = append(opts, "Assignees", "Labels", "Projects", "Milestone")
|
||||
q := &survey.MultiSelect{
|
||||
Message: "What would you like to edit?",
|
||||
Options: opts,
|
||||
}
|
||||
err := survey.AskOne(q, &results)
|
||||
results, err := multiSelectSurvey("What would you like to edit?", []string{}, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if contains(results, "Title") {
|
||||
editable.TitleEdited = true
|
||||
editable.Title.Edited = true
|
||||
}
|
||||
if contains(results, "Body") {
|
||||
editable.BodyEdited = true
|
||||
editable.Body.Edited = true
|
||||
}
|
||||
if contains(results, "Reviewers") {
|
||||
editable.ReviewersEdited = true
|
||||
editable.Reviewers.Edited = true
|
||||
}
|
||||
if contains(results, "Assignees") {
|
||||
editable.AssigneesEdited = true
|
||||
editable.Assignees.Edited = true
|
||||
}
|
||||
if contains(results, "Labels") {
|
||||
editable.LabelsEdited = true
|
||||
editable.Labels.Edited = true
|
||||
}
|
||||
if contains(results, "Projects") {
|
||||
editable.ProjectsEdited = true
|
||||
editable.Projects.Edited = true
|
||||
}
|
||||
if contains(results, "Milestone") {
|
||||
editable.MilestoneEdited = true
|
||||
editable.Milestone.Edited = true
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -242,11 +262,11 @@ func FieldsToEditSurvey(editable *Editable) error {
|
|||
|
||||
func FetchOptions(client *api.Client, repo ghrepo.Interface, editable *Editable) error {
|
||||
input := api.RepoMetadataInput{
|
||||
Reviewers: editable.ReviewersEdited,
|
||||
Assignees: editable.AssigneesEdited,
|
||||
Labels: editable.LabelsEdited,
|
||||
Projects: editable.ProjectsEdited,
|
||||
Milestones: editable.MilestoneEdited,
|
||||
Reviewers: editable.Reviewers.Edited,
|
||||
Assignees: editable.Assignees.Edited,
|
||||
Labels: editable.Labels.Edited,
|
||||
Projects: editable.Projects.Edited,
|
||||
Milestones: editable.Milestone.Edited,
|
||||
}
|
||||
metadata, err := api.RepoMetadata(client, repo, input)
|
||||
if err != nil {
|
||||
|
|
@ -275,11 +295,11 @@ func FetchOptions(client *api.Client, repo ghrepo.Interface, editable *Editable)
|
|||
}
|
||||
|
||||
editable.Metadata = *metadata
|
||||
editable.ReviewersOptions = append(users, teams...)
|
||||
editable.AssigneesOptions = users
|
||||
editable.LabelsOptions = labels
|
||||
editable.ProjectsOptions = projects
|
||||
editable.MilestoneOptions = milestones
|
||||
editable.Reviewers.Options = append(users, teams...)
|
||||
editable.Assignees.Options = users
|
||||
editable.Labels.Options = labels
|
||||
editable.Projects.Options = projects
|
||||
editable.Milestone.Options = milestones
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -297,9 +317,9 @@ func titleSurvey(title string) (string, error) {
|
|||
func bodySurvey(body, editorCommand string) (string, error) {
|
||||
var result string
|
||||
q := &surveyext.GhEditor{
|
||||
BlankAllowed: true,
|
||||
EditorCommand: editorCommand,
|
||||
Editor: &survey.Editor{Message: "Body",
|
||||
Editor: &survey.Editor{
|
||||
Message: "Body",
|
||||
FileName: "*.md",
|
||||
Default: body,
|
||||
HideDefault: true,
|
||||
|
|
@ -310,79 +330,21 @@ func bodySurvey(body, editorCommand string) (string, error) {
|
|||
return result, err
|
||||
}
|
||||
|
||||
func reviewersSurvey(reviewers api.ReviewRequests, opts []string) ([]string, error) {
|
||||
if len(opts) == 0 {
|
||||
func multiSelectSurvey(message string, defaults, options []string) ([]string, error) {
|
||||
if len(options) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
logins := []string{}
|
||||
for _, a := range reviewers.Nodes {
|
||||
logins = append(logins, a.RequestedReviewer.Login)
|
||||
}
|
||||
var results []string
|
||||
q := &survey.MultiSelect{
|
||||
Message: "Reviewers",
|
||||
Options: opts,
|
||||
Default: logins,
|
||||
Message: message,
|
||||
Options: options,
|
||||
Default: defaults,
|
||||
}
|
||||
err := survey.AskOne(q, &results)
|
||||
return results, err
|
||||
}
|
||||
|
||||
func assigneesSurvey(assignees api.Assignees, opts []string) ([]string, error) {
|
||||
if len(opts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
logins := []string{}
|
||||
for _, a := range assignees.Nodes {
|
||||
logins = append(logins, a.Login)
|
||||
}
|
||||
var results []string
|
||||
q := &survey.MultiSelect{
|
||||
Message: "Assignees",
|
||||
Options: opts,
|
||||
Default: logins,
|
||||
}
|
||||
err := survey.AskOne(q, &results)
|
||||
return results, err
|
||||
}
|
||||
|
||||
func labelsSurvey(labels api.Labels, opts []string) ([]string, error) {
|
||||
if len(opts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
names := []string{}
|
||||
for _, l := range labels.Nodes {
|
||||
names = append(names, l.Name)
|
||||
}
|
||||
var results []string
|
||||
q := &survey.MultiSelect{
|
||||
Message: "Labels",
|
||||
Options: opts,
|
||||
Default: names,
|
||||
}
|
||||
err := survey.AskOne(q, &results)
|
||||
return results, err
|
||||
}
|
||||
|
||||
func projectsSurvey(projectCards api.ProjectCards, opts []string) ([]string, error) {
|
||||
if len(opts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
names := []string{}
|
||||
for _, c := range projectCards.Nodes {
|
||||
names = append(names, c.Project.Name)
|
||||
}
|
||||
var results []string
|
||||
q := &survey.MultiSelect{
|
||||
Message: "Projects",
|
||||
Options: opts,
|
||||
Default: names,
|
||||
}
|
||||
err := survey.AskOne(q, &results)
|
||||
return results, err
|
||||
}
|
||||
|
||||
func milestoneSurvey(milestone api.Milestone, opts []string) (string, error) {
|
||||
func milestoneSurvey(title string, opts []string) (string, error) {
|
||||
if len(opts) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
|
@ -390,7 +352,7 @@ func milestoneSurvey(milestone api.Milestone, opts []string) (string, error) {
|
|||
q := &survey.Select{
|
||||
Message: "Milestone",
|
||||
Options: opts,
|
||||
Default: milestone.Title,
|
||||
Default: title,
|
||||
}
|
||||
err := survey.AskOne(q, &result)
|
||||
return result, err
|
||||
|
|
@ -405,24 +367,3 @@ func confirmSurvey() (bool, error) {
|
|||
err := survey.AskOne(q, &result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func toParams(s []string, mapper func([]string) ([]string, error)) (*[]githubv4.ID, error) {
|
||||
ids, err := mapper(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gIds := make([]githubv4.ID, len(ids))
|
||||
for i, v := range ids {
|
||||
gIds[i] = v
|
||||
}
|
||||
return &gIds, nil
|
||||
}
|
||||
|
||||
func toParam(s string, mapper func(string) (string, error)) (*githubv4.ID, error) {
|
||||
id, err := mapper(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gId := githubv4.ID(id)
|
||||
return &gId, nil
|
||||
}
|
||||
|
|
|
|||
46
pkg/set/string_set.go
Normal file
46
pkg/set/string_set.go
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package set
|
||||
|
||||
var exists = struct{}{}
|
||||
|
||||
type stringSet struct {
|
||||
m map[string]struct{}
|
||||
}
|
||||
|
||||
func NewStringSet() *stringSet {
|
||||
s := &stringSet{}
|
||||
s.m = make(map[string]struct{})
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *stringSet) Add(value string) {
|
||||
s.m[value] = exists
|
||||
}
|
||||
|
||||
func (s *stringSet) AddValues(values []string) {
|
||||
for _, v := range values {
|
||||
s.Add(v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stringSet) Remove(value string) {
|
||||
delete(s.m, value)
|
||||
}
|
||||
|
||||
func (s *stringSet) RemoveValues(values []string) {
|
||||
for _, v := range values {
|
||||
s.Remove(v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stringSet) Contains(value string) bool {
|
||||
_, c := s.m[value]
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *stringSet) ToSlice() []string {
|
||||
r := make([]string, 0, len(s.m))
|
||||
for k := range s.m {
|
||||
r = append(r, k)
|
||||
}
|
||||
return r
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue