Allow standalone command to create issues
This commit is contained in:
parent
ab2e28e29e
commit
1b66405f39
6 changed files with 148 additions and 93 deletions
|
@ -23,7 +23,7 @@ func GrepAddCmd() *cobra.Command {
|
|||
Run: grepAddCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP("file-only", "f", false, "generates one ticket per file instead of per match")
|
||||
cmd.Flags().BoolP("file-only", "f", false, "Generates one ticket per file instead of per match")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func AgAddCmd() *cobra.Command {
|
|||
RunE: agAddCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP("file-only", "f", false, "generates one ticket per file instead of per match")
|
||||
cmd.Flags().BoolP("file-only", "f", false, "Generates one ticket per file instead of per match")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ func GovetAddCmd() *cobra.Command {
|
|||
RunE: govetAddCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP("file-only", "f", false, "generates one ticket per file instead of per match")
|
||||
cmd.Flags().BoolP("file-only", "f", false, "Generates one ticket per file instead of per match")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func CsvAddCmd() *cobra.Command {
|
|||
RunE: csvAddCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP("file-only", "f", false, "generates one ticket per file instead of per match")
|
||||
cmd.Flags().BoolP("file-only", "f", false, "Generates one ticket per file instead of per match")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
12
cmd/init.go
12
cmd/init.go
|
@ -15,14 +15,16 @@ func InitCmd() *cobra.Command {
|
|||
Run: initCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().StringP("url", "u", "", "the jira server URL")
|
||||
cmd.Flags().StringP("url", "u", "", "The jira server URL")
|
||||
_ = cmd.MarkFlagRequired("url")
|
||||
cmd.Flags().StringP("project", "p", "", "the jira project key to associate the tickets with")
|
||||
cmd.Flags().StringP("project", "p", "", "The jira project key to associate the tickets with")
|
||||
_ = cmd.MarkFlagRequired("project")
|
||||
cmd.Flags().StringP("epic", "e", "", "the epic id to associate this campaign with")
|
||||
cmd.Flags().StringP("epic", "e", "", "The epic id to associate this campaign with")
|
||||
_ = cmd.MarkFlagRequired("epic")
|
||||
cmd.Flags().StringP("summary", "s", "", "the summary of the tickets")
|
||||
cmd.Flags().StringP("summary", "s", "", "The summary of the tickets")
|
||||
_ = cmd.MarkFlagRequired("summary")
|
||||
cmd.Flags().StringP("template", "t", "", "The template path for the description of the tickets")
|
||||
_ = cmd.MarkFlagRequired("template")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -32,12 +34,14 @@ func initCmdF(cmd *cobra.Command, _ []string) {
|
|||
project, _ := cmd.Flags().GetString("project")
|
||||
epic, _ := cmd.Flags().GetString("epic")
|
||||
summary, _ := cmd.Flags().GetString("summary")
|
||||
template, _ := cmd.Flags().GetString("template")
|
||||
|
||||
cmp := &model.Campaign{
|
||||
Url: url,
|
||||
Project: project,
|
||||
Epic: epic,
|
||||
Summary: summary,
|
||||
Template: template,
|
||||
}
|
||||
if err := campaign.Save(cmp); err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
|
|
|
@ -5,12 +5,17 @@ import (
|
|||
)
|
||||
|
||||
func JiraPublishCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "jira",
|
||||
Short: "Publishes the campaign tickets in JIRA",
|
||||
Args: cobra.NoArgs,
|
||||
Run: jiraPublishCmdF,
|
||||
RunE: jiraPublishCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP("all", "a", false, "Publish all the tickets of the campaign")
|
||||
cmd.Flags().IntP("batch", "b", 0, "Number of tickets to publish")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func PublishCmd() *cobra.Command {
|
||||
|
@ -26,4 +31,15 @@ func PublishCmd() *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func jiraPublishCmdF(_ *cobra.Command, _ []string) {}
|
||||
func jiraPublishCmdF(cmd *cobra.Command, _ []string) error {
|
||||
/*
|
||||
all, _ := cmd.Flags().GetBool("all")
|
||||
batch, _ := cmd.Flags().GetInt("batch")
|
||||
|
||||
if !all && batch == 0 {
|
||||
return fmt.Errorf("One of --all or --batch flags is required")
|
||||
}
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/config"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/jira"
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -34,19 +33,19 @@ func CreateJiraTicketStandaloneCmd() *cobra.Command {
|
|||
RunE: createJiraTicketStandaloneCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().String("url", "", "the jira server URL")
|
||||
cmd.Flags().String("url", "", "The jira server URL")
|
||||
_ = cmd.MarkFlagRequired("url")
|
||||
cmd.Flags().String("epic", "", "the jira epic id to associate the ticket with")
|
||||
cmd.Flags().String("epic", "", "The jira epic id to associate the ticket with")
|
||||
_ = cmd.MarkFlagRequired("epic")
|
||||
cmd.Flags().String("team", "", "the team for the new ticket")
|
||||
_ = cmd.MarkFlagRequired("epic")
|
||||
cmd.Flags().String("username", "", "the jira username")
|
||||
cmd.Flags().String("token", "", "the jira token")
|
||||
cmd.Flags().String("summary", "", "the summary of the ticket")
|
||||
cmd.Flags().StringP("project", "p", "", "The jira project key to associate the tickets with")
|
||||
_ = cmd.MarkFlagRequired("project")
|
||||
cmd.Flags().String("summary", "", "The summary of the ticket")
|
||||
_ = cmd.MarkFlagRequired("summary")
|
||||
cmd.Flags().String("template", "", "the template to render the description of the ticket")
|
||||
cmd.Flags().String("template", "", "The template to render the description of the ticket")
|
||||
_ = cmd.MarkFlagRequired("template")
|
||||
cmd.Flags().StringSliceP("vars", "v", []string{}, "the variables to use in the template")
|
||||
cmd.Flags().String("username", "", "The jira username")
|
||||
cmd.Flags().String("token", "", "The jira token")
|
||||
cmd.Flags().StringSliceP("vars", "v", []string{}, "The variables to use in the template")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -59,16 +58,16 @@ func GetJiraTicketStandaloneCmd() *cobra.Command {
|
|||
Run: getJiraTicketStandaloneCmdF,
|
||||
}
|
||||
|
||||
cmd.Flags().String("url", "", "the jira server URL")
|
||||
cmd.Flags().String("url", "", "The jira server URL")
|
||||
_ = cmd.MarkFlagRequired("url")
|
||||
cmd.Flags().String("username", "", "the jira username")
|
||||
cmd.Flags().String("token", "", "the jira token")
|
||||
cmd.Flags().String("username", "", "The jira username")
|
||||
cmd.Flags().String("token", "", "The jira token")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getVarMap(vars []string) (map[string]string, error) {
|
||||
varMap := map[string]string{}
|
||||
func getVarMap(vars []string) (map[string]interface{}, error) {
|
||||
varMap := map[string]interface{}{}
|
||||
for _, v := range vars {
|
||||
parts := strings.Split(v, "=")
|
||||
if len(parts) < 2 {
|
||||
|
@ -81,12 +80,12 @@ func getVarMap(vars []string) (map[string]string, error) {
|
|||
|
||||
func createJiraTicketStandaloneCmdF(cmd *cobra.Command, _ []string) error {
|
||||
url, _ := cmd.Flags().GetString("url")
|
||||
epicId, _ := cmd.Flags().GetString("epic")
|
||||
team, _ := cmd.Flags().GetString("team")
|
||||
epic, _ := cmd.Flags().GetString("epic")
|
||||
project, _ := cmd.Flags().GetString("project")
|
||||
username, _ := cmd.Flags().GetString("username")
|
||||
token, _ := cmd.Flags().GetString("token")
|
||||
summaryTmplStr, _ := cmd.Flags().GetString("summary")
|
||||
templatePath, _ := cmd.Flags().GetString("template")
|
||||
summary, _ := cmd.Flags().GetString("summary")
|
||||
template, _ := cmd.Flags().GetString("template")
|
||||
vars, _ := cmd.Flags().GetStringSlice("vars")
|
||||
|
||||
if username == "" || token == "" {
|
||||
|
@ -108,39 +107,25 @@ func createJiraTicketStandaloneCmdF(cmd *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("error processing vars: %w", err)
|
||||
}
|
||||
|
||||
sumTmpl, err := template.New("").Parse(summaryTmplStr)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
var summaryBytes bytes.Buffer
|
||||
if err := sumTmpl.Execute(&summaryBytes, varMap); err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
summary := summaryBytes.String()
|
||||
|
||||
descTmpl, err := template.ParseFiles(templatePath)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
var descriptionBytes bytes.Buffer
|
||||
if err := descTmpl.Execute(&descriptionBytes, varMap); err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
description := descriptionBytes.String()
|
||||
|
||||
jiraClient, err := jira.NewClient(url, username, token)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
ticketKey, err := jiraClient.CreateIssue(epicId, team, summary, description)
|
||||
campaign := &model.Campaign{
|
||||
Epic: epic,
|
||||
Project: project,
|
||||
Summary: summary,
|
||||
Template: template,
|
||||
}
|
||||
ticket := &model.Ticket{Data: varMap}
|
||||
|
||||
issue, err := jiraClient.CreateTicket(ticket, campaign)
|
||||
if err != nil {
|
||||
ErrorAndExit(cmd, err)
|
||||
}
|
||||
|
||||
cmd.Printf("Ticket %s successfully created in JIRA", ticketKey)
|
||||
cmd.Printf("Ticket %s successfully created in JIRA", issue.Key)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
100
jira/jira.go
100
jira/jira.go
|
@ -1,6 +1,13 @@
|
|||
package jira
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"text/template"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||
|
||||
jira "gopkg.in/andygrunwald/go-jira.v1"
|
||||
)
|
||||
|
||||
|
@ -8,6 +15,64 @@ type JiraClient struct {
|
|||
*jira.Client
|
||||
}
|
||||
|
||||
func (c *JiraClient) GetIssueFromTicket(ticket *model.Ticket, campaign *model.Campaign) (*jira.Issue, error) {
|
||||
summaryTmpl, err := template.New("").Parse(campaign.Summary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var summaryBytes bytes.Buffer
|
||||
if err := summaryTmpl.Execute(&summaryBytes, ticket.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
summary := summaryBytes.String()
|
||||
|
||||
descriptionTemplate, err := template.ParseFiles(campaign.Template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var descriptionBytes bytes.Buffer
|
||||
if err := descriptionTemplate.Execute(&descriptionBytes, ticket.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
description := descriptionBytes.String()
|
||||
|
||||
data := map[string]string{
|
||||
"Description": description,
|
||||
"Summary": summary,
|
||||
"Project": campaign.Project,
|
||||
"Issue Type": "Story",
|
||||
"Epic Link": campaign.Epic,
|
||||
}
|
||||
|
||||
if team, ok := ticket.Data["team"]; ok {
|
||||
data["team"] = team.(string)
|
||||
}
|
||||
|
||||
createMetaInfo, _, err := c.Issue.GetCreateMeta(campaign.Project)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
project := createMetaInfo.GetProjectWithKey(campaign.Project)
|
||||
if project == nil {
|
||||
return nil, fmt.Errorf("Error retrieving project with key %s", campaign.Project)
|
||||
}
|
||||
|
||||
issueType := project.GetIssueTypeWithName("Story")
|
||||
if issueType == nil {
|
||||
return nil, fmt.Errorf("Error retrieving issue type with name Story")
|
||||
}
|
||||
|
||||
issue, err := jira.InitIssueWithMetaAndFields(project, issueType, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return issue, nil
|
||||
}
|
||||
|
||||
func NewClient(url, username, token string) (*JiraClient, error) {
|
||||
tp := jira.BasicAuthTransport{
|
||||
Username: username,
|
||||
|
@ -22,38 +87,21 @@ func NewClient(url, username, token string) (*JiraClient, error) {
|
|||
return &JiraClient{client}, nil
|
||||
}
|
||||
|
||||
func (c *JiraClient) CreateIssue(epicId, team, summary, description string) (string, error) {
|
||||
/*
|
||||
data := map[string]interface{}{
|
||||
"fields": map[string]interface{}{
|
||||
"project": map[string]interface{}{"key": "MM"},
|
||||
"summary": summary,
|
||||
"description": description,
|
||||
"issuetype": map[string]interface{}{"name": "Story"},
|
||||
"customfield_10007": epicId,
|
||||
"customfield_11101": map[string]interface{}{"value": team},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(data)
|
||||
func (c *JiraClient) CreateTicket(ticket *model.Ticket, campaign *model.Campaign) (*jira.Issue, error) {
|
||||
issue, err := c.GetIssueFromTicket(ticket, campaign)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := http.DoPost(c.Username, c.Token, c.Url+"issue/", body)
|
||||
b, _ := json.MarshalIndent(issue, "", " ")
|
||||
fmt.Println(string(b))
|
||||
|
||||
newIssue, _, err := c.Issue.Create(issue)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
issue, err := IssueFromJson(res.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return issue.Key, nil
|
||||
*/
|
||||
return "", nil
|
||||
return newIssue, nil
|
||||
}
|
||||
|
||||
func (c *JiraClient) GetIssue(issueNo string) (*jira.Issue, error) {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package model
|
||||
|
||||
// ToDo: add key-value extra params as a map to allow for customfield_whatever = team
|
||||
type Campaign struct {
|
||||
Url string `json:"url"`
|
||||
Project string `json:"project"`
|
||||
Epic string `json:"epic"`
|
||||
Summary string `json:"summary"`
|
||||
Template string `json:"template"`
|
||||
Tickets []*Ticket `json:"tickets,omitempty"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue