mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
feat(milestone): milestone tables, views, forms and one selection model
milestone view printed the list row, and milestone list hid the due date and progress. milestone list now shows ID TITLE [STATE] DUE PROGRESS, open milestones first and by due date; milestone view shows the state, due date, progress, description and the milestone's web page (also --web). Every milestone command addresses milestones by title or ID. Mutations report ✓ lines: milestone create also prints the new milestone's URL and takes the title as an argument; close and reopen skip milestones already in that state; delete names the milestone in its confirmation; milestone issue add and remove report one line such as "✓ Added #1, #2 to milestone "v1.0" in alice/x". milestone issue list uses the issue table. milestone edit without flags on a terminal opens the milestone form with the current values, and every milestone command completes milestone titles and has help text with examples. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
14 files changed
+606
-257
No files matched your search
@@ -57,7 +57,7 @@ func TestRemoveMilestoneRejectsDifferentMembership(t *testing.T) {
|
||||
_, _ = w.Write([]byte(`{"milestone":{"id":9}}`))
|
||||
}))
|
||||
service := Issues{Client: client, Repository: "alice/project"}
|
||||
_, err := service.RemoveMilestone(context.Background(), 7, 8)
|
||||
require.ErrorContains(t, err, "not assigned to milestone 8")
|
||||
_, err := service.RemoveMilestone(context.Background(), 7, Milestone{ID: 8, Title: "v1.0"})
|
||||
require.EqualError(t, err, `#7 is not in milestone "v1.0"`)
|
||||
require.Zero(t, mutations)
|
||||
}
|
||||
@@ -206,6 +206,21 @@ func (s Milestones) List(ctx context.Context, state string, limit, page int) ([]
|
||||
return convertAll(milestones, milestoneFrom), nil
|
||||
}
|
||||
|
||||
// ListPage is List with the number of milestones in state, as the server counts them.
|
||||
func (s Milestones) ListPage(ctx context.Context, state string, limit, page int) (Page[Milestone], error) {
|
||||
owner, repo, err := splitRepository(s.Repository)
|
||||
if err != nil {
|
||||
return Page[Milestone]{}, err
|
||||
}
|
||||
milestones, err := listPage(limit, page, func(limit, page int) ([]*gitea.Milestone, http.Header, error) {
|
||||
milestones, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Milestone, *gitea.Response, error) {
|
||||
return c.Repositories.ListMilestones(ctx, owner, repo, gitea.ListMilestoneOption{ListOptions: listOptions(limit, page), State: gitea.StateType(state)})
|
||||
})
|
||||
return milestones, headerOf(resp), err
|
||||
})
|
||||
return Page[Milestone]{Items: convertAll(milestones.Items, milestoneFrom), More: milestones.More, Total: milestones.Total, Counted: milestones.Counted}, err
|
||||
}
|
||||
|
||||
// Create creates one milestone.
|
||||
func (s Milestones) Create(ctx context.Context, opts MilestoneOptions) (Milestone, error) {
|
||||
owner, repo, err := splitRepository(s.Repository)
|
||||
@@ -388,13 +403,13 @@ func mergeUnique[T any](current, add, remove []T, equal func(T, T) bool) []T {
|
||||
}
|
||||
|
||||
// RemoveMilestone refuses to clear an issue belonging to another milestone.
|
||||
func (s Issues) RemoveMilestone(ctx context.Context, n, id int64) (Issue, error) {
|
||||
func (s Issues) RemoveMilestone(ctx context.Context, n int64, milestone Milestone) (Issue, error) {
|
||||
current, err := s.View(ctx, n)
|
||||
if err != nil {
|
||||
return Issue{}, err
|
||||
}
|
||||
if current.Milestone == nil || current.Milestone.ID != id {
|
||||
return Issue{}, fmt.Errorf("issue is not assigned to milestone %d", id)
|
||||
if current.Milestone == nil || current.Milestone.ID != milestone.ID {
|
||||
return Issue{}, fmt.Errorf("#%d is not in milestone %q", n, milestone.Title)
|
||||
}
|
||||
cleared := int64(0)
|
||||
return s.Edit(ctx, n, IssueEdit{Milestone: &cleared})
|
||||
|
||||
Reference in new issue
Block a user