mirror of
https://github.com/go-gitea/gitea
synced 2025-07-25 03:38:36 +00:00
Merge branch 'main' into lunny/refactor-issue
This commit is contained in:
2
Makefile
2
Makefile
@@ -179,6 +179,7 @@ TEST_PGSQL_DBNAME ?= testgitea
|
|||||||
TEST_PGSQL_USERNAME ?= postgres
|
TEST_PGSQL_USERNAME ?= postgres
|
||||||
TEST_PGSQL_PASSWORD ?= postgres
|
TEST_PGSQL_PASSWORD ?= postgres
|
||||||
TEST_PGSQL_SCHEMA ?= gtestschema
|
TEST_PGSQL_SCHEMA ?= gtestschema
|
||||||
|
TEST_MINIO_ENDPOINT ?= minio:9000
|
||||||
TEST_MSSQL_HOST ?= mssql:1433
|
TEST_MSSQL_HOST ?= mssql:1433
|
||||||
TEST_MSSQL_DBNAME ?= gitea
|
TEST_MSSQL_DBNAME ?= gitea
|
||||||
TEST_MSSQL_USERNAME ?= sa
|
TEST_MSSQL_USERNAME ?= sa
|
||||||
@@ -574,6 +575,7 @@ generate-ini-pgsql:
|
|||||||
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
|
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
|
||||||
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
|
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
|
||||||
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
|
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
|
||||||
|
-e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \
|
||||||
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
|
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
|
||||||
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
||||||
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
|
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
|
||||||
|
@@ -179,27 +179,6 @@ func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) {
|
|||||||
return &task, nil
|
return &task, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMigratingTaskByID returns the migrating task by repo's id
|
|
||||||
func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) {
|
|
||||||
task := Task{
|
|
||||||
ID: id,
|
|
||||||
DoerID: doerID,
|
|
||||||
Type: structs.TaskTypeMigrateRepo,
|
|
||||||
}
|
|
||||||
has, err := db.GetEngine(ctx).Get(&task)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, nil, ErrTaskDoesNotExist{id, 0, task.Type}
|
|
||||||
}
|
|
||||||
|
|
||||||
var opts migration.MigrateOptions
|
|
||||||
if err := json.Unmarshal([]byte(task.PayloadContent), &opts); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return &task, &opts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateTask creates a task on database
|
// CreateTask creates a task on database
|
||||||
func CreateTask(ctx context.Context, task *Task) error {
|
func CreateTask(ctx context.Context, task *Task) error {
|
||||||
return db.Insert(ctx, task)
|
return db.Insert(ctx, task)
|
||||||
|
@@ -65,7 +65,19 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
|
|||||||
builder.Like{"LOWER(full_name)", lowerKeyword},
|
builder.Like{"LOWER(full_name)", lowerKeyword},
|
||||||
)
|
)
|
||||||
if opts.SearchByEmail {
|
if opts.SearchByEmail {
|
||||||
keywordCond = keywordCond.Or(builder.Like{"LOWER(email)", lowerKeyword})
|
var emailCond builder.Cond
|
||||||
|
emailCond = builder.Like{"LOWER(email)", lowerKeyword}
|
||||||
|
if opts.Actor == nil {
|
||||||
|
emailCond = emailCond.And(builder.Eq{"keep_email_private": false})
|
||||||
|
} else if !opts.Actor.IsAdmin {
|
||||||
|
emailCond = emailCond.And(
|
||||||
|
builder.Or(
|
||||||
|
builder.Eq{"keep_email_private": false},
|
||||||
|
builder.Eq{"id": opts.Actor.ID},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
keywordCond = keywordCond.Or(emailCond)
|
||||||
}
|
}
|
||||||
|
|
||||||
cond = cond.And(keywordCond)
|
cond = cond.And(keywordCond)
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||||
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
|
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/typesniffer"
|
"code.gitea.io/gitea/modules/typesniffer"
|
||||||
@@ -197,8 +198,33 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete deletes indexes by ids
|
// Delete entries by repoId
|
||||||
func (b *Indexer) Delete(ctx context.Context, repoID int64) error {
|
func (b *Indexer) Delete(ctx context.Context, repoID int64) error {
|
||||||
|
if err := b.doDelete(ctx, repoID); err != nil {
|
||||||
|
// Maybe there is a conflict during the delete operation, so we should retry after a refresh
|
||||||
|
log.Warn("Deletion of entries of repo %v within index %v was erroneus. Trying to refresh index before trying again", repoID, b.inner.VersionedIndexName(), err)
|
||||||
|
if err := b.refreshIndex(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := b.doDelete(ctx, repoID); err != nil {
|
||||||
|
log.Error("Could not delete entries of repo %v within index %v", repoID, b.inner.VersionedIndexName())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Indexer) refreshIndex(ctx context.Context) error {
|
||||||
|
if _, err := b.inner.Client.Refresh(b.inner.VersionedIndexName()).Do(ctx); err != nil {
|
||||||
|
log.Error("Error while trying to refresh index %v", b.inner.VersionedIndexName(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete entries by repoId
|
||||||
|
func (b *Indexer) doDelete(ctx context.Context, repoID int64) error {
|
||||||
_, err := b.inner.Client.DeleteByQuery(b.inner.VersionedIndexName()).
|
_, err := b.inner.Client.DeleteByQuery(b.inner.VersionedIndexName()).
|
||||||
Query(elastic.NewTermsQuery("repo_id", repoID)).
|
Query(elastic.NewTermsQuery("repo_id", repoID)).
|
||||||
Do(ctx)
|
Do(ctx)
|
||||||
|
1782
options/locale/locale_ga-IE.ini
Normal file
1782
options/locale/locale_ga-IE.ini
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1926,6 +1926,7 @@ pulls.delete.text=本当にこのプルリクエストを削除しますか? (
|
|||||||
pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ <strong>%[1]s</strong> にプッシュしました
|
pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ <strong>%[1]s</strong> にプッシュしました
|
||||||
|
|
||||||
pull.deleted_branch=(削除済み):%s
|
pull.deleted_branch=(削除済み):%s
|
||||||
|
pull.agit_documentation=AGitに関するドキュメントを確認する
|
||||||
|
|
||||||
comments.edit.already_changed=コメントの変更を保存できません。 他のユーザーによって内容がすでに変更されているようです。 変更を上書きしないようにするため、ページを更新してからもう一度編集してください
|
comments.edit.already_changed=コメントの変更を保存できません。 他のユーザーによって内容がすでに変更されているようです。 変更を上書きしないようにするため、ページを更新してからもう一度編集してください
|
||||||
|
|
||||||
|
@@ -1040,6 +1040,7 @@ issue_labels_helper=Escolha um conjunto de rótulos para as questões.
|
|||||||
license=Licença
|
license=Licença
|
||||||
license_helper=Escolha um ficheiro de licença.
|
license_helper=Escolha um ficheiro de licença.
|
||||||
license_helper_desc=Uma licença rege o que os outros podem, ou não, fazer com o seu código fonte. Não tem a certeza sobre qual a mais indicada para o seu trabalho? Veja: <a target="_blank" rel="noopener noreferrer" href="%s">Escolher uma licença.</a>
|
license_helper_desc=Uma licença rege o que os outros podem, ou não, fazer com o seu código fonte. Não tem a certeza sobre qual a mais indicada para o seu trabalho? Veja: <a target="_blank" rel="noopener noreferrer" href="%s">Escolher uma licença.</a>
|
||||||
|
multiple_licenses=Múltiplas licenças
|
||||||
object_format=Formato dos elementos
|
object_format=Formato dos elementos
|
||||||
object_format_helper=Formato dos elementos do repositório. Não poderá ser alterado mais tarde. SHA1 é o mais compatível.
|
object_format_helper=Formato dos elementos do repositório. Não poderá ser alterado mais tarde. SHA1 é o mais compatível.
|
||||||
readme=README
|
readme=README
|
||||||
@@ -2941,6 +2942,7 @@ dashboard.start_schedule_tasks=Iniciar tarefas de agendamento das operações
|
|||||||
dashboard.sync_branch.started=Sincronização de ramos iniciada
|
dashboard.sync_branch.started=Sincronização de ramos iniciada
|
||||||
dashboard.sync_tag.started=Sincronização de etiquetas iniciada
|
dashboard.sync_tag.started=Sincronização de etiquetas iniciada
|
||||||
dashboard.rebuild_issue_indexer=Reconstruir indexador de questões
|
dashboard.rebuild_issue_indexer=Reconstruir indexador de questões
|
||||||
|
dashboard.sync_repo_licenses=Sincronizar licenças do repositório
|
||||||
|
|
||||||
users.user_manage_panel=Gestão das contas de utilizadores
|
users.user_manage_panel=Gestão das contas de utilizadores
|
||||||
users.new_account=Criar conta de utilizador
|
users.new_account=Criar conta de utilizador
|
||||||
|
@@ -1124,9 +1124,20 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
|
|||||||
// Check if current user has fork of repository or in the same repository.
|
// Check if current user has fork of repository or in the same repository.
|
||||||
headRepo := repo_model.GetForkedRepo(ctx, headUser.ID, baseRepo.ID)
|
headRepo := repo_model.GetForkedRepo(ctx, headUser.ID, baseRepo.ID)
|
||||||
if headRepo == nil && !isSameRepo {
|
if headRepo == nil && !isSameRepo {
|
||||||
log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
|
err := baseRepo.GetBaseRepo(ctx)
|
||||||
ctx.NotFound("GetForkedRepo")
|
if err != nil {
|
||||||
return nil, nil, nil, "", ""
|
ctx.Error(http.StatusInternalServerError, "GetBaseRepo", err)
|
||||||
|
return nil, nil, nil, "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if baseRepo's base repository is the same as headUser's repository.
|
||||||
|
if baseRepo.BaseRepo == nil || baseRepo.BaseRepo.OwnerID != headUser.ID {
|
||||||
|
log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
|
||||||
|
ctx.NotFound("GetBaseRepo")
|
||||||
|
return nil, nil, nil, "", ""
|
||||||
|
}
|
||||||
|
// Assign headRepo so it can be used below.
|
||||||
|
headRepo = baseRepo.BaseRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
var headGitRepo *git.Repository
|
var headGitRepo *git.Repository
|
||||||
|
@@ -68,11 +68,12 @@ func Search(ctx *context.APIContext) {
|
|||||||
users = []*user_model.User{user_model.NewActionsUser()}
|
users = []*user_model.User{user_model.NewActionsUser()}
|
||||||
default:
|
default:
|
||||||
users, maxResults, err = user_model.SearchUsers(ctx, &user_model.SearchUserOptions{
|
users, maxResults, err = user_model.SearchUsers(ctx, &user_model.SearchUserOptions{
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
Keyword: ctx.FormTrim("q"),
|
Keyword: ctx.FormTrim("q"),
|
||||||
UID: uid,
|
UID: uid,
|
||||||
Type: user_model.UserTypeIndividual,
|
Type: user_model.UserTypeIndividual,
|
||||||
ListOptions: listOptions,
|
SearchByEmail: true,
|
||||||
|
ListOptions: listOptions,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
||||||
|
@@ -15,6 +15,7 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@@ -288,3 +289,40 @@ func MigrateCancelPost(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
ctx.Redirect(ctx.Repo.Repository.Link())
|
ctx.Redirect(ctx.Repo.Repository.Link())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MigrateStatus returns migrate task's status
|
||||||
|
func MigrateStatus(ctx *context.Context) {
|
||||||
|
task, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID)
|
||||||
|
if err != nil {
|
||||||
|
if admin_model.IsErrTaskDoesNotExist(err) {
|
||||||
|
ctx.JSON(http.StatusNotFound, map[string]any{
|
||||||
|
"err": "task does not exist or you do not have access to this task",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Error("GetMigratingTask: %v", err)
|
||||||
|
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
||||||
|
"err": http.StatusText(http.StatusInternalServerError),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
message := task.Message
|
||||||
|
|
||||||
|
if task.Message != "" && task.Message[0] == '{' {
|
||||||
|
// assume message is actually a translatable string
|
||||||
|
var translatableMessage admin_model.TranslatableMessage
|
||||||
|
if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
|
||||||
|
translatableMessage = admin_model.TranslatableMessage{
|
||||||
|
Format: "migrate.migrating_failed.error",
|
||||||
|
Args: []any{task.Message},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, map[string]any{
|
||||||
|
"status": task.Status,
|
||||||
|
"message": message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
|
||||||
"code.gitea.io/gitea/services/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TaskStatus returns task's status
|
|
||||||
func TaskStatus(ctx *context.Context) {
|
|
||||||
task, opts, err := admin_model.GetMigratingTaskByID(ctx, ctx.PathParamInt64("task"), ctx.Doer.ID)
|
|
||||||
if err != nil {
|
|
||||||
if admin_model.IsErrTaskDoesNotExist(err) {
|
|
||||||
ctx.JSON(http.StatusNotFound, map[string]any{
|
|
||||||
"error": "task `" + strconv.FormatInt(ctx.PathParamInt64("task"), 10) + "` does not exist",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
|
||||||
"err": err,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
message := task.Message
|
|
||||||
|
|
||||||
if task.Message != "" && task.Message[0] == '{' {
|
|
||||||
// assume message is actually a translatable string
|
|
||||||
var translatableMessage admin_model.TranslatableMessage
|
|
||||||
if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
|
|
||||||
translatableMessage = admin_model.TranslatableMessage{
|
|
||||||
Format: "migrate.migrating_failed.error",
|
|
||||||
Args: []any{task.Message},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, map[string]any{
|
|
||||||
"status": task.Status,
|
|
||||||
"message": message,
|
|
||||||
"repo-id": task.RepoID,
|
|
||||||
"repo-name": opts.RepoName,
|
|
||||||
"start": task.StartTime,
|
|
||||||
"end": task.EndTime,
|
|
||||||
})
|
|
||||||
}
|
|
@@ -669,7 +669,6 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Get("/forgot_password", auth.ForgotPasswd)
|
m.Get("/forgot_password", auth.ForgotPasswd)
|
||||||
m.Post("/forgot_password", auth.ForgotPasswdPost)
|
m.Post("/forgot_password", auth.ForgotPasswdPost)
|
||||||
m.Post("/logout", auth.SignOut)
|
m.Post("/logout", auth.SignOut)
|
||||||
m.Get("/task/{task}", reqSignIn, user.TaskStatus)
|
|
||||||
m.Get("/stopwatches", reqSignIn, user.GetStopwatches)
|
m.Get("/stopwatches", reqSignIn, user.GetStopwatches)
|
||||||
m.Get("/search", ignExploreSignIn, user.Search)
|
m.Get("/search", ignExploreSignIn, user.Search)
|
||||||
m.Group("/oauth2", func() {
|
m.Group("/oauth2", func() {
|
||||||
@@ -1042,6 +1041,13 @@ func registerRoutes(m *web.Router) {
|
|||||||
}, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment())
|
}, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment())
|
||||||
// end "/{username}/-": packages, projects, code
|
// end "/{username}/-": packages, projects, code
|
||||||
|
|
||||||
|
m.Group("/{username}/{reponame}/-", func() {
|
||||||
|
m.Group("/migrate", func() {
|
||||||
|
m.Get("/status", repo.MigrateStatus)
|
||||||
|
})
|
||||||
|
}, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
|
||||||
|
// end "/{username}/{reponame}/-": migrate
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}/settings", func() {
|
m.Group("/{username}/{reponame}/settings", func() {
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Combo("").Get(repo_setting.Settings).
|
m.Combo("").Get(repo_setting.Settings).
|
||||||
|
@@ -614,7 +614,10 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/")
|
isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink ||
|
||||||
|
ctx.Link == ctx.Repo.RepoLink+"/settings" ||
|
||||||
|
strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") ||
|
||||||
|
ctx.Link == ctx.Repo.RepoLink+"/-/migrate/status"
|
||||||
|
|
||||||
// Disable everything when the repo is being created
|
// Disable everything when the repo is being created
|
||||||
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
|
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<div class="ui stackable middle very relaxed page grid">
|
<div class="ui stackable middle very relaxed page grid">
|
||||||
<div id="repo_migrating" class="sixteen wide center aligned centered column" data-migrating-task-id="{{.MigrateTask.ID}}">
|
<div id="repo_migrating" class="sixteen wide center aligned centered column" data-migrating-repo-link="{{.Link}}">
|
||||||
<div>
|
<div>
|
||||||
<img src="{{AssetUrlPrefix}}/img/loading.png">
|
<img src="{{AssetUrlPrefix}}/img/loading.png">
|
||||||
</div>
|
</div>
|
||||||
|
@@ -56,11 +56,15 @@ TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root T
|
|||||||
## Run pgsql integration tests
|
## Run pgsql integration tests
|
||||||
Setup a pgsql database inside docker
|
Setup a pgsql database inside docker
|
||||||
```
|
```
|
||||||
docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container)
|
docker run -e "POSTGRES_DB=test" -e "POSTGRES_USER=postgres" -e "POSTGRES_PASSWORD=postgres" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container)
|
||||||
|
```
|
||||||
|
Setup minio inside docker
|
||||||
|
```
|
||||||
|
docker run --rm -p 9000:9000 -e MINIO_ROOT_USER=123456 -e MINIO_ROOT_PASSWORD=12345678 --name minio bitnami/minio:2023.8.31
|
||||||
```
|
```
|
||||||
Start tests based on the database container
|
Start tests based on the database container
|
||||||
```
|
```
|
||||||
TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
|
TEST_MINIO_ENDPOINT=localhost:9000 TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=postgres TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run mssql integration tests
|
## Run mssql integration tests
|
||||||
|
@@ -42,7 +42,7 @@ make test-sqlite
|
|||||||
## 如何使用 mysql 数据库进行集成测试
|
## 如何使用 mysql 数据库进行集成测试
|
||||||
首先在docker容器里部署一个 mysql 数据库
|
首先在docker容器里部署一个 mysql 数据库
|
||||||
```
|
```
|
||||||
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:8 #(just ctrl-c to stop db and clean the container)
|
docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:8 #(just ctrl-c to stop db and clean the container)
|
||||||
```
|
```
|
||||||
之后便可以基于这个数据库进行集成测试
|
之后便可以基于这个数据库进行集成测试
|
||||||
```
|
```
|
||||||
@@ -52,17 +52,21 @@ TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root T
|
|||||||
## 如何使用 pgsql 数据库进行集成测试
|
## 如何使用 pgsql 数据库进行集成测试
|
||||||
同上,首先在 docker 容器里部署一个 pgsql 数据库
|
同上,首先在 docker 容器里部署一个 pgsql 数据库
|
||||||
```
|
```
|
||||||
docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:14 #(just ctrl-c to stop db and clean the container)
|
docker run -e "POSTGRES_DB=test" -e "POSTGRES_USER=postgres" -e "POSTGRES_PASSWORD=postgres" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container)
|
||||||
|
```
|
||||||
|
在docker内设置minio
|
||||||
|
```
|
||||||
|
docker run --rm -p 9000:9000 -e MINIO_ROOT_USER=123456 -e MINIO_ROOT_PASSWORD=12345678 --name minio bitnami/minio:2023.8.31
|
||||||
```
|
```
|
||||||
之后便可以基于这个数据库进行集成测试
|
之后便可以基于这个数据库进行集成测试
|
||||||
```
|
```
|
||||||
TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
|
TEST_MINIO_ENDPOINT=localhost:9000 TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=postgres TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run mssql integration tests
|
## Run mssql integration tests
|
||||||
同上,首先在 docker 容器里部署一个 mssql 数据库
|
同上,首先在 docker 容器里部署一个 mssql 数据库
|
||||||
```
|
```
|
||||||
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container)
|
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=Standard" -e "SA_PASSWORD=MwantsaSecurePassword1" -p 1433:1433 --rm --name mssql microsoft/mssql-server-linux:latest #(just ctrl-c to stop db and clean the container)
|
||||||
```
|
```
|
||||||
之后便可以基于这个数据库进行集成测试
|
之后便可以基于这个数据库进行集成测试
|
||||||
```
|
```
|
||||||
|
@@ -109,3 +109,39 @@ func TestAPIUserSearchNotLoggedInUserHidden(t *testing.T) {
|
|||||||
DecodeJSON(t, resp, &results)
|
DecodeJSON(t, resp, &results)
|
||||||
assert.Empty(t, results.Data)
|
assert.Empty(t, results.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPIUserSearchByEmail(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
// admin can search user with private email
|
||||||
|
adminUsername := "user1"
|
||||||
|
session := loginUser(t, adminUsername)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser)
|
||||||
|
query := "user2@example.com"
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query).
|
||||||
|
AddTokenAuth(token)
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var results SearchResults
|
||||||
|
DecodeJSON(t, resp, &results)
|
||||||
|
assert.Equal(t, 1, len(results.Data))
|
||||||
|
assert.Equal(t, query, results.Data[0].Email)
|
||||||
|
|
||||||
|
// no login user can not search user with private email
|
||||||
|
req = NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &results)
|
||||||
|
assert.Empty(t, results.Data)
|
||||||
|
|
||||||
|
// user can search self with private email
|
||||||
|
user2 := "user2"
|
||||||
|
session = loginUser(t, user2)
|
||||||
|
token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser)
|
||||||
|
req = NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query).
|
||||||
|
AddTokenAuth(token)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
DecodeJSON(t, resp, &results)
|
||||||
|
assert.Equal(t, 1, len(results.Data))
|
||||||
|
assert.Equal(t, query, results.Data[0].Email)
|
||||||
|
}
|
||||||
|
@@ -199,3 +199,30 @@ func TestPullBranchDelete(t *testing.T) {
|
|||||||
session.MakeRequest(t, req, http.StatusOK)
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup:
|
||||||
|
The base repository is: user2/repo1
|
||||||
|
Fork repository to: user1/repo1
|
||||||
|
Push extra commit to: user2/repo1, which changes README.md
|
||||||
|
Create a PR on user1/repo1
|
||||||
|
|
||||||
|
Test checks:
|
||||||
|
Check if pull request can be created from base to the fork repository.
|
||||||
|
*/
|
||||||
|
func TestPullCreatePrFromBaseToFork(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
sessionFork := loginUser(t, "user1")
|
||||||
|
testRepoFork(t, sessionFork, "user2", "repo1", "user1", "repo1", "")
|
||||||
|
|
||||||
|
// Edit base repository
|
||||||
|
sessionBase := loginUser(t, "user2")
|
||||||
|
testEditFile(t, sessionBase, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||||
|
|
||||||
|
// Create a PR
|
||||||
|
resp := testPullCreateDirectly(t, sessionFork, "user1", "repo1", "master", "user2", "repo1", "master", "This is a pull title")
|
||||||
|
// check the redirected URL
|
||||||
|
url := test.RedirectURL(resp)
|
||||||
|
assert.Regexp(t, "^/user1/repo1/pulls/[0-9]*$", url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -115,7 +115,7 @@ MINIO_BASE_PATH = repo-avatars/
|
|||||||
[storage]
|
[storage]
|
||||||
STORAGE_TYPE = minio
|
STORAGE_TYPE = minio
|
||||||
SERVE_DIRECT = false
|
SERVE_DIRECT = false
|
||||||
MINIO_ENDPOINT = minio:9000
|
MINIO_ENDPOINT = {{TEST_MINIO_ENDPOINT}}
|
||||||
MINIO_ACCESS_KEY_ID = 123456
|
MINIO_ACCESS_KEY_ID = 123456
|
||||||
MINIO_SECRET_ACCESS_KEY = 12345678
|
MINIO_SECRET_ACCESS_KEY = 12345678
|
||||||
MINIO_BUCKET = gitea
|
MINIO_BUCKET = gitea
|
||||||
|
@@ -1,19 +1,17 @@
|
|||||||
import {hideElem, showElem} from '../utils/dom.ts';
|
import {hideElem, showElem} from '../utils/dom.ts';
|
||||||
import {GET, POST} from '../modules/fetch.ts';
|
import {GET, POST} from '../modules/fetch.ts';
|
||||||
|
|
||||||
const {appSubUrl} = window.config;
|
|
||||||
|
|
||||||
export function initRepoMigrationStatusChecker() {
|
export function initRepoMigrationStatusChecker() {
|
||||||
const repoMigrating = document.querySelector('#repo_migrating');
|
const repoMigrating = document.querySelector('#repo_migrating');
|
||||||
if (!repoMigrating) return;
|
if (!repoMigrating) return;
|
||||||
|
|
||||||
document.querySelector('#repo_migrating_retry').addEventListener('click', doMigrationRetry);
|
document.querySelector('#repo_migrating_retry')?.addEventListener('click', doMigrationRetry);
|
||||||
|
|
||||||
const task = repoMigrating.getAttribute('data-migrating-task-id');
|
const repoLink = repoMigrating.getAttribute('data-migrating-repo-link');
|
||||||
|
|
||||||
// returns true if the refresh still needs to be called after a while
|
// returns true if the refresh still needs to be called after a while
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
const res = await GET(`${appSubUrl}/user/task/${task}`);
|
const res = await GET(`${repoLink}/-/migrate/status`);
|
||||||
if (res.status !== 200) return true; // continue to refresh if network error occurs
|
if (res.status !== 200) return true; // continue to refresh if network error occurs
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
Reference in New Issue
Block a user