diff --git a/models/issues/pull.go b/models/issues/pull.go index 5fe95d56cc253..4a5782f836c89 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -268,6 +268,10 @@ func (pr *PullRequest) LoadAttributes(ctx context.Context) (err error) { return nil } +func (pr *PullRequest) IsAgitFlow() bool { + return pr.Flow == PullRequestFlowAGit +} + // LoadHeadRepo loads the head repository, pr.HeadRepo will remain nil if it does not exist // and thus ErrRepoNotExist will never be returned func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) { diff --git a/modules/actions/task_state.go b/modules/actions/task_state.go index 31a74be3fd360..1f36e021a59aa 100644 --- a/modules/actions/task_state.go +++ b/modules/actions/task_state.go @@ -18,8 +18,32 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep { return fullStepsOfEmptySteps(task) } - firstStep := task.Steps[0] + // firstStep is the first step that has run or running, not include preStep. + // For example, + // 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): firstStep is step1. + // 2. preStep(Success) -> step1(Skipped) -> step2(Success) -> postStep(Success): firstStep is step2. + // 3. preStep(Success) -> step1(Running) -> step2(Waiting) -> postStep(Waiting): firstStep is step1. + // 4. preStep(Success) -> step1(Skipped) -> step2(Skipped) -> postStep(Skipped): firstStep is nil. + // 5. preStep(Success) -> step1(Cancelled) -> step2(Cancelled) -> postStep(Cancelled): firstStep is nil. + var firstStep *actions_model.ActionTaskStep + // lastHasRunStep is the last step that has run. + // For example, + // 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1. + // 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3. + // 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2. + // So its Stopped is the Started of postStep when there are no more steps to run. + var lastHasRunStep *actions_model.ActionTaskStep + var logIndex int64 + for _, step := range task.Steps { + if firstStep == nil && (step.Status.HasRun() || step.Status.IsRunning()) { + firstStep = step + } + if step.Status.HasRun() { + lastHasRunStep = step + } + logIndex += step.LogLength + } preStep := &actions_model.ActionTaskStep{ Name: preStepName, @@ -28,32 +52,17 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep { Status: actions_model.StatusRunning, } - if firstStep.Status.HasRun() || firstStep.Status.IsRunning() { + // No step has run or is running, so preStep is equal to the task + if firstStep == nil { + preStep.Stopped = task.Stopped + preStep.Status = task.Status + } else { preStep.LogLength = firstStep.LogIndex preStep.Stopped = firstStep.Started preStep.Status = actions_model.StatusSuccess - } else if task.Status.IsDone() { - preStep.Stopped = task.Stopped - preStep.Status = actions_model.StatusFailure - if task.Status.IsSkipped() { - preStep.Status = actions_model.StatusSkipped - } } logIndex += preStep.LogLength - // lastHasRunStep is the last step that has run. - // For example, - // 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1. - // 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3. - // 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2. - // So its Stopped is the Started of postStep when there are no more steps to run. - var lastHasRunStep *actions_model.ActionTaskStep - for _, step := range task.Steps { - if step.Status.HasRun() { - lastHasRunStep = step - } - logIndex += step.LogLength - } if lastHasRunStep == nil { lastHasRunStep = preStep } diff --git a/modules/actions/task_state_test.go b/modules/actions/task_state_test.go index 28213d781befe..ff0fd5719511e 100644 --- a/modules/actions/task_state_test.go +++ b/modules/actions/task_state_test.go @@ -137,6 +137,25 @@ func TestFullSteps(t *testing.T) { {Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0}, }, }, + { + name: "first step is skipped", + task: &actions_model.ActionTask{ + Steps: []*actions_model.ActionTaskStep{ + {Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0}, + {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090}, + }, + Status: actions_model.StatusSuccess, + Started: 10000, + Stopped: 10100, + LogLength: 100, + }, + want: []*actions_model.ActionTaskStep{ + {Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010}, + {Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0}, + {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090}, + {Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 10100}, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 957e73b171d32..f77fd203a2d6b 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1927,6 +1927,7 @@ pulls.delete.text = Do you really want to delete this pull request? (This will p pulls.recently_pushed_new_branches = You pushed on branch %[1]s %[2]s pull.deleted_branch = (deleted):%s +pull.agit_documentation = Review documentation about AGit comments.edit.already_changed = Unable to save changes to the comment. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 4ff86b5a6647b..9396115b0d249 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -317,7 +317,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b case git.EntryModeBlob: ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form) default: - ctx.Error(http.StatusInternalServerError, err.Error()) + ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", fileErr.Path), tplEditFile, &form) } } else { ctx.Error(http.StatusInternalServerError, err.Error()) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 95299b44d5a25..ced0bbc15a00e 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -164,7 +164,19 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) { ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch } ctx.Data["BaseTarget"] = pull.BaseBranch - ctx.Data["HeadBranchLink"] = pull.GetHeadBranchLink(ctx) + headBranchLink := "" + if pull.Flow == issues_model.PullRequestFlowGithub { + b, err := git_model.GetBranch(ctx, ctx.Repo.Repository.ID, pull.HeadBranch) + switch { + case err == nil: + if !b.IsDeleted { + headBranchLink = pull.GetHeadBranchLink(ctx) + } + case !git_model.IsErrBranchNotExist(err): + log.Error("GetBranch: %v", err) + } + } + ctx.Data["HeadBranchLink"] = headBranchLink ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink(ctx) } diff --git a/services/repository/branch.go b/services/repository/branch.go index 7fc99930776a1..f5cdb72a7bb08 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -483,13 +483,12 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R } rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName) - if err != nil { + if err != nil && !git_model.IsErrBranchNotExist(err) { return fmt.Errorf("GetBranch: %vc", err) } - if rawBranch.IsDeleted { - return nil - } + // database branch record not exist or it's a deleted branch + notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted commit, err := gitRepo.GetBranchCommit(branchName) if err != nil { @@ -497,8 +496,10 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R } if err := db.WithTx(ctx, func(ctx context.Context) error { - if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil { - return err + if !notExist { + if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil { + return err + } } return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{ diff --git a/services/webhook/discord.go b/services/webhook/discord.go index f27b39dac3716..59e87a7e1fb67 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -11,6 +11,7 @@ import ( "net/url" "strconv" "strings" + "unicode/utf8" webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" @@ -154,8 +155,14 @@ func (d discordConvertor) Push(p *api.PushPayload) (DiscordPayload, error) { var text string // for each commit, generate attachment text for i, commit := range p.Commits { - text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, - strings.TrimRight(commit.Message, "\r\n"), commit.Author.Name) + // limit the commit message display to just the summary, otherwise it would be hard to read + message := strings.TrimRight(strings.SplitN(commit.Message, "\n", 1)[0], "\r") + + // a limit of 50 is set because GitHub does the same + if utf8.RuneCountInString(message) > 50 { + message = fmt.Sprintf("%.47s...", message) + } + text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, message, commit.Author.Name) // add linebreak to each commit but the last if i < len(p.Commits)-1 { text += "\n" diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index c04b95383bf13..fbb4b24ef12dd 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -80,6 +80,20 @@ func TestDiscordPayload(t *testing.T) { assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL) }) + t.Run("PushWithLongCommitMessage", func(t *testing.T) { + p := pushTestMultilineCommitMessagePayload() + + pl, err := dc.Push(p) + require.NoError(t, err) + + assert.Len(t, pl.Embeds, 1) + assert.Equal(t, "[test/repo:test] 2 new commits", pl.Embeds[0].Title) + assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好... - user1\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好... - user1", pl.Embeds[0].Description) + assert.Equal(t, p.Sender.UserName, pl.Embeds[0].Author.Name) + assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.Embeds[0].Author.URL) + assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL) + }) + t.Run("Issue", func(t *testing.T) { p := issueTestPayload() diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go index fc6e7140e7be0..d6a77c9442560 100644 --- a/services/webhook/general_test.go +++ b/services/webhook/general_test.go @@ -64,9 +64,17 @@ func forkTestPayload() *api.ForkPayload { } func pushTestPayload() *api.PushPayload { + return pushTestPayloadWithCommitMessage("commit message") +} + +func pushTestMultilineCommitMessagePayload() *api.PushPayload { + return pushTestPayloadWithCommitMessage("This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好 ⚠️⚠️️\n\nThis is the message body.") +} + +func pushTestPayloadWithCommitMessage(message string) *api.PushPayload { commit := &api.PayloadCommit{ ID: "2020558fe2e34debb818a514715839cabd25e778", - Message: "commit message", + Message: message, URL: "http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778", Author: &api.PayloadUser{ Name: "user1", diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 49c40be5a94d8..e49e90df56c9f 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -109,7 +109,7 @@
File path contains leading or trailing whitespace.
'; + // Add display 'block' because display is set to 'none' in formantic\build\semantic.css + warningDiv.style.display = 'block'; + const inputContainer = document.querySelector('.repo-editor-header'); + inputContainer.insertAdjacentElement('beforebegin', warningDiv); } + showElem(warningDiv); + } else if (warningDiv) { + hideElem(warningDiv); } joinTreePath(); });