Add API to get issue/pull comments and events (timeline) (#17403)
* Add API to get issue/pull comments and events (timeline) Adds an API to get both comments and events in one endpoint with all required data. Closes go-gitea/gitea#13250 * Fix swagger * Don't show code comments (use review api instead) * fmt * Fix comment * Time -> TrackedTime * Use var directly * Add logger * Fix lint * Fix test * Add comments * fmt * [test] get issue directly by ID * Update test * Add description for changed refs * Fix build issues + lint * Fix build * Use string enums * Update swagger * Support `page` and `limit` params * fmt + swagger * Use global slices Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
549fd03c0e
commit
7db2f110ad
9 changed files with 577 additions and 0 deletions
|
@ -180,3 +180,25 @@ func TestAPIDeleteComment(t *testing.T) {
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
|
unittest.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPIListIssueTimeline(t *testing.T) {
|
||||||
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
|
// load comment
|
||||||
|
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 1}).(*models.Issue)
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
|
|
||||||
|
// make request
|
||||||
|
session := loginUser(t, repoOwner.Name)
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/timeline",
|
||||||
|
repoOwner.Name, repo.Name, issue.Index)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
// check if lens of list returned by API and
|
||||||
|
// lists extracted directly from DB are the same
|
||||||
|
var comments []*api.TimelineComment
|
||||||
|
DecodeJSON(t, resp, &comments)
|
||||||
|
expectedCount := unittest.GetCount(t, &models.Comment{IssueID: issue.ID})
|
||||||
|
assert.EqualValues(t, expectedCount, len(comments))
|
||||||
|
}
|
||||||
|
|
|
@ -110,6 +110,47 @@ const (
|
||||||
CommentTypeChangeIssueRef
|
CommentTypeChangeIssueRef
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var commentStrings = []string{
|
||||||
|
"comment",
|
||||||
|
"reopen",
|
||||||
|
"close",
|
||||||
|
"issue_ref",
|
||||||
|
"commit_ref",
|
||||||
|
"comment_ref",
|
||||||
|
"pull_ref",
|
||||||
|
"label",
|
||||||
|
"milestone",
|
||||||
|
"assignees",
|
||||||
|
"change_title",
|
||||||
|
"delete_branch",
|
||||||
|
"start_tracking",
|
||||||
|
"stop_tracking",
|
||||||
|
"add_time_manual",
|
||||||
|
"cancel_tracking",
|
||||||
|
"added_deadline",
|
||||||
|
"modified_deadline",
|
||||||
|
"removed_deadline",
|
||||||
|
"add_dependency",
|
||||||
|
"remove_dependency",
|
||||||
|
"code",
|
||||||
|
"review",
|
||||||
|
"lock",
|
||||||
|
"unlock",
|
||||||
|
"change_target_branch",
|
||||||
|
"delete_time_manual",
|
||||||
|
"review_request",
|
||||||
|
"merge_pull",
|
||||||
|
"pull_push",
|
||||||
|
"project",
|
||||||
|
"project_board",
|
||||||
|
"dismiss_review",
|
||||||
|
"change_issue_ref",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t CommentType) String() string {
|
||||||
|
return commentStrings[t]
|
||||||
|
}
|
||||||
|
|
||||||
// RoleDescriptor defines comment tag type
|
// RoleDescriptor defines comment tag type
|
||||||
type RoleDescriptor int
|
type RoleDescriptor int
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,3 +25,143 @@ func ToComment(c *models.Comment) *api.Comment {
|
||||||
Updated: c.UpdatedUnix.AsTime(),
|
Updated: c.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToTimelineComment converts a models.Comment to the api.TimelineComment format
|
||||||
|
func ToTimelineComment(c *models.Comment, doer *user_model.User) *api.TimelineComment {
|
||||||
|
err := c.LoadMilestone()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadMilestone: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.LoadAssigneeUserAndTeam()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadAssigneeUserAndTeam: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.LoadResolveDoer()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadResolveDoer: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.LoadDepIssueDetails()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadDepIssueDetails: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.LoadTime()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadTime: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.LoadLabel()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadLabel: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
comment := &api.TimelineComment{
|
||||||
|
ID: c.ID,
|
||||||
|
Type: c.Type.String(),
|
||||||
|
Poster: ToUser(c.Poster, nil),
|
||||||
|
HTMLURL: c.HTMLURL(),
|
||||||
|
IssueURL: c.IssueURL(),
|
||||||
|
PRURL: c.PRURL(),
|
||||||
|
Body: c.Content,
|
||||||
|
Created: c.CreatedUnix.AsTime(),
|
||||||
|
Updated: c.UpdatedUnix.AsTime(),
|
||||||
|
|
||||||
|
OldProjectID: c.OldProjectID,
|
||||||
|
ProjectID: c.ProjectID,
|
||||||
|
|
||||||
|
OldTitle: c.OldTitle,
|
||||||
|
NewTitle: c.NewTitle,
|
||||||
|
|
||||||
|
OldRef: c.OldRef,
|
||||||
|
NewRef: c.NewRef,
|
||||||
|
|
||||||
|
RefAction: c.RefAction.String(),
|
||||||
|
RefCommitSHA: c.CommitSHA,
|
||||||
|
|
||||||
|
ReviewID: c.ReviewID,
|
||||||
|
|
||||||
|
RemovedAssignee: c.RemovedAssignee,
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.OldMilestone != nil {
|
||||||
|
comment.OldMilestone = ToAPIMilestone(c.OldMilestone)
|
||||||
|
}
|
||||||
|
if c.Milestone != nil {
|
||||||
|
comment.Milestone = ToAPIMilestone(c.Milestone)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Time != nil {
|
||||||
|
comment.TrackedTime = ToTrackedTime(c.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.RefIssueID != 0 {
|
||||||
|
issue, err := models.GetIssueByID(c.RefIssueID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetIssueByID(%d): %v", c.RefIssueID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comment.RefIssue = ToAPIIssue(issue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.RefCommentID != 0 {
|
||||||
|
com, err := models.GetCommentByID(c.RefCommentID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetCommentByID(%d): %v", c.RefCommentID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = com.LoadPoster()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LoadPoster: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comment.RefComment = ToComment(com)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Label != nil {
|
||||||
|
var org *user_model.User
|
||||||
|
var repo *repo_model.Repository
|
||||||
|
if c.Label.BelongsToOrg() {
|
||||||
|
var err error
|
||||||
|
org, err = user_model.GetUserByID(c.Label.OrgID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetUserByID(%d): %v", c.Label.OrgID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Label.BelongsToRepo() {
|
||||||
|
var err error
|
||||||
|
repo, err = repo_model.GetRepositoryByID(c.Label.RepoID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetRepositoryByID(%d): %v", c.Label.RepoID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comment.Label = ToLabel(c.Label, repo, org)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Assignee != nil {
|
||||||
|
comment.Assignee = ToUser(c.Assignee, nil)
|
||||||
|
}
|
||||||
|
if c.AssigneeTeam != nil {
|
||||||
|
comment.AssigneeTeam = ToTeam(c.AssigneeTeam)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ResolveDoer != nil {
|
||||||
|
comment.ResolveDoer = ToUser(c.ResolveDoer, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.DependentIssue != nil {
|
||||||
|
comment.DependentIssue = ToAPIIssue(c.DependentIssue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return comment
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,13 @@ var (
|
||||||
giteaHostInit sync.Once
|
giteaHostInit sync.Once
|
||||||
giteaHost string
|
giteaHost string
|
||||||
giteaIssuePullPattern *regexp.Regexp
|
giteaIssuePullPattern *regexp.Regexp
|
||||||
|
|
||||||
|
actionStrings = []string{
|
||||||
|
"none",
|
||||||
|
"closes",
|
||||||
|
"reopens",
|
||||||
|
"neutered",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// XRefAction represents the kind of effect a cross reference has once is resolved
|
// XRefAction represents the kind of effect a cross reference has once is resolved
|
||||||
|
@ -65,6 +72,10 @@ const (
|
||||||
XRefActionNeutered // 3
|
XRefActionNeutered // 3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (a XRefAction) String() string {
|
||||||
|
return actionStrings[a]
|
||||||
|
}
|
||||||
|
|
||||||
// IssueReference contains an unverified cross-reference to a local issue or pull request
|
// IssueReference contains an unverified cross-reference to a local issue or pull request
|
||||||
type IssueReference struct {
|
type IssueReference struct {
|
||||||
Index int64
|
Index int64
|
||||||
|
|
|
@ -35,3 +35,48 @@ type EditIssueCommentOption struct {
|
||||||
// required: true
|
// required: true
|
||||||
Body string `json:"body" binding:"Required"`
|
Body string `json:"body" binding:"Required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimelineComment represents a timeline comment (comment of any type) on a commit or issue
|
||||||
|
type TimelineComment struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
HTMLURL string `json:"html_url"`
|
||||||
|
PRURL string `json:"pull_request_url"`
|
||||||
|
IssueURL string `json:"issue_url"`
|
||||||
|
Poster *User `json:"user"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
// swagger:strfmt date-time
|
||||||
|
Created time.Time `json:"created_at"`
|
||||||
|
// swagger:strfmt date-time
|
||||||
|
Updated time.Time `json:"updated_at"`
|
||||||
|
|
||||||
|
OldProjectID int64 `json:"old_project_id"`
|
||||||
|
ProjectID int64 `json:"project_id"`
|
||||||
|
OldMilestone *Milestone `json:"old_milestone"`
|
||||||
|
Milestone *Milestone `json:"milestone"`
|
||||||
|
TrackedTime *TrackedTime `json:"tracked_time"`
|
||||||
|
OldTitle string `json:"old_title"`
|
||||||
|
NewTitle string `json:"new_title"`
|
||||||
|
OldRef string `json:"old_ref"`
|
||||||
|
NewRef string `json:"new_ref"`
|
||||||
|
|
||||||
|
RefIssue *Issue `json:"ref_issue"`
|
||||||
|
RefComment *Comment `json:"ref_comment"`
|
||||||
|
RefAction string `json:"ref_action"`
|
||||||
|
// commit SHA where issue/PR was referenced
|
||||||
|
RefCommitSHA string `json:"ref_commit_sha"`
|
||||||
|
|
||||||
|
ReviewID int64 `json:"review_id"`
|
||||||
|
|
||||||
|
Label *Label `json:"label"`
|
||||||
|
|
||||||
|
Assignee *User `json:"assignee"`
|
||||||
|
AssigneeTeam *Team `json:"assignee_team"`
|
||||||
|
// whether the assignees were removed or added
|
||||||
|
RemovedAssignee bool `json:"removed_assignee"`
|
||||||
|
|
||||||
|
ResolveDoer *User `json:"resolve_doer"`
|
||||||
|
|
||||||
|
DependentIssue *Issue `json:"dependent_issue"`
|
||||||
|
}
|
||||||
|
|
|
@ -842,6 +842,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
m.Combo("/{id}", reqToken()).Patch(bind(api.EditIssueCommentOption{}), repo.EditIssueCommentDeprecated).
|
m.Combo("/{id}", reqToken()).Patch(bind(api.EditIssueCommentOption{}), repo.EditIssueCommentDeprecated).
|
||||||
Delete(repo.DeleteIssueCommentDeprecated)
|
Delete(repo.DeleteIssueCommentDeprecated)
|
||||||
})
|
})
|
||||||
|
m.Get("/timeline", repo.ListIssueCommentsAndTimeline)
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
m.Combo("").Get(repo.ListIssueLabels).
|
m.Combo("").Get(repo.ListIssueLabels).
|
||||||
Post(reqToken(), bind(api.IssueLabelsOption{}), repo.AddIssueLabels).
|
Post(reqToken(), bind(api.IssueLabelsOption{}), repo.AddIssueLabels).
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -102,6 +104,115 @@ func ListIssueComments(ctx *context.APIContext) {
|
||||||
ctx.JSON(http.StatusOK, &apiComments)
|
ctx.JSON(http.StatusOK, &apiComments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListIssueCommentsAndTimeline list all the comments and events of an issue
|
||||||
|
func ListIssueCommentsAndTimeline(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/timeline issue issueGetCommentsAndTimeline
|
||||||
|
// ---
|
||||||
|
// summary: List all comments and events on an issue
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: owner
|
||||||
|
// in: path
|
||||||
|
// description: owner of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: repo
|
||||||
|
// in: path
|
||||||
|
// description: name of the repo
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: index
|
||||||
|
// in: path
|
||||||
|
// description: index of the issue
|
||||||
|
// type: integer
|
||||||
|
// format: int64
|
||||||
|
// required: true
|
||||||
|
// - name: since
|
||||||
|
// in: query
|
||||||
|
// description: if provided, only comments updated since the specified time are returned.
|
||||||
|
// type: string
|
||||||
|
// format: date-time
|
||||||
|
// - name: page
|
||||||
|
// in: query
|
||||||
|
// description: page number of results to return (1-based)
|
||||||
|
// type: integer
|
||||||
|
// - name: limit
|
||||||
|
// in: query
|
||||||
|
// description: page size of results
|
||||||
|
// type: integer
|
||||||
|
// - name: before
|
||||||
|
// in: query
|
||||||
|
// description: if provided, only comments updated before the provided time are returned.
|
||||||
|
// type: string
|
||||||
|
// format: date-time
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/TimelineList"
|
||||||
|
|
||||||
|
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetRawIssueByIndex", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
issue.Repo = ctx.Repo.Repository
|
||||||
|
|
||||||
|
opts := &models.FindCommentsOptions{
|
||||||
|
ListOptions: utils.GetListOptions(ctx),
|
||||||
|
IssueID: issue.ID,
|
||||||
|
Since: since,
|
||||||
|
Before: before,
|
||||||
|
Type: models.CommentTypeUnknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
comments, err := models.FindComments(opts)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "FindComments", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := models.CommentList(comments).LoadPosters(); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadPosters", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiComments []*api.TimelineComment
|
||||||
|
for _, comment := range comments {
|
||||||
|
if comment.Type != models.CommentTypeCode && isXRefCommentAccessible(ctx.User, comment, issue.RepoID) {
|
||||||
|
comment.Issue = issue
|
||||||
|
apiComments = append(apiComments, convert.ToTimelineComment(comment, ctx.User))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetTotalCountHeader(int64(len(apiComments)))
|
||||||
|
ctx.JSON(http.StatusOK, &apiComments)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isXRefCommentAccessible(user *user_model.User, c *models.Comment, issueRepoID int64) bool {
|
||||||
|
// Remove comments that the user has no permissions to see
|
||||||
|
if models.CommentTypeIsRef(c.Type) && c.RefRepoID != issueRepoID && c.RefRepoID != 0 {
|
||||||
|
var err error
|
||||||
|
// Set RefRepo for description in template
|
||||||
|
c.RefRepo, err = repo_model.GetRepositoryByID(c.RefRepoID)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
perm, err := models.GetUserRepoPermission(c.RefRepo, user)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !perm.CanReadIssuesOrPulls(c.RefIsPull) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// ListRepoIssueComments returns all issue-comments for a repo
|
// ListRepoIssueComments returns all issue-comments for a repo
|
||||||
func ListRepoIssueComments(ctx *context.APIContext) {
|
func ListRepoIssueComments(ctx *context.APIContext) {
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/issues/comments issue issueGetRepoComments
|
// swagger:operation GET /repos/{owner}/{repo}/issues/comments issue issueGetRepoComments
|
||||||
|
|
|
@ -36,6 +36,13 @@ type swaggerResponseCommentList struct {
|
||||||
Body []api.Comment `json:"body"`
|
Body []api.Comment `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimelineList
|
||||||
|
// swagger:response TimelineList
|
||||||
|
type swaggerResponseTimelineList struct {
|
||||||
|
// in:body
|
||||||
|
Body []api.TimelineComment `json:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
// Label
|
// Label
|
||||||
// swagger:response Label
|
// swagger:response Label
|
||||||
type swaggerResponseLabel struct {
|
type swaggerResponseLabel struct {
|
||||||
|
|
|
@ -6057,6 +6057,73 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/repos/{owner}/{repo}/issues/{index}/timeline": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"issue"
|
||||||
|
],
|
||||||
|
"summary": "List all comments and events on an issue",
|
||||||
|
"operationId": "issueGetCommentsAndTimeline",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "owner of the repo",
|
||||||
|
"name": "owner",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the repo",
|
||||||
|
"name": "repo",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "index of the issue",
|
||||||
|
"name": "index",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "if provided, only comments updated since the specified time are returned.",
|
||||||
|
"name": "since",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page number of results to return (1-based)",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page size of results",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "if provided, only comments updated before the provided time are returned.",
|
||||||
|
"name": "before",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/TimelineList"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/repos/{owner}/{repo}/issues/{index}/times": {
|
"/repos/{owner}/{repo}/issues/{index}/times": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -17396,6 +17463,126 @@
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/timeutil"
|
"x-go-package": "code.gitea.io/gitea/modules/timeutil"
|
||||||
},
|
},
|
||||||
|
"TimelineComment": {
|
||||||
|
"description": "TimelineComment represents a timeline comment (comment of any type) on a commit or issue",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"assignee": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
},
|
||||||
|
"assignee_team": {
|
||||||
|
"$ref": "#/definitions/Team"
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Body"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"x-go-name": "Created"
|
||||||
|
},
|
||||||
|
"dependent_issue": {
|
||||||
|
"$ref": "#/definitions/Issue"
|
||||||
|
},
|
||||||
|
"html_url": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "HTMLURL"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "ID"
|
||||||
|
},
|
||||||
|
"issue_url": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "IssueURL"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"$ref": "#/definitions/Label"
|
||||||
|
},
|
||||||
|
"milestone": {
|
||||||
|
"$ref": "#/definitions/Milestone"
|
||||||
|
},
|
||||||
|
"new_ref": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "NewRef"
|
||||||
|
},
|
||||||
|
"new_title": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "NewTitle"
|
||||||
|
},
|
||||||
|
"old_milestone": {
|
||||||
|
"$ref": "#/definitions/Milestone"
|
||||||
|
},
|
||||||
|
"old_project_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "OldProjectID"
|
||||||
|
},
|
||||||
|
"old_ref": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "OldRef"
|
||||||
|
},
|
||||||
|
"old_title": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "OldTitle"
|
||||||
|
},
|
||||||
|
"project_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "ProjectID"
|
||||||
|
},
|
||||||
|
"pull_request_url": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "PRURL"
|
||||||
|
},
|
||||||
|
"ref_action": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "RefAction"
|
||||||
|
},
|
||||||
|
"ref_comment": {
|
||||||
|
"$ref": "#/definitions/Comment"
|
||||||
|
},
|
||||||
|
"ref_commit_sha": {
|
||||||
|
"description": "commit SHA where issue/PR was referenced",
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "RefCommitSHA"
|
||||||
|
},
|
||||||
|
"ref_issue": {
|
||||||
|
"$ref": "#/definitions/Issue"
|
||||||
|
},
|
||||||
|
"removed_assignee": {
|
||||||
|
"description": "whether the assignees were removed or added",
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "RemovedAssignee"
|
||||||
|
},
|
||||||
|
"resolve_doer": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
},
|
||||||
|
"review_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "ReviewID"
|
||||||
|
},
|
||||||
|
"tracked_time": {
|
||||||
|
"$ref": "#/definitions/TrackedTime"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Type"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"x-go-name": "Updated"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
|
},
|
||||||
"TopicName": {
|
"TopicName": {
|
||||||
"description": "TopicName a list of repo topic names",
|
"description": "TopicName a list of repo topic names",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -18525,6 +18712,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"TimelineList": {
|
||||||
|
"description": "TimelineList",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/TimelineComment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"TopicListResponse": {
|
"TopicListResponse": {
|
||||||
"description": "TopicListResponse",
|
"description": "TopicListResponse",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
Reference in a new issue