Compare commits

..

5 Commits

Author SHA1 Message Date
Brecht Van Lommel
c8139c0f64
Webhooks: for issue close/reopen action, add commit ID that caused it (#22583)
The `commit_id` property name is the same as equivalent functionality in
GitHub. If the action was not caused by a commit, an empty string is
used.

This can for example be used to automatically add a Resolved label to an
issue fixed by a commit, or clear it when the issue is reopened.
2023-01-24 23:47:53 -05:00
Brecht Van Lommel
a31fedd2c2 Add templates to customize text when creating and migrating repositories
These can be used to explain which types of repositories a Gitea instance is
willing to host, or other rules for creating repositories.
2023-01-24 22:36:48 -05:00
Sybren
25f4b7d7cd
Prevent duplicate labels when importing more than 99 (#22591)
Importing labels (via `gitea restore-repo`) did not split them up into
batches properly. The first "batch" would create all labels, the second
"batch" would create all labels except those in the first "batch", etc.
This meant that when importing more than 99 labels (the batch size)
there would always be duplicate ones.

This is solved by actually passing `labels[:lbBatchSize]` to the
`CreateLabels()` function, instead of the entire list `labels`.
2023-01-24 19:44:55 +00:00
Yarden Shoham
b91bc68092
Remove address from DCO (#22595)
I copy-pasted from https://developercertificate.org/
2023-01-24 18:52:38 +00:00
Sybren
95e8ea9440
Allow setting redirect_to cookie on OAuth login (#22594)
The regular login flow can use a `redirect_to` cookie to ensure the user
ends their authentication flow on the same page as where they started
it.

This commit adds the same functionality to the OAuth login URLs, so that
you can use URLs like these to directly use a specific OAuth provider:

`/user/oauth2/{provider}?redirect_to={post-login path}`

Only the `auth.SignInOAuth()` function needed a change for this, as the
rest of the login flow is aware of this cookie and uses it properly
already.
2023-01-24 11:41:38 -05:00
22 changed files with 37 additions and 29 deletions

4
DCO
View File

@ -2,8 +2,6 @@ Developer Certificate of Origin
Version 1.1 Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors. Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed. license document, but changing it is not allowed.
@ -33,4 +31,4 @@ By making a contribution to this project, I certify that:
are public and that a record of the contribution (including all are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved. this project or the open source license(s) involved.

View File

@ -56,7 +56,7 @@ func (a *actionNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model
} }
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers // NotifyIssueChangeStatus notifies close or reopen issue to notifiers
func (a *actionNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { func (a *actionNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) {
// Compose comment action, could be plain comment, close or reopen issue/pull request. // Compose comment action, could be plain comment, close or reopen issue/pull request.
// This object will be used to notify watchers in the end of function. // This object will be used to notify watchers in the end of function.
act := &activities_model.Action{ act := &activities_model.Action{

View File

@ -23,7 +23,7 @@ type Notifier interface {
NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) NotifyRenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string)
NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) NotifyTransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string)
NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User)
NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool)
NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) NotifyDeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue)
NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) NotifyIssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64)
NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) NotifyIssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment)

View File

@ -32,7 +32,7 @@ func (*NullNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.Iss
} }
// NotifyIssueChangeStatus places a place holder function // NotifyIssueChangeStatus places a place holder function
func (*NullNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { func (*NullNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
} }
// NotifyDeleteIssue notify when some issue deleted // NotifyDeleteIssue notify when some issue deleted

View File

@ -54,7 +54,7 @@ func (m *mailNotifier) NotifyNewIssue(ctx context.Context, issue *issues_model.I
} }
} }
func (m *mailNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { func (m *mailNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
var actionType activities_model.ActionType var actionType activities_model.ActionType
if issue.IsPull { if issue.IsPull {
if isClosed { if isClosed {

View File

@ -77,9 +77,9 @@ func NotifyNewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*
} }
// NotifyIssueChangeStatus notifies close or reopen issue to notifiers // NotifyIssueChangeStatus notifies close or reopen issue to notifiers
func NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) { func NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) {
for _, notifier := range notifiers { for _, notifier := range notifiers {
notifier.NotifyIssueChangeStatus(ctx, doer, issue, actionComment, closeOrReopen) notifier.NotifyIssueChangeStatus(ctx, doer, commitID, issue, actionComment, closeOrReopen)
} }
} }

View File

@ -93,7 +93,7 @@ func (ns *notificationService) NotifyNewIssue(ctx context.Context, issue *issues
} }
} }
func (ns *notificationService) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { func (ns *notificationService) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
_ = ns.issueQueue.Push(issueNotificationOpts{ _ = ns.issueQueue.Push(issueNotificationOpts{
IssueID: issue.ID, IssueID: issue.ID,
NotificationAuthorID: doer.ID, NotificationAuthorID: doer.ID,

View File

@ -352,6 +352,7 @@ type IssuePayload struct {
Issue *Issue `json:"issue"` Issue *Issue `json:"issue"`
Repository *Repository `json:"repository"` Repository *Repository `json:"repository"`
Sender *User `json:"sender"` Sender *User `json:"sender"`
CommitID string `json:"commit_id"`
} }
// JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces. // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces.
@ -386,6 +387,7 @@ type PullRequestPayload struct {
PullRequest *PullRequest `json:"pull_request"` PullRequest *PullRequest `json:"pull_request"`
Repository *Repository `json:"repository"` Repository *Repository `json:"repository"`
Sender *User `json:"sender"` Sender *User `json:"sender"`
CommitID string `json:"commit_id"`
Review *ReviewPayload `json:"review"` Review *ReviewPayload `json:"review"`
} }

View File

@ -654,7 +654,7 @@ func CreateIssue(ctx *context.APIContext) {
} }
if form.Closed { if form.Closed {
if err := issue_service.ChangeStatus(issue, ctx.Doer, true); err != nil { if err := issue_service.ChangeStatus(issue, ctx.Doer, "", true); err != nil {
if issues_model.IsErrDependenciesLeft(err) { if issues_model.IsErrDependenciesLeft(err) {
ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
return return
@ -826,7 +826,7 @@ func EditIssue(ctx *context.APIContext) {
} }
if statusChangeComment != nil { if statusChangeComment != nil {
notification.NotifyIssueChangeStatus(ctx, ctx.Doer, issue, statusChangeComment, issue.IsClosed) notification.NotifyIssueChangeStatus(ctx, ctx.Doer, "", issue, statusChangeComment, issue.IsClosed)
} }
// Refetch from database to assign some automatic values // Refetch from database to assign some automatic values

View File

@ -600,7 +600,7 @@ func EditPullRequest(ctx *context.APIContext) {
} }
if statusChangeComment != nil { if statusChangeComment != nil {
notification.NotifyIssueChangeStatus(ctx, ctx.Doer, issue, statusChangeComment, issue.IsClosed) notification.NotifyIssueChangeStatus(ctx, ctx.Doer, "", issue, statusChangeComment, issue.IsClosed)
} }
// change pull target branch // change pull target branch

View File

@ -847,6 +847,11 @@ func SignInOAuth(ctx *context.Context) {
return return
} }
redirectTo := ctx.FormString("redirect_to")
if len(redirectTo) > 0 {
middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
}
// try to do a direct callback flow, so we don't authenticate the user again but use the valid accesstoken to get the user // try to do a direct callback flow, so we don't authenticate the user again but use the valid accesstoken to get the user
user, gothUser, err := oAuth2UserLoginCallback(authSource, ctx.Req, ctx.Resp) user, gothUser, err := oAuth2UserLoginCallback(authSource, ctx.Req, ctx.Resp)
if err == nil && user != nil { if err == nil && user != nil {

View File

@ -2599,7 +2599,7 @@ func UpdateIssueStatus(ctx *context.Context) {
} }
for _, issue := range issues { for _, issue := range issues {
if issue.IsClosed != isClosed { if issue.IsClosed != isClosed {
if err := issue_service.ChangeStatus(issue, ctx.Doer, isClosed); err != nil { if err := issue_service.ChangeStatus(issue, ctx.Doer, "", isClosed); err != nil {
if issues_model.IsErrDependenciesLeft(err) { if issues_model.IsErrDependenciesLeft(err) {
ctx.JSON(http.StatusPreconditionFailed, map[string]interface{}{ ctx.JSON(http.StatusPreconditionFailed, map[string]interface{}{
"error": "cannot close this issue because it still has open dependencies", "error": "cannot close this issue because it still has open dependencies",
@ -2696,7 +2696,7 @@ func NewComment(ctx *context.Context) {
ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index)) ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index))
} else { } else {
isClosed := form.Status == "close" isClosed := form.Status == "close"
if err := issue_service.ChangeStatus(issue, ctx.Doer, isClosed); err != nil { if err := issue_service.ChangeStatus(issue, ctx.Doer, "", isClosed); err != nil {
log.Error("ChangeStatus: %v", err) log.Error("ChangeStatus: %v", err)
if issues_model.IsErrDependenciesLeft(err) { if issues_model.IsErrDependenciesLeft(err) {

View File

@ -193,7 +193,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm
} }
if close != refIssue.IsClosed { if close != refIssue.IsClosed {
refIssue.Repo = refRepo refIssue.Repo = refRepo
if err := ChangeStatus(refIssue, doer, close); err != nil { if err := ChangeStatus(refIssue, doer, c.Sha1, close); err != nil {
return err return err
} }
} }

View File

@ -14,13 +14,13 @@ import (
) )
// ChangeStatus changes issue status to open or closed. // ChangeStatus changes issue status to open or closed.
func ChangeStatus(issue *issues_model.Issue, doer *user_model.User, closed bool) error { func ChangeStatus(issue *issues_model.Issue, doer *user_model.User, commitID string, closed bool) error {
return changeStatusCtx(db.DefaultContext, issue, doer, closed) return changeStatusCtx(db.DefaultContext, issue, doer, commitID, closed)
} }
// changeStatusCtx changes issue status to open or closed. // changeStatusCtx changes issue status to open or closed.
// TODO: if context is not db.DefaultContext we get a deadlock!!! // TODO: if context is not db.DefaultContext we get a deadlock!!!
func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, closed bool) error { func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, commitID string, closed bool) error {
comment, err := issues_model.ChangeIssueStatus(ctx, issue, doer, closed) comment, err := issues_model.ChangeIssueStatus(ctx, issue, doer, closed)
if err != nil { if err != nil {
if issues_model.IsErrDependenciesLeft(err) && closed { if issues_model.IsErrDependenciesLeft(err) && closed {
@ -37,7 +37,7 @@ func changeStatusCtx(ctx context.Context, issue *issues_model.Issue, doer *user_
} }
} }
notification.NotifyIssueChangeStatus(ctx, doer, issue, comment, closed) notification.NotifyIssueChangeStatus(ctx, doer, commitID, issue, comment, closed)
return nil return nil
} }

View File

@ -281,7 +281,7 @@ func migrateRepository(doer *user_model.User, downloader base.Downloader, upload
lbBatchSize = len(labels) lbBatchSize = len(labels)
} }
if err := uploader.CreateLabels(labels...); err != nil { if err := uploader.CreateLabels(labels[:lbBatchSize]...); err != nil {
return err return err
} }
labels = labels[lbBatchSize:] labels = labels[lbBatchSize:]

View File

@ -225,7 +225,7 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
} }
close := ref.RefAction == references.XRefActionCloses close := ref.RefAction == references.XRefActionCloses
if close != ref.Issue.IsClosed { if close != ref.Issue.IsClosed {
if err = issue_service.ChangeStatus(ref.Issue, doer, close); err != nil { if err = issue_service.ChangeStatus(ref.Issue, doer, pr.MergedCommitID, close); err != nil {
// Allow ErrDependenciesLeft // Allow ErrDependenciesLeft
if !issues_model.IsErrDependenciesLeft(err) { if !issues_model.IsErrDependenciesLeft(err) {
return err return err

View File

@ -532,7 +532,7 @@ func CloseBranchPulls(doer *user_model.User, repoID int64, branch string) error
var errs errlist var errs errlist
for _, pr := range prs { for _, pr := range prs {
if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !issues_model.IsErrPullWasClosed(err) && !issues_model.IsErrDependenciesLeft(err) { if err = issue_service.ChangeStatus(pr.Issue, doer, "", true); err != nil && !issues_model.IsErrPullWasClosed(err) && !issues_model.IsErrDependenciesLeft(err) {
errs = append(errs, err) errs = append(errs, err)
} }
} }
@ -566,7 +566,7 @@ func CloseRepoBranchesPulls(ctx context.Context, doer *user_model.User, repo *re
if pr.BaseRepoID == repo.ID { if pr.BaseRepoID == repo.ID {
continue continue
} }
if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !issues_model.IsErrPullWasClosed(err) { if err = issue_service.ChangeStatus(pr.Issue, doer, "", true); err != nil && !issues_model.IsErrPullWasClosed(err) {
errs = append(errs, err) errs = append(errs, err)
} }
} }

View File

@ -229,7 +229,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user
} }
} }
func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) { func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo)
var err error var err error
if issue.IsPull { if issue.IsPull {
@ -243,6 +243,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
CommitID: commitID,
} }
if isClosed { if isClosed {
apiPullRequest.Action = api.HookIssueClosed apiPullRequest.Action = api.HookIssueClosed
@ -256,6 +257,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use
Issue: convert.ToAPIIssue(ctx, issue), Issue: convert.ToAPIIssue(ctx, issue),
Repository: convert.ToRepo(ctx, issue.Repo, mode), Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(doer, nil), Sender: convert.ToUser(doer, nil),
CommitID: commitID,
} }
if isClosed { if isClosed {
apiIssue.Action = api.HookIssueClosed apiIssue.Action = api.HookIssueClosed

View File

@ -9,10 +9,7 @@
</h3> </h3>
<div class="ui attached segment"> <div class="ui attached segment">
{{template "base/alert" .}} {{template "base/alert" .}}
{{template "repo/create_helper" .}}
{{if not $.DisableMigrations}}
<p class="ui center">{{.locale.Tr "repo.new_repo_helper" ((printf "%s%s" AppSubUrl "/repo/migrate")|Escape) | Safe}}</p>
{{end}}
{{if not .CanCreateRepo}} {{if not .CanCreateRepo}}
<div class="ui negative message"> <div class="ui negative message">

View File

@ -0,0 +1,3 @@
{{if not $.DisableMigrations}}
<p class="ui center">{{.locale.Tr "repo.new_repo_helper" ((printf "%s%s" AppSubUrl "/repo/migrate")|Escape) | Safe}}</p>
{{end}}

View File

View File

@ -2,6 +2,7 @@
<div class="page-content repository new migrate"> <div class="page-content repository new migrate">
<div class="ui middle very relaxed page grid"> <div class="ui middle very relaxed page grid">
<div class="column"> <div class="column">
{{template "repo/migrate/helper" .}}
<div class="ui three stackable cards"> <div class="ui three stackable cards">
{{range .Services}} {{range .Services}}
<a class="ui card df ac" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}&org={{$.Org}}&mirror={{$.Mirror}}"> <a class="ui card df ac" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}&org={{$.Org}}&mirror={{$.Mirror}}">