mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-10 15:32:55 +09:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
918d3d96ff | ||
|
|
92c91d7d8b | ||
|
|
9dc76b2036 | ||
|
|
802a4314ef | ||
|
|
edd4ab49c8 | ||
|
|
55e6cde7c1 | ||
|
|
729fa06468 | ||
|
|
b228a0aa44 | ||
|
|
9e7e11224f | ||
|
|
85880b2a0b | ||
|
|
211bb911e3 | ||
|
|
0554d1dd01 | ||
|
|
00e55dd223 | ||
|
|
b28c3245cc | ||
|
|
ddfb729168 | ||
|
|
6ef62e3f8e | ||
|
|
2c4f1ed13e | ||
|
|
fa3fe1e28a | ||
|
|
62f5cf4386 | ||
|
|
779d1185e7 | ||
|
|
f3d0c76afc | ||
|
|
5a4729d5e2 | ||
|
|
88a7349375 | ||
|
|
c3398906a1 | ||
|
|
330fa75945 |
30
CHANGELOG.md
30
CHANGELOG.md
@@ -4,6 +4,36 @@ This changelog goes through all the changes that have been made in each release
|
|||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
|
|
||||||
|
## [1.14.1](https://github.com/go-gitea/gitea/releases/tag/v1.14.1) - 2021-04-15
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix bug clone wiki (#15499) (#15502)
|
||||||
|
* Github Migration ignore rate limit, if not enabled (#15490) (#15495)
|
||||||
|
* Use subdir for URL (#15446) (#15493)
|
||||||
|
* Query the DB for the hash before inserting in to email_hash (#15457) (#15491)
|
||||||
|
* Ensure review dismissal only dismisses the correct review (#15477) (#15489)
|
||||||
|
* Use index of the supported tags to choose user lang (#15452) (#15488)
|
||||||
|
* Fix wrong file link in code search page (#15466) (#15486)
|
||||||
|
* Quick template fix for built-in SSH server in admin config (#15464) (#15481)
|
||||||
|
* Prevent superfluous response.WriteHeader (#15456) (#15476)
|
||||||
|
* Fix ambiguous argument error on tags (#15432) (#15474)
|
||||||
|
* Add created_unix instead of expiry to migration (#15458) (#15463)
|
||||||
|
* Fix repository search (#15428) (#15442)
|
||||||
|
* Prevent NPE on avatar direct rendering if federated avatars disabled (#15434) (#15439)
|
||||||
|
* Fix wiki clone urls (#15430) (#15431)
|
||||||
|
* Fix dingtalk icon url at webhook (#15417) (#15426)
|
||||||
|
* Standardise icon on projects PR page (#15387) (#15408)
|
||||||
|
* ENHANCEMENTS
|
||||||
|
* Add option to skip LFS/attachment files for `dump` (#15407) (#15492)
|
||||||
|
* Clone panel fixes (#15436)
|
||||||
|
* Use semantic dropdown for code search query type (#15276) (#15364)
|
||||||
|
* BUILD
|
||||||
|
* Build go-git variants for windows (#15482) (#15487)
|
||||||
|
* Lock down build-images dependencies (Partial #15479) (#15480)
|
||||||
|
* MISC
|
||||||
|
* Performance improvement for list pull requests (#15447) (#15500)
|
||||||
|
* Fix potential copy lfs records failure when fork a repository (#15441) (#15485)
|
||||||
|
|
||||||
## [1.14.0](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-04-11
|
## [1.14.0](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-04-11
|
||||||
|
|
||||||
* SECURITY
|
* SECURITY
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -577,6 +577,9 @@ release-windows: | $(DIST_DIRS)
|
|||||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||||
fi
|
fi
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||||
|
ifeq (,$(findstring gogit,$(TAGS)))
|
||||||
|
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||||
|
endif
|
||||||
ifeq ($(CI),drone)
|
ifeq ($(CI),drone)
|
||||||
cp /build/* $(DIST)/binaries
|
cp /build/* $(DIST)/binaries
|
||||||
endif
|
endif
|
||||||
@@ -699,8 +702,8 @@ generate-gitignore:
|
|||||||
GO111MODULE=on $(GO) run build/generate-gitignores.go
|
GO111MODULE=on $(GO) run build/generate-gitignores.go
|
||||||
|
|
||||||
.PHONY: generate-images
|
.PHONY: generate-images
|
||||||
generate-images:
|
generate-images: | node_modules
|
||||||
npm install --no-save --no-package-lock fabric imagemin-zopfli
|
npm install --no-save --no-package-lock fabric@4 imagemin-zopfli@7
|
||||||
node build/generate-images.js $(TAGS)
|
node build/generate-images.js $(TAGS)
|
||||||
|
|
||||||
.PHONY: generate-manpage
|
.PHONY: generate-manpage
|
||||||
|
|||||||
16
cmd/dump.go
16
cmd/dump.go
@@ -129,6 +129,14 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
|
|||||||
Name: "skip-custom-dir",
|
Name: "skip-custom-dir",
|
||||||
Usage: "Skip custom directory",
|
Usage: "Skip custom directory",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "skip-lfs-data",
|
||||||
|
Usage: "Skip LFS data",
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "skip-attachment-data",
|
||||||
|
Usage: "Skip attachment data",
|
||||||
|
},
|
||||||
cli.GenericFlag{
|
cli.GenericFlag{
|
||||||
Name: "type",
|
Name: "type",
|
||||||
Value: outputTypeEnum,
|
Value: outputTypeEnum,
|
||||||
@@ -214,7 +222,9 @@ func runDump(ctx *cli.Context) error {
|
|||||||
fatal("Failed to include repositories: %v", err)
|
fatal("Failed to include repositories: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
|
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") {
|
||||||
|
log.Info("Skip dumping LFS data")
|
||||||
|
} else if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
|
||||||
info, err := object.Stat()
|
info, err := object.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -313,7 +323,9 @@ func runDump(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
|
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") {
|
||||||
|
log.Info("Skip dumping attachment data")
|
||||||
|
} else if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
|
||||||
info, err := object.Stat()
|
info, err := object.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ func HashedAvatarLink(email string) string {
|
|||||||
// we don't care about any DB problem just return the lowerEmail
|
// we don't care about any DB problem just return the lowerEmail
|
||||||
return lowerEmail, nil
|
return lowerEmail, nil
|
||||||
}
|
}
|
||||||
|
has, err := sess.Where("email = ? AND hash = ?", emailHash.Email, emailHash.Hash).Get(new(EmailHash))
|
||||||
|
if has || err != nil {
|
||||||
|
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
||||||
|
return lowerEmail, nil
|
||||||
|
}
|
||||||
_, _ = sess.Insert(emailHash)
|
_, _ = sess.Insert(emailHash)
|
||||||
if err := sess.Commit(); err != nil {
|
if err := sess.Commit(); err != nil {
|
||||||
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) {
|
|||||||
|
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
issue.Repo = repoMaps[issue.RepoID]
|
issue.Repo = repoMaps[issue.RepoID]
|
||||||
|
if issue.PullRequest != nil {
|
||||||
|
issue.PullRequest.BaseRepo = issue.Repo
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return valuesRepository(repoMaps), nil
|
return valuesRepository(repoMaps), nil
|
||||||
}
|
}
|
||||||
@@ -516,6 +519,11 @@ func (issues IssueList) LoadDiscussComments() error {
|
|||||||
return issues.loadComments(x, builder.Eq{"comment.type": CommentTypeComment})
|
return issues.loadComments(x, builder.Eq{"comment.type": CommentTypeComment})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPullRequests loads pull requests
|
||||||
|
func (issues IssueList) LoadPullRequests() error {
|
||||||
|
return issues.loadPullRequests(x)
|
||||||
|
}
|
||||||
|
|
||||||
// GetApprovalCounts returns a map of issue ID to slice of approval counts
|
// GetApprovalCounts returns a map of issue ID to slice of approval counts
|
||||||
// FIXME: only returns official counts due to double counting of non-official approvals
|
// FIXME: only returns official counts due to double counting of non-official approvals
|
||||||
func (issues IssueList) GetApprovalCounts() (map[int64][]*ReviewCount, error) {
|
func (issues IssueList) GetApprovalCounts() (map[int64][]*ReviewCount, error) {
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
|
|
||||||
func addSessionTable(x *xorm.Engine) error {
|
func addSessionTable(x *xorm.Engine) error {
|
||||||
type Session struct {
|
type Session struct {
|
||||||
Key string `xorm:"pk CHAR(16)"`
|
Key string `xorm:"pk CHAR(16)"`
|
||||||
Data []byte `xorm:"BLOB"`
|
Data []byte `xorm:"BLOB"`
|
||||||
CreatedUnix timeutil.TimeStamp
|
Expiry timeutil.TimeStamp
|
||||||
}
|
}
|
||||||
return x.Sync2(new(Session))
|
return x.Sync2(new(Session))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -566,7 +566,11 @@ func DismissReview(review *Review, isDismiss bool) (err error) {
|
|||||||
|
|
||||||
review.Dismissed = isDismiss
|
review.Dismissed = isDismiss
|
||||||
|
|
||||||
_, err = x.Cols("dismissed").Update(review)
|
if review.ID == 0 {
|
||||||
|
return ErrReviewNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = x.ID(review.ID).Cols("dismissed").Update(review)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,11 +143,57 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDismissReview(t *testing.T) {
|
func TestDismissReview(t *testing.T) {
|
||||||
review1 := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
review2 := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
|
||||||
assert.NoError(t, DismissReview(review1, true))
|
rejectReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||||
assert.NoError(t, DismissReview(review2, true))
|
requestReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||||
assert.NoError(t, DismissReview(review2, true))
|
approveReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 8}).(*Review)
|
||||||
assert.NoError(t, DismissReview(review2, false))
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
assert.NoError(t, DismissReview(review2, false))
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(rejectReviewExample, true))
|
||||||
|
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||||
|
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||||
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(requestReviewExample, true))
|
||||||
|
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||||
|
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||||
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(requestReviewExample, true))
|
||||||
|
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||||
|
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||||
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(requestReviewExample, false))
|
||||||
|
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||||
|
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||||
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(requestReviewExample, false))
|
||||||
|
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||||
|
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||||
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(rejectReviewExample, false))
|
||||||
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
|
assert.NoError(t, DismissReview(approveReviewExample, true))
|
||||||
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
assert.True(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
package context
|
package context
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
// ResponseWriter represents a response writer for HTTP
|
// ResponseWriter represents a response writer for HTTP
|
||||||
type ResponseWriter interface {
|
type ResponseWriter interface {
|
||||||
@@ -60,8 +62,10 @@ func (r *Response) WriteHeader(statusCode int) {
|
|||||||
}
|
}
|
||||||
r.beforeExecuted = true
|
r.beforeExecuted = true
|
||||||
}
|
}
|
||||||
r.status = statusCode
|
if r.status == 0 {
|
||||||
r.ResponseWriter.WriteHeader(statusCode)
|
r.status = statusCode
|
||||||
|
r.ResponseWriter.WriteHeader(statusCode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush flush cached data
|
// Flush flush cached data
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package git
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -14,32 +15,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBlob_Data(t *testing.T) {
|
func TestBlob_Data(t *testing.T) {
|
||||||
output := `Copyright (c) 2016 The Gitea Authors
|
output := "file2\n"
|
||||||
Copyright (c) 2015 The Gogs Authors
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||||
|
repo, err := OpenRepository(bareRepo1Path)
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
if !assert.NoError(t, err) {
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
t.Fatal()
|
||||||
in the Software without restriction, including without limitation the rights
|
}
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
`
|
|
||||||
repo, err := OpenRepository("../../.git")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
defer repo.Close()
|
defer repo.Close()
|
||||||
|
|
||||||
testBlob, err := repo.GetBlob("a8d4b49dd073a4a38a7e58385eeff7cc52568697")
|
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
r, err := testBlob.DataAsync()
|
r, err := testBlob.DataAsync()
|
||||||
@@ -53,13 +37,14 @@ THE SOFTWARE.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_Blob_Data(b *testing.B) {
|
func Benchmark_Blob_Data(b *testing.B) {
|
||||||
repo, err := OpenRepository("../../.git")
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||||
|
repo, err := OpenRepository(bareRepo1Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
defer repo.Close()
|
defer repo.Close()
|
||||||
|
|
||||||
testBlob, err := repo.GetBlob("a8d4b49dd073a4a38a7e58385eeff7cc52568697")
|
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,14 +21,7 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) {
|
|||||||
|
|
||||||
// GetTagCommitID returns last commit ID string of given tag.
|
// GetTagCommitID returns last commit ID string of given tag.
|
||||||
func (repo *Repository) GetTagCommitID(name string) (string, error) {
|
func (repo *Repository) GetTagCommitID(name string) (string, error) {
|
||||||
stdout, err := NewCommand("rev-list", "-n", "1", TagPrefix+name).RunInDir(repo.Path)
|
return repo.GetRefCommitID(TagPrefix + name)
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "unknown revision or path") {
|
|
||||||
return "", ErrNotExist{name, ""}
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(stdout), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertToSHA1 returns a Hash object from a potential ID string
|
// ConvertToSHA1 returns a Hash object from a potential ID string
|
||||||
|
|||||||
@@ -132,6 +132,11 @@ func (g *GithubDownloaderV3) sleep() {
|
|||||||
func (g *GithubDownloaderV3) RefreshRate() error {
|
func (g *GithubDownloaderV3) RefreshRate() error {
|
||||||
rates, _, err := g.client.RateLimits(g.ctx)
|
rates, _, err := g.client.RateLimits(g.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// if rate limit is not enabled, ignore it
|
||||||
|
if strings.Contains(err.Error(), "404") {
|
||||||
|
g.rate = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy lfs files failure should not be ignored
|
||||||
|
if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
|
||||||
|
rollbackRemoveFn()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
repoPath := models.RepoPath(owner.Name, repo.Name)
|
repoPath := models.RepoPath(owner.Name, repo.Name)
|
||||||
if stdout, err := git.NewCommand(
|
if stdout, err := git.NewCommand(
|
||||||
"clone", "--bare", oldRepoPath, repoPath).
|
"clone", "--bare", oldRepoPath, repoPath).
|
||||||
@@ -92,6 +98,7 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// even if below operations failed, it could be ignored. And they will be retried
|
||||||
ctx := models.DefaultDBContext()
|
ctx := models.DefaultDBContext()
|
||||||
if err = repo.UpdateSize(ctx); err != nil {
|
if err = repo.UpdateSize(ctx); err != nil {
|
||||||
log.Error("Failed to update size for repository: %v", err)
|
log.Error("Failed to update size for repository: %v", err)
|
||||||
@@ -100,11 +107,5 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
|
|||||||
log.Error("Copy language stat from oldRepo failed")
|
log.Error("Copy language stat from oldRepo failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
|
|
||||||
if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
|
|
||||||
log.Error("Rollback deleteRepository: %v", errDelete)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return repo, nil
|
return repo, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,9 @@ type LangType struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
matcher language.Matcher
|
matcher language.Matcher
|
||||||
allLangs []LangType
|
allLangs []LangType
|
||||||
|
supportedTags []language.Tag
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllLangs returns all supported langauages
|
// AllLangs returns all supported langauages
|
||||||
@@ -51,12 +52,12 @@ func InitLocales() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := make([]language.Tag, len(setting.Langs))
|
supportedTags = make([]language.Tag, len(setting.Langs))
|
||||||
for i, lang := range setting.Langs {
|
for i, lang := range setting.Langs {
|
||||||
tags[i] = language.Raw.Make(lang)
|
supportedTags[i] = language.Raw.Make(lang)
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher = language.NewMatcher(tags)
|
matcher = language.NewMatcher(supportedTags)
|
||||||
for i := range setting.Names {
|
for i := range setting.Names {
|
||||||
key := "locale_" + setting.Langs[i] + ".ini"
|
key := "locale_" + setting.Langs[i] + ".ini"
|
||||||
if err = i18n.SetMessageWithDesc(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
|
if err = i18n.SetMessageWithDesc(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
|
||||||
@@ -79,8 +80,9 @@ func InitLocales() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Match matches accept languages
|
// Match matches accept languages
|
||||||
func Match(tags ...language.Tag) (tag language.Tag, index int, c language.Confidence) {
|
func Match(tags ...language.Tag) language.Tag {
|
||||||
return matcher.Match(tags...)
|
_, i, _ := matcher.Match(tags...)
|
||||||
|
return supportedTags[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// locale represents the information of localization.
|
// locale represents the information of localization.
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale {
|
|||||||
// The first element in the list is chosen to be the default language automatically.
|
// The first element in the list is chosen to be the default language automatically.
|
||||||
if len(lang) == 0 {
|
if len(lang) == 0 {
|
||||||
tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
|
tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
|
||||||
tag, _, _ := translation.Match(tags...)
|
tag := translation.Match(tags...)
|
||||||
lang = tag.String()
|
lang = tag.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,9 +103,11 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
|||||||
|
|
||||||
isWiki := false
|
isWiki := false
|
||||||
var unitType = models.UnitTypeCode
|
var unitType = models.UnitTypeCode
|
||||||
|
var wikiRepoName string
|
||||||
if strings.HasSuffix(reponame, ".wiki") {
|
if strings.HasSuffix(reponame, ".wiki") {
|
||||||
isWiki = true
|
isWiki = true
|
||||||
unitType = models.UnitTypeWiki
|
unitType = models.UnitTypeWiki
|
||||||
|
wikiRepoName = reponame
|
||||||
reponame = reponame[:len(reponame)-5]
|
reponame = reponame[:len(reponame)-5]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +316,11 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isWiki { // you cannot send wiki operation before create the repository
|
||||||
|
ctx.HandleText(http.StatusNotFound, "Repository not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
|
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
|
||||||
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
|
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
|
||||||
return
|
return
|
||||||
@@ -363,6 +370,9 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
|||||||
r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name
|
r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name
|
||||||
|
|
||||||
dir := models.RepoPath(username, reponame)
|
dir := models.RepoPath(username, reponame)
|
||||||
|
if isWiki {
|
||||||
|
dir = models.RepoPath(username, wikiRepoName)
|
||||||
|
}
|
||||||
|
|
||||||
return &serviceHandler{cfg, w, r, dir, cfg.Env}
|
return &serviceHandler{cfg, w, r, dir, cfg.Env}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,14 +241,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
approvalCounts, err := models.IssueList(issues).GetApprovalCounts()
|
var issueList = models.IssueList(issues)
|
||||||
|
approvalCounts, err := issueList.GetApprovalCounts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ApprovalCounts", err)
|
ctx.ServerError("ApprovalCounts", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var commitStatus = make(map[int64]*models.CommitStatus, len(issues))
|
|
||||||
|
|
||||||
// Get posters.
|
// Get posters.
|
||||||
for i := range issues {
|
for i := range issues {
|
||||||
// Check read status
|
// Check read status
|
||||||
@@ -258,16 +257,12 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||||||
ctx.ServerError("GetIsRead", err)
|
ctx.ServerError("GetIsRead", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if issues[i].IsPull {
|
commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues)
|
||||||
if err := issues[i].LoadPullRequest(); err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("LoadPullRequest", err)
|
ctx.ServerError("GetIssuesLastCommitStatus", err)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
var statuses, _ = pull_service.GetLastCommitStatus(issues[i].PullRequest)
|
|
||||||
commitStatus[issues[i].PullRequest.ID] = models.CalcCommitStatus(statuses)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Issues"] = issues
|
ctx.Data["Issues"] = issues
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
@@ -40,7 +39,7 @@ func Search(ctx *context.Context) {
|
|||||||
ctx.Data["Keyword"] = keyword
|
ctx.Data["Keyword"] = keyword
|
||||||
ctx.Data["Language"] = language
|
ctx.Data["Language"] = language
|
||||||
ctx.Data["queryType"] = queryType
|
ctx.Data["queryType"] = queryType
|
||||||
ctx.Data["SourcePath"] = path.Join(setting.AppSubURL, ctx.Repo.Repository.Owner.Name, ctx.Repo.Repository.Name)
|
ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL()
|
||||||
ctx.Data["SearchResults"] = searchResults
|
ctx.Data["SearchResults"] = searchResults
|
||||||
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
||||||
ctx.Data["RequireHighlightJS"] = true
|
ctx.Data["RequireHighlightJS"] = true
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ package user
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Avatar redirect browser to user avatar of requested size
|
// Avatar redirect browser to user avatar of requested size
|
||||||
@@ -70,8 +72,21 @@ func AvatarByEmailHash(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var avatarURL *url.URL
|
var avatarURL *url.URL
|
||||||
avatarURL, err = models.LibravatarURL(email)
|
|
||||||
if err != nil {
|
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
|
||||||
|
avatarURL, err = models.LibravatarURL(email)
|
||||||
|
if err != nil {
|
||||||
|
avatarURL, err = url.Parse(models.DefaultAvatarLink())
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("invalid default avatar url", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if !setting.DisableGravatar {
|
||||||
|
copyOfGravatarSourceURL := *setting.GravatarSourceURL
|
||||||
|
avatarURL = ©OfGravatarSourceURL
|
||||||
|
avatarURL.Path = path.Join(avatarURL.Path, hash)
|
||||||
|
} else {
|
||||||
avatarURL, err = url.Parse(models.DefaultAvatarLink())
|
avatarURL, err = url.Parse(models.DefaultAvatarLink())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("invalid default avatar url", err)
|
ctx.ServerError("invalid default avatar url", err)
|
||||||
|
|||||||
@@ -546,14 +546,14 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// maps pull request IDs to their CommitStatus. Will be posted to ctx.Data.
|
// maps pull request IDs to their CommitStatus. Will be posted to ctx.Data.
|
||||||
var commitStatus = make(map[int64]*models.CommitStatus, len(issues))
|
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
issue.Repo = showReposMap[issue.RepoID]
|
issue.Repo = showReposMap[issue.RepoID]
|
||||||
|
}
|
||||||
|
|
||||||
if isPullList {
|
commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues)
|
||||||
var statuses, _ = pull_service.GetLastCommitStatus(issue.PullRequest)
|
if err != nil {
|
||||||
commitStatus[issue.PullRequest.ID] = models.CalcCommitStatus(statuses)
|
ctx.ServerError("GetIssuesLastCommitStatus", err)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -643,33 +642,74 @@ func GetSquashMergeCommitMessages(pr *models.PullRequest) string {
|
|||||||
return stringBuilder.String()
|
return stringBuilder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLastCommitStatus returns list of commit statuses for latest commit on this pull request.
|
// GetIssuesLastCommitStatus returns a map
|
||||||
func GetLastCommitStatus(pr *models.PullRequest) (status []*models.CommitStatus, err error) {
|
func GetIssuesLastCommitStatus(issues models.IssueList) (map[int64]*models.CommitStatus, error) {
|
||||||
if err = pr.LoadBaseRepo(); err != nil {
|
if err := issues.LoadPullRequests(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := issues.LoadRepositories(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
gitRepos = make(map[int64]*git.Repository)
|
||||||
|
res = make(map[int64]*models.CommitStatus)
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
defer func() {
|
||||||
|
for _, gitRepo := range gitRepos {
|
||||||
|
gitRepo.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, issue := range issues {
|
||||||
|
if !issue.IsPull {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gitRepo, ok := gitRepos[issue.RepoID]
|
||||||
|
if !ok {
|
||||||
|
gitRepo, err = git.OpenRepository(issue.Repo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gitRepos[issue.RepoID] = gitRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := getLastCommitStatus(gitRepo, issue.PullRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res[issue.PullRequest.ID] = status
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLastCommitStatus returns list of commit statuses for latest commit on this pull request.
|
||||||
|
func GetLastCommitStatus(pr *models.PullRequest) (status *models.CommitStatus, err error) {
|
||||||
|
if err = pr.LoadBaseRepo(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer gitRepo.Close()
|
defer gitRepo.Close()
|
||||||
|
|
||||||
compareInfo, err := gitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName())
|
return getLastCommitStatus(gitRepo, pr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLastCommitStatus get pr's last commit status. PR's last commit status is the head commit id's last commit status
|
||||||
|
func getLastCommitStatus(gitRepo *git.Repository, pr *models.PullRequest) (status *models.CommitStatus, err error) {
|
||||||
|
sha, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if compareInfo.Commits.Len() == 0 {
|
|
||||||
return nil, errors.New("pull request has no commits")
|
|
||||||
}
|
|
||||||
|
|
||||||
sha := compareInfo.Commits.Front().Value.(*git.Commit).ID.String()
|
|
||||||
statusList, err := models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, models.ListOptions{})
|
statusList, err := models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, models.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return statusList, nil
|
return models.CalcCommitStatus(statusList), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head
|
// IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
<dd>{{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
<dd>{{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||||
{{if not .SSH.Disabled}}
|
{{if not .SSH.Disabled}}
|
||||||
<dt>{{.i18n.Tr "admin.config.ssh_start_builtin_server"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.ssh_start_builtin_server"}}</dt>
|
||||||
<dd>{{if not .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
<dd>{{if .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.ssh_domain"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.ssh_domain"}}</dt>
|
||||||
<dd>{{.SSH.Domain}}</dd>
|
<dd>{{.SSH.Domain}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.ssh_port"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.ssh_port"}}</dt>
|
||||||
|
|||||||
@@ -3,29 +3,27 @@
|
|||||||
{{template "explore/navbar" .}}
|
{{template "explore/navbar" .}}
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
<form class="ui form ignore-dirty" style="max-width: 100%">
|
<form class="ui form ignore-dirty" style="max-width: 100%">
|
||||||
<input type="hidden" name="tab" value="{{$.TabName}}">
|
<input type="hidden" name="tab" value="{{$.TabName}}">
|
||||||
<div class="ui fluid action input">
|
<div class="ui fluid action input">
|
||||||
<div class="twelve wide field">
|
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
||||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
<div class="ui dropdown selection">
|
||||||
</div>
|
<input name="t" type="hidden" value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="two wide field mx-2">
|
<div class="text">{{.i18n.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
|
||||||
<select name="t">
|
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
|
||||||
<option value="">{{.i18n.Tr "explore.search.fuzzy"}}</option>
|
<div class="item" data-value="">{{.i18n.Tr "explore.search.fuzzy"}}</div>
|
||||||
<option value="match" {{if eq .queryType "match"}}selected{{end}}>{{.i18n.Tr "explore.search.match"}}</option>
|
<div class="item" data-value="match">{{.i18n.Tr "explore.search.match"}}</div>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="three field">
|
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
|
||||||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
<div class="ui divider"></div>
|
||||||
</form>
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
|
|
||||||
<div class="ui user list">
|
<div class="ui user list">
|
||||||
{{if .SearchResults}}
|
{{if .SearchResults}}
|
||||||
<h3>
|
<h3>
|
||||||
{{.i18n.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
|
{{.i18n.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="df ac fw">
|
<div class="df ac fw">
|
||||||
{{range $term := .SearchResultLanguages}}
|
{{range $term := .SearchResultLanguages}}
|
||||||
<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}/explore/code?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
|
<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}/explore/code?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
|
||||||
@@ -35,34 +33,34 @@
|
|||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="repository search">
|
<div class="repository search">
|
||||||
{{range $result := .SearchResults}}
|
{{range $result := .SearchResults}}
|
||||||
{{$repo := (index $.RepoMaps .RepoID)}}
|
{{$repo := (index $.RepoMaps .RepoID)}}
|
||||||
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
|
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
|
||||||
<h4 class="ui top attached normal header">
|
<h4 class="ui top attached normal header">
|
||||||
<span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span>
|
<span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span>
|
||||||
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached table segment">
|
<div class="ui attached table segment">
|
||||||
<div class="file-body file-code code-view">
|
<div class="file-body file-code code-view">
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="lines-num">
|
<td class="lines-num">
|
||||||
{{range .LineNumbers}}
|
{{range .LineNumbers}}
|
||||||
<a href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
|
<a href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td class="lines-code"><pre><code class="chroma"><ol class="linenums">{{.FormattedLines | Safe}}</ol></code></pre></td>
|
<td class="lines-code"><pre><code class="chroma"><ol class="linenums">{{.FormattedLines | Safe}}</ol></code></pre></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "shared/searchbottom" dict "root" $ "result" .}}
|
{{template "shared/searchbottom" dict "root" $ "result" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div>{{$.i18n.Tr "explore.code_no_results"}}</div>
|
<div>{{$.i18n.Tr "explore.code_no_results"}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
{{else if eq .HookType "discord"}}
|
{{else if eq .HookType "discord"}}
|
||||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/discord.png">
|
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/discord.png">
|
||||||
{{else if eq .HookType "dingtalk"}}
|
{{else if eq .HookType "dingtalk"}}
|
||||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/dingtalk.png">
|
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/dingtalk.ico">
|
||||||
{{else if eq .HookType "telegram"}}
|
{{else if eq .HookType "telegram"}}
|
||||||
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/telegram.png">
|
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/telegram.png">
|
||||||
{{else if eq .HookType "msteams"}}
|
{{else if eq .HookType "msteams"}}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{{if not $.DisableHTTP}}
|
{{if not $.DisableHTTP}}
|
||||||
<button class="ui basic clone button no-transition" id="repo-clone-https" data-link="{{.CloneLink.HTTPS}}">
|
<button class="ui basic clone button no-transition" id="repo-clone-https" data-link="{{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}">
|
||||||
{{if UseHTTPS}}HTTPS{{else}}HTTP{{end}}
|
{{if UseHTTPS}}HTTPS{{else}}HTTP{{end}}
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
|
{{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
|
||||||
<button class="ui basic clone button no-transition" id="repo-clone-ssh" data-link="{{.CloneLink.SSH}}">
|
<button class="ui basic clone button no-transition" id="repo-clone-ssh" data-link="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}">
|
||||||
SSH
|
SSH
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not $.DisableHTTP}}
|
{{if not $.DisableHTTP}}
|
||||||
<input id="repo-clone-url" value="{{$.CloneLink.HTTPS}}" readonly>
|
<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}" readonly>
|
||||||
{{else if and (not .DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
|
{{else if and (not .DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
|
||||||
<input id="repo-clone-url" value="{{$.CloneLink.SSH}}" readonly>
|
<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}" readonly>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
|
{{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
|
||||||
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
|
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
|
|
||||||
<p class="ui center">{{.i18n.Tr "repo.new_repo_helper" "/repo/migrate" | Safe}}</p>
|
<p class="ui center">{{.i18n.Tr "repo.new_repo_helper" (printf "%s%s" AppSubUrl "/repo/migrate") | Safe}}</p>
|
||||||
|
|
||||||
{{if not .CanCreateRepo}}
|
{{if not .CanCreateRepo}}
|
||||||
<div class="ui negative message">
|
<div class="ui negative message">
|
||||||
|
|||||||
@@ -110,13 +110,13 @@
|
|||||||
{{if eq $n 0}}
|
{{if eq $n 0}}
|
||||||
<div class="ui action tiny input" id="clone-panel">
|
<div class="ui action tiny input" id="clone-panel">
|
||||||
{{template "repo/clone_buttons" .}}
|
{{template "repo/clone_buttons" .}}
|
||||||
<div class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right">
|
<button id="download-btn" class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right">
|
||||||
{{svg "octicon-download"}}
|
{{svg "octicon-download"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip"}} ZIP</a>
|
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip"}} ZIP</a>
|
||||||
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a>
|
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="three wide column">
|
<div class="three wide column">
|
||||||
{{if $.PageIsOrgSettingsLabels}}
|
{{if $.PageIsOrgSettingsLabels}}
|
||||||
<a class="ui right open-issues" href="/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
<a class="ui right open-issues" href="{{AppSubUrl}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -158,10 +158,23 @@
|
|||||||
<div class="card board-card" data-issue="{{.ID}}">
|
<div class="card board-card" data-issue="{{.ID}}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="{{if .IsClosed}}red{{else}}green{{end}}">
|
<span>
|
||||||
{{if .IsPull}}{{svg "octicon-git-merge"}}
|
{{if .IsPull}}
|
||||||
{{else if .IsClosed}}{{svg "octicon-issue-closed"}}
|
{{if .PullRequest.HasMerged}}
|
||||||
{{else}}{{svg "octicon-issue-opened"}}
|
{{svg "octicon-git-merge" 16 "text purple"}}
|
||||||
|
{{else}}
|
||||||
|
{{if .IsClosed}}
|
||||||
|
{{svg "octicon-git-pull-request" 16 "text red"}}
|
||||||
|
{{else}}
|
||||||
|
{{svg "octicon-git-pull-request" 16 "text green"}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
{{if .IsClosed}}
|
||||||
|
{{svg "octicon-issue-closed" 16 "text red"}}
|
||||||
|
{{else}}
|
||||||
|
{{svg "octicon-issue-opened" 16 "text green"}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
<a class="project-board-title" href="{{$.RepoLink}}/issues/{{.Index}}">#{{.Index}} {{.Title}}</a>
|
<a class="project-board-title" href="{{$.RepoLink}}/issues/{{.Index}}">#{{.Index}} {{.Title}}</a>
|
||||||
|
|||||||
@@ -5,20 +5,16 @@
|
|||||||
<div class="ui repo-search">
|
<div class="ui repo-search">
|
||||||
<form class="ui form ignore-dirty" method="get">
|
<form class="ui form ignore-dirty" method="get">
|
||||||
<div class="ui fluid action input">
|
<div class="ui fluid action input">
|
||||||
<div class="twelve wide field">
|
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}">
|
||||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}">
|
<div class="ui dropdown selection">
|
||||||
</div>
|
<input name="t" type="hidden" value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="two wide field">
|
<div class="text">{{.i18n.Tr (printf "repo.search.%s" (or .queryType "fuzzy"))}}</div>
|
||||||
<select name="t">
|
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
|
||||||
<option value="">{{.i18n.Tr "repo.search.fuzzy"}}</option>
|
<div class="item" data-value="">{{.i18n.Tr "repo.search.fuzzy"}}</div>
|
||||||
<option value="match" {{if eq .queryType "match"}}selected{{end}}>{{.i18n.Tr "repo.search.match"}}</option>
|
<div class="item" data-value="match">{{.i18n.Tr "repo.search.match"}}</div>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="three field">
|
|
||||||
<button class="ui button" type="submit">
|
|
||||||
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button class="ui icon button" type="submit">{{svg "octicon-search" 16}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,12 +62,12 @@
|
|||||||
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}}
|
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and .Milestone (ne $.listType "milestone")}}
|
{{if and .Milestone (ne $.listType "milestone")}}
|
||||||
<a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}>
|
<a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}>
|
||||||
{{svg "octicon-milestone" 14 "mr-2"}}{{.Milestone.Name}}
|
{{svg "octicon-milestone" 14 "mr-2"}}{{.Milestone.Name}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Ref}}
|
{{if .Ref}}
|
||||||
<a class="ref" {{if $.RepoLink}}href="{{$.RepoLink}}{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}>
|
<a class="ref" {{if $.RepoLink}}href="{{$.RepoLink}}{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}>
|
||||||
{{svg "octicon-git-branch" 14 "mr-2"}}{{index $.IssueRefEndNames .ID}}
|
{{svg "octicon-git-branch" 14 "mr-2"}}{{index $.IssueRefEndNames .ID}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if .NeedsPassword}}
|
{{if .NeedsPassword}}
|
||||||
<form class="ui form" action="/user/activate" method="post">
|
<form class="ui form" action="{{AppSubUrl}}/user/activate" method="post">
|
||||||
<div class="required inline field">
|
<div class="required inline field">
|
||||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
<label for="password">{{.i18n.Tr "password"}}</label>
|
||||||
<input id="password" name="password" type="password" autocomplete="off" required>
|
<input id="password" name="password" type="password" autocomplete="off" required>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment repos-search">
|
<div class="ui attached segment repos-search">
|
||||||
<div class="ui fluid right action left icon input" :class="{loading: isLoading}">
|
<div class="ui fluid right action left icon input" :class="{loading: isLoading}">
|
||||||
<input @input="searchRepos(reposFilter)" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
|
<input @input="changeReposFilter(reposFilter)" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
|
||||||
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
|
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
|
||||||
<div class="ui dropdown icon button" title="{{.i18n.Tr "home.filter"}}">
|
<div class="ui dropdown icon button" title="{{.i18n.Tr "home.filter"}}">
|
||||||
<i class="icon df ac jc m-0">{{svg "octicon-filter" 16}}</i>
|
<i class="icon df ac jc m-0">{{svg "octicon-filter" 16}}</i>
|
||||||
|
|||||||
@@ -3109,7 +3109,7 @@ function initVueComponents() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.searchRepos(this.reposFilter);
|
this.changeReposFilter(this.reposFilter);
|
||||||
$(this.$el).find('.poping.up').popup();
|
$(this.$el).find('.poping.up').popup();
|
||||||
$(this.$el).find('.dropdown').dropdown();
|
$(this.$el).find('.dropdown').dropdown();
|
||||||
this.setCheckboxes();
|
this.setCheckboxes();
|
||||||
|
|||||||
@@ -240,6 +240,15 @@ a.muted:hover,
|
|||||||
border-color: var(--color-primary) !important;
|
border-color: var(--color-primary) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* currently used for search bar dropdowns in repo search and explore code */
|
||||||
|
.ui.action.input:not([class*="left action"]) > .ui.dropdown.selection {
|
||||||
|
min-width: 10em;
|
||||||
|
|
||||||
|
&:not(:focus):not(:hover) {
|
||||||
|
border-right-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ui.action.input:not([class*="left action"]) > input:focus {
|
.ui.action.input:not([class*="left action"]) > input:focus {
|
||||||
border-right-color: var(--color-primary);
|
border-right-color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,18 +201,25 @@
|
|||||||
.clone.button {
|
.clone.button {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 7.5px 5px;
|
padding: 7.5px 5px;
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-radius: var(--border-radius) 0 0 var(--border-radius);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#repo-clone-https,
|
#repo-clone-https,
|
||||||
#repo-clone-ssh,
|
#repo-clone-ssh {
|
||||||
#clipboard-btn {
|
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#download-btn {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:first-of-type {
|
||||||
|
border-radius: var(--border-radius) 0 0 var(--border-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:last-of-type {
|
||||||
|
border-radius: 0 var(--border-radius) var(--border-radius) 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.icon.button {
|
.icon.button {
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user