Skip to content

Commit d7fd235

Browse files
committed
Merge commit '53dfbbb2eee5f9ae7b1a127b51fd9ab5accf5e89'
* commit '53dfbbb2eee5f9ae7b1a127b51fd9ab5accf5e89': Update issue.go with labels documentation (labels content, not ids) (go-gitea#35522) Fix markup init after issue comment editing (go-gitea#35536) [Fix] Trigger 'unlabeled' event when label is Deleted from PR (go-gitea#34316) [skip ci] Updated translations via Crowdin
2 parents ddc978c + 53dfbbb commit d7fd235

File tree

10 files changed

+291
-55
lines changed

10 files changed

+291
-55
lines changed

modules/actions/workflows.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,28 @@ func matchIssuesEvent(issuePayload *api.IssuePayload, evt *jobparser.Event) bool
377377
// Actions with the same name:
378378
// opened, edited, closed, reopened, assigned, unassigned, milestoned, demilestoned
379379
// Actions need to be converted:
380-
// label_updated -> labeled
380+
// label_updated -> labeled (when adding) or unlabeled (when removing)
381381
// label_cleared -> unlabeled
382382
// Unsupported activity types:
383383
// deleted, transferred, pinned, unpinned, locked, unlocked
384384

385-
action := issuePayload.Action
386-
switch action {
385+
actions := []string{}
386+
switch issuePayload.Action {
387387
case api.HookIssueLabelUpdated:
388-
action = "labeled"
388+
if len(issuePayload.Changes.AddedLabels) > 0 {
389+
actions = append(actions, "labeled")
390+
}
391+
if len(issuePayload.Changes.RemovedLabels) > 0 {
392+
actions = append(actions, "unlabeled")
393+
}
389394
case api.HookIssueLabelCleared:
390-
action = "unlabeled"
395+
actions = append(actions, "unlabeled")
396+
default:
397+
actions = append(actions, string(issuePayload.Action))
391398
}
399+
392400
for _, val := range vals {
393-
if glob.MustCompile(val, '/').Match(string(action)) {
401+
if slices.ContainsFunc(actions, glob.MustCompile(val, '/').Match) {
394402
matchTimes++
395403
break
396404
}

modules/actions/workflows_test.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,184 @@ func TestDetectMatched(t *testing.T) {
154154
})
155155
}
156156
}
157+
158+
func TestMatchIssuesEvent(t *testing.T) {
159+
testCases := []struct {
160+
desc string
161+
payload *api.IssuePayload
162+
yamlOn string
163+
expected bool
164+
eventType string
165+
}{
166+
{
167+
desc: "Label deletion should trigger unlabeled event",
168+
payload: &api.IssuePayload{
169+
Action: api.HookIssueLabelUpdated,
170+
Issue: &api.Issue{
171+
Labels: []*api.Label{},
172+
},
173+
Changes: &api.ChangesPayload{
174+
RemovedLabels: []*api.Label{
175+
{ID: 123, Name: "deleted-label"},
176+
},
177+
},
178+
},
179+
yamlOn: "on:\n issues:\n types: [unlabeled]",
180+
expected: true,
181+
eventType: "unlabeled",
182+
},
183+
{
184+
desc: "Label deletion with existing labels should trigger unlabeled event",
185+
payload: &api.IssuePayload{
186+
Action: api.HookIssueLabelUpdated,
187+
Issue: &api.Issue{
188+
Labels: []*api.Label{
189+
{ID: 456, Name: "existing-label"},
190+
},
191+
},
192+
Changes: &api.ChangesPayload{
193+
AddedLabels: nil,
194+
RemovedLabels: []*api.Label{
195+
{ID: 123, Name: "deleted-label"},
196+
},
197+
},
198+
},
199+
yamlOn: "on:\n issues:\n types: [unlabeled]",
200+
expected: true,
201+
eventType: "unlabeled",
202+
},
203+
{
204+
desc: "Label addition should trigger labeled event",
205+
payload: &api.IssuePayload{
206+
Action: api.HookIssueLabelUpdated,
207+
Issue: &api.Issue{
208+
Labels: []*api.Label{
209+
{ID: 123, Name: "new-label"},
210+
},
211+
},
212+
Changes: &api.ChangesPayload{
213+
AddedLabels: []*api.Label{
214+
{ID: 123, Name: "new-label"},
215+
},
216+
RemovedLabels: []*api.Label{}, // Empty array, no labels removed
217+
},
218+
},
219+
yamlOn: "on:\n issues:\n types: [labeled]",
220+
expected: true,
221+
eventType: "labeled",
222+
},
223+
{
224+
desc: "Label clear should trigger unlabeled event",
225+
payload: &api.IssuePayload{
226+
Action: api.HookIssueLabelCleared,
227+
Issue: &api.Issue{
228+
Labels: []*api.Label{},
229+
},
230+
},
231+
yamlOn: "on:\n issues:\n types: [unlabeled]",
232+
expected: true,
233+
eventType: "unlabeled",
234+
},
235+
{
236+
desc: "Both adding and removing labels should trigger labeled event",
237+
payload: &api.IssuePayload{
238+
Action: api.HookIssueLabelUpdated,
239+
Issue: &api.Issue{
240+
Labels: []*api.Label{
241+
{ID: 789, Name: "new-label"},
242+
},
243+
},
244+
Changes: &api.ChangesPayload{
245+
AddedLabels: []*api.Label{
246+
{ID: 789, Name: "new-label"},
247+
},
248+
RemovedLabels: []*api.Label{
249+
{ID: 123, Name: "deleted-label"},
250+
},
251+
},
252+
},
253+
yamlOn: "on:\n issues:\n types: [labeled]",
254+
expected: true,
255+
eventType: "labeled",
256+
},
257+
{
258+
desc: "Both adding and removing labels should trigger unlabeled event",
259+
payload: &api.IssuePayload{
260+
Action: api.HookIssueLabelUpdated,
261+
Issue: &api.Issue{
262+
Labels: []*api.Label{
263+
{ID: 789, Name: "new-label"},
264+
},
265+
},
266+
Changes: &api.ChangesPayload{
267+
AddedLabels: []*api.Label{
268+
{ID: 789, Name: "new-label"},
269+
},
270+
RemovedLabels: []*api.Label{
271+
{ID: 123, Name: "deleted-label"},
272+
},
273+
},
274+
},
275+
yamlOn: "on:\n issues:\n types: [unlabeled]",
276+
expected: true,
277+
eventType: "unlabeled",
278+
},
279+
{
280+
desc: "Both adding and removing labels should trigger both events",
281+
payload: &api.IssuePayload{
282+
Action: api.HookIssueLabelUpdated,
283+
Issue: &api.Issue{
284+
Labels: []*api.Label{
285+
{ID: 789, Name: "new-label"},
286+
},
287+
},
288+
Changes: &api.ChangesPayload{
289+
AddedLabels: []*api.Label{
290+
{ID: 789, Name: "new-label"},
291+
},
292+
RemovedLabels: []*api.Label{
293+
{ID: 123, Name: "deleted-label"},
294+
},
295+
},
296+
},
297+
yamlOn: "on:\n issues:\n types: [labeled, unlabeled]",
298+
expected: true,
299+
eventType: "multiple",
300+
},
301+
}
302+
303+
for _, tc := range testCases {
304+
t.Run(tc.desc, func(t *testing.T) {
305+
evts, err := GetEventsFromContent([]byte(tc.yamlOn))
306+
assert.NoError(t, err)
307+
assert.Len(t, evts, 1)
308+
309+
// Test if the event matches as expected
310+
assert.Equal(t, tc.expected, matchIssuesEvent(tc.payload, evts[0]))
311+
312+
// For extra validation, check that action mapping works correctly
313+
if tc.eventType == "multiple" {
314+
// Skip direct action mapping validation for multiple events case
315+
// as one action can map to multiple event types
316+
return
317+
}
318+
319+
// Determine expected action for single event case
320+
var expectedAction string
321+
switch tc.payload.Action {
322+
case api.HookIssueLabelUpdated:
323+
if tc.eventType == "labeled" {
324+
expectedAction = "labeled"
325+
} else if tc.eventType == "unlabeled" {
326+
expectedAction = "unlabeled"
327+
}
328+
case api.HookIssueLabelCleared:
329+
expectedAction = "unlabeled"
330+
default:
331+
expectedAction = string(tc.payload.Action)
332+
}
333+
334+
assert.Equal(t, expectedAction, tc.eventType, "Event type should match expected")
335+
})
336+
}
337+
}

modules/structs/hook.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,10 @@ type ChangesPayload struct {
418418
Body *ChangesFromPayload `json:"body,omitempty"`
419419
// Changes made to the reference
420420
Ref *ChangesFromPayload `json:"ref,omitempty"`
421+
// Changes made to the labels added
422+
AddedLabels []*Label `json:"added_labels"`
423+
// Changes made to the labels removed
424+
RemovedLabels []*Label `json:"removed_labels"`
421425
}
422426

423427
// PullRequestPayload represents a payload information of pull request event.

options/locale/locale_ja-JP.ini

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,13 @@ repo.transfer.body=承認または拒否するには %s を開きます。 も
551551
repo.collaborator.added.subject=%s が %s にあなたを追加しました
552552
repo.collaborator.added.text=あなたは次のリポジトリの共同作業者に追加されました:
553553

554+
repo.actions.run.failed=実行に失敗しました
555+
repo.actions.run.succeeded=実行に成功しました
556+
repo.actions.run.cancelled=実行がキャンセルされました
557+
repo.actions.jobs.all_succeeded=すべてのジョブが成功しました
558+
repo.actions.jobs.all_failed=すべてのジョブが失敗しました
559+
repo.actions.jobs.some_not_successful=いくつかのジョブが成功しませんでした
560+
repo.actions.jobs.all_cancelled=すべてのジョブがキャンセルされました
554561

555562
team_invite.subject=%[1]s さんが %[2]s への参加にあなたを招待しました
556563
team_invite.text_1=%[1]s さんが、組織 %[3]s 内のチーム %[2]s への参加に、あなたを招待しました。
@@ -3722,10 +3729,14 @@ swift.install=あなたの <code>Package.swift</code> ファイルにパッケ
37223729
swift.install2=そして次のコマンドを実行します:
37233730
vagrant.install=Vagrant ボックスを追加するには、次のコマンドを実行します。
37243731
settings.link=このパッケージをリポジトリにリンク
3732+
settings.link.description=パッケージをリポジトリにリンクすると、リポジトリのパッケージ一覧にそのパッケージが表示されます。 リンクできるのは、同じオーナーが所有するリポジトリのみです。 入力欄を空にするとリンクを削除します。
37253733
settings.link.select=リポジトリを選択
37263734
settings.link.button=リポジトリのリンクを更新
3727-
settings.link.success=リポジトリのリンクが正常に更新されました
3735+
settings.link.success=リポジトリのリンクを更新しました
37283736
settings.link.error=リポジトリのリンクの更新に失敗しました。
3737+
settings.link.repo_not_found=リポジトリ %s が見つかりません。
3738+
settings.unlink.error=リポジトリのリンクの削除に失敗しました。
3739+
settings.unlink.success=リポジトリのリンクを削除しました。
37293740
settings.delete=パッケージ削除
37303741
settings.delete.description=パッケージの削除は恒久的で元に戻すことはできません。
37313742
settings.delete.notice=%s (%s) を削除しようとしています。この操作は元に戻せません。よろしいですか?

routers/api/v1/repo/issue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ func ListIssues(ctx *context.APIContext) {
351351
// enum: [closed, open, all]
352352
// - name: labels
353353
// in: query
354-
// description: comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded
354+
// description: comma separated list of label names. Fetch only issues that have any of this label names. Non existent labels are discarded.
355355
// type: string
356356
// - name: q
357357
// in: query

routers/web/repo/issue_comment.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import (
99
"html/template"
1010
"net/http"
1111
"strconv"
12+
"strings"
1213

1314
issues_model "code.gitea.io/gitea/models/issues"
1415
"code.gitea.io/gitea/models/renderhelper"
1516
user_model "code.gitea.io/gitea/models/user"
1617
"code.gitea.io/gitea/modules/git"
1718
"code.gitea.io/gitea/modules/gitrepo"
19+
"code.gitea.io/gitea/modules/htmlutil"
1820
"code.gitea.io/gitea/modules/log"
1921
"code.gitea.io/gitea/modules/markup/markdown"
2022
repo_module "code.gitea.io/gitea/modules/repository"
@@ -287,9 +289,10 @@ func UpdateCommentContent(ctx *context.Context) {
287289
ctx.ServerError("RenderString", err)
288290
return
289291
}
290-
} else {
291-
contentEmpty := fmt.Sprintf(`<span class="no-content">%s</span>`, ctx.Tr("repo.issues.no_content"))
292-
renderedContent = template.HTML(contentEmpty)
292+
}
293+
294+
if strings.TrimSpace(string(renderedContent)) == "" {
295+
renderedContent = htmlutil.HTMLFormat(`<span class="no-content">%s</span>`, ctx.Tr("repo.issues.no_content"))
293296
}
294297

295298
ctx.JSON(http.StatusOK, map[string]any{

0 commit comments

Comments
 (0)