0
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-07-19 12:50:52 +02:00

Merge branch 'go-gitea:main' into main

This commit is contained in:
badhezi 2025-05-12 16:39:04 +03:00 committed by GitHub
commit 016c2f3025
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 281 additions and 69 deletions

View File

@ -171,6 +171,7 @@ func (run *ActionRun) IsSchedule() bool {
func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error {
_, err := db.GetEngine(ctx).ID(repo.ID).
NoAutoTime().
SetExpr("num_action_runs",
builder.Select("count(*)").From("action_run").
Where(builder.Eq{"repo_id": repo.ID}),

View File

@ -249,7 +249,7 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
}
repo.Status = RepositoryPendingTransfer
if err := UpdateRepositoryCols(ctx, repo, "status"); err != nil {
if err := UpdateRepositoryColsNoAutoTime(ctx, repo, "status"); err != nil {
return err
}

View File

@ -25,7 +25,7 @@ func UpdateRepositoryOwnerNames(ctx context.Context, ownerID int64, ownerName st
}
defer committer.Close()
if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&Repository{
if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").NoAutoTime().Update(&Repository{
OwnerName: ownerName,
}); err != nil {
return err
@ -40,8 +40,8 @@ func UpdateRepositoryUpdatedTime(ctx context.Context, repoID int64, updateTime t
return err
}
// UpdateRepositoryCols updates repository's columns
func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string) error {
// UpdateRepositoryColsWithAutoTime updates repository's columns
func UpdateRepositoryColsWithAutoTime(ctx context.Context, repo *Repository, cols ...string) error {
_, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).Update(repo)
return err
}

View File

@ -117,6 +117,7 @@ files=文件
error=错误
error404=您正尝试访问的页面 <strong>不存在</strong> 或 <strong>您尚未被授权</strong> 查看该页面。
error503=服务器无法完成您的请求,请稍后重试。
go_back=返回
invalid_data=无效数据: %v
@ -129,6 +130,7 @@ pin=固定
unpin=取消置顶
artifacts=制品
expired=已过期
confirm_delete_artifact=您确定要删除制品'%s'吗?
archived=已归档
@ -449,6 +451,7 @@ use_scratch_code=使用验证口令
twofa_scratch_used=你已经使用了你的验证口令。你将会转到两步验证设置页面以便移除你的注册设备或者重新生成新的验证口令。
twofa_passcode_incorrect=你的验证码不正确。如果你丢失了你的设备,请使用你的验证口令。
twofa_scratch_token_incorrect=你的验证口令不正确。
twofa_required=您必须设置两步验证来访问仓库,或者尝试重新登录。
login_userpass=登录
login_openid=OpenID
oauth_signup_tab=注册帐号
@ -1524,7 +1527,7 @@ issues.move_to_column_of_project=`将此对象移至 %s 的 %s 中在 %s 上`
issues.change_milestone_at=`%[3]s 修改了里程碑从 <b>%[1]s</b> 到 <b>%[2]s</b>`
issues.change_project_at=于 %[3]s 将此从项目 <b>%[1]s</b> 移到 <b>%[2]s</b>
issues.remove_milestone_at=`%[2]s 删除了里程碑 <b>%[1]s</b>`
issues.remove_project_at=`从 <b>%s</b> 项目 %s 中删除`
issues.remove_project_at=`于 %[2]s 将此工单项目 <b>%[1]s</b> 中删除`
issues.deleted_milestone=(已删除)
issues.deleted_project=`(已删除)`
issues.self_assign_at=`于 %s 指派给自己`
@ -1877,6 +1880,7 @@ pulls.add_prefix=添加 <strong>%s</strong> 前缀
pulls.remove_prefix=删除 <strong>%s</strong> 前缀
pulls.data_broken=此合并请求因为派生仓库信息缺失而中断。
pulls.files_conflicted=此合并请求有变更与目标分支冲突。
pulls.is_checking=正在进行合并冲突检测 ...
pulls.is_ancestor=此分支已经包含在目标分支中,没有什么可以合并。
pulls.is_empty=此分支上的更改已经在目标分支上。这将是一个空提交。
pulls.required_status_check_failed=一些必要的检查没有成功
@ -3724,7 +3728,11 @@ creation.name_placeholder=不区分大小写,字母数字或下划线不能以
creation.value_placeholder=输入任何内容,开头和结尾的空白都会被省略
creation.description_placeholder=输入简短描述(可选)。
save_success=密钥 '%s' 保存成功。
save_failed=密钥保存失败。
add_secret=添加密钥
edit_secret=编辑密钥
deletion=删除密钥
deletion.description=删除密钥是永久性的,无法撤消。继续吗?
deletion.success=此Secret已被删除。
@ -3841,6 +3849,8 @@ deleted.display_name=已删除项目
type-1.display_name=个人项目
type-2.display_name=仓库项目
type-3.display_name=组织项目
enter_fullscreen=全屏
exit_fullscreen=退出全屏
[git.filemode]
changed_filemode=%[1]s -> %[2]s

View File

@ -895,6 +895,15 @@ func EditIssue(ctx *context.APIContext) {
issue.MilestoneID != *form.Milestone {
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = *form.Milestone
if issue.MilestoneID > 0 {
issue.Milestone, err = issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, *form.Milestone)
if err != nil {
ctx.APIErrorInternal(err)
return
}
} else {
issue.Milestone = nil
}
if err = issue_service.ChangeMilestoneAssign(ctx, issue, ctx.Doer, oldMilestoneID); err != nil {
ctx.APIErrorInternal(err)
return

View File

@ -609,15 +609,17 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
return
}
oldContent := comment.Content
comment.Content = form.Body
if err := issue_service.UpdateComment(ctx, comment, comment.ContentVersion, ctx.Doer, oldContent); err != nil {
if errors.Is(err, user_model.ErrBlockedUser) {
ctx.APIError(http.StatusForbidden, err)
} else {
ctx.APIErrorInternal(err)
if form.Body != comment.Content {
oldContent := comment.Content
comment.Content = form.Body
if err := issue_service.UpdateComment(ctx, comment, comment.ContentVersion, ctx.Doer, oldContent); err != nil {
if errors.Is(err, user_model.ErrBlockedUser) {
ctx.APIError(http.StatusForbidden, err)
} else {
ctx.APIErrorInternal(err)
}
return
}
return
}
ctx.JSON(http.StatusOK, convert.ToAPIComment(ctx, ctx.Repo.Repository, comment))

View File

@ -706,6 +706,11 @@ func EditPullRequest(ctx *context.APIContext) {
issue.MilestoneID != form.Milestone {
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = form.Milestone
issue.Milestone, err = issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, form.Milestone)
if err != nil {
ctx.APIErrorInternal(err)
return
}
if err = issue_service.ChangeMilestoneAssign(ctx, issue, ctx.Doer, oldMilestoneID); err != nil {
ctx.APIErrorInternal(err)
return

View File

@ -220,7 +220,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
if len(cols) > 0 {
if err := repo_model.UpdateRepositoryCols(ctx, repo, cols...); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, cols...); err != nil {
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),

View File

@ -376,12 +376,6 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
}
}
if ctx.Repo.Repository.IsEmpty {
if isEmpty, err := ctx.Repo.GitRepo.IsEmpty(); err == nil && !isEmpty {
_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
}
}
redirectForCommitChoice(ctx, form.CommitChoice, branchName, form.TreePath)
}
@ -790,7 +784,7 @@ func UploadFilePost(ctx *context.Context) {
if ctx.Repo.Repository.IsEmpty {
if isEmpty, err := ctx.Repo.GitRepo.IsEmpty(); err == nil && !isEmpty {
_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
_ = repo_model.UpdateRepositoryColsWithAutoTime(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, IsEmpty: false}, "is_empty")
}
}

View File

@ -418,6 +418,16 @@ func UpdateIssueMilestone(ctx *context.Context) {
continue
}
issue.MilestoneID = milestoneID
if milestoneID > 0 {
var err error
issue.Milestone, err = issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, milestoneID)
if err != nil {
ctx.ServerError("GetMilestoneByRepoID", err)
return
}
} else {
issue.Milestone = nil
}
if err := issue_service.ChangeMilestoneAssign(ctx, issue, ctx.Doer, oldMilestoneID); err != nil {
ctx.ServerError("ChangeMilestoneAssign", err)
return

View File

@ -239,23 +239,30 @@ func UpdateCommentContent(ctx *context.Context) {
return
}
oldContent := comment.Content
newContent := ctx.FormString("content")
contentVersion := ctx.FormInt("content_version")
// allow to save empty content
comment.Content = newContent
if err = issue_service.UpdateComment(ctx, comment, contentVersion, ctx.Doer, oldContent); err != nil {
if errors.Is(err, user_model.ErrBlockedUser) {
ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_user"))
} else if errors.Is(err, issues_model.ErrCommentAlreadyChanged) {
ctx.JSONError(ctx.Tr("repo.comments.edit.already_changed"))
} else {
ctx.ServerError("UpdateComment", err)
}
if contentVersion != comment.ContentVersion {
ctx.JSONError(ctx.Tr("repo.comments.edit.already_changed"))
return
}
if newContent != comment.Content {
// allow to save empty content
oldContent := comment.Content
comment.Content = newContent
if err = issue_service.UpdateComment(ctx, comment, contentVersion, ctx.Doer, oldContent); err != nil {
if errors.Is(err, user_model.ErrBlockedUser) {
ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_user"))
} else if errors.Is(err, issues_model.ErrCommentAlreadyChanged) {
ctx.JSONError(ctx.Tr("repo.comments.edit.already_changed"))
} else {
ctx.ServerError("UpdateComment", err)
}
return
}
}
if err := comment.LoadAttachments(ctx); err != nil {
ctx.ServerError("LoadAttachments", err)
return

View File

@ -109,7 +109,7 @@ func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, err
return wikiGitRepo, nil, errBranch
}
// update the default branch in the database
errDb := repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, DefaultWikiBranch: gitRepoDefaultBranch}, "default_wiki_branch")
errDb := repo_model.UpdateRepositoryColsNoAutoTime(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, DefaultWikiBranch: gitRepoDefaultBranch}, "default_wiki_branch")
if errDb != nil {
return wikiGitRepo, nil, errDb
}

View File

@ -245,7 +245,7 @@ func TestDefaultWikiBranch(t *testing.T) {
assert.NoError(t, wiki_service.ChangeDefaultWikiBranch(db.DefaultContext, repoWithNoWiki, "main"))
// repo with wiki
assert.NoError(t, repo_model.UpdateRepositoryCols(db.DefaultContext, &repo_model.Repository{ID: 1, DefaultWikiBranch: "wrong-branch"}))
assert.NoError(t, repo_model.UpdateRepositoryColsNoAutoTime(db.DefaultContext, &repo_model.Repository{ID: 1, DefaultWikiBranch: "wrong-branch"}))
ctx, _ := contexttest.MockContext(t, "user2/repo1/wiki")
ctx.SetPathParam("*", "Home")

View File

@ -148,7 +148,7 @@ func (g *GiteaLocalUploader) CreateRepo(ctx context.Context, repo *base.Reposito
return err
}
g.repo.ObjectFormatName = objectFormat.Name()
return repo_model.UpdateRepositoryCols(ctx, g.repo, "object_format_name")
return repo_model.UpdateRepositoryColsNoAutoTime(ctx, g.repo, "object_format_name")
}
// Close closes this uploader
@ -975,7 +975,7 @@ func (g *GiteaLocalUploader) Finish(ctx context.Context) error {
}
g.repo.Status = repo_model.RepositoryReady
return repo_model.UpdateRepositoryCols(ctx, g.repo, "status")
return repo_model.UpdateRepositoryColsWithAutoTime(ctx, g.repo, "status")
}
func (g *GiteaLocalUploader) remapUser(ctx context.Context, source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) error {

View File

@ -71,7 +71,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
// erase authentication before storing in database
u.User = nil
m.Repo.OriginalURL = u.String()
return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url")
return repo_model.UpdateRepositoryColsNoAutoTime(ctx, m.Repo, "original_url")
}
// mirrorSyncResult contains information of a updated reference.
@ -653,7 +653,7 @@ func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, re
}
m.Repo.IsEmpty = false
// Update the is empty and default_branch columns
if err := repo_model.UpdateRepositoryCols(ctx, m.Repo, "default_branch", "is_empty"); err != nil {
if err := repo_model.UpdateRepositoryColsWithAutoTime(ctx, m.Repo, "default_branch", "is_empty"); err != nil {
log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err)
desc := fmt.Sprintf("Failed to update default branch of repository '%s': %v", m.Repo.RepoPath(), err)
if err = system_model.CreateRepositoryNotice(desc); err != nil {

View File

@ -100,7 +100,7 @@ func AdoptRepository(ctx context.Context, doer, owner *user_model.User, opts Cre
// 4 - update repository status
repo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
if err = repo_model.UpdateRepositoryColsWithAutoTime(ctx, repo, "status"); err != nil {
return nil, fmt.Errorf("UpdateRepositoryCols: %w", err)
}

View File

@ -40,7 +40,7 @@ func UploadAvatar(ctx context.Context, repo *repo_model.Repository, data []byte)
// Users can upload the same image to other repo - prefix it with ID
// Then repo will be removed - only it avatar file will be removed
repo.Avatar = newAvatar
if err := repo_model.UpdateRepositoryCols(ctx, repo, "avatar"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "avatar"); err != nil {
return fmt.Errorf("UploadAvatar: Update repository avatar: %w", err)
}
@ -77,7 +77,7 @@ func DeleteAvatar(ctx context.Context, repo *repo_model.Repository) error {
defer committer.Close()
repo.Avatar = ""
if err := repo_model.UpdateRepositoryCols(ctx, repo, "avatar"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "avatar"); err != nil {
return fmt.Errorf("DeleteAvatar: Update repository avatar: %w", err)
}
@ -112,5 +112,5 @@ func generateAvatar(ctx context.Context, templateRepo, generateRepo *repo_model.
return err
}
return repo_model.UpdateRepositoryCols(ctx, generateRepo, "avatar")
return repo_model.UpdateRepositoryColsNoAutoTime(ctx, generateRepo, "avatar")
}

View File

@ -321,7 +321,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, owner *user_model.User,
// 7 - update repository status to be ready
if needsUpdateToReady {
repo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
if err = repo_model.UpdateRepositoryColsWithAutoTime(ctx, repo, "status"); err != nil {
return nil, fmt.Errorf("UpdateRepositoryCols: %w", err)
}
}

View File

@ -306,7 +306,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if repo.IsEmpty {
if isEmpty, err := gitRepo.IsEmpty(); err == nil && !isEmpty {
_ = repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: repo.ID, IsEmpty: false, DefaultBranch: opts.NewBranch}, "is_empty", "default_branch")
_ = repo_model.UpdateRepositoryColsWithAutoTime(ctx, &repo_model.Repository{ID: repo.ID, IsEmpty: false, DefaultBranch: opts.NewBranch}, "is_empty", "default_branch")
}
}

View File

@ -198,7 +198,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
// 8 - update repository status to be ready
repo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
if err = repo_model.UpdateRepositoryColsWithAutoTime(ctx, repo, "status"); err != nil {
return nil, fmt.Errorf("UpdateRepositoryCols: %w", err)
}

View File

@ -283,7 +283,7 @@ func pushNewBranch(ctx context.Context, repo *repo_model.Repository, pusher *use
}
}
// Update the is empty and default_branch columns
if err := repo_model.UpdateRepositoryCols(ctx, repo, "default_branch", "is_empty"); err != nil {
if err := repo_model.UpdateRepositoryColsWithAutoTime(ctx, repo, "default_branch", "is_empty"); err != nil {
return nil, fmt.Errorf("UpdateRepositoryCols: %w", err)
}
}

View File

@ -205,7 +205,7 @@ func updateRepository(ctx context.Context, repo *repo_model.Repository, visibili
e := db.GetEngine(ctx)
if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil {
if _, err = e.ID(repo.ID).NoAutoTime().AllCols().Update(repo); err != nil {
return fmt.Errorf("update: %w", err)
}

View File

@ -184,7 +184,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
// 6 - update repository status to be ready
generateRepo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, generateRepo, "status"); err != nil {
if err = repo_model.UpdateRepositoryColsWithAutoTime(ctx, generateRepo, "status"); err != nil {
return nil, fmt.Errorf("UpdateRepositoryCols: %w", err)
}

View File

@ -160,7 +160,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
repo.OwnerName = newOwner.Name
// Update repository.
if err := repo_model.UpdateRepositoryCols(ctx, repo, "owner_id", "owner_name"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "owner_id", "owner_name"); err != nil {
return fmt.Errorf("update owner: %w", err)
}
@ -304,7 +304,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
return fmt.Errorf("deleteRepositoryTransfer: %w", err)
}
repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "status"); err != nil {
return err
}
@ -495,7 +495,7 @@ func RejectRepositoryTransfer(ctx context.Context, repo *repo_model.Repository,
}
repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "status"); err != nil {
return err
}
@ -543,7 +543,7 @@ func CancelRepositoryTransfer(ctx context.Context, repoTransfer *repo_model.Repo
}
repoTransfer.Repo.Status = repo_model.RepositoryReady
if err := repo_model.UpdateRepositoryCols(ctx, repoTransfer.Repo, "status"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repoTransfer.Repo, "status"); err != nil {
return err
}

View File

@ -365,7 +365,7 @@ func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, n
}
return db.WithTx(ctx, func(ctx context.Context) error {
repo.DefaultWikiBranch = newBranch
if err := repo_model.UpdateRepositoryCols(ctx, repo, "default_wiki_branch"); err != nil {
if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "default_wiki_branch"); err != nil {
return fmt.Errorf("unable to update database: %w", err)
}

View File

@ -184,6 +184,15 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content,
return int64(id)
}
func testIssueChangeMilestone(t *testing.T, session *TestSession, repoLink string, issueID, milestoneID int64) {
req := NewRequestWithValues(t, "POST", fmt.Sprintf(repoLink+"/issues/milestone?issue_ids=%d", issueID), map[string]string{
"_csrf": GetUserCSRFToken(t, session),
"id": strconv.FormatInt(milestoneID, 10),
})
resp := session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, `{"ok":true}`, strings.TrimSpace(resp.Body.String()))
}
func TestNewIssue(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")

View File

@ -56,16 +56,21 @@ func TestNewWebHookLink(t *testing.T) {
}
}
func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, userName, repoName, url, event string) {
func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, userName, repoName, url, event string, branchFilter ...string) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
var branchFilterString string
if len(branchFilter) > 0 {
branchFilterString = branchFilter[0]
}
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+userName+"/"+repoName+"/hooks", api.CreateHookOption{
Type: "gitea",
Config: api.CreateHookOptionConfig{
"content_type": "json",
"url": url,
},
Events: []string{event},
Active: true,
Events: []string{event},
Active: true,
BranchFilter: branchFilterString,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
}
@ -241,19 +246,68 @@ func Test_WebhookIssueComment(t *testing.T) {
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_comment")
// 2. trigger the webhook
issueURL := testNewIssue(t, session, "user2", "repo1", "Title2", "Description2")
testIssueAddComment(t, session, issueURL, "issue title2 comment1", "")
t.Run("create comment", func(t *testing.T) {
// 2. trigger the webhook
issueURL := testNewIssue(t, session, "user2", "repo1", "Title2", "Description2")
testIssueAddComment(t, session, issueURL, "issue title2 comment1", "")
// 3. validate the webhook is triggered
assert.Equal(t, "issue_comment", triggeredEvent)
assert.Len(t, payloads, 1)
assert.EqualValues(t, "created", payloads[0].Action)
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
assert.Equal(t, "Title2", payloads[0].Issue.Title)
assert.Equal(t, "Description2", payloads[0].Issue.Body)
assert.Equal(t, "issue title2 comment1", payloads[0].Comment.Body)
// 3. validate the webhook is triggered
assert.Equal(t, "issue_comment", triggeredEvent)
assert.Len(t, payloads, 1)
assert.EqualValues(t, "created", payloads[0].Action)
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
assert.Equal(t, "Title2", payloads[0].Issue.Title)
assert.Equal(t, "Description2", payloads[0].Issue.Body)
assert.Equal(t, "issue title2 comment1", payloads[0].Comment.Body)
})
t.Run("update comment", func(t *testing.T) {
payloads = make([]api.IssueCommentPayload, 0, 2)
triggeredEvent = ""
// 2. trigger the webhook
issueURL := testNewIssue(t, session, "user2", "repo1", "Title3", "Description3")
commentID := testIssueAddComment(t, session, issueURL, "issue title3 comment1", "")
modifiedContent := "issue title2 comment1 - modified"
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{
"_csrf": GetUserCSRFToken(t, session),
"content": modifiedContent,
})
session.MakeRequest(t, req, http.StatusOK)
// 3. validate the webhook is triggered
assert.Equal(t, "issue_comment", triggeredEvent)
assert.Len(t, payloads, 2)
assert.EqualValues(t, "edited", payloads[1].Action)
assert.Equal(t, "repo1", payloads[1].Issue.Repo.Name)
assert.Equal(t, "user2/repo1", payloads[1].Issue.Repo.FullName)
assert.Equal(t, "Title3", payloads[1].Issue.Title)
assert.Equal(t, "Description3", payloads[1].Issue.Body)
assert.Equal(t, modifiedContent, payloads[1].Comment.Body)
})
t.Run("Update comment with no content change", func(t *testing.T) {
payloads = make([]api.IssueCommentPayload, 0, 2)
triggeredEvent = ""
commentContent := "issue title3 comment1"
// 2. trigger the webhook
issueURL := testNewIssue(t, session, "user2", "repo1", "Title3", "Description3")
commentID := testIssueAddComment(t, session, issueURL, commentContent, "")
payloads = make([]api.IssueCommentPayload, 0, 2)
triggeredEvent = ""
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{
"_csrf": GetUserCSRFToken(t, session),
"content": commentContent,
})
session.MakeRequest(t, req, http.StatusOK)
// 3. validate the webhook is not triggered because no content change
assert.Empty(t, triggeredEvent)
assert.Empty(t, payloads)
})
})
}
@ -322,6 +376,45 @@ func Test_WebhookPush(t *testing.T) {
})
}
func Test_WebhookPushDevBranch(t *testing.T) {
var payloads []api.PushPayload
var triggeredEvent string
provider := newMockWebhookProvider(func(r *http.Request) {
content, _ := io.ReadAll(r.Body)
var payload api.PushPayload
err := json.Unmarshal(content, &payload)
assert.NoError(t, err)
payloads = append(payloads, payload)
triggeredEvent = "push"
}, http.StatusOK)
defer provider.Close()
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// 1. create a new webhook with special webhook for repo1
session := loginUser(t, "user2")
// only for dev branch
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "develop")
// 2. this should not trigger the webhook
testCreateFile(t, session, "user2", "repo1", "master", "test_webhook_push.md", "# a test file for webhook push")
assert.Empty(t, triggeredEvent)
assert.Empty(t, payloads)
// 3. trigger the webhook
testCreateFile(t, session, "user2", "repo1", "develop", "test_webhook_push.md", "# a test file for webhook push")
// 4. validate the webhook is triggered
assert.Equal(t, "push", triggeredEvent)
assert.Len(t, payloads, 1)
assert.Equal(t, "repo1", payloads[0].Repo.Name)
assert.Equal(t, "develop", payloads[0].Branch())
assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
assert.Len(t, payloads[0].Commits, 1)
assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added)
})
}
func Test_WebhookIssue(t *testing.T) {
var payloads []api.IssuePayload
var triggeredEvent string
@ -355,6 +448,78 @@ func Test_WebhookIssue(t *testing.T) {
})
}
func Test_WebhookIssueMilestone(t *testing.T) {
var payloads []api.IssuePayload
var triggeredEvent string
provider := newMockWebhookProvider(func(r *http.Request) {
content, _ := io.ReadAll(r.Body)
var payload api.IssuePayload
err := json.Unmarshal(content, &payload)
assert.NoError(t, err)
payloads = append(payloads, payload)
triggeredEvent = "issues"
}, http.StatusOK)
defer provider.Close()
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a new webhook with special webhook for repo1
session := loginUser(t, "user2")
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_milestone")
t.Run("assign a milestone", func(t *testing.T) {
// trigger the webhook
testIssueChangeMilestone(t, session, repo1.Link(), 1, 1)
// validate the webhook is triggered
assert.Equal(t, "issues", triggeredEvent)
assert.Len(t, payloads, 1)
assert.Equal(t, "milestoned", string(payloads[0].Action))
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
assert.Equal(t, "issue1", payloads[0].Issue.Title)
assert.Equal(t, "content for the first issue", payloads[0].Issue.Body)
assert.EqualValues(t, 1, payloads[0].Issue.Milestone.ID)
})
t.Run("change a milestong", func(t *testing.T) {
// trigger the webhook again
triggeredEvent = ""
payloads = make([]api.IssuePayload, 0, 1)
// change milestone to 2
testIssueChangeMilestone(t, session, repo1.Link(), 1, 2)
// validate the webhook is triggered
assert.Equal(t, "issues", triggeredEvent)
assert.Len(t, payloads, 1)
assert.Equal(t, "milestoned", string(payloads[0].Action))
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
assert.Equal(t, "issue1", payloads[0].Issue.Title)
assert.Equal(t, "content for the first issue", payloads[0].Issue.Body)
assert.EqualValues(t, 2, payloads[0].Issue.Milestone.ID)
})
t.Run("remove a milestone", func(t *testing.T) {
// trigger the webhook again
triggeredEvent = ""
payloads = make([]api.IssuePayload, 0, 1)
// change milestone to 0
testIssueChangeMilestone(t, session, repo1.Link(), 1, 0)
// validate the webhook is triggered
assert.Equal(t, "issues", triggeredEvent)
assert.Len(t, payloads, 1)
assert.Equal(t, "demilestoned", string(payloads[0].Action))
assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
assert.Equal(t, "issue1", payloads[0].Issue.Title)
assert.Equal(t, "content for the first issue", payloads[0].Issue.Body)
assert.Nil(t, payloads[0].Issue.Milestone)
})
})
}
func Test_WebhookPullRequest(t *testing.T) {
var payloads []api.PullRequestPayload
var triggeredEvent string