package internal
import (
"fmt"
"github.com/pkg/errors"
"gitlab.com/pcanilho/go-jira"
"gopkg.in/yaml.v2"
"io"
"strings"
)
func (j *jiraController) CreateIssue(opts *IssueCreationOptions) (*jira.Issue, error) {
// Fetch object from key
projectObj, _, err := j.client.Project.GetWithContext(j.ctx, opts.Project)
if err != nil {
return nil, errors.Wrapf(err, "unable to find a project ID matching the key [%s]", opts.Project)
}
// Type
if len(strings.TrimSpace(opts.IssueType)) == 0 {
return nil, fmt.Errorf("an issue type must be specified")
}
// Assignee
var assignee *jira.User
if len(strings.TrimSpace(opts.Assignee)) > 0 {
assignee = &jira.User{Name: opts.Assignee}
}
// Components
var components []*jira.Component
for _, c := range opts.Components {
components = append(components, &jira.Component{
Name: c,
})
}
// Priority
var priority *jira.Priority
if len(strings.TrimSpace(opts.Priority)) > 0 {
priority = &jira.Priority{Name: opts.Priority}
}
// Set fields
newIssueFields := &jira.IssueFields{
Type: jira.IssueType{Name: opts.IssueType},
Project: *projectObj,
Description: opts.Description,
Reporter: &jira.User{Name: j.username},
Summary: opts.Summary,
Unknowns: opts.CustomFields,
Labels: opts.Labels,
Assignee: assignee,
Components: components,
Priority: priority,
}
// Create the issue
issue, resp, err := j.client.Issue.CreateWithContext(j.ctx, &jira.Issue{Fields: newIssueFields})
if err != nil {
if resp != nil {
b, _ := io.ReadAll(resp.Body)
fmt.Println(string(b))
}
return nil, errors.Wrapf(err, "unable to create the Jira ticket with summary [%s]", opts.Summary)
}
// If comment was provided
if len(strings.TrimSpace(opts.Comment)) > 0 {
if _, err = j.AddCommentToIssue(issue.Key, opts.Comment); err != nil {
return issue, errors.Wrapf(err, "unable to attach comment to the newly created ticket [%s]", issue.Key)
}
}
// If attachments were provided
if len(opts.Attachments) > 0 {
if err = j.UploadAttachmentsToIssue(issue.Key, opts.Attachments...); err != nil {
return issue, errors.Wrapf(err, "unable to upload attachments to the newly created ticket [%s]", issue.Key)
}
}
return issue, nil
}
func (j *jiraController) SearchIssues(jql string, options *jira.SearchOptions, maxOccurrences int) ([]jira.Issue, error) {
issues, resp, err := j.client.Issue.SearchWithContext(j.ctx, jql, options)
if err != nil {
if resp != nil {
b, _ := io.ReadAll(resp.Body)
fmt.Println(string(b))
}
return nil, errors.Wrapf(err, "unable to search issues with the provided JQL query [%s]", jql)
}
if maxOccurrences > 0 && len(issues) > maxOccurrences {
return nil, fmt.Errorf("the provided JQL query returned [%d] instead of the desired max occurrence value [%d]",
len(issues), maxOccurrences)
}
return issues, nil
}
func (j *jiraController) CloneIssue(issueID interface{}) (*jira.Issue, error) {
issue, err := j.getIssueFromIdentifier(issueID)
if err != nil {
return nil, err
}
createOptions := &IssueCreationOptions{
Summary: issue.Fields.Summary,
Description: issue.Fields.Description,
Project: issue.Fields.Project.Key,
IssueType: issue.Fields.Type.Name,
CustomFields: issue.Fields.Unknowns,
}
return j.CreateIssue(createOptions)
}
func (j *jiraController) GetIssue(identifier string, options *jira.GetQueryOptions) (*jira.Issue, error) {
issue, _, err := j.client.Issue.Get(identifier, options)
if err != nil {
return nil, errors.Wrapf(err, "unable to retrieve issue with provided identifier [%s]", identifier)
}
return issue, nil
}
func (j *jiraController) AddCommentToIssue(issueID interface{}, comment string) (*jira.Comment, error) {
issue, err := j.getIssueFromIdentifier(issueID)
if err != nil {
return nil, err
}
updatedComment, _, err := j.client.Issue.AddCommentWithContext(j.ctx, issue.ID, &jira.Comment{
Author: jira.User{Name: j.username},
Body: comment,
})
if err != nil {
return nil, errors.Wrapf(err, "unable to add comment to the issue [%s]", issueID)
}
return updatedComment, nil
}
func (j *jiraController) UpdateIssue(issueID interface{}, data map[string]interface{}) (*jira.Issue, error) {
if issueID == nil {
return nil, fmt.Errorf("cannot update a nil instance of the [jira.Issue] object")
}
issue, err := j.getIssueFromIdentifier(issueID)
if err != nil {
return nil, err
}
resp, err := j.client.Issue.UpdateIssueWithContext(j.ctx, issue.ID, mapToPayload(data))
if err != nil {
if resp != nil {
b, _ := io.ReadAll(resp.Body)
fmt.Println(string(b))
}
return nil, errors.Wrapf(err, "unable to update the issue with ID [%v]", issue.ID)
}
return issue, nil
}
func (j *jiraController) UploadAttachmentsToIssue(issueID interface{}, attachments ...*IssueAttachment) error {
issue, err := j.getIssueFromIdentifier(issueID)
if err != nil {
return err
}
for _, a := range attachments {
if _, _, err = j.client.Issue.PostAttachmentWithContext(j.ctx, issue.ID, a.Reader, a.Filename); err != nil {
return errors.Wrapf(err, "unable to upload the attachment [%s]", a.Filename)
}
}
return nil
}
func (j *jiraController) DeleteIssue(issueID interface{}) error {
issue, err := j.getIssueFromIdentifier(issueID)
if err != nil {
return err
}
_, err = j.client.Issue.DeleteWithContext(j.ctx, issue.ID)
if err != nil {
return errors.Wrapf(err, "unable to delete issue with provided identifier [%s]", issueID)
}
return nil
}
// Helpers
func (j *jiraController) getIssueFromIdentifier(issueID interface{}) (*jira.Issue, error) {
switch ji := issueID.(type) {
case *jira.Issue:
return ji, nil
case string:
return j.GetIssue(ji, nil)
}
return nil, fmt.Errorf("the issue identifier must be given in [string] or [*jira.Issue] format")
}
type uploadPayload struct {
Upload struct {
Data map[string]interface{} `yaml:",inline"`
} `yaml:"update"`
}
type setEntry struct {
Set string `json:"set"`
}
func mapToPayload(data map[string]interface{}) (out map[string]interface{}) {
var inter uploadPayload
inter.Upload.Data = make(map[string]interface{})
for k, v := range data {
inter.Upload.Data[k] = []setEntry{{fmt.Sprintf("%v", v)}}
}
b, _ := yaml.Marshal(inter)
_ = yaml.Unmarshal(b, &out)
return
}
|
The pages are generated with Golds v0.3.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |