mirror of https://github.com/go-gitea/gitea
Merge branch 'main' into fix-incorrect-recently-pushed-new-branches-check
This commit is contained in:
commit
a7fc27917c
|
@ -804,11 +804,6 @@
|
|||
"path": "github.com/nektos/act/pkg/LICENSE",
|
||||
"licenseText": "MIT License\n\nCopyright (c) 2022 The Gitea Authors\nCopyright (c) 2019\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
|
||||
},
|
||||
{
|
||||
"name": "github.com/nfnt/resize",
|
||||
"path": "github.com/nfnt/resize/LICENSE",
|
||||
"licenseText": "Copyright (c) 2012, Jan Schlicht \u003cjan.schlicht@gmail.com\u003e\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or without fee is hereby granted, provided that the above copyright notice\nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS\nOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\nTORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\nTHIS SOFTWARE.\n"
|
||||
},
|
||||
{
|
||||
"name": "github.com/niklasfasching/go-org/org",
|
||||
"path": "github.com/niklasfasching/go-org/org/LICENSE",
|
||||
|
@ -824,11 +819,6 @@
|
|||
"path": "github.com/olekukonko/tablewriter/LICENSE.md",
|
||||
"licenseText": "Copyright (C) 2014 by Oleku Konko\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
|
||||
},
|
||||
{
|
||||
"name": "github.com/oliamb/cutter",
|
||||
"path": "github.com/oliamb/cutter/LICENSE",
|
||||
"licenseText": "The MIT License (MIT)\n\nCopyright (c) 2014 Olivier Amblet\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
||||
},
|
||||
{
|
||||
"name": "github.com/olivere/elastic/v7",
|
||||
"path": "github.com/olivere/elastic/v7/LICENSE",
|
||||
|
|
|
@ -67,7 +67,7 @@ sudo chown 1000:1000 config/ data/
|
|||
|
||||
> If you don't give the volume correct permissions, the container may not start.
|
||||
|
||||
For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:dev-rootless` would be an appropriate tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev-rootless` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev-rootless`)
|
||||
For a stable release you could use `:latest-rootless`, `:1-rootless` or specify a certain release like `:{{< version >}}-rootless`, but if you'd like to use the latest development version then `:nightly-rootless` would be an appropriate tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-nightly-rootless` tag, where x is the minor version of Gitea. (e.g. `:1.16-nightly-rootless`)
|
||||
|
||||
## Custom port
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ image as a service. Since there is no database available, one can be initialized
|
|||
Create a directory like `gitea` and paste the following content into a file named `docker-compose.yml`.
|
||||
Note that the volume should be owned by the user/group with the UID/GID specified in the config file.
|
||||
If you don't give the volume correct permissions, the container may not start.
|
||||
For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:dev` tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-dev` tag, where x is the minor version of Gitea. (e.g. `:1.16-dev`)
|
||||
For a stable release you can use `:latest`, `:1` or specify a certain release like `:{{< version >}}`, but if you'd like to use the latest development version of Gitea then you could use the `:nightly` tag. If you'd like to run the latest commit from a release branch you can use the `:1.x-nightly` tag, where x is the minor version of Gitea. (e.g. `:1.16-nightly`)
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
|
|
@ -44,7 +44,7 @@ The following package managers are currently supported:
|
|||
| [NuGet]({{< relref "doc/usage/packages/nuget.en-us.md" >}}) | .NET | `nuget` |
|
||||
| [Pub]({{< relref "doc/usage/packages/pub.en-us.md" >}}) | Dart | `dart`, `flutter` |
|
||||
| [PyPI]({{< relref "doc/usage/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.en-us.md" >}}) | - | `yum`, `dnf` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.en-us.md" >}}) | - | `yum`, `dnf`, `zypper` |
|
||||
| [RubyGems]({{< relref "doc/usage/packages/rubygems.en-us.md" >}}) | Ruby | `gem`, `Bundler` |
|
||||
| [Swift]({{< relref "doc/usage/packages/rubygems.en-us.md" >}}) | Swift | `swift` |
|
||||
| [Vagrant]({{< relref "doc/usage/packages/vagrant.en-us.md" >}}) | - | `vagrant` |
|
||||
|
|
|
@ -44,7 +44,7 @@ menu:
|
|||
| [NuGet]({{< relref "doc/usage/packages/nuget.zh-cn.md" >}}) | .NET | `nuget` |
|
||||
| [Pub]({{< relref "doc/usage/packages/pub.zh-cn.md" >}}) | Dart | `dart`, `flutter` |
|
||||
| [PyPI]({{< relref "doc/usage/packages/pypi.zh-cn.md" >}}) | Python | `pip`, `twine` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.zh-cn.md" >}}) | - | `yum`, `dnf` |
|
||||
| [RPM]({{< relref "doc/usage/packages/rpm.zh-cn.md" >}}) | - | `yum`, `dnf`, `zypper` |
|
||||
| [RubyGems]({{< relref "doc/usage/packages/rubygems.zh-cn.md" >}}) | Ruby | `gem`, `Bundler` |
|
||||
| [Swift]({{< relref "doc/usage/packages/rubygems.zh-cn.md" >}}) | Swift | `swift` |
|
||||
| [Vagrant]({{< relref "doc/usage/packages/vagrant.zh-cn.md" >}}) | - | `vagrant` |
|
||||
|
|
|
@ -22,7 +22,7 @@ Publish [RPM](https://rpm.org/) packages for your user or organization.
|
|||
|
||||
## Requirements
|
||||
|
||||
To work with the RPM registry, you need to use a package manager like `yum` or `dnf` to consume packages.
|
||||
To work with the RPM registry, you need to use a package manager like `yum`, `dnf` or `zypper` to consume packages.
|
||||
|
||||
The following examples use `dnf`.
|
||||
|
||||
|
@ -79,7 +79,7 @@ The server responds with the following HTTP Status codes.
|
|||
|
||||
## Delete a package
|
||||
|
||||
To delete a Debian package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
|
||||
To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
|
||||
|
||||
```
|
||||
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
|
||||
|
|
|
@ -22,7 +22,7 @@ menu:
|
|||
|
||||
## 要求
|
||||
|
||||
要使用RPM注册表,您需要使用像 `yum` 或 `dnf` 这样的软件包管理器来消费软件包。
|
||||
要使用RPM注册表,您需要使用像 `yum`, `dnf` 或 `zypper` 这样的软件包管理器来消费软件包。
|
||||
|
||||
以下示例使用 `dnf`。
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -81,9 +81,7 @@ require (
|
|||
github.com/minio/sha256-simd v1.0.1
|
||||
github.com/msteinert/pam v1.1.0
|
||||
github.com/nektos/act v0.2.48
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/niklasfasching/go-org v1.7.0
|
||||
github.com/oliamb/cutter v0.2.2
|
||||
github.com/olivere/elastic/v7 v7.0.32
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4
|
||||
|
|
4
go.sum
4
go.sum
|
@ -921,8 +921,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
|||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
|
||||
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o=
|
||||
|
@ -939,8 +937,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
|
|||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k=
|
||||
github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
|
||||
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
||||
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
|
|
@ -551,7 +551,7 @@ func GetIssueWithAttrsByID(id int64) (*Issue, error) {
|
|||
|
||||
// GetIssuesByIDs return issues with the given IDs.
|
||||
func GetIssuesByIDs(ctx context.Context, issueIDs []int64) (IssueList, error) {
|
||||
issues := make([]*Issue, 0, 10)
|
||||
issues := make([]*Issue, 0, len(issueIDs))
|
||||
return issues, db.GetEngine(ctx).In("id", issueIDs).Find(&issues)
|
||||
}
|
||||
|
||||
|
|
|
@ -316,15 +316,13 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if len(reviews) > 0 {
|
||||
err = LoadReviewers(ctx, reviews)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, review := range reviews {
|
||||
pr.RequestedReviewers = append(pr.RequestedReviewers, review.Reviewer)
|
||||
}
|
||||
if err = reviews.LoadReviewers(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, review := range reviews {
|
||||
pr.RequestedReviewers = append(pr.RequestedReviewers, review.Reviewer)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -162,27 +162,6 @@ func (r *Review) LoadReviewer(ctx context.Context) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// LoadReviewers loads reviewers
|
||||
func LoadReviewers(ctx context.Context, reviews []*Review) (err error) {
|
||||
reviewerIds := make([]int64, len(reviews))
|
||||
for i := 0; i < len(reviews); i++ {
|
||||
reviewerIds[i] = reviews[i].ReviewerID
|
||||
}
|
||||
reviewers, err := user_model.GetPossibleUserByIDs(ctx, reviewerIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*user_model.User, len(reviewers))
|
||||
for _, reviewer := range reviewers {
|
||||
userMap[reviewer.ID] = reviewer
|
||||
}
|
||||
for _, review := range reviews {
|
||||
review.Reviewer = userMap[review.ReviewerID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadReviewerTeam loads reviewer team
|
||||
func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
|
||||
if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
|
||||
|
@ -236,71 +215,6 @@ func GetReviewByID(ctx context.Context, id int64) (*Review, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// FindReviewOptions represent possible filters to find reviews
|
||||
type FindReviewOptions struct {
|
||||
db.ListOptions
|
||||
Type ReviewType
|
||||
IssueID int64
|
||||
ReviewerID int64
|
||||
OfficialOnly bool
|
||||
}
|
||||
|
||||
func (opts *FindReviewOptions) toCond() builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
if opts.IssueID > 0 {
|
||||
cond = cond.And(builder.Eq{"issue_id": opts.IssueID})
|
||||
}
|
||||
if opts.ReviewerID > 0 {
|
||||
cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
|
||||
}
|
||||
if opts.Type != ReviewTypeUnknown {
|
||||
cond = cond.And(builder.Eq{"type": opts.Type})
|
||||
}
|
||||
if opts.OfficialOnly {
|
||||
cond = cond.And(builder.Eq{"official": true})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
||||
// FindReviews returns reviews passing FindReviewOptions
|
||||
func FindReviews(ctx context.Context, opts FindReviewOptions) ([]*Review, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
sess := db.GetEngine(ctx).Where(opts.toCond())
|
||||
if opts.Page > 0 {
|
||||
sess = db.SetSessionPagination(sess, &opts)
|
||||
}
|
||||
return reviews, sess.
|
||||
Asc("created_unix").
|
||||
Asc("id").
|
||||
Find(&reviews)
|
||||
}
|
||||
|
||||
// FindLatestReviews returns only latest reviews per user, passing FindReviewOptions
|
||||
func FindLatestReviews(ctx context.Context, opts FindReviewOptions) ([]*Review, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
cond := opts.toCond()
|
||||
sess := db.GetEngine(ctx).Where(cond)
|
||||
if opts.Page > 0 {
|
||||
sess = db.SetSessionPagination(sess, &opts)
|
||||
}
|
||||
|
||||
sess.In("id", builder.
|
||||
Select("max ( id ) ").
|
||||
From("review").
|
||||
Where(cond).
|
||||
GroupBy("reviewer_id"))
|
||||
|
||||
return reviews, sess.
|
||||
Asc("created_unix").
|
||||
Asc("id").
|
||||
Find(&reviews)
|
||||
}
|
||||
|
||||
// CountReviews returns count of reviews passing FindReviewOptions
|
||||
func CountReviews(opts FindReviewOptions) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{})
|
||||
}
|
||||
|
||||
// CreateReviewOptions represent the options to create a review. Type, Issue and Reviewer are required.
|
||||
type CreateReviewOptions struct {
|
||||
Content string
|
||||
|
@ -533,76 +447,6 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co
|
|||
return review, comm, committer.Commit()
|
||||
}
|
||||
|
||||
// GetReviewOptions represent filter options for GetReviews
|
||||
type GetReviewOptions struct {
|
||||
IssueID int64
|
||||
ReviewerID int64
|
||||
Dismissed util.OptionalBool
|
||||
}
|
||||
|
||||
// GetReviews return reviews based on GetReviewOptions
|
||||
func GetReviews(ctx context.Context, opts *GetReviewOptions) ([]*Review, error) {
|
||||
if opts == nil {
|
||||
return nil, fmt.Errorf("opts are nil")
|
||||
}
|
||||
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
if opts.IssueID != 0 {
|
||||
sess = sess.Where("issue_id=?", opts.IssueID)
|
||||
}
|
||||
if opts.ReviewerID != 0 {
|
||||
sess = sess.Where("reviewer_id=?", opts.ReviewerID)
|
||||
}
|
||||
if !opts.Dismissed.IsNone() {
|
||||
sess = sess.Where("dismissed=?", opts.Dismissed.IsTrue())
|
||||
}
|
||||
|
||||
reviews := make([]*Review, 0, 4)
|
||||
return reviews, sess.Find(&reviews)
|
||||
}
|
||||
|
||||
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||
func GetReviewsByIssueID(issueID int64) ([]*Review, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
|
||||
sess := db.GetEngine(db.DefaultContext)
|
||||
|
||||
// Get latest review of each reviewer, sorted in order they were made
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
teamReviewRequests := make([]*Review, 0, 5)
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id <> 0 AND original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
|
||||
issueID).
|
||||
Find(&teamReviewRequests); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(teamReviewRequests) > 0 {
|
||||
reviews = append(reviews, teamReviewRequests...)
|
||||
}
|
||||
|
||||
return reviews, nil
|
||||
}
|
||||
|
||||
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
||||
func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) ([]*Review, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
|
||||
// Get latest review of each reviewer, sorted in order they were made
|
||||
if err := db.GetEngine(db.DefaultContext).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reviews, nil
|
||||
}
|
||||
|
||||
// GetReviewByIssueIDAndUserID get the latest review of reviewer for a pull request
|
||||
func GetReviewByIssueIDAndUserID(ctx context.Context, issueID, userID int64) (*Review, error) {
|
||||
review := new(Review)
|
||||
|
@ -654,7 +498,7 @@ func MarkReviewsAsNotStale(issueID int64, commitID string) (err error) {
|
|||
}
|
||||
|
||||
// DismissReview change the dismiss status of a review
|
||||
func DismissReview(review *Review, isDismiss bool) (err error) {
|
||||
func DismissReview(ctx context.Context, review *Review, isDismiss bool) (err error) {
|
||||
if review.Dismissed == isDismiss || (review.Type != ReviewTypeApprove && review.Type != ReviewTypeReject) {
|
||||
return nil
|
||||
}
|
||||
|
@ -665,7 +509,7 @@ func DismissReview(review *Review, isDismiss bool) (err error) {
|
|||
return ErrReviewNotExist{}
|
||||
}
|
||||
|
||||
_, err = db.GetEngine(db.DefaultContext).ID(review.ID).Cols("dismissed").Update(review)
|
||||
_, err = db.GetEngine(ctx).ID(review.ID).Cols("dismissed").Update(review)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issues
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type ReviewList []*Review
|
||||
|
||||
// LoadReviewers loads reviewers
|
||||
func (reviews ReviewList) LoadReviewers(ctx context.Context) error {
|
||||
reviewerIds := make([]int64, len(reviews))
|
||||
for i := 0; i < len(reviews); i++ {
|
||||
reviewerIds[i] = reviews[i].ReviewerID
|
||||
}
|
||||
reviewers, err := user_model.GetPossibleUserByIDs(ctx, reviewerIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*user_model.User, len(reviewers))
|
||||
for _, reviewer := range reviewers {
|
||||
userMap[reviewer.ID] = reviewer
|
||||
}
|
||||
for _, review := range reviews {
|
||||
review.Reviewer = userMap[review.ReviewerID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (reviews ReviewList) LoadIssues(ctx context.Context) error {
|
||||
issueIds := container.Set[int64]{}
|
||||
for i := 0; i < len(reviews); i++ {
|
||||
issueIds.Add(reviews[i].IssueID)
|
||||
}
|
||||
|
||||
issues, err := GetIssuesByIDs(ctx, issueIds.Values())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := issues.LoadRepositories(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
issueMap := make(map[int64]*Issue, len(issues))
|
||||
for _, issue := range issues {
|
||||
issueMap[issue.ID] = issue
|
||||
}
|
||||
|
||||
for _, review := range reviews {
|
||||
review.Issue = issueMap[review.IssueID]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindReviewOptions represent possible filters to find reviews
|
||||
type FindReviewOptions struct {
|
||||
db.ListOptions
|
||||
Type ReviewType
|
||||
IssueID int64
|
||||
ReviewerID int64
|
||||
OfficialOnly bool
|
||||
Dismissed util.OptionalBool
|
||||
}
|
||||
|
||||
func (opts *FindReviewOptions) toCond() builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
if opts.IssueID > 0 {
|
||||
cond = cond.And(builder.Eq{"issue_id": opts.IssueID})
|
||||
}
|
||||
if opts.ReviewerID > 0 {
|
||||
cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
|
||||
}
|
||||
if opts.Type != ReviewTypeUnknown {
|
||||
cond = cond.And(builder.Eq{"type": opts.Type})
|
||||
}
|
||||
if opts.OfficialOnly {
|
||||
cond = cond.And(builder.Eq{"official": true})
|
||||
}
|
||||
if !opts.Dismissed.IsNone() {
|
||||
cond = cond.And(builder.Eq{"dismissed": opts.Dismissed.IsTrue()})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
||||
// FindReviews returns reviews passing FindReviewOptions
|
||||
func FindReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
sess := db.GetEngine(ctx).Where(opts.toCond())
|
||||
if opts.Page > 0 && !opts.IsListAll() {
|
||||
sess = db.SetSessionPagination(sess, &opts)
|
||||
}
|
||||
return reviews, sess.
|
||||
Asc("created_unix").
|
||||
Asc("id").
|
||||
Find(&reviews)
|
||||
}
|
||||
|
||||
// FindLatestReviews returns only latest reviews per user, passing FindReviewOptions
|
||||
func FindLatestReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
cond := opts.toCond()
|
||||
sess := db.GetEngine(ctx).Where(cond)
|
||||
if opts.Page > 0 {
|
||||
sess = db.SetSessionPagination(sess, &opts)
|
||||
}
|
||||
|
||||
sess.In("id", builder.
|
||||
Select("max ( id ) ").
|
||||
From("review").
|
||||
Where(cond).
|
||||
GroupBy("reviewer_id"))
|
||||
|
||||
return reviews, sess.
|
||||
Asc("created_unix").
|
||||
Asc("id").
|
||||
Find(&reviews)
|
||||
}
|
||||
|
||||
// CountReviews returns count of reviews passing FindReviewOptions
|
||||
func CountReviews(opts FindReviewOptions) (int64, error) {
|
||||
return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{})
|
||||
}
|
||||
|
||||
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
||||
func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) (ReviewList, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
|
||||
// Get latest review of each reviewer, sorted in order they were made
|
||||
if err := db.GetEngine(db.DefaultContext).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reviews, nil
|
||||
}
|
||||
|
||||
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||
func GetReviewsByIssueID(issueID int64) (ReviewList, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
|
||||
sess := db.GetEngine(db.DefaultContext)
|
||||
|
||||
// Get latest review of each reviewer, sorted in order they were made
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
teamReviewRequests := make([]*Review, 0, 5)
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id <> 0 AND original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
|
||||
issueID).
|
||||
Find(&teamReviewRequests); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(teamReviewRequests) > 0 {
|
||||
reviews = append(reviews, teamReviewRequests...)
|
||||
}
|
||||
|
||||
return reviews, nil
|
||||
}
|
|
@ -159,7 +159,7 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
|||
|
||||
allReviews, err = issues_model.GetReviewsByIssueID(issue.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, issues_model.LoadReviewers(db.DefaultContext, allReviews))
|
||||
assert.NoError(t, allReviews.LoadReviewers(db.DefaultContext))
|
||||
if assert.Len(t, allReviews, 3) {
|
||||
for i, review := range allReviews {
|
||||
assert.Equal(t, expectedReviews[i].Reviewer, review.Reviewer)
|
||||
|
@ -179,46 +179,46 @@ func TestDismissReview(t *testing.T) {
|
|||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(rejectReviewExample, true))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, rejectReviewExample, true))
|
||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, true))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, true))
|
||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, true))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, true))
|
||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, false))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, false))
|
||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, false))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, false))
|
||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||
assert.True(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(rejectReviewExample, false))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, rejectReviewExample, false))
|
||||
assert.False(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.False(t, approveReviewExample.Dismissed)
|
||||
|
||||
assert.NoError(t, issues_model.DismissReview(approveReviewExample, true))
|
||||
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, approveReviewExample, true))
|
||||
assert.False(t, rejectReviewExample.Dismissed)
|
||||
assert.False(t, requestReviewExample.Dismissed)
|
||||
assert.True(t, approveReviewExample.Dismissed)
|
||||
|
|
|
@ -17,8 +17,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/avatar/identicon"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/oliamb/cutter"
|
||||
"golang.org/x/image/draw"
|
||||
|
||||
_ "golang.org/x/image/webp" // for processing webp images
|
||||
)
|
||||
|
@ -81,28 +80,10 @@ func processAvatarImage(data []byte, maxOriginSize int64) ([]byte, error) {
|
|||
}
|
||||
|
||||
// try to crop and resize the origin image if necessary
|
||||
if imgCfg.Width != imgCfg.Height {
|
||||
var newSize, ax, ay int
|
||||
if imgCfg.Width > imgCfg.Height {
|
||||
newSize = imgCfg.Height
|
||||
ax = (imgCfg.Width - imgCfg.Height) / 2
|
||||
} else {
|
||||
newSize = imgCfg.Width
|
||||
ay = (imgCfg.Height - imgCfg.Width) / 2
|
||||
}
|
||||
img = cropSquare(img)
|
||||
|
||||
img, err = cutter.Crop(img, cutter.Config{
|
||||
Width: newSize,
|
||||
Height: newSize,
|
||||
Anchor: image.Point{X: ax, Y: ay},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
targetSize := uint(DefaultAvatarSize * setting.Avatar.RenderedSizeFactor)
|
||||
img = resize.Resize(targetSize, targetSize, img, resize.Bilinear)
|
||||
targetSize := DefaultAvatarSize * setting.Avatar.RenderedSizeFactor
|
||||
img = scale(img, targetSize, targetSize, draw.BiLinear)
|
||||
|
||||
// try to encode the cropped/resized image to png
|
||||
bs := bytes.Buffer{}
|
||||
|
@ -124,3 +105,35 @@ func processAvatarImage(data []byte, maxOriginSize int64) ([]byte, error) {
|
|||
func ProcessAvatarImage(data []byte) ([]byte, error) {
|
||||
return processAvatarImage(data, setting.Avatar.MaxOriginSize)
|
||||
}
|
||||
|
||||
// scale resizes the image to width x height using the given scaler.
|
||||
func scale(src image.Image, width, height int, scale draw.Scaler) image.Image {
|
||||
rect := image.Rect(0, 0, width, height)
|
||||
dst := image.NewRGBA(rect)
|
||||
scale.Scale(dst, rect, src, src.Bounds(), draw.Over, nil)
|
||||
return dst
|
||||
}
|
||||
|
||||
// cropSquare crops the largest square image from the center of the image.
|
||||
// If the image is already square, it is returned unchanged.
|
||||
func cropSquare(src image.Image) image.Image {
|
||||
bounds := src.Bounds()
|
||||
if bounds.Dx() == bounds.Dy() {
|
||||
return src
|
||||
}
|
||||
|
||||
var rect image.Rectangle
|
||||
if bounds.Dx() > bounds.Dy() {
|
||||
// width > height
|
||||
size := bounds.Dy()
|
||||
rect = image.Rect((bounds.Dx()-size)/2, 0, (bounds.Dx()+size)/2, size)
|
||||
} else {
|
||||
// width < height
|
||||
size := bounds.Dx()
|
||||
rect = image.Rect(0, (bounds.Dy()-size)/2, size, (bounds.Dy()+size)/2)
|
||||
}
|
||||
|
||||
dst := image.NewRGBA(rect)
|
||||
draw.Draw(dst, rect, src, rect.Min, draw.Src)
|
||||
return dst
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) {
|
|||
key += remaining
|
||||
}
|
||||
section = strings.ToLower(section)
|
||||
ok = section != "" && key != ""
|
||||
ok = key != ""
|
||||
if !ok {
|
||||
section = ""
|
||||
key = ""
|
||||
|
|
|
@ -48,6 +48,12 @@ func TestDecodeEnvironmentKey(t *testing.T) {
|
|||
assert.Equal(t, "", key)
|
||||
assert.False(t, file)
|
||||
|
||||
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA____KEY")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "", section)
|
||||
assert.Equal(t, "KEY", key)
|
||||
assert.False(t, file)
|
||||
|
||||
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC__KEY")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "sec", section)
|
||||
|
|
|
@ -327,7 +327,7 @@ type MigrateRepoOptions struct {
|
|||
// required: true
|
||||
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
|
||||
// enum: git,github,gitea,gitlab
|
||||
// enum: git,github,gitea,gitlab,gogs,onedev,gitbucket,codebase
|
||||
Service string `json:"service"`
|
||||
AuthUsername string `json:"auth_username"`
|
||||
AuthPassword string `json:"auth_password"`
|
||||
|
|
|
@ -69,4 +69,5 @@ type CommitDateOptions struct {
|
|||
// CommitAffectedFiles store information about files affected by the commit
|
||||
type CommitAffectedFiles struct {
|
||||
Filename string `json:"filename"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ func (r *Route) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Han
|
|||
return middlewares, handlerFunc
|
||||
}
|
||||
|
||||
func (r *Route) Methods(method, pattern string, h []any) {
|
||||
func (r *Route) Methods(method, pattern string, h ...any) {
|
||||
middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h)
|
||||
fullPattern := r.getPattern(pattern)
|
||||
if strings.Contains(method, ",") {
|
||||
|
@ -126,49 +126,44 @@ func (r *Route) Any(pattern string, h ...any) {
|
|||
r.R.With(middlewares...).HandleFunc(r.getPattern(pattern), handlerFunc)
|
||||
}
|
||||
|
||||
// RouteMethods delegate special methods, it is an alias of "Methods", while the "pattern" is the first parameter
|
||||
func (r *Route) RouteMethods(pattern, methods string, h ...any) {
|
||||
r.Methods(methods, pattern, h)
|
||||
}
|
||||
|
||||
// Delete delegate delete method
|
||||
func (r *Route) Delete(pattern string, h ...any) {
|
||||
r.Methods("DELETE", pattern, h)
|
||||
r.Methods("DELETE", pattern, h...)
|
||||
}
|
||||
|
||||
// Get delegate get method
|
||||
func (r *Route) Get(pattern string, h ...any) {
|
||||
r.Methods("GET", pattern, h)
|
||||
r.Methods("GET", pattern, h...)
|
||||
}
|
||||
|
||||
// GetOptions delegate get and options method
|
||||
func (r *Route) GetOptions(pattern string, h ...any) {
|
||||
r.Methods("GET,OPTIONS", pattern, h)
|
||||
r.Methods("GET,OPTIONS", pattern, h...)
|
||||
}
|
||||
|
||||
// PostOptions delegate post and options method
|
||||
func (r *Route) PostOptions(pattern string, h ...any) {
|
||||
r.Methods("POST,OPTIONS", pattern, h)
|
||||
r.Methods("POST,OPTIONS", pattern, h...)
|
||||
}
|
||||
|
||||
// Head delegate head method
|
||||
func (r *Route) Head(pattern string, h ...any) {
|
||||
r.Methods("HEAD", pattern, h)
|
||||
r.Methods("HEAD", pattern, h...)
|
||||
}
|
||||
|
||||
// Post delegate post method
|
||||
func (r *Route) Post(pattern string, h ...any) {
|
||||
r.Methods("POST", pattern, h)
|
||||
r.Methods("POST", pattern, h...)
|
||||
}
|
||||
|
||||
// Put delegate put method
|
||||
func (r *Route) Put(pattern string, h ...any) {
|
||||
r.Methods("PUT", pattern, h)
|
||||
r.Methods("PUT", pattern, h...)
|
||||
}
|
||||
|
||||
// Patch delegate patch method
|
||||
func (r *Route) Patch(pattern string, h ...any) {
|
||||
r.Methods("PATCH", pattern, h)
|
||||
r.Methods("PATCH", pattern, h...)
|
||||
}
|
||||
|
||||
// ServeHTTP implements http.Handler
|
||||
|
|
|
@ -3328,6 +3328,8 @@ pub.install = To install the package using Dart, run the following command:
|
|||
pypi.requires = Requires Python
|
||||
pypi.install = To install the package using pip, run the following command:
|
||||
rpm.registry = Setup this registry from the command line:
|
||||
rpm.distros.redhat = on RedHat based distributions
|
||||
rpm.distros.suse = on SUSE based distributions
|
||||
rpm.install = To install the package, run the following command:
|
||||
rubygems.install = To install the package using gem, run the following command:
|
||||
rubygems.install2 = or add it to the Gemfile:
|
||||
|
|
|
@ -634,7 +634,7 @@ func ContainerRoutes() *web.Route {
|
|||
)
|
||||
|
||||
// Manual mapping of routes because {image} can contain slashes which chi does not support
|
||||
r.RouteMethods("/*", "HEAD,GET,POST,PUT,PATCH,DELETE", func(ctx *context.Context) {
|
||||
r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "/*", func(ctx *context.Context) {
|
||||
path := ctx.Params("*")
|
||||
isHead := ctx.Req.Method == "HEAD"
|
||||
isGet := ctx.Req.Method == "GET"
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
func Routes() *web.Route {
|
||||
base := web.NewRoute()
|
||||
base.Use(common.ProtocolMiddlewares()...)
|
||||
base.RouteMethods("/assets/*", "GET, HEAD", public.AssetsHandlerFunc("/assets/"))
|
||||
base.Methods("GET, HEAD", "/assets/*", public.AssetsHandlerFunc("/assets/"))
|
||||
|
||||
r := web.NewRoute()
|
||||
r.Use(common.Sessioner(), Contexter())
|
||||
|
|
|
@ -3503,8 +3503,15 @@ type userSearchResponse struct {
|
|||
|
||||
// IssuePosters get posters for current repo's issues/pull requests
|
||||
func IssuePosters(ctx *context.Context) {
|
||||
issuePosters(ctx, false)
|
||||
}
|
||||
|
||||
func PullPosters(ctx *context.Context) {
|
||||
issuePosters(ctx, true)
|
||||
}
|
||||
|
||||
func issuePosters(ctx *context.Context, isPullList bool) {
|
||||
repo := ctx.Repo.Repository
|
||||
isPullList := ctx.Params(":type") == "pulls"
|
||||
search := strings.TrimSpace(ctx.FormString("q"))
|
||||
posters, err := repo_model.GetIssuePostersWithSearch(ctx, repo, isPullList, search, setting.UI.DefaultShowFullName)
|
||||
if err != nil {
|
||||
|
|
|
@ -108,12 +108,12 @@ func Routes() *web.Route {
|
|||
routes := web.NewRoute()
|
||||
|
||||
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
|
||||
routes.RouteMethods("/assets/*", "GET, HEAD", CorsHandler(), public.AssetsHandlerFunc("/assets/"))
|
||||
routes.RouteMethods("/avatars/*", "GET, HEAD", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.RouteMethods("/repo-avatars/*", "GET, HEAD", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
routes.RouteMethods("/apple-touch-icon.png", "GET, HEAD", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.RouteMethods("/apple-touch-icon-precomposed.png", "GET, HEAD", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.RouteMethods("/favicon.ico", "GET, HEAD", misc.StaticRedirect("/assets/img/favicon.png"))
|
||||
routes.Methods("GET, HEAD", "/assets/*", CorsHandler(), public.AssetsHandlerFunc("/assets/"))
|
||||
routes.Methods("GET, HEAD", "/avatars/*", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.Methods("GET, HEAD", "/repo-avatars/*", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.Methods("GET, HEAD", "/apple-touch-icon-precomposed.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.Methods("GET, HEAD", "/favicon.ico", misc.StaticRedirect("/assets/img/favicon.png"))
|
||||
|
||||
_ = templates.HTMLRenderer()
|
||||
|
||||
|
@ -129,7 +129,7 @@ func Routes() *web.Route {
|
|||
|
||||
if setting.Service.EnableCaptcha {
|
||||
// The captcha http.Handler should only fire on /captcha/* so we can just mount this on that url
|
||||
routes.RouteMethods("/captcha/*", "GET,HEAD", append(mid, captcha.Captchaer(context.GetImageCaptcha()))...)
|
||||
routes.Methods("GET,HEAD", "/captcha/*", append(mid, captcha.Captchaer(context.GetImageCaptcha()))...)
|
||||
}
|
||||
|
||||
if setting.HasRobotsTxt {
|
||||
|
@ -773,7 +773,7 @@ func registerRoutes(m *web.Route) {
|
|||
addSettingVariablesRoutes()
|
||||
}, actions.MustEnableActions)
|
||||
|
||||
m.RouteMethods("/delete", "GET,POST", org.SettingsDelete)
|
||||
m.Methods("GET,POST", "/delete", org.SettingsDelete)
|
||||
|
||||
m.Group("/packages", func() {
|
||||
m.Get("", org.Packages)
|
||||
|
@ -1151,10 +1151,8 @@ func registerRoutes(m *web.Route) {
|
|||
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Group("", func() {
|
||||
m.Group("/{type:issues|pulls}", func() {
|
||||
m.Get("", repo.Issues)
|
||||
m.Get("/posters", repo.IssuePosters)
|
||||
})
|
||||
m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because other routes like "/pulls/{index}" has higher priority
|
||||
m.Get("/{type:issues|pulls}", repo.Issues)
|
||||
m.Get("/{type:issues|pulls}/{index}", repo.ViewIssue)
|
||||
m.Group("/{type:issues|pulls}/{index}/content-history", func() {
|
||||
m.Get("/overview", repo.GetContentHistoryOverview)
|
||||
|
@ -1276,6 +1274,7 @@ func registerRoutes(m *web.Route) {
|
|||
return cancel
|
||||
})
|
||||
|
||||
m.Get("/pulls/posters", repo.PullPosters)
|
||||
m.Group("/pulls/{index}", func() {
|
||||
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||
m.Get(".diff", repo.DownloadPullDiff)
|
||||
|
|
|
@ -106,6 +106,10 @@ func WebfingerQuery(ctx *context.Context) {
|
|||
Type: "application/activity+json",
|
||||
Href: appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
|
||||
},
|
||||
{
|
||||
Rel: "http://openid.net/specs/connect/1.0/issuer",
|
||||
Href: appURL.String(),
|
||||
},
|
||||
}
|
||||
|
||||
ctx.Resp.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
|
|
|
@ -196,10 +196,11 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
|
|||
}
|
||||
|
||||
affectedFileList := make([]*api.CommitAffectedFiles, 0, len(fileStatus.Added)+len(fileStatus.Removed)+len(fileStatus.Modified))
|
||||
for _, files := range [][]string{fileStatus.Added, fileStatus.Removed, fileStatus.Modified} {
|
||||
for filestatus, files := range map[string][]string{"added": fileStatus.Added, "removed": fileStatus.Removed, "modified": fileStatus.Modified} {
|
||||
for _, filename := range files {
|
||||
affectedFileList = append(affectedFileList, &api.CommitAffectedFiles{
|
||||
Filename: filename,
|
||||
Status: filestatus,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -309,6 +309,17 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
|
|||
if err := issues_model.MarkReviewsAsStale(pr.IssueID); err != nil {
|
||||
log.Error("MarkReviewsAsStale: %v", err)
|
||||
}
|
||||
|
||||
// dismiss all approval reviews if protected branch rule item enabled.
|
||||
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
|
||||
if err != nil {
|
||||
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
|
||||
}
|
||||
if pb != nil && pb.DismissStaleApprovals {
|
||||
if err := DismissApprovalReviews(ctx, doer, pr); err != nil {
|
||||
log.Error("DismissApprovalReviews: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := issues_model.MarkReviewsAsNotStale(pr.IssueID, newCommitID); err != nil {
|
||||
log.Error("MarkReviewsAsNotStale: %v", err)
|
||||
|
|
|
@ -316,6 +316,52 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos
|
|||
return review, comm, nil
|
||||
}
|
||||
|
||||
// DismissApprovalReviews dismiss all approval reviews because of new commits
|
||||
func DismissApprovalReviews(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest) error {
|
||||
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
ListAll: true,
|
||||
},
|
||||
IssueID: pull.IssueID,
|
||||
Type: issues_model.ReviewTypeApprove,
|
||||
Dismissed: util.OptionalBoolFalse,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := reviews.LoadIssues(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.WithTx(ctx, func(subCtx context.Context) error {
|
||||
for _, review := range reviews {
|
||||
if err := issues_model.DismissReview(subCtx, review, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
comment, err := issue_service.CreateComment(ctx, &issues_model.CreateCommentOptions{
|
||||
Doer: doer,
|
||||
Content: "New commits pushed, approval review dismissed automatically according to repository settings",
|
||||
Type: issues_model.CommentTypeDismissReview,
|
||||
ReviewID: review.ID,
|
||||
Issue: review.Issue,
|
||||
Repo: review.Issue.Repo,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
comment.Review = review
|
||||
comment.Poster = doer
|
||||
comment.Issue = review.Issue
|
||||
|
||||
notification.NotifyPullReviewDismiss(ctx, doer, review, comment)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DismissReview dismissing stale review by repo admin
|
||||
func DismissReview(ctx context.Context, reviewID, repoID int64, message string, doer *user_model.User, isDismiss, dismissPriors bool) (comment *issues_model.Comment, err error) {
|
||||
review, err := issues_model.GetReviewByID(ctx, reviewID)
|
||||
|
@ -337,12 +383,12 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
|
|||
return nil, fmt.Errorf("reviews's repository is not the same as the one we expect")
|
||||
}
|
||||
|
||||
if err := issues_model.DismissReview(review, isDismiss); err != nil {
|
||||
if err := issues_model.DismissReview(ctx, review, isDismiss); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dismissPriors {
|
||||
reviews, err := issues_model.GetReviews(ctx, &issues_model.GetReviewOptions{
|
||||
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
|
||||
IssueID: review.IssueID,
|
||||
ReviewerID: review.ReviewerID,
|
||||
Dismissed: util.OptionalBoolFalse,
|
||||
|
@ -351,7 +397,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
|
|||
return nil, err
|
||||
}
|
||||
for _, oldReview := range reviews {
|
||||
if err = issues_model.DismissReview(oldReview, true); err != nil {
|
||||
if err = issues_model.DismissReview(ctx, oldReview, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -361,9 +407,6 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
if err := review.Issue.LoadPullRequest(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := review.Issue.LoadAttributes(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -257,12 +257,12 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
|
|||
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
|
||||
}
|
||||
|
||||
notification.NotifyPushCommits(ctx, pusher, repo, opts, commits)
|
||||
|
||||
if err = git_model.UpdateBranch(ctx, repo.ID, opts.PusherID, branch, newCommit); err != nil {
|
||||
return fmt.Errorf("git_model.UpdateBranch %s:%s failed: %v", repo.FullName(), branch, err)
|
||||
}
|
||||
|
||||
notification.NotifyPushCommits(ctx, pusher, repo, opts, commits)
|
||||
|
||||
// Cache for big repository
|
||||
if err := CacheRef(graceful.GetManager().HammerContext(), repo, gitRepo, opts.RefFullName); err != nil {
|
||||
log.Error("repo_module.CacheRef %s/%s failed: %v", repo.ID, branch, err)
|
||||
|
|
|
@ -4,12 +4,20 @@
|
|||
<div class="ui form">
|
||||
<div class="field">
|
||||
<label>{{svg "octicon-terminal"}} {{.locale.Tr "packages.rpm.registry"}}</label>
|
||||
<div class="markup"><pre class="code-block"><code>dnf config-manager --add-repo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm.repo"></gitea-origin-url></code></pre></div>
|
||||
<div class="markup"><pre class="code-block"><code># {{.locale.Tr "packages.rpm.distro.redhat"}}
|
||||
dnf config-manager --add-repo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm.repo"></gitea-origin-url>
|
||||
|
||||
# {{.locale.Tr "packages.rpm.distro.suse"}}
|
||||
zypper addrepo <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/rpm.repo"></gitea-origin-url></code></pre></div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{svg "octicon-terminal"}} {{.locale.Tr "packages.rpm.install"}}</label>
|
||||
<div class="markup">
|
||||
<pre class="code-block"><code>dnf install {{$.PackageDescriptor.Package.Name}}</code></pre>
|
||||
<pre class="code-block"><code># {{.locale.Tr "packages.rpm.distro.redhat"}}
|
||||
dnf install {{$.PackageDescriptor.Package.Name}}
|
||||
|
||||
# {{.locale.Tr "packages.rpm.distro.suse"}}
|
||||
zypper install {{$.PackageDescriptor.Package.Name}}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
|
|
@ -16399,6 +16399,10 @@
|
|||
"filename": {
|
||||
"type": "string",
|
||||
"x-go-name": "Filename"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"x-go-name": "Status"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
|
@ -19727,7 +19731,11 @@
|
|||
"git",
|
||||
"github",
|
||||
"gitea",
|
||||
"gitlab"
|
||||
"gitlab",
|
||||
"gogs",
|
||||
"onedev",
|
||||
"gitbucket",
|
||||
"codebase"
|
||||
],
|
||||
"x-go-name": "Service"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue