Skip to content

Commit

Permalink
feat: Add issues unlink command
Browse files Browse the repository at this point in the history
  • Loading branch information
Sushil Kumar Gupta committed Apr 20, 2022
1 parent 75cfa19 commit a103669
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 0 deletions.
149 changes: 149 additions & 0 deletions internal/cmd/issue/unlink/unlink.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package unlinkParams

import (
"fmt"
"os"

"github.com/AlecAivazis/survey/v2"
"github.com/ankitpokhrel/jira-cli/api"
"github.com/ankitpokhrel/jira-cli/internal/cmdutil"
"github.com/ankitpokhrel/jira-cli/internal/query"
"github.com/ankitpokhrel/jira-cli/pkg/jira"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

const (
helpText = `Unlink disconnects two issues from each other, if already connected.`
examples = `$ jira issue unlink ISSUE-1 ISSUE-2`
optionCancel = "Cancel"
)

// NewCmdUnlink is an unlink command.
func NewCmdUnlink() *cobra.Command {
cmd := cobra.Command{
Use: "unlink INWARD_ISSUE_KEY OUTWARD_ISSUE_KEY",
Short: "Unlink disconnects two issues from each other",
Long: helpText,
Example: examples,
Aliases: []string{"ln"},
Annotations: map[string]string{
"help:args": "INWARD_ISSUE_KEY\tIssue key of the source issue, eg: ISSUE-1\n" +
"OUTWARD_ISSUE_KEY\tIssue key of the target issue, eg: ISSUE-2.",
},
Run: unlink,
}

cmd.Flags().Bool("web", false, "Open inward issue in web browser after successful unlinking")

return &cmd
}

func unlink(cmd *cobra.Command, args []string) {
project := viper.GetString("project.key")
params := parseArgsAndFlags(cmd.Flags(), args, project)
client := api.Client(jira.Config{Debug: params.debug})
uc := unlinkCmd{
client: client,
params: params,
}

cmdutil.ExitIfError(uc.setInwardIssueKey(project))
cmdutil.ExitIfError(uc.setOutwardIssueKey(project))

// TODO: Why is this being compared with optionCancel?!
if uc.params.outwardIssueKey == optionCancel {
cmdutil.Fail("Action aborted")
os.Exit(0)
}

err := func() error {
s := cmdutil.Info("Unlinking issues")
defer s.Stop()

return client.UnlinkIssue(uc.params.inwardIssueKey, uc.params.outwardIssueKey)
}()
cmdutil.ExitIfError(err)

server := viper.GetString("server")

cmdutil.Success("Issues unlinked")
fmt.Printf("%s/browse/%s\n", server, uc.params.inwardIssueKey)

if web, _ := cmd.Flags().GetBool("web"); web {
err := cmdutil.Navigate(server, uc.params.inwardIssueKey)
cmdutil.ExitIfError(err)
}
}

type unlinkParams struct {
inwardIssueKey string
outwardIssueKey string
debug bool
}

func parseArgsAndFlags(flags query.FlagParser, args []string, project string) *unlinkParams {
var inwardIssueKey, outwardIssueKey string

nargs := len(args)
if nargs >= 1 {
inwardIssueKey = cmdutil.GetJiraIssueKey(project, args[0])
}
if nargs >= 2 {
outwardIssueKey = cmdutil.GetJiraIssueKey(project, args[1])
}

debug, err := flags.GetBool("debug")
cmdutil.ExitIfError(err)

return &unlinkParams{
inwardIssueKey: inwardIssueKey,
outwardIssueKey: outwardIssueKey,
debug: debug,
}
}

type unlinkCmd struct {
client *jira.Client
params *unlinkParams
}

func (uc *unlinkCmd) setInwardIssueKey(project string) error {
if uc.params.inwardIssueKey != "" {
return nil
}

var ans string

qs := &survey.Question{
Name: "inwardIssueKey",
Prompt: &survey.Input{Message: "Inward issue key"},
Validate: survey.Required,
}
if err := survey.Ask([]*survey.Question{qs}, &ans); err != nil {
return err
}
uc.params.inwardIssueKey = cmdutil.GetJiraIssueKey(project, ans)

return nil
}

func (uc *unlinkCmd) setOutwardIssueKey(project string) error {
if uc.params.outwardIssueKey != "" {
return nil
}

var ans string

qs := &survey.Question{
Name: "outwardIssueKey",
Prompt: &survey.Input{Message: "Outward issue key"},
Validate: survey.Required,
}
if err := survey.Ask([]*survey.Question{qs}, &ans); err != nil {
return err
}
uc.params.outwardIssueKey = cmdutil.GetJiraIssueKey(project, ans)

return nil
}
27 changes: 27 additions & 0 deletions pkg/jira/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,33 @@ func (c *Client) LinkIssue(inwardIssue, outwardIssue, linkType string) error {
return nil
}

// UnlinkIssue disconnects two issues using DELETE /issueLink/{linkId} endpoint.
func (c *Client) UnlinkIssue(inwardIssue, outwardIssue string) error {
// TODO: Get linkID using both inward and outward issues before calling delete.
// See: To obtain the ID of the issue link, use
// https://your-domain.atlassian.net/rest/api/3/issue/[linked issue key]?fields=issuelinks.
// Filter out the links by outwardIssue.

linkID := 123

res, err := c.DeleteV2(context.Background(), fmt.Sprintf("/issueLink/%d", linkID), Header{
"Accept": "application/json",
"Content-Type": "application/json",
})
if err != nil {
return err
}
if res == nil {
return ErrEmptyResponse
}
defer func() { _ = res.Body.Close() }()

if res.StatusCode != http.StatusNoContent {
return formatUnexpectedResponse(res)
}
return nil
}

type issueCommentRequest struct {
Body string `json:"body"`
}
Expand Down

0 comments on commit a103669

Please sign in to comment.