未验证 提交 57b8337d 编写于 作者: M Mislav Marohnić 提交者: GitHub

Merge pull request #2432 from jfahrer/master

Add the ability to edit issues

Fixes #1686, fixes #1151, ref. #1523
......@@ -20,6 +20,7 @@ var (
issue [-a <ASSIGNEE>] [-c <CREATOR>] [-@ <USER>] [-s <STATE>] [-f <FORMAT>] [-M <MILESTONE>] [-l <LABELS>] [-d <DATE>] [-o <SORT_KEY> [-^]] [-L <LIMIT>]
issue show [-f <FORMAT>] <NUMBER>
issue create [-oc] [-m <MESSAGE>|-F <FILE>] [--edit] [-a <USERS>] [-M <MILESTONE>] [-l <LABELS>]
issue update <NUMBER> [-m <MESSAGE>|-F <FILE>] [--edit] [-a <USERS>] [-M <MILESTONE>] [-l <LABELS>] [-s <STATE>]
issue labels [--color]
issue transfer <NUMBER> <REPO>
`,
......@@ -35,6 +36,10 @@ With no arguments, show a list of open issues.
* _create_:
Open an issue in the current repository.
* _update_:
Update fields of an existing issue specified by <NUMBER>. Use ''--edit''
to edit the title and message interactively in the text editor.
* _labels_:
List the labels available in this repository.
......@@ -227,6 +232,20 @@ hub-pr(1), hub(1)
Key: "transfer",
Run: transferIssue,
}
cmdUpdate = &Command{
Key: "update",
Run: updateIssue,
KnownFlags: `
-m, --message MSG
-F, --file FILE
-M, --milestone NAME
-l, --labels LIST
-a, --assign USER
-e, --edit
-s, --state STATE
`,
}
)
func init() {
......@@ -234,6 +253,7 @@ func init() {
cmdIssue.Use(cmdCreateIssue)
cmdIssue.Use(cmdLabel)
cmdIssue.Use(cmdTransfer)
cmdIssue.Use(cmdUpdate)
CmdRunner.Use(cmdIssue)
}
......@@ -587,21 +607,11 @@ text is the title and the rest is the description.`, project))
"body": body,
}
flagIssueLabels := commaSeparated(args.Flag.AllValues("--labels"))
if len(flagIssueLabels) > 0 {
params["labels"] = flagIssueLabels
}
setLabelsFromArgs(params, args)
flagIssueAssignees := commaSeparated(args.Flag.AllValues("--assign"))
if len(flagIssueAssignees) > 0 {
params["assignees"] = flagIssueAssignees
}
setAssigneesFromArgs(params, args)
milestoneNumber, err := milestoneValueToNumber(args.Flag.Value("--milestone"), gh, project)
utils.Check(err)
if milestoneNumber > 0 {
params["milestone"] = milestoneNumber
}
setMilestoneFromArgs(params, args, gh, project)
args.NoForward()
if args.Noop {
......@@ -618,6 +628,79 @@ text is the title and the rest is the description.`, project))
messageBuilder.Cleanup()
}
func updateIssue(cmd *Command, args *Args) {
issueNumber := 0
if args.ParamsSize() > 0 {
issueNumber, _ = strconv.Atoi(args.GetParam(0))
}
if issueNumber == 0 {
utils.Check(cmd.UsageError(""))
}
if !hasField(args, "--message", "--file", "--labels", "--milestone", "--assign", "--state", "--edit") {
utils.Check(cmd.UsageError("please specify fields to update"))
}
localRepo, err := github.LocalRepo()
utils.Check(err)
project, err := localRepo.MainProject()
utils.Check(err)
gh := github.NewClient(project.Host)
params := map[string]interface{}{}
setLabelsFromArgs(params, args)
setAssigneesFromArgs(params, args)
setMilestoneFromArgs(params, args, gh, project)
if args.Flag.HasReceived("--state") {
params["state"] = args.Flag.Value("--state")
}
if hasField(args, "--message", "--file", "--edit") {
messageBuilder := &github.MessageBuilder{
Filename: "ISSUE_EDITMSG",
Title: "issue",
}
messageBuilder.AddCommentedSection(fmt.Sprintf(`Editing issue #%d for %s
Update the message for this issue. The first block of
text is the title and the rest is the description.`, issueNumber, project))
messageBuilder.Edit = args.Flag.Bool("--edit")
flagIssueMessage := args.Flag.AllValues("--message")
if len(flagIssueMessage) > 0 {
messageBuilder.Message = strings.Join(flagIssueMessage, "\n\n")
} else if args.Flag.HasReceived("--file") {
messageBuilder.Message, err = msgFromFile(args.Flag.Value("--file"))
utils.Check(err)
} else {
issue, err := gh.FetchIssue(project, strconv.Itoa(issueNumber))
utils.Check(err)
existingMessage := fmt.Sprintf("%s\n\n%s", issue.Title, issue.Body)
messageBuilder.Message = strings.Replace(existingMessage, "\r\n", "\n", -1)
}
title, body, err := messageBuilder.Extract()
utils.Check(err)
if title == "" {
utils.Check(fmt.Errorf("Aborting creation due to empty issue title"))
}
params["title"] = title
params["body"] = body
defer messageBuilder.Cleanup()
}
args.NoForward()
if args.Noop {
ui.Printf("Would update issue #%d for %s\n", issueNumber, project)
} else {
err := gh.UpdateIssue(project, issueNumber, params)
utils.Check(err)
}
}
func listLabels(cmd *Command, args *Args) {
localRepo, err := github.LocalRepo()
utils.Check(err)
......@@ -642,6 +725,43 @@ func listLabels(cmd *Command, args *Args) {
}
}
func hasField(args *Args, names ...string) bool {
found := false
for _, name := range names {
if args.Flag.HasReceived(name) {
found = true
}
}
return found
}
func setLabelsFromArgs(params map[string]interface{}, args *Args) {
if !args.Flag.HasReceived("--labels") {
return
}
params["labels"] = commaSeparated(args.Flag.AllValues("--labels"))
}
func setAssigneesFromArgs(params map[string]interface{}, args *Args) {
if !args.Flag.HasReceived("--assign") {
return
}
params["assignees"] = commaSeparated(args.Flag.AllValues("--assign"))
}
func setMilestoneFromArgs(params map[string]interface{}, args *Args, gh *github.Client, project *github.Project) {
if !args.Flag.HasReceived("--milestone") {
return
}
milestoneNumber, err := milestoneValueToNumber(args.Flag.Value("--milestone"), gh, project)
utils.Check(err)
if milestoneNumber == 0 {
params["milestone"] = nil
} else {
params["milestone"] = milestoneNumber
}
}
func colorizeOutput(colorSet bool, when string) bool {
if !colorSet || when == "auto" {
colorConfig, _ := git.Config("color.ui")
......
......@@ -475,6 +475,9 @@ func parsePullRequestIssueNumber(url string) string {
func commaSeparated(l []string) []string {
res := []string{}
for _, i := range l {
if i == "" {
continue
}
res = append(res, strings.Split(i, ",")...)
}
return res
......
......@@ -596,7 +596,7 @@ text is the title and the rest is the description.`, tagName, project))
messageBuilder.Edit = args.Flag.Bool("--edit")
} else {
messageBuilder.Edit = true
messageBuilder.Message = fmt.Sprintf("%s\n\n%s", release.Name, release.Body)
messageBuilder.Message = strings.Replace(fmt.Sprintf("%s\n\n%s", release.Name, release.Body), "\r\n", "\n", -1)
}
title, body, err := messageBuilder.Extract()
......
......@@ -593,6 +593,165 @@ Feature: hub issue
https://github.com/github/hub/issues/1337\n
"""
Scenario: Update an issue's title
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => "Not workie, pls fix",
:body => "",
:milestone => :no,
:assignees => :no,
:labels => :no,
:state => :no
}
"""
Then I successfully run `hub issue update 1337 -m "Not workie, pls fix"`
Scenario: Update an issue's state
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => :no,
:labels => :no,
:state => "closed"
}
"""
Then I successfully run `hub issue update 1337 -s closed`
Scenario: Update an issue's labels
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => :no,
:body => :no,
:milestone => :no,
:assignees => :no,
:labels => ["bug", "important"]
}
"""
Then I successfully run `hub issue update 1337 -l bug,important`
Scenario: Update an issue's milestone
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => :no,
:body => :no,
:milestone => 42,
:assignees => :no,
:labels => :no
}
"""
Then I successfully run `hub issue update 1337 -M 42`
Scenario: Upate an issue's milestone by name
Given the GitHub API server:
"""
get('/repos/github/hub/milestones') {
status 200
json [
{ :number => 237, :title => "prerelease" },
{ :number => 42, :title => "Hello World!" }
]
}
patch('/repos/github/hub/issues/1337') {
assert :title => :no,
:body => :no,
:milestone => 42,
:assignees => :no,
:labels => :no
}
"""
Then I successfully run `hub issue update 1337 -M "hello world!"`
Scenario: Update an issue's assignees
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => :no,
:body => :no,
:milestone => :no,
:assignees => ["Cornwe19"],
:labels => :no
}
"""
Then I successfully run `hub issue update 1337 -a Cornwe19`
Scenario: Update an issue's title, labels, milestone, and assignees
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => "Not workie, pls fix",
:body => "",
:milestone => 42,
:assignees => ["Cornwe19"],
:labels => ["bug", "important"]
}
"""
Then I successfully run `hub issue update 1337 -m "Not workie, pls fix" -M 42 -l bug,important -a Cornwe19`
Scenario: Clear existing issue labels, assignees, milestone
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => :no,
:body => :no,
:milestone => nil,
:assignees => [],
:labels => []
}
"""
Then I successfully run `hub issue update 1337 --milestone= --assign= --labels=`
Scenario: Update an issue's title and body manually
Given the git commit editor is "vim"
And the text editor adds:
"""
My new title
"""
Given the GitHub API server:
"""
get('/repos/github/hub/issues/1337') {
json \
:number => 1337,
:title => "My old title",
:body => "My old body"
}
patch('/repos/github/hub/issues/1337') {
assert :title => "My new title",
:body => "My old title\n\nMy old body",
:milestone => :no,
:assignees => :no,
:labels => :no
}
"""
Then I successfully run `hub issue update 1337 --edit`
Scenario: Update an issue's title and body via a file
Given a file named "my-issue.md" with:
"""
My new title
My new body
"""
Given the GitHub API server:
"""
patch('/repos/github/hub/issues/1337') {
assert :title => "My new title",
:body => "My new body",
:milestone => :no,
:assignees => :no,
:labels => :no
}
"""
Then I successfully run `hub issue update 1337 -F my-issue.md`
Scenario: Update an issue without specifying fields to update
When I run `hub issue update 1337`
Then the exit status should be 1
Then the stderr should contain "please specify fields to update"
Then the stderr should contain "Usage: hub issue"
Scenario: Fetch issue labels
Given the GitHub API server:
"""
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册