-
-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add sprint agile apis #471
Open
limseong
wants to merge
1
commit into
andygrunwald:main
Choose a base branch
from
limseong:feature/sprint-agile-apis
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"golang.org/x/term" | ||
"log" | ||
"os" | ||
"strconv" | ||
"syscall" | ||
"time" | ||
|
||
jira "github.com/andygrunwald/go-jira" | ||
) | ||
|
||
// This example implement the behaviour of Jira's "Complete sprint" button. | ||
// It creates a new sprint and close the sprint currently active. | ||
// Then all issues under the closed sprint are moved to the newly created sprint. | ||
func main() { | ||
sc := bufio.NewScanner(os.Stdin) | ||
|
||
fmt.Print("Jira URL: ") | ||
sc.Scan() | ||
jiraURL := sc.Text() | ||
|
||
fmt.Print("Jira Username: ") | ||
sc.Scan() | ||
username := sc.Text() | ||
|
||
fmt.Print("Jira Password: ") | ||
bytePassword, _ := term.ReadPassword(int(syscall.Stdin)) | ||
password := string(bytePassword) | ||
|
||
fmt.Print("\nJira Board ID : ") | ||
sc.Scan() | ||
boardIDstr := sc.Text() | ||
boardID, err := strconv.Atoi(boardIDstr) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
tp := jira.BasicAuthTransport{ | ||
Username: username, | ||
Password: password, | ||
} | ||
|
||
client, err := jira.NewClient(tp.Client(), jiraURL) | ||
if err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
|
||
// create a new sprint | ||
start := time.Now() | ||
end := start.AddDate(0, 0, 7) | ||
s := jira.Sprint{ | ||
Name: "New Sprint", | ||
StartDate: &start, | ||
EndDate: &end, | ||
OriginBoardID: boardID, | ||
} | ||
futureSprint, _, err := client.Sprint.Create(&s) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Println("New sprint created ID:", futureSprint.ID) | ||
|
||
// get the sprint currently active | ||
sprints, _, err := client.Board.GetAllSprintsWithOptions(boardID, &jira.GetAllSprintsOptions{ | ||
State: "active", | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if len(sprints.Values) != 1 { | ||
log.Fatal("Retrieved active sprint list has invalid length") | ||
} | ||
activeSprint := sprints.Values[0] | ||
log.Println("Active sprint retrieved ID:", activeSprint.ID) | ||
|
||
// get all non-subtask issues of the active sprint | ||
issues, _, err := client.Sprint.GetIssuesForSprintWithOptions(activeSprint.ID, &jira.GetIssuesForSprintOptions{ | ||
Jql: "type NOT IN ('Sub-task')", | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Println("All non-subtask issues of the active sprint retrieved length:", len(issues)) | ||
for _, i := range issues { | ||
log.Printf("\t(%s) %s", i.ID, i.Fields.Summary) | ||
} | ||
|
||
// complete the active sprint | ||
completeParam := make(map[string]interface{}) | ||
completeParam["state"] = "closed" | ||
resp, err := client.Sprint.UpdateSprint(activeSprint.ID, completeParam) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
resp.Body.Close() | ||
log.Println("Active sprint completed") | ||
|
||
// move the issues previously under the active sprint to the newly created sprint | ||
var issueIDs []string | ||
for _, i := range issues { | ||
issueIDs = append(issueIDs, i.ID) | ||
} | ||
resp, err = client.Sprint.MoveIssuesToSprint(futureSprint.ID, issueIDs) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
resp.Body.Close() | ||
log.Println("The issues from the active sprint have been moved to the new sprint") | ||
|
||
// start the newly created sprint | ||
startParam := make(map[string]interface{}) | ||
startParam["state"] = "active" | ||
resp, err = client.Sprint.UpdateSprint(futureSprint.ID, startParam) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
resp.Body.Close() | ||
log.Println("The new sprint has been started") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,13 @@ type IssuesInSprintResult struct { | |
Issues []Issue `json:"issues"` | ||
} | ||
|
||
type GetIssuesForSprintOptions struct { | ||
// Jql filters results to issues that match the given JQL. | ||
Jql string `url:"jql,omitempty"` | ||
|
||
SearchOptions | ||
} | ||
|
||
// MoveIssuesToSprintWithContext moves issues to a sprint, for a given sprint Id. | ||
// Issues can only be moved to open or active sprints. | ||
// The maximum number of issues that can be moved in one operation is 50. | ||
|
@@ -81,6 +88,39 @@ func (s *SprintService) GetIssuesForSprint(sprintID int) ([]Issue, *Response, er | |
return s.GetIssuesForSprintWithContext(context.Background(), sprintID) | ||
} | ||
|
||
// GetIssuesForSprintWithOptionsWithContext returns all issues in a sprint, for a given sprint Id. | ||
// The issues are filtered out with the given options. | ||
// This only includes issues that the user has permission to view. | ||
// By default, the returned issues are ordered by rank. | ||
// | ||
// Jira API Docs: https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/sprint-getIssuesForSprint | ||
func (s *SprintService) GetIssuesForSprintWithOptionsWithContext(ctx context.Context, sprintID int, options *GetIssuesForSprintOptions) ([]Issue, *Response, error) { | ||
apiEndpoint := fmt.Sprintf("rest/agile/1.0/sprint/%d/issue", sprintID) | ||
url, err := addOptions(apiEndpoint, options) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
req, err := s.client.NewRequestWithContext(ctx, "GET", url, nil) | ||
|
||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
result := new(IssuesInSprintResult) | ||
resp, err := s.client.Do(req, result) | ||
if err != nil { | ||
err = NewJiraError(resp, err) | ||
} | ||
|
||
return result.Issues, resp, err | ||
} | ||
|
||
// GetIssuesForSprintWithOptions wraps GetIssuesForSprintWithOptionsWithContext using the background context. | ||
func (s *SprintService) GetIssuesForSprintWithOptions(sprintID int, options *GetIssuesForSprintOptions) ([]Issue, *Response, error) { | ||
return s.GetIssuesForSprintWithOptionsWithContext(context.Background(), sprintID, options) | ||
} | ||
|
||
// GetIssueWithContext returns a full representation of the issue for the given issue key. | ||
// Jira will attempt to identify the issue by the issueIdOrKey path parameter. | ||
// This can be an issue id, or an issue key. | ||
|
@@ -123,3 +163,54 @@ func (s *SprintService) GetIssueWithContext(ctx context.Context, issueID string, | |
func (s *SprintService) GetIssue(issueID string, options *GetQueryOptions) (*Issue, *Response, error) { | ||
return s.GetIssueWithContext(context.Background(), issueID, options) | ||
} | ||
|
||
// CreateWithContext creates a sprint from a JSON representation. | ||
// | ||
// Jira API docs: https://docs.atlassian.com/jira-software/REST/7.3.1/#agile/1.0/sprint-createSprint | ||
func (s *SprintService) CreateWithContext(ctx context.Context, sprint *Sprint) (*Sprint, *Response, error) { | ||
apiEndpoint := "rest/agile/1.0/sprint" | ||
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, sprint) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
created := new(Sprint) | ||
resp, err := s.client.Do(req, created) | ||
if err != nil { | ||
jerr := NewJiraError(resp, err) | ||
return nil, resp, jerr | ||
} | ||
|
||
return created, resp, nil | ||
} | ||
|
||
// Create wraps CreateWithContext using the background context. | ||
func (s *SprintService) Create(sprint *Sprint) (*Sprint, *Response, error) { | ||
return s.CreateWithContext(context.Background(), sprint) | ||
} | ||
|
||
// UpdateSprintWithContext partially updates a sprint from a JSON representation. The sprint is found by ID. | ||
// | ||
// Jira API docs: https://docs.atlassian.com/jira-software/REST/7.3.1/#agile/1.0/sprint-partiallyUpdateSprint | ||
// Caller must close resp.Body | ||
func (s *SprintService) UpdateSprintWithContext(ctx context.Context, sprintID int, data map[string]interface{}) (*Response, error) { | ||
apiEndpoint := fmt.Sprintf("rest/agile/1.0/sprint/%v", sprintID) | ||
|
||
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
resp, err := s.client.Do(req, nil) | ||
if err != nil { | ||
jerr := NewJiraError(resp, err) | ||
return resp, jerr | ||
} | ||
|
||
return resp, nil | ||
} | ||
|
||
// UpdateSprint wraps UpdateSprintWithContext using the background context. | ||
// Caller must close resp.Body | ||
func (s *SprintService) UpdateSprint(sprintID int, data map[string]interface{}) (*Response, error) { | ||
return s.UpdateSprintWithContext(context.Background(), sprintID, data) | ||
} | ||
Comment on lines
+192
to
+216
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've followed the format that caller must close response body |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sprint
struct has been used only in unmarshaling JSON responses from /boards API call.So adding
omitempty
will not break any of current behaviours.