428 lines
9.3 KiB
Go
428 lines
9.3 KiB
Go
package shared
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/AlecAivazis/survey/v2"
|
|
"github.com/cli/cli/api"
|
|
"github.com/cli/cli/internal/ghrepo"
|
|
"github.com/cli/cli/pkg/surveyext"
|
|
"github.com/shurcooL/githubv4"
|
|
)
|
|
|
|
type Editable struct {
|
|
Title string
|
|
TitleDefault string
|
|
TitleEdited bool
|
|
|
|
Body string
|
|
BodyDefault string
|
|
BodyEdited 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
|
|
}
|
|
|
|
func (e Editable) Dirty() bool {
|
|
return e.TitleEdited ||
|
|
e.BodyEdited ||
|
|
e.ReviewersEdited ||
|
|
e.AssigneesEdited ||
|
|
e.LabelsEdited ||
|
|
e.ProjectsEdited ||
|
|
e.MilestoneEdited
|
|
}
|
|
|
|
func (e Editable) TitleParam() *githubv4.String {
|
|
if !e.TitleEdited {
|
|
return nil
|
|
}
|
|
s := githubv4.String(e.Title)
|
|
return &s
|
|
}
|
|
|
|
func (e Editable) BodyParam() *githubv4.String {
|
|
if !e.BodyEdited {
|
|
return nil
|
|
}
|
|
s := githubv4.String(e.Body)
|
|
return &s
|
|
}
|
|
|
|
func (e Editable) ReviewersParams() (*[]githubv4.ID, *[]githubv4.ID, error) {
|
|
if !e.ReviewersEdited {
|
|
return nil, nil, nil
|
|
}
|
|
var userReviewers []string
|
|
var teamReviewers []string
|
|
for _, r := range e.Reviewers {
|
|
if strings.ContainsRune(r, '/') {
|
|
teamReviewers = append(teamReviewers, r)
|
|
} else {
|
|
userReviewers = append(userReviewers, r)
|
|
}
|
|
}
|
|
userIds, err := toParams(userReviewers, e.Metadata.MembersToIDs)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
teamIds, err := toParams(teamReviewers, e.Metadata.TeamsToIDs)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return userIds, teamIds, nil
|
|
}
|
|
|
|
func (e Editable) AssigneesParam(client *api.Client, repo ghrepo.Interface) (*[]githubv4.ID, error) {
|
|
if !e.AssigneesEdited {
|
|
return nil, nil
|
|
}
|
|
meReplacer := NewMeReplacer(client, repo.RepoHost())
|
|
assignees, err := meReplacer.ReplaceSlice(e.Assignees)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return toParams(assignees, e.Metadata.MembersToIDs)
|
|
}
|
|
|
|
func (e Editable) LabelsParam() (*[]githubv4.ID, error) {
|
|
if !e.LabelsEdited {
|
|
return nil, nil
|
|
}
|
|
return toParams(e.Labels, e.Metadata.LabelsToIDs)
|
|
}
|
|
|
|
func (e Editable) ProjectsParam() (*[]githubv4.ID, error) {
|
|
if !e.ProjectsEdited {
|
|
return nil, nil
|
|
}
|
|
return toParams(e.Projects, e.Metadata.ProjectsToIDs)
|
|
}
|
|
|
|
func (e Editable) MilestoneParam() (*githubv4.ID, error) {
|
|
if !e.MilestoneEdited {
|
|
return nil, nil
|
|
}
|
|
if e.Milestone == noMilestone || e.Milestone == "" {
|
|
return githubv4.NewID(nil), nil
|
|
}
|
|
return toParam(e.Milestone, e.Metadata.MilestoneToID)
|
|
}
|
|
|
|
func EditFieldsSurvey(editable *Editable, editorCommand string) error {
|
|
var err error
|
|
if editable.TitleEdited {
|
|
editable.Title, err = titleSurvey(editable.TitleDefault)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if editable.BodyEdited {
|
|
editable.Body, err = bodySurvey(editable.BodyDefault, editorCommand)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if editable.ReviewersEdited {
|
|
editable.Reviewers, err = reviewersSurvey(editable.ReviewersDefault, editable.ReviewersOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if editable.AssigneesEdited {
|
|
editable.Assignees, err = assigneesSurvey(editable.AssigneesDefault, editable.AssigneesOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if editable.LabelsEdited {
|
|
editable.Labels, err = labelsSurvey(editable.LabelsDefault, editable.LabelsOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if editable.ProjectsEdited {
|
|
editable.Projects, err = projectsSurvey(editable.ProjectsDefault, editable.ProjectsOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if editable.MilestoneEdited {
|
|
editable.Milestone, err = milestoneSurvey(editable.MilestoneDefault, editable.MilestoneOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
confirm, err := confirmSurvey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !confirm {
|
|
return fmt.Errorf("Discarding...")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func FieldsToEditSurvey(editable *Editable) error {
|
|
contains := func(s []string, str string) bool {
|
|
for _, v := range s {
|
|
if v == str {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
results := []string{}
|
|
opts := []string{"Title", "Body"}
|
|
if editable.ReviewersAllowed {
|
|
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)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if contains(results, "Title") {
|
|
editable.TitleEdited = true
|
|
}
|
|
if contains(results, "Body") {
|
|
editable.BodyEdited = true
|
|
}
|
|
if contains(results, "Reviewers") {
|
|
editable.ReviewersEdited = true
|
|
}
|
|
if contains(results, "Assignees") {
|
|
editable.AssigneesEdited = true
|
|
}
|
|
if contains(results, "Labels") {
|
|
editable.LabelsEdited = true
|
|
}
|
|
if contains(results, "Projects") {
|
|
editable.ProjectsEdited = true
|
|
}
|
|
if contains(results, "Milestone") {
|
|
editable.MilestoneEdited = true
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
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,
|
|
}
|
|
metadata, err := api.RepoMetadata(client, repo, input)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var users []string
|
|
for _, u := range metadata.AssignableUsers {
|
|
users = append(users, u.Login)
|
|
}
|
|
var teams []string
|
|
for _, t := range metadata.Teams {
|
|
teams = append(teams, fmt.Sprintf("%s/%s", repo.RepoOwner(), t.Slug))
|
|
}
|
|
var labels []string
|
|
for _, l := range metadata.Labels {
|
|
labels = append(labels, l.Name)
|
|
}
|
|
var projects []string
|
|
for _, l := range metadata.Projects {
|
|
projects = append(projects, l.Name)
|
|
}
|
|
milestones := []string{noMilestone}
|
|
for _, m := range metadata.Milestones {
|
|
milestones = append(milestones, m.Title)
|
|
}
|
|
|
|
editable.Metadata = *metadata
|
|
editable.ReviewersOptions = append(users, teams...)
|
|
editable.AssigneesOptions = users
|
|
editable.LabelsOptions = labels
|
|
editable.ProjectsOptions = projects
|
|
editable.MilestoneOptions = milestones
|
|
|
|
return nil
|
|
}
|
|
|
|
func titleSurvey(title string) (string, error) {
|
|
var result string
|
|
q := &survey.Input{
|
|
Message: "Title",
|
|
Default: title,
|
|
}
|
|
err := survey.AskOne(q, &result)
|
|
return result, err
|
|
}
|
|
|
|
func bodySurvey(body, editorCommand string) (string, error) {
|
|
var result string
|
|
q := &surveyext.GhEditor{
|
|
BlankAllowed: true,
|
|
EditorCommand: editorCommand,
|
|
Editor: &survey.Editor{Message: "Body",
|
|
FileName: "*.md",
|
|
Default: body,
|
|
HideDefault: true,
|
|
AppendDefault: true,
|
|
},
|
|
}
|
|
err := survey.AskOne(q, &result)
|
|
return result, err
|
|
}
|
|
|
|
func reviewersSurvey(reviewers api.ReviewRequests, opts []string) ([]string, error) {
|
|
if len(opts) == 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,
|
|
}
|
|
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) {
|
|
if len(opts) == 0 {
|
|
return "", nil
|
|
}
|
|
var result string
|
|
q := &survey.Select{
|
|
Message: "Milestone",
|
|
Options: opts,
|
|
Default: milestone.Title,
|
|
}
|
|
err := survey.AskOne(q, &result)
|
|
return result, err
|
|
}
|
|
|
|
func confirmSurvey() (bool, error) {
|
|
var result bool
|
|
q := &survey.Confirm{
|
|
Message: "Submit?",
|
|
Default: true,
|
|
}
|
|
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
|
|
}
|