Fix #29000 Fix #28685 Fix #18568 Related: #27497 And by the way fix #24036, add a Cancel button there (one line)tags/v1.22.0-rc0
@@ -562,6 +562,8 @@ var migrations = []Migration{ | |||
NewMigration("Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges), | |||
// v288 -> v289 | |||
NewMigration("Add user_blocking table", v1_22.AddUserBlockingTable), | |||
// v289 -> v290 | |||
NewMigration("Add default_wiki_branch to repository table", v1_22.AddDefaultWikiBranch), | |||
} | |||
// GetCurrentDBVersion returns the current db version |
@@ -0,0 +1,18 @@ | |||
// Copyright 2024 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package v1_22 //nolint | |||
import "xorm.io/xorm" | |||
func AddDefaultWikiBranch(x *xorm.Engine) error { | |||
type Repository struct { | |||
ID int64 | |||
DefaultWikiBranch string | |||
} | |||
if err := x.Sync(&Repository{}); err != nil { | |||
return err | |||
} | |||
_, err := x.Exec("UPDATE `repository` SET default_wiki_branch = 'master' WHERE (default_wiki_branch IS NULL) OR (default_wiki_branch = '')") | |||
return err | |||
} |
@@ -136,6 +136,7 @@ type Repository struct { | |||
OriginalServiceType api.GitServiceType `xorm:"index"` | |||
OriginalURL string `xorm:"VARCHAR(2048)"` | |||
DefaultBranch string | |||
DefaultWikiBranch string | |||
NumWatches int | |||
NumStars int | |||
@@ -285,6 +286,9 @@ func (repo *Repository) AfterLoad() { | |||
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones | |||
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects | |||
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns | |||
if repo.DefaultWikiBranch == "" { | |||
repo.DefaultWikiBranch = setting.Repository.DefaultBranch | |||
} | |||
} | |||
// LoadAttributes loads attributes of the repository. |
@@ -8,11 +8,11 @@ package git | |||
import ( | |||
"context" | |||
"errors" | |||
"path/filepath" | |||
gitealog "code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/util" | |||
"github.com/go-git/go-billy/v5" | |||
"github.com/go-git/go-billy/v5/osfs" | |||
@@ -52,7 +52,7 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) { | |||
if err != nil { | |||
return nil, err | |||
} else if !isDir(repoPath) { | |||
return nil, errors.New("no such file or directory") | |||
return nil, util.NewNotExistErrorf("no such file or directory") | |||
} | |||
fs := osfs.New(repoPath) |
@@ -9,10 +9,10 @@ package git | |||
import ( | |||
"bufio" | |||
"context" | |||
"errors" | |||
"path/filepath" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/util" | |||
) | |||
func init() { | |||
@@ -54,7 +54,7 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) { | |||
if err != nil { | |||
return nil, err | |||
} else if !isDir(repoPath) { | |||
return nil, errors.New("no such file or directory") | |||
return nil, util.NewNotExistErrorf("no such file or directory") | |||
} | |||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! |
@@ -2092,6 +2092,8 @@ settings.branches.add_new_rule = Add New Rule | |||
settings.advanced_settings = Advanced Settings | |||
settings.wiki_desc = Enable Repository Wiki | |||
settings.use_internal_wiki = Use Built-In Wiki | |||
settings.default_wiki_branch_name = Default Wiki Branch Name | |||
settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch. | |||
settings.use_external_wiki = Use External Wiki | |||
settings.external_wiki_url = External Wiki URL | |||
settings.external_wiki_url_error = The external wiki URL is not a valid URL. |
@@ -488,6 +488,13 @@ func SettingsPost(ctx *context.Context) { | |||
} | |||
} | |||
if form.DefaultWikiBranch != "" { | |||
if err := wiki_service.ChangeDefaultWikiBranch(ctx, repo, form.DefaultWikiBranch); err != nil { | |||
log.Error("ChangeDefaultWikiBranch failed, err: %v", err) | |||
ctx.Flash.Warning(ctx.Tr("repo.settings.failed_to_change_default_wiki_branch")) | |||
} | |||
} | |||
if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() { | |||
if !validation.IsValidExternalURL(form.ExternalTrackerURL) { | |||
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error")) |
@@ -93,17 +93,32 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) | |||
} | |||
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) { | |||
wikiRepo, err := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository) | |||
if err != nil { | |||
ctx.ServerError("OpenRepository", err) | |||
return nil, nil, err | |||
wikiGitRepo, errGitRepo := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository) | |||
if errGitRepo != nil { | |||
ctx.ServerError("OpenRepository", errGitRepo) | |||
return nil, nil, errGitRepo | |||
} | |||
commit, err := wikiRepo.GetBranchCommit(wiki_service.DefaultBranch) | |||
if err != nil { | |||
return wikiRepo, nil, err | |||
commit, errCommit := wikiGitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultWikiBranch) | |||
if git.IsErrNotExist(errCommit) { | |||
// if the default branch recorded in database is out of sync, then re-sync it | |||
gitRepoDefaultBranch, errBranch := wikiGitRepo.GetDefaultBranch() | |||
if errBranch != nil { | |||
return wikiGitRepo, nil, errBranch | |||
} | |||
// update the default branch in the database | |||
errDb := repo_model.UpdateRepositoryCols(ctx, &repo_model.Repository{ID: ctx.Repo.Repository.ID, DefaultWikiBranch: gitRepoDefaultBranch}, "default_wiki_branch") | |||
if errDb != nil { | |||
return wikiGitRepo, nil, errDb | |||
} | |||
ctx.Repo.Repository.DefaultWikiBranch = gitRepoDefaultBranch | |||
// retry to get the commit from the correct default branch | |||
commit, errCommit = wikiGitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultWikiBranch) | |||
} | |||
return wikiRepo, commit, nil | |||
if errCommit != nil { | |||
return wikiGitRepo, nil, errCommit | |||
} | |||
return wikiGitRepo, commit, nil | |||
} | |||
// wikiContentsByEntry returns the contents of the wiki page referenced by the | |||
@@ -316,7 +331,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { | |||
} | |||
// get commit count - wiki revisions | |||
commitsCount, _ := wikiRepo.FileCommitsCount(wiki_service.DefaultBranch, pageFilename) | |||
commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.DefaultWikiBranch, pageFilename) | |||
ctx.Data["CommitCount"] = commitsCount | |||
return wikiRepo, entry | |||
@@ -368,7 +383,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) | |||
ctx.Data["footerContent"] = "" | |||
// get commit count - wiki revisions | |||
commitsCount, _ := wikiRepo.FileCommitsCount(wiki_service.DefaultBranch, pageFilename) | |||
commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.DefaultWikiBranch, pageFilename) | |||
ctx.Data["CommitCount"] = commitsCount | |||
// get page | |||
@@ -380,7 +395,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) | |||
// get Commit Count | |||
commitsHistory, err := wikiRepo.CommitsByFileAndRange( | |||
git.CommitsByFileAndRangeOptions{ | |||
Revision: wiki_service.DefaultBranch, | |||
Revision: ctx.Repo.Repository.DefaultWikiBranch, | |||
File: pageFilename, | |||
Page: page, | |||
}) | |||
@@ -402,20 +417,17 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) | |||
func renderEditPage(ctx *context.Context) { | |||
wikiRepo, commit, err := findWikiRepoCommit(ctx) | |||
if err != nil { | |||
defer func() { | |||
if wikiRepo != nil { | |||
wikiRepo.Close() | |||
_ = wikiRepo.Close() | |||
} | |||
}() | |||
if err != nil { | |||
if !git.IsErrNotExist(err) { | |||
ctx.ServerError("GetBranchCommit", err) | |||
} | |||
return | |||
} | |||
defer func() { | |||
if wikiRepo != nil { | |||
wikiRepo.Close() | |||
} | |||
}() | |||
// get requested pagename | |||
pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*")) | |||
@@ -584,17 +596,15 @@ func WikiPages(ctx *context.Context) { | |||
ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived | |||
wikiRepo, commit, err := findWikiRepoCommit(ctx) | |||
if err != nil { | |||
if wikiRepo != nil { | |||
wikiRepo.Close() | |||
} | |||
return | |||
} | |||
defer func() { | |||
if wikiRepo != nil { | |||
wikiRepo.Close() | |||
_ = wikiRepo.Close() | |||
} | |||
}() | |||
if err != nil { | |||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki") | |||
return | |||
} | |||
entries, err := commit.ListEntries() | |||
if err != nil { |
@@ -9,6 +9,7 @@ import ( | |||
"net/url" | |||
"testing" | |||
"code.gitea.io/gitea/models/db" | |||
repo_model "code.gitea.io/gitea/models/repo" | |||
"code.gitea.io/gitea/models/unittest" | |||
"code.gitea.io/gitea/modules/git" | |||
@@ -221,3 +222,32 @@ func TestWikiRaw(t *testing.T) { | |||
} | |||
} | |||
} | |||
func TestDefaultWikiBranch(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
assert.NoError(t, repo_model.UpdateRepositoryCols(db.DefaultContext, &repo_model.Repository{ID: 1, DefaultWikiBranch: "wrong-branch"})) | |||
ctx, _ := contexttest.MockContext(t, "user2/repo1/wiki") | |||
ctx.SetParams("*", "Home") | |||
contexttest.LoadRepo(t, ctx, 1) | |||
assert.Equal(t, "wrong-branch", ctx.Repo.Repository.DefaultWikiBranch) | |||
Wiki(ctx) // after the visiting, the out-of-sync database record will update the branch name to "master" | |||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) | |||
assert.Equal(t, "master", ctx.Repo.Repository.DefaultWikiBranch) | |||
// invalid branch name should fail | |||
assert.Error(t, wiki_service.ChangeDefaultWikiBranch(db.DefaultContext, repo, "the bad name")) | |||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) | |||
assert.Equal(t, "master", repo.DefaultWikiBranch) | |||
// the same branch name, should succeed (actually a no-op) | |||
assert.NoError(t, wiki_service.ChangeDefaultWikiBranch(db.DefaultContext, repo, "master")) | |||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) | |||
assert.Equal(t, "master", repo.DefaultWikiBranch) | |||
// change to another name | |||
assert.NoError(t, wiki_service.ChangeDefaultWikiBranch(db.DefaultContext, repo, "main")) | |||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) | |||
assert.Equal(t, "main", repo.DefaultWikiBranch) | |||
} |
@@ -133,6 +133,7 @@ type RepoSettingForm struct { | |||
EnableCode bool | |||
EnableWiki bool | |||
EnableExternalWiki bool | |||
DefaultWikiBranch string | |||
ExternalWikiURL string | |||
EnableIssues bool | |||
EnableExternalTracker bool |
@@ -173,6 +173,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re | |||
} | |||
repo.DefaultBranch = setting.Repository.DefaultBranch | |||
repo.DefaultWikiBranch = setting.Repository.DefaultBranch | |||
if len(opts.DefaultBranch) > 0 { | |||
repo.DefaultBranch = opts.DefaultBranch | |||
@@ -240,6 +241,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt | |||
TrustModel: opts.TrustModel, | |||
IsMirror: opts.IsMirror, | |||
DefaultBranch: opts.DefaultBranch, | |||
DefaultWikiBranch: setting.Repository.DefaultBranch, | |||
ObjectFormatName: opts.ObjectFormatName, | |||
} | |||
@@ -25,6 +25,54 @@ import ( | |||
"code.gitea.io/gitea/modules/util" | |||
) | |||
func cloneWiki(ctx context.Context, u *user_model.User, opts migration.MigrateOptions, migrateTimeout time.Duration) (string, error) { | |||
wikiPath := repo_model.WikiPath(u.Name, opts.RepoName) | |||
wikiRemotePath := repo_module.WikiRemoteURL(ctx, opts.CloneAddr) | |||
if wikiRemotePath == "" { | |||
return "", nil | |||
} | |||
if err := util.RemoveAll(wikiPath); err != nil { | |||
return "", fmt.Errorf("failed to remove existing wiki dir %q, err: %w", wikiPath, err) | |||
} | |||
cleanIncompleteWikiPath := func() { | |||
if err := util.RemoveAll(wikiPath); err != nil { | |||
log.Error("Failed to remove incomplete wiki dir %q, err: %v", wikiPath, err) | |||
} | |||
} | |||
if err := git.Clone(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{ | |||
Mirror: true, | |||
Quiet: true, | |||
Timeout: migrateTimeout, | |||
SkipTLSVerify: setting.Migrations.SkipTLSVerify, | |||
}); err != nil { | |||
log.Error("Clone wiki failed, err: %v", err) | |||
cleanIncompleteWikiPath() | |||
return "", err | |||
} | |||
if err := git.WriteCommitGraph(ctx, wikiPath); err != nil { | |||
cleanIncompleteWikiPath() | |||
return "", err | |||
} | |||
wikiRepo, err := git.OpenRepository(ctx, wikiPath) | |||
if err != nil { | |||
cleanIncompleteWikiPath() | |||
return "", fmt.Errorf("failed to open wiki repo %q, err: %w", wikiPath, err) | |||
} | |||
defer wikiRepo.Close() | |||
defaultBranch, err := wikiRepo.GetDefaultBranch() | |||
if err != nil { | |||
cleanIncompleteWikiPath() | |||
return "", fmt.Errorf("failed to get wiki repo default branch for %q, err: %w", wikiPath, err) | |||
} | |||
return defaultBranch, nil | |||
} | |||
// MigrateRepositoryGitData starts migrating git related data after created migrating repository | |||
func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, | |||
repo *repo_model.Repository, opts migration.MigrateOptions, | |||
@@ -44,21 +92,20 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, | |||
migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||
var err error | |||
if err = util.RemoveAll(repoPath); err != nil { | |||
return repo, fmt.Errorf("Failed to remove %s: %w", repoPath, err) | |||
if err := util.RemoveAll(repoPath); err != nil { | |||
return repo, fmt.Errorf("failed to remove existing repo dir %q, err: %w", repoPath, err) | |||
} | |||
if err = git.Clone(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{ | |||
if err := git.Clone(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{ | |||
Mirror: true, | |||
Quiet: true, | |||
Timeout: migrateTimeout, | |||
SkipTLSVerify: setting.Migrations.SkipTLSVerify, | |||
}); err != nil { | |||
if errors.Is(err, context.DeadlineExceeded) { | |||
return repo, fmt.Errorf("Clone timed out. Consider increasing [git.timeout] MIGRATE in app.ini. Underlying Error: %w", err) | |||
return repo, fmt.Errorf("clone timed out, consider increasing [git.timeout] MIGRATE in app.ini, underlying err: %w", err) | |||
} | |||
return repo, fmt.Errorf("Clone: %w", err) | |||
return repo, fmt.Errorf("clone error: %w", err) | |||
} | |||
if err := git.WriteCommitGraph(ctx, repoPath); err != nil { | |||
@@ -66,37 +113,18 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, | |||
} | |||
if opts.Wiki { | |||
wikiPath := repo_model.WikiPath(u.Name, opts.RepoName) | |||
wikiRemotePath := repo_module.WikiRemoteURL(ctx, opts.CloneAddr) | |||
if len(wikiRemotePath) > 0 { | |||
if err := util.RemoveAll(wikiPath); err != nil { | |||
return repo, fmt.Errorf("Failed to remove %s: %w", wikiPath, err) | |||
} | |||
if err := git.Clone(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{ | |||
Mirror: true, | |||
Quiet: true, | |||
Timeout: migrateTimeout, | |||
Branch: "master", | |||
SkipTLSVerify: setting.Migrations.SkipTLSVerify, | |||
}); err != nil { | |||
log.Warn("Clone wiki: %v", err) | |||
if err := util.RemoveAll(wikiPath); err != nil { | |||
return repo, fmt.Errorf("Failed to remove %s: %w", wikiPath, err) | |||
} | |||
} else { | |||
if err := git.WriteCommitGraph(ctx, wikiPath); err != nil { | |||
return repo, err | |||
} | |||
} | |||
defaultWikiBranch, err := cloneWiki(ctx, u, opts, migrateTimeout) | |||
if err != nil { | |||
return repo, fmt.Errorf("clone wiki error: %w", err) | |||
} | |||
repo.DefaultWikiBranch = defaultWikiBranch | |||
} | |||
if repo.OwnerID == u.ID { | |||
repo.Owner = u | |||
} | |||
if err = repo_module.CheckDaemonExportOK(ctx, repo); err != nil { | |||
if err := repo_module.CheckDaemonExportOK(ctx, repo); err != nil { | |||
return repo, fmt.Errorf("checkDaemonExportOK: %w", err) | |||
} | |||
@@ -6,18 +6,22 @@ package wiki | |||
import ( | |||
"context" | |||
"errors" | |||
"fmt" | |||
"os" | |||
"strings" | |||
"code.gitea.io/gitea/models/db" | |||
repo_model "code.gitea.io/gitea/models/repo" | |||
system_model "code.gitea.io/gitea/models/system" | |||
"code.gitea.io/gitea/models/unit" | |||
user_model "code.gitea.io/gitea/models/user" | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/gitrepo" | |||
"code.gitea.io/gitea/modules/log" | |||
repo_module "code.gitea.io/gitea/modules/repository" | |||
"code.gitea.io/gitea/modules/sync" | |||
"code.gitea.io/gitea/modules/util" | |||
asymkey_service "code.gitea.io/gitea/services/asymkey" | |||
repo_service "code.gitea.io/gitea/services/repository" | |||
) | |||
@@ -25,10 +29,7 @@ import ( | |||
// TODO: use clustered lock (unique queue? or *abuse* cache) | |||
var wikiWorkingPool = sync.NewExclusivePool() | |||
const ( | |||
DefaultRemote = "origin" | |||
DefaultBranch = "master" | |||
) | |||
const DefaultRemote = "origin" | |||
// InitWiki initializes a wiki for repository, | |||
// it does nothing when repository already has wiki. | |||
@@ -41,25 +42,25 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error { | |||
return fmt.Errorf("InitRepository: %w", err) | |||
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil { | |||
return fmt.Errorf("createDelegateHooks: %w", err) | |||
} else if _, _, err = git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+DefaultBranch).RunStdString(&git.RunOpts{Dir: repo.WikiPath()}); err != nil { | |||
return fmt.Errorf("unable to set default wiki branch to master: %w", err) | |||
} else if _, _, err = git.NewCommand(ctx, "symbolic-ref", "HEAD").AddDynamicArguments(git.BranchPrefix + repo.DefaultWikiBranch).RunStdString(&git.RunOpts{Dir: repo.WikiPath()}); err != nil { | |||
return fmt.Errorf("unable to set default wiki branch to %q: %w", repo.DefaultWikiBranch, err) | |||
} | |||
return nil | |||
} | |||
// prepareGitPath try to find a suitable file path with file name by the given raw wiki name. | |||
// return: existence, prepared file path with name, error | |||
func prepareGitPath(gitRepo *git.Repository, wikiPath WebPath) (bool, string, error) { | |||
func prepareGitPath(gitRepo *git.Repository, defaultWikiBranch string, wikiPath WebPath) (bool, string, error) { | |||
unescaped := string(wikiPath) + ".md" | |||
gitPath := WebPathToGitPath(wikiPath) | |||
// Look for both files | |||
filesInIndex, err := gitRepo.LsTree(DefaultBranch, unescaped, gitPath) | |||
filesInIndex, err := gitRepo.LsTree(defaultWikiBranch, unescaped, gitPath) | |||
if err != nil { | |||
if strings.Contains(err.Error(), "Not a valid object name master") { | |||
return false, gitPath, nil | |||
if strings.Contains(err.Error(), "Not a valid object name") { | |||
return false, gitPath, nil // branch doesn't exist | |||
} | |||
log.Error("%v", err) | |||
log.Error("Wiki LsTree failed, err: %v", err) | |||
return false, gitPath, err | |||
} | |||
@@ -95,7 +96,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
return fmt.Errorf("InitWiki: %w", err) | |||
} | |||
hasMasterBranch := git.IsBranchExist(ctx, repo.WikiPath(), DefaultBranch) | |||
hasDefaultBranch := git.IsBranchExist(ctx, repo.WikiPath(), repo.DefaultWikiBranch) | |||
basePath, err := repo_module.CreateTemporaryPath("update-wiki") | |||
if err != nil { | |||
@@ -112,8 +113,8 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
Shared: true, | |||
} | |||
if hasMasterBranch { | |||
cloneOpts.Branch = DefaultBranch | |||
if hasDefaultBranch { | |||
cloneOpts.Branch = repo.DefaultWikiBranch | |||
} | |||
if err := git.Clone(ctx, repo.WikiPath(), basePath, cloneOpts); err != nil { | |||
@@ -128,14 +129,14 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
} | |||
defer gitRepo.Close() | |||
if hasMasterBranch { | |||
if hasDefaultBranch { | |||
if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil { | |||
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err) | |||
return fmt.Errorf("fnable to read HEAD tree to index in: %s %w", basePath, err) | |||
} | |||
} | |||
isWikiExist, newWikiPath, err := prepareGitPath(gitRepo, newWikiName) | |||
isWikiExist, newWikiPath, err := prepareGitPath(gitRepo, repo.DefaultWikiBranch, newWikiName) | |||
if err != nil { | |||
return err | |||
} | |||
@@ -151,7 +152,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
isOldWikiExist := true | |||
oldWikiPath := newWikiPath | |||
if oldWikiName != newWikiName { | |||
isOldWikiExist, oldWikiPath, err = prepareGitPath(gitRepo, oldWikiName) | |||
isOldWikiExist, oldWikiPath, err = prepareGitPath(gitRepo, repo.DefaultWikiBranch, oldWikiName) | |||
if err != nil { | |||
return err | |||
} | |||
@@ -200,7 +201,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
} else { | |||
commitTreeOpts.NoGPGSign = true | |||
} | |||
if hasMasterBranch { | |||
if hasDefaultBranch { | |||
commitTreeOpts.Parents = []string{"HEAD"} | |||
} | |||
@@ -212,7 +213,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
if err := git.Push(gitRepo.Ctx, basePath, git.PushOptions{ | |||
Remote: DefaultRemote, | |||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, DefaultBranch), | |||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, repo.DefaultWikiBranch), | |||
Env: repo_module.FullPushingEnvironment( | |||
doer, | |||
doer, | |||
@@ -269,7 +270,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
if err := git.Clone(ctx, repo.WikiPath(), basePath, git.CloneRepoOptions{ | |||
Bare: true, | |||
Shared: true, | |||
Branch: DefaultBranch, | |||
Branch: repo.DefaultWikiBranch, | |||
}); err != nil { | |||
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err) | |||
return fmt.Errorf("failed to clone repository: %s (%w)", repo.FullName(), err) | |||
@@ -287,7 +288,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
return fmt.Errorf("unable to read HEAD tree to index in: %s %w", basePath, err) | |||
} | |||
found, wikiPath, err := prepareGitPath(gitRepo, wikiName) | |||
found, wikiPath, err := prepareGitPath(gitRepo, repo.DefaultWikiBranch, wikiName) | |||
if err != nil { | |||
return err | |||
} | |||
@@ -331,7 +332,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model | |||
if err := git.Push(gitRepo.Ctx, basePath, git.PushOptions{ | |||
Remote: DefaultRemote, | |||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, DefaultBranch), | |||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, repo.DefaultWikiBranch), | |||
Env: repo_module.FullPushingEnvironment( | |||
doer, | |||
doer, | |||
@@ -358,3 +359,37 @@ func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error { | |||
system_model.RemoveAllWithNotice(ctx, "Delete repository wiki", repo.WikiPath()) | |||
return nil | |||
} | |||
func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, newBranch string) error { | |||
if !git.IsValidRefPattern(newBranch) { | |||
return fmt.Errorf("invalid branch name: %s", newBranch) | |||
} | |||
return db.WithTx(ctx, func(ctx context.Context) error { | |||
repo.DefaultWikiBranch = newBranch | |||
if err := repo_model.UpdateRepositoryCols(ctx, repo, "default_wiki_branch"); err != nil { | |||
return fmt.Errorf("unable to update database: %w", err) | |||
} | |||
gitRepo, err := gitrepo.OpenWikiRepository(ctx, repo) | |||
if errors.Is(err, util.ErrNotExist) { | |||
return nil // no git repo on storage, no need to do anything else | |||
} else if err != nil { | |||
return fmt.Errorf("unable to open repository: %w", err) | |||
} | |||
defer gitRepo.Close() | |||
oldDefBranch, err := gitRepo.GetDefaultBranch() | |||
if err != nil { | |||
return fmt.Errorf("unable to get default branch: %w", err) | |||
} | |||
if oldDefBranch == newBranch { | |||
return nil | |||
} | |||
err = gitRepo.RenameBranch(oldDefBranch, newBranch) | |||
if err != nil { | |||
return fmt.Errorf("unable to rename default branch: %w", err) | |||
} | |||
return nil | |||
}) | |||
} |
@@ -170,7 +170,7 @@ func TestRepository_AddWikiPage(t *testing.T) { | |||
return | |||
} | |||
defer gitRepo.Close() | |||
masterTree, err := gitRepo.GetTree(DefaultBranch) | |||
masterTree, err := gitRepo.GetTree(repo.DefaultWikiBranch) | |||
assert.NoError(t, err) | |||
gitPath := WebPathToGitPath(webPath) | |||
entry, err := masterTree.GetTreeEntryByPath(gitPath) | |||
@@ -215,7 +215,7 @@ func TestRepository_EditWikiPage(t *testing.T) { | |||
// Now need to show that the page has been added: | |||
gitRepo, err := gitrepo.OpenWikiRepository(git.DefaultContext, repo) | |||
assert.NoError(t, err) | |||
masterTree, err := gitRepo.GetTree(DefaultBranch) | |||
masterTree, err := gitRepo.GetTree(repo.DefaultWikiBranch) | |||
assert.NoError(t, err) | |||
gitPath := WebPathToGitPath(webPath) | |||
entry, err := masterTree.GetTreeEntryByPath(gitPath) | |||
@@ -242,7 +242,7 @@ func TestRepository_DeleteWikiPage(t *testing.T) { | |||
return | |||
} | |||
defer gitRepo.Close() | |||
masterTree, err := gitRepo.GetTree(DefaultBranch) | |||
masterTree, err := gitRepo.GetTree(repo.DefaultWikiBranch) | |||
assert.NoError(t, err) | |||
gitPath := WebPathToGitPath("Home") | |||
_, err = masterTree.GetTreeEntryByPath(gitPath) | |||
@@ -280,7 +280,7 @@ func TestPrepareWikiFileName(t *testing.T) { | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
webPath := UserTitleToWebPath("", tt.arg) | |||
existence, newWikiPath, err := prepareGitPath(gitRepo, webPath) | |||
existence, newWikiPath, err := prepareGitPath(gitRepo, repo.DefaultWikiBranch, webPath) | |||
if (err != nil) != tt.wantErr { | |||
assert.NoError(t, err) | |||
return | |||
@@ -312,7 +312,7 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) { | |||
} | |||
defer gitRepo.Close() | |||
existence, newWikiPath, err := prepareGitPath(gitRepo, "Home") | |||
existence, newWikiPath, err := prepareGitPath(gitRepo, "master", "Home") | |||
assert.False(t, existence) | |||
assert.NoError(t, err) | |||
assert.EqualValues(t, "Home.md", newWikiPath) |
@@ -335,6 +335,10 @@ | |||
<label>{{ctx.Locale.Tr "repo.settings.use_internal_wiki"}}</label> | |||
</div> | |||
</div> | |||
<div class="inline field gt-pl-4"> | |||
<label>{{ctx.Locale.Tr "repo.settings.default_wiki_branch_name"}}</label> | |||
<input name="default_wiki_branch" value="{{.Repository.DefaultWikiBranch}}"> | |||
</div> | |||
<div class="field"> | |||
<div class="ui radio checkbox{{if $isExternalWikiGlobalDisabled}} disabled{{end}}"{{if $isExternalWikiGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> | |||
<input class="enable-system-radio" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.Context $.UnitTypeExternalWiki}}checked{{end}}> |
@@ -36,9 +36,8 @@ | |||
</div> | |||
<div class="divider"></div> | |||
<div class="text right"> | |||
<button class="ui primary button"> | |||
{{ctx.Locale.Tr "repo.wiki.save_page"}} | |||
</button> | |||
<a class="ui basic cancel button" href="{{.Link}}">{{ctx.Locale.Tr "cancel"}}</a> | |||
<button class="ui primary button">{{ctx.Locale.Tr "repo.wiki.save_page"}}</button> | |||
</div> | |||
</form> | |||
</div> |
@@ -10,6 +10,7 @@ | |||
{{end}} | |||
</span> | |||
</h2> | |||
{{if .IsRepositoryAdmin}}<div>{{ctx.Locale.Tr "repo.default_branch"}}: {{.Repository.DefaultWikiBranch}}</div>{{end}} | |||
<table class="ui table wiki-pages-list"> | |||
<tbody> | |||
{{range .Pages}} |