mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-29 03:38:52 +03:00
fix: labels are missing in the pull request payload removing a label
When ReplaceIssueLabels calls issue.LoadLabels it was a noop because
issue.isLabelsLoaded is still set to true because of the call to
issue.LoadLabels that was done at the beginning of the function.
(cherry picked from commit c801838690
)
This commit is contained in:
parent
09a35a7cb8
commit
eda6b436dc
2 changed files with 133 additions and 56 deletions
|
@ -496,6 +496,7 @@ func ReplaceIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue.isLabelsLoaded = false
|
||||||
issue.Labels = nil
|
issue.Labels = nil
|
||||||
if err = issue.LoadLabels(ctx); err != nil {
|
if err = issue.LoadLabels(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -84,7 +84,23 @@ jobs:
|
||||||
baseGitRepo.Close()
|
baseGitRepo.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// prepare the pull request
|
// prepare the repository labels
|
||||||
|
labelStr := "/api/v1/repos/user2/repo-pull-request/labels"
|
||||||
|
labelsCount := 2
|
||||||
|
labels := make([]*api.Label, labelsCount)
|
||||||
|
for i := 0; i < labelsCount; i++ {
|
||||||
|
color := "abcdef"
|
||||||
|
req := NewRequestWithJSON(t, "POST", labelStr, &api.CreateLabelOption{
|
||||||
|
Name: fmt.Sprintf("label%d", i),
|
||||||
|
Color: color,
|
||||||
|
}).AddTokenAuth(token)
|
||||||
|
resp := MakeRequest(t, req, http.StatusCreated)
|
||||||
|
labels[i] = new(api.Label)
|
||||||
|
DecodeJSON(t, resp, &labels[i])
|
||||||
|
assert.Equal(t, color, labels[i].Color)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the pull request
|
||||||
testEditFileToNewBranch(t, session, "user2", "repo-pull-request", "main", "wip-something", "README.md", "Hello, world 1")
|
testEditFileToNewBranch(t, session, "user2", "repo-pull-request", "main", "wip-something", "README.md", "Hello, world 1")
|
||||||
testPullCreate(t, session, "user2", "repo-pull-request", true, "main", "wip-something", "Commit status PR")
|
testPullCreate(t, session, "user2", "repo-pull-request", true, "main", "wip-something", "Commit status PR")
|
||||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: baseRepo.ID})
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: baseRepo.ID})
|
||||||
|
@ -94,24 +110,15 @@ jobs:
|
||||||
issueURL := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%s", "user2", "repo-pull-request", fmt.Sprintf("%d", pr.Issue.Index))
|
issueURL := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%s", "user2", "repo-pull-request", fmt.Sprintf("%d", pr.Issue.Index))
|
||||||
|
|
||||||
// prepare the labels
|
// prepare the labels
|
||||||
labelStr := "/api/v1/repos/user2/repo-pull-request/labels"
|
|
||||||
req := NewRequestWithJSON(t, "POST", labelStr, &api.CreateLabelOption{
|
|
||||||
Name: "mylabel",
|
|
||||||
Color: "abcdef",
|
|
||||||
Description: "description mylabel",
|
|
||||||
}).AddTokenAuth(token)
|
|
||||||
resp := MakeRequest(t, req, http.StatusCreated)
|
|
||||||
label := new(api.Label)
|
|
||||||
DecodeJSON(t, resp, &label)
|
|
||||||
labelURL := fmt.Sprintf("%s/labels", issueURL)
|
labelURL := fmt.Sprintf("%s/labels", issueURL)
|
||||||
|
|
||||||
// prepare the milestone
|
// prepare the milestone
|
||||||
milestoneStr := "/api/v1/repos/user2/repo-pull-request/milestones"
|
milestoneStr := "/api/v1/repos/user2/repo-pull-request/milestones"
|
||||||
req = NewRequestWithJSON(t, "POST", milestoneStr, &api.CreateMilestoneOption{
|
req := NewRequestWithJSON(t, "POST", milestoneStr, &api.CreateMilestoneOption{
|
||||||
Title: "mymilestone",
|
Title: "mymilestone",
|
||||||
State: "open",
|
State: "open",
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
resp = MakeRequest(t, req, http.StatusCreated)
|
resp := MakeRequest(t, req, http.StatusCreated)
|
||||||
milestone := new(api.Milestone)
|
milestone := new(api.Milestone)
|
||||||
DecodeJSON(t, resp, &milestone)
|
DecodeJSON(t, resp, &milestone)
|
||||||
|
|
||||||
|
@ -128,47 +135,97 @@ jobs:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
assertActionRun := func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRun *actions_model.ActionRun) {
|
||||||
|
assert.Equal(t, fmt.Sprintf("%s.yml", onType), actionRun.WorkflowID)
|
||||||
|
assert.Equal(t, sha, actionRun.CommitSHA)
|
||||||
|
assert.Equal(t, actions_module.GithubEventPullRequest, actionRun.TriggerEvent)
|
||||||
|
event, err := actionRun.GetPullRequestEventPayload()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, action, event.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
type assertType func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun)
|
||||||
|
assertActionRuns := func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) {
|
||||||
|
require.Len(t, actionRuns, 1)
|
||||||
|
assertActionRun(t, sha, onType, action, actionRuns[0])
|
||||||
|
}
|
||||||
|
|
||||||
for _, testCase := range []struct {
|
for _, testCase := range []struct {
|
||||||
onType string
|
onType string
|
||||||
jobID string
|
jobID string
|
||||||
doSomething func()
|
doSomething func()
|
||||||
action api.HookIssueAction
|
actionRunCount int
|
||||||
hasLabel bool
|
action api.HookIssueAction
|
||||||
|
assert assertType
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
onType: "opened",
|
onType: "opened",
|
||||||
doSomething: func() {},
|
doSomething: func() {},
|
||||||
action: api.HookIssueOpened,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueOpened,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "synchronize",
|
onType: "synchronize",
|
||||||
doSomething: func() {
|
doSomething: func() {
|
||||||
testEditFile(t, session, "user2", "repo-pull-request", "wip-something", "README.md", "Hello, world 2")
|
testEditFile(t, session, "user2", "repo-pull-request", "wip-something", "README.md", "Hello, world 2")
|
||||||
},
|
},
|
||||||
action: api.HookIssueSynchronized,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueSynchronized,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "labeled",
|
onType: "labeled",
|
||||||
doSomething: func() {
|
doSomething: func() {
|
||||||
req := NewRequestWithJSON(t, "POST", labelURL, &api.IssueLabelsOption{
|
req := NewRequestWithJSON(t, "POST", labelURL, &api.IssueLabelsOption{
|
||||||
Labels: []any{label.ID},
|
Labels: []any{labels[0].ID, labels[1].ID},
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusOK)
|
MakeRequest(t, req, http.StatusOK)
|
||||||
},
|
},
|
||||||
action: api.HookIssueLabelUpdated,
|
actionRunCount: 2,
|
||||||
hasLabel: true,
|
action: api.HookIssueLabelUpdated,
|
||||||
|
assert: func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) {
|
||||||
|
assertActionRun(t, sha, onType, api.HookIssueLabelUpdated, actionRuns[0])
|
||||||
|
assertActionRun(t, sha, onType, api.HookIssueLabelUpdated, actionRuns[1])
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "unlabeled",
|
onType: "unlabeled",
|
||||||
doSomething: func() {
|
doSomething: func() {
|
||||||
req := NewRequestWithJSON(t, "PUT", labelURL, &api.IssueLabelsOption{
|
req := NewRequestWithJSON(t, "PUT", labelURL, &api.IssueLabelsOption{
|
||||||
Labels: []any{},
|
Labels: []any{labels[0].ID},
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusOK)
|
MakeRequest(t, req, http.StatusOK)
|
||||||
},
|
},
|
||||||
action: api.HookIssueLabelCleared,
|
actionRunCount: 3,
|
||||||
hasLabel: true,
|
action: api.HookIssueLabelCleared,
|
||||||
|
assert: func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) {
|
||||||
|
foundPayloadWithLabels := false
|
||||||
|
knownLabels := []string{"label0", "label1"}
|
||||||
|
for _, actionRun := range actionRuns {
|
||||||
|
assert.Equal(t, sha, actionRun.CommitSHA)
|
||||||
|
assert.Equal(t, actions_module.GithubEventPullRequest, actionRun.TriggerEvent)
|
||||||
|
event, err := actionRun.GetPullRequestEventPayload()
|
||||||
|
require.NoError(t, err)
|
||||||
|
switch event.Action {
|
||||||
|
case api.HookIssueLabelUpdated:
|
||||||
|
assert.Equal(t, "labeled.yml", actionRun.WorkflowID)
|
||||||
|
assert.Equal(t, "label0", event.Label.Name)
|
||||||
|
require.Len(t, event.PullRequest.Labels, 1)
|
||||||
|
assert.Contains(t, "label0", event.PullRequest.Labels[0].Name)
|
||||||
|
case api.HookIssueLabelCleared:
|
||||||
|
assert.Equal(t, "unlabeled.yml", actionRun.WorkflowID)
|
||||||
|
assert.Contains(t, knownLabels, event.Label.Name)
|
||||||
|
if len(event.PullRequest.Labels) > 0 {
|
||||||
|
foundPayloadWithLabels = true
|
||||||
|
assert.Contains(t, knownLabels, event.PullRequest.Labels[0].Name)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
require.Fail(t, fmt.Sprintf("unexpected action '%s'", event.Action))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, foundPayloadWithLabels, "expected at least one clear label payload with non empty labels")
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "assigned",
|
onType: "assigned",
|
||||||
|
@ -178,7 +235,9 @@ jobs:
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusCreated)
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
},
|
},
|
||||||
action: api.HookIssueAssigned,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueAssigned,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "unassigned",
|
onType: "unassigned",
|
||||||
|
@ -188,7 +247,9 @@ jobs:
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusCreated)
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
},
|
},
|
||||||
action: api.HookIssueUnassigned,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueUnassigned,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "milestoned",
|
onType: "milestoned",
|
||||||
|
@ -198,7 +259,9 @@ jobs:
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusCreated)
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
},
|
},
|
||||||
action: api.HookIssueMilestoned,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueMilestoned,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "demilestoned",
|
onType: "demilestoned",
|
||||||
|
@ -209,7 +272,9 @@ jobs:
|
||||||
}).AddTokenAuth(token)
|
}).AddTokenAuth(token)
|
||||||
MakeRequest(t, req, http.StatusCreated)
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
},
|
},
|
||||||
action: api.HookIssueDemilestoned,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueDemilestoned,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "closed",
|
onType: "closed",
|
||||||
|
@ -219,7 +284,9 @@ jobs:
|
||||||
err = issue_service.ChangeStatus(db.DefaultContext, pr.Issue, user2, sha, true)
|
err = issue_service.ChangeStatus(db.DefaultContext, pr.Issue, user2, sha, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
},
|
},
|
||||||
action: api.HookIssueClosed,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueClosed,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onType: "reopened",
|
onType: "reopened",
|
||||||
|
@ -229,43 +296,52 @@ jobs:
|
||||||
err = issue_service.ChangeStatus(db.DefaultContext, pr.Issue, user2, sha, false)
|
err = issue_service.ChangeStatus(db.DefaultContext, pr.Issue, user2, sha, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
},
|
},
|
||||||
action: api.HookIssueReOpened,
|
actionRunCount: 1,
|
||||||
|
action: api.HookIssueReOpened,
|
||||||
|
assert: assertActionRuns,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(testCase.onType, func(t *testing.T) {
|
t.Run(testCase.onType, func(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
// cleanup leftovers, start from scratch
|
||||||
|
_, err = db.DeleteByBean(db.DefaultContext, actions_model.ActionRun{RepoID: baseRepo.ID})
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = db.DeleteByBean(db.DefaultContext, actions_model.ActionRunJob{RepoID: baseRepo.ID})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
// trigger the onType event
|
// trigger the onType event
|
||||||
testCase.doSomething()
|
testCase.doSomething()
|
||||||
count++
|
count := testCase.actionRunCount
|
||||||
context := fmt.Sprintf("%[1]s / %[1]s (pull_request)", testCase.onType)
|
context := fmt.Sprintf("%[1]s / %[1]s (pull_request)", testCase.onType)
|
||||||
|
|
||||||
// wait for a new ActionRun to be created
|
var actionRuns []*actions_model.ActionRun
|
||||||
assert.Eventually(t, func() bool {
|
|
||||||
return count == unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID})
|
// wait for ActionRun(s) to be created
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
actionRuns = make([]*actions_model.ActionRun, 0)
|
||||||
|
require.NoError(t, db.GetEngine(db.DefaultContext).Where("repo_id=?", baseRepo.ID).Find(&actionRuns))
|
||||||
|
return assert.Len(t, actionRuns, count)
|
||||||
}, 30*time.Second, 1*time.Second)
|
}, 30*time.Second, 1*time.Second)
|
||||||
|
|
||||||
// verify the expected ActionRun was created
|
// verify the expected ActionRuns were created
|
||||||
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
|
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{RepoID: baseRepo.ID, WorkflowID: fmt.Sprintf("%s.yml", testCase.onType)})
|
|
||||||
|
|
||||||
assert.Equal(t, sha, actionRun.CommitSHA)
|
|
||||||
assert.Equal(t, actions_module.GithubEventPullRequest, actionRun.TriggerEvent)
|
|
||||||
event, err := actionRun.GetPullRequestEventPayload()
|
|
||||||
if testCase.hasLabel {
|
|
||||||
assert.NotNil(t, event.Label)
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, testCase.action, event.Action)
|
|
||||||
|
|
||||||
// verify the expected ActionRunJob was created and is StatusWaiting
|
|
||||||
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{JobID: testCase.onType, CommitSHA: sha})
|
|
||||||
assert.Equal(t, actions_model.StatusWaiting, job.Status)
|
|
||||||
|
|
||||||
// verify the commit status changes to CommitStatusSuccess when the job changes to StatusSuccess
|
// verify the commit status changes to CommitStatusSuccess when the job changes to StatusSuccess
|
||||||
assert.True(t, checkCommitStatus(sha, context, api.CommitStatusPending))
|
assert.True(t, checkCommitStatus(sha, context, api.CommitStatusPending))
|
||||||
job.Status = actions_model.StatusSuccess
|
for _, actionRun := range actionRuns {
|
||||||
actions_service.CreateCommitStatus(db.DefaultContext, job)
|
// verify the expected ActionRunJob was created and is StatusWaiting
|
||||||
|
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{RunID: actionRun.ID, CommitSHA: sha})
|
||||||
|
assert.Equal(t, actions_model.StatusWaiting, job.Status)
|
||||||
|
|
||||||
|
// change the state of the job to success
|
||||||
|
job.Status = actions_model.StatusSuccess
|
||||||
|
actions_service.CreateCommitStatus(db.DefaultContext, job)
|
||||||
|
}
|
||||||
|
// verify the commit status changed to CommitStatusSuccess because the job(s) changed to StatusSuccess
|
||||||
assert.True(t, checkCommitStatus(sha, context, api.CommitStatusSuccess))
|
assert.True(t, checkCommitStatus(sha, context, api.CommitStatusSuccess))
|
||||||
|
|
||||||
|
testCase.assert(t, sha, testCase.onType, testCase.action, actionRuns)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue