Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
* upstream/main:
  Add pages to view watched repos and subscribed issues/PRs (go-gitea#17156)
  Fix the hook related FAQ contents (go-gitea#21297)
  Check if email is used when updating user (go-gitea#21289)
  Add name field for org api (go-gitea#21270)
  Add API endpoint to get changed files of a PR (go-gitea#21177)
  • Loading branch information
zjjhot committed Sep 30, 2022
2 parents 5f9a9b9 + 08609d4 commit 6ca2711
Show file tree
Hide file tree
Showing 21 changed files with 790 additions and 24 deletions.
10 changes: 5 additions & 5 deletions docs/content/doc/help/faq.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,13 @@ Our translations are currently crowd-sourced on our [Crowdin project](https://cr

Whether you want to change a translation or add a new one, it will need to be there as all translations are overwritten in our CI via the Crowdin integration.

## Hooks aren't running
## Push Hook / Webhook aren't running

If Gitea is not running hooks, a common cause is incorrect setup of SSH keys.
If you can push but can't see push activities on the home dashboard, or the push doesn't trigger webhook, there are a few possibilities:

See [SSH Issues](#ssh-issues) for more information.

You can also try logging into the administration panel and running the `Resynchronize pre-receive, update and post-receive hooks of all repositories.` option.
1. The git hooks are out of sync: run "Resynchronize pre-receive, update and post-receive hooks of all repositories" on the site admin panel
2. The git repositories (and hooks) are stored on some filesystems (ex: mounted by NAS) which don't support script execution, make sure the filesystem supports `chmod a+x any-script`
3. If you are using docker, make sure Docker Server (not the client) >= 20.10.6

## SSH issues

Expand Down
4 changes: 2 additions & 2 deletions models/fixtures/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
head_repo_id: 1
base_repo_id: 1
head_branch: pr-to-update
base_branch: branch1
merge_base: 1234567890abcdef
base_branch: branch2
merge_base: 985f0301dba5e7b34be866819cd15ad3d8f508ee
has_merged: false

-
Expand Down
35 changes: 35 additions & 0 deletions models/issues/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,7 @@ type IssuesOptions struct { //nolint
PosterID int64
MentionedID int64
ReviewRequestedID int64
SubscriberID int64
MilestoneIDs []int64
ProjectID int64
ProjectBoardID int64
Expand Down Expand Up @@ -1299,6 +1300,10 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
}

if opts.SubscriberID > 0 {
applySubscribedCondition(sess, opts.SubscriberID)
}

if len(opts.MilestoneIDs) > 0 {
sess.In("issue.milestone_id", opts.MilestoneIDs)
}
Expand Down Expand Up @@ -1463,6 +1468,36 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64)
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
}

func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session {
return sess.And(
builder.
NotIn("issue.id",
builder.Select("issue_id").
From("issue_watch").
Where(builder.Eq{"is_watching": false, "user_id": subscriberID}),
),
).And(
builder.Or(
builder.In("issue.id", builder.
Select("issue_id").
From("issue_watch").
Where(builder.Eq{"is_watching": true, "user_id": subscriberID}),
),
builder.In("issue.id", builder.
Select("issue_id").
From("comment").
Where(builder.Eq{"poster_id": subscriberID}),
),
builder.Eq{"issue.poster_id": subscriberID},
builder.In("issue.repo_id", builder.
Select("id").
From("watch").
Where(builder.Eq{"user_id": subscriberID, "mode": true}),
),
),
)
}

// CountIssuesByRepo map from repoID to number of issues matching the options
func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
e := db.GetEngine(db.DefaultContext)
Expand Down
17 changes: 11 additions & 6 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -893,14 +893,19 @@ func UpdateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...s
if err != nil {
return err
}
if !has {
// 1. Update old primary email
if _, err = e.Where("uid=? AND is_primary=?", u.ID, true).Cols("is_primary").Update(&EmailAddress{
IsPrimary: false,
}); err != nil {
return err
if has && emailAddress.UID != u.ID {
return ErrEmailAlreadyUsed{
Email: u.Email,
}
}
// 1. Update old primary email
if _, err = e.Where("uid=? AND is_primary=?", u.ID, true).Cols("is_primary").Update(&EmailAddress{
IsPrimary: false,
}); err != nil {
return err
}

if !has {
emailAddress.Email = u.Email
emailAddress.UID = u.ID
emailAddress.IsActivated = true
Expand Down
16 changes: 16 additions & 0 deletions models/user/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,26 @@ func TestUpdateUser(t *testing.T) {
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.True(t, user.KeepActivityPrivate)

newEmail := "new_" + user.Email
user.Email = newEmail
assert.NoError(t, user_model.UpdateUser(db.DefaultContext, user, true))
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
assert.Equal(t, newEmail, user.Email)

user.Email = "no mail@mail.org"
assert.Error(t, user_model.UpdateUser(db.DefaultContext, user, true))
}

func TestUpdateUserEmailAlreadyUsed(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})

user2.Email = user3.Email
err := user_model.UpdateUser(db.DefaultContext, user2, true)
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}

func TestNewUserRedirect(t *testing.T) {
// redirect to a completely new name
assert.NoError(t, unittest.PrepareTestDatabase())
Expand Down
35 changes: 35 additions & 0 deletions modules/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
webhook_service "code.gitea.io/gitea/services/webhook"
)

Expand Down Expand Up @@ -295,6 +296,7 @@ func ToOrganization(org *organization.Organization) *api.Organization {
return &api.Organization{
ID: org.ID,
AvatarURL: org.AsUser().AvatarLink(),
Name: org.Name,
UserName: org.Name,
FullName: org.FullName,
Description: org.Description,
Expand Down Expand Up @@ -414,3 +416,36 @@ func ToLFSLock(l *git_model.LFSLock) *api.LFSLock {
},
}
}

// ToChangedFile convert a gitdiff.DiffFile to api.ChangedFile
func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile {
status := "changed"
if f.IsDeleted {
status = "deleted"
} else if f.IsCreated {
status = "added"
} else if f.IsRenamed && f.Type == gitdiff.DiffFileCopy {
status = "copied"
} else if f.IsRenamed && f.Type == gitdiff.DiffFileRename {
status = "renamed"
} else if f.Addition == 0 && f.Deletion == 0 {
status = "unchanged"
}

file := &api.ChangedFile{
Filename: f.GetDiffFileName(),
Status: status,
Additions: f.Addition,
Deletions: f.Deletion,
Changes: f.Addition + f.Deletion,
HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
}

if status == "rename" {
file.PreviousFilename = f.OldName
}

return file
}
4 changes: 3 additions & 1 deletion modules/structs/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ package structs
// Organization represents an organization
type Organization struct {
ID int64 `json:"id"`
UserName string `json:"username"`
Name string `json:"name"`
FullName string `json:"full_name"`
AvatarURL string `json:"avatar_url"`
Description string `json:"description"`
Website string `json:"website"`
Location string `json:"location"`
Visibility string `json:"visibility"`
RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"`
// deprecated
UserName string `json:"username"`
}

// OrganizationPermissions list different users permissions on an organization
Expand Down
13 changes: 13 additions & 0 deletions modules/structs/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,16 @@ type EditPullRequestOption struct {
RemoveDeadline *bool `json:"unset_due_date"`
AllowMaintainerEdit *bool `json:"allow_maintainer_edit"`
}

// ChangedFile store information about files affected by the pull request
type ChangedFile struct {
Filename string `json:"filename"`
PreviousFilename string `json:"previous_filename,omitempty"`
Status string `json:"status"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
Changes int `json:"changes"`
HTMLURL string `json:"html_url,omitempty"`
ContentsURL string `json:"contents_url,omitempty"`
RawURL string `json:"raw_url,omitempty"`
}
3 changes: 3 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3034,6 +3034,9 @@ pin = Pin notification
mark_as_read = Mark as read
mark_as_unread = Mark as unread
mark_all_as_read = Mark all as read
subscriptions = Subscriptions
watching = Watching
no_subscriptions = No subscriptions

[gpg]
default_key=Signed with default key
Expand Down
1 change: 1 addition & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,7 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get(".{diffType:diff|patch}", repo.DownloadPullDiffOrPatch)
m.Post("/update", reqToken(), repo.UpdatePullRequest)
m.Get("/commits", repo.GetPullRequestCommits)
m.Get("/files", repo.GetPullRequestFiles)
m.Combo("/merge").Get(repo.IsPullRequestMerged).
Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest).
Delete(reqToken(), mustNotBeArchived, repo.CancelScheduledAutoMerge)
Expand Down
136 changes: 136 additions & 0 deletions routers/api/v1/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/automerge"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/gitdiff"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
Expand Down Expand Up @@ -1323,3 +1325,137 @@ func GetPullRequestCommits(ctx *context.APIContext) {

ctx.JSON(http.StatusOK, &apiCommits)
}

// GetPullRequestFiles gets all changed files associated with a given PR
func GetPullRequestFiles(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/pulls/{index}/files repository repoGetPullRequestFiles
// ---
// summary: Get changed files for a pull request
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the pull request to get
// type: integer
// format: int64
// required: true
// - name: skip-to
// in: query
// description: skip to given file
// type: string
// - name: whitespace
// in: query
// description: whitespace behavior
// type: string
// enum: [ignore-all, ignore-change, ignore-eol, show-all]
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
// type: integer
// responses:
// "200":
// "$ref": "#/responses/ChangedFileList"
// "404":
// "$ref": "#/responses/notFound"

pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
}
return
}

if err := pr.LoadBaseRepo(); err != nil {
ctx.InternalServerError(err)
return
}

if err := pr.LoadHeadRepo(); err != nil {
ctx.InternalServerError(err)
return
}

baseGitRepo := ctx.Repo.GitRepo

var prInfo *git.CompareInfo
if pr.HasMerged {
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false)
} else {
prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false)
}
if err != nil {
ctx.ServerError("GetCompareInfo", err)
return
}

headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
ctx.ServerError("GetRefCommitID", err)
return
}

startCommitID := prInfo.MergeBase
endCommitID := headCommitID

maxLines, maxFiles := setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles

diff, err := gitdiff.GetDiff(baseGitRepo,
&gitdiff.DiffOptions{
BeforeCommitID: startCommitID,
AfterCommitID: endCommitID,
SkipTo: ctx.FormString("skip-to"),
MaxLines: maxLines,
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
MaxFiles: maxFiles,
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.FormString("whitespace")),
})
if err != nil {
ctx.ServerError("GetDiff", err)
return
}

listOptions := utils.GetListOptions(ctx)

totalNumberOfFiles := diff.NumFiles
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))

start, end := listOptions.GetStartEnd()

if end > totalNumberOfFiles {
end = totalNumberOfFiles
}

apiFiles := make([]*api.ChangedFile, 0, end-start)
for i := start; i < end; i++ {
apiFiles = append(apiFiles, convert.ToChangedFile(diff.Files[i], pr.HeadRepo, endCommitID))
}

ctx.SetLinkHeader(totalNumberOfFiles, listOptions.PageSize)
ctx.SetTotalCountHeader(int64(totalNumberOfFiles))

ctx.RespHeader().Set("X-Page", strconv.Itoa(listOptions.Page))
ctx.RespHeader().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
ctx.RespHeader().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
ctx.RespHeader().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
ctx.AppendAccessControlExposeHeaders("X-Page", "X-PerPage", "X-PageCount", "X-HasMore")

ctx.JSON(http.StatusOK, &apiFiles)
}
Loading

0 comments on commit 6ca2711

Please sign in to comment.