mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-31 11:52:10 +00:00
Remove local clones & make hooks run on merge/edit/upload (#6672)
* Add options to git.Clone to make it more capable * Begin the process of removing the local copy and tidy up * Remove Wiki LocalCopy Checkouts * Remove the last LocalRepo helpers * Remove WithTemporaryFile * Enable push-hooks for these routes * Ensure tests cope with hooks Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove Repository.LocalCopyPath() * Move temporary repo to use the standard temporary path * Fix the tests Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove LocalWikiPath * Fix missing remove Signed-off-by: Andrew Thornton <art27@cantab.net> * Use AppURL for Oauth user link (#6894) * Use AppURL for Oauth user link Fix #6843 * Update oauth.go * Update oauth.go * internal/ssh: ignore env command totally (#6825) * ssh: ignore env command totally * Remove commented code Needed fix described in issue #6889 * Escape the commit message on issues update and title in telegram hook (#6901) * update sdk to latest (#6903) * improve description of branch protection (fix #6886) (#6906) The branch protection description text were not quite accurate. * Fix logging documentation (#6904) * ENABLE_MACARON_REDIRECT should be REDIRECT_MACARON_LOG * Allow DISABLE_ROUTER_LOG to be set in the [log] section * [skip ci] Updated translations via Crowdin * Move sdk structs to modules/structs (#6905) * move sdk structs to moduels/structs * fix tests * fix fmt * fix swagger * fix vendor
This commit is contained in:
parent
34eee25bd4
commit
ce8de35334
33 changed files with 1652 additions and 1417 deletions
231
models/wiki.go
231
models/wiki.go
|
@ -6,15 +6,13 @@ package models
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/sync"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
@ -89,34 +87,6 @@ func (repo *Repository) InitWiki() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// LocalWikiPath returns the local wiki repository copy path.
|
||||
func LocalWikiPath() string {
|
||||
if filepath.IsAbs(setting.Repository.Local.LocalWikiPath) {
|
||||
return setting.Repository.Local.LocalWikiPath
|
||||
}
|
||||
return path.Join(setting.AppDataPath, setting.Repository.Local.LocalWikiPath)
|
||||
}
|
||||
|
||||
// LocalWikiPath returns the path to the local wiki repository (?).
|
||||
func (repo *Repository) LocalWikiPath() string {
|
||||
return path.Join(LocalWikiPath(), com.ToStr(repo.ID))
|
||||
}
|
||||
|
||||
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
|
||||
func (repo *Repository) updateLocalWiki() error {
|
||||
// Don't pass branch name here because it fails to clone and
|
||||
// checkout to a specific branch when wiki is an empty repository.
|
||||
var branch = ""
|
||||
if com.IsExist(repo.LocalWikiPath()) {
|
||||
branch = "master"
|
||||
}
|
||||
return UpdateLocalCopyBranch(repo.WikiPath(), repo.LocalWikiPath(), branch)
|
||||
}
|
||||
|
||||
func discardLocalWikiChanges(localPath string) error {
|
||||
return discardLocalRepoBranchChanges(localPath, "master")
|
||||
}
|
||||
|
||||
// nameAllowed checks if a wiki name is allowed
|
||||
func nameAllowed(name string) error {
|
||||
for _, reservedName := range reservedWikiNames {
|
||||
|
@ -132,7 +102,6 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
|
|||
if err = nameAllowed(newWikiName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
|
@ -140,54 +109,113 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
|
|||
return fmt.Errorf("InitWiki: %v", err)
|
||||
}
|
||||
|
||||
localPath := repo.LocalWikiPath()
|
||||
if err = discardLocalWikiChanges(localPath); err != nil {
|
||||
return fmt.Errorf("discardLocalWikiChanges: %v", err)
|
||||
} else if err = repo.updateLocalWiki(); err != nil {
|
||||
return fmt.Errorf("UpdateLocalWiki: %v", err)
|
||||
hasMasterBranch := git.IsBranchExist(repo.WikiPath(), "master")
|
||||
|
||||
basePath, err := CreateTemporaryPath("update-wiki")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer RemoveTemporaryPath(basePath)
|
||||
|
||||
cloneOpts := git.CloneRepoOptions{
|
||||
Bare: true,
|
||||
Shared: true,
|
||||
}
|
||||
|
||||
newWikiPath := path.Join(localPath, WikiNameToFilename(newWikiName))
|
||||
if hasMasterBranch {
|
||||
cloneOpts.Branch = "master"
|
||||
}
|
||||
|
||||
// If not a new file, show perform update not create.
|
||||
if err := git.Clone(repo.WikiPath(), basePath, cloneOpts); err != nil {
|
||||
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
|
||||
return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(basePath)
|
||||
if err != nil {
|
||||
log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
|
||||
return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
|
||||
}
|
||||
|
||||
if hasMasterBranch {
|
||||
if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
|
||||
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
|
||||
return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
newWikiPath := WikiNameToFilename(newWikiName)
|
||||
if isNew {
|
||||
if com.IsExist(newWikiPath) {
|
||||
return ErrWikiAlreadyExist{newWikiPath}
|
||||
filesInIndex, err := gitRepo.LsFiles(newWikiPath)
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
for _, file := range filesInIndex {
|
||||
if file == newWikiPath {
|
||||
return ErrWikiAlreadyExist{newWikiPath}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
oldWikiPath := path.Join(localPath, WikiNameToFilename(oldWikiName))
|
||||
if err := os.Remove(oldWikiPath); err != nil {
|
||||
return fmt.Errorf("Failed to remove %s: %v", oldWikiPath, err)
|
||||
oldWikiPath := WikiNameToFilename(oldWikiName)
|
||||
filesInIndex, err := gitRepo.LsFiles(oldWikiPath)
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
found := false
|
||||
for _, file := range filesInIndex {
|
||||
if file == oldWikiPath {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SECURITY: if new file is a symlink to non-exist critical file,
|
||||
// attack content can be written to the target file (e.g. authorized_keys2)
|
||||
// as a new page operation.
|
||||
// So we want to make sure the symlink is removed before write anything.
|
||||
// The new file we created will be in normal text format.
|
||||
if err = os.RemoveAll(newWikiPath); err != nil {
|
||||
// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
|
||||
|
||||
objectHash, err := gitRepo.HashObject(strings.NewReader(content))
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(newWikiPath, []byte(content), 0666); err != nil {
|
||||
return fmt.Errorf("WriteFile: %v", err)
|
||||
if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(message) == 0 {
|
||||
message = "Update page '" + newWikiName + "'"
|
||||
tree, err := gitRepo.WriteTree()
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, git.PushOptions{
|
||||
|
||||
commitTreeOpts := git.CommitTreeOpts{
|
||||
Message: message,
|
||||
}
|
||||
if hasMasterBranch {
|
||||
commitTreeOpts.Parents = []string{"HEAD"}
|
||||
}
|
||||
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, commitTreeOpts)
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := git.Push(basePath, git.PushOptions{
|
||||
Remote: "origin",
|
||||
Branch: "master",
|
||||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
|
||||
Env: PushingEnvironment(doer, repo),
|
||||
}); err != nil {
|
||||
log.Error("%v", err)
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
|
@ -210,31 +238,74 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error)
|
|||
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
localPath := repo.LocalWikiPath()
|
||||
if err = discardLocalWikiChanges(localPath); err != nil {
|
||||
return fmt.Errorf("discardLocalWikiChanges: %v", err)
|
||||
} else if err = repo.updateLocalWiki(); err != nil {
|
||||
return fmt.Errorf("UpdateLocalWiki: %v", err)
|
||||
if err = repo.InitWiki(); err != nil {
|
||||
return fmt.Errorf("InitWiki: %v", err)
|
||||
}
|
||||
|
||||
filename := path.Join(localPath, WikiNameToFilename(wikiName))
|
||||
basePath, err := CreateTemporaryPath("update-wiki")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer RemoveTemporaryPath(basePath)
|
||||
|
||||
if err := os.Remove(filename); err != nil {
|
||||
return fmt.Errorf("Failed to remove %s: %v", filename, err)
|
||||
if err := git.Clone(repo.WikiPath(), basePath, git.CloneRepoOptions{
|
||||
Bare: true,
|
||||
Shared: true,
|
||||
Branch: "master",
|
||||
}); err != nil {
|
||||
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
|
||||
return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(basePath)
|
||||
if err != nil {
|
||||
log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
|
||||
return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
|
||||
}
|
||||
|
||||
if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil {
|
||||
log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err)
|
||||
return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
|
||||
}
|
||||
|
||||
wikiPath := WikiNameToFilename(wikiName)
|
||||
filesInIndex, err := gitRepo.LsFiles(wikiPath)
|
||||
found := false
|
||||
for _, file := range filesInIndex {
|
||||
if file == wikiPath {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
err := gitRepo.RemoveFilesFromIndex(wikiPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
|
||||
|
||||
tree, err := gitRepo.WriteTree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message := "Delete page '" + wikiName + "'"
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
||||
Committer: doer.NewGitSig(),
|
||||
Message: message,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, git.PushOptions{
|
||||
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), tree, git.CommitTreeOpts{
|
||||
Message: message,
|
||||
Parents: []string{"HEAD"},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := git.Push(basePath, git.PushOptions{
|
||||
Remote: "origin",
|
||||
Branch: "master",
|
||||
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
|
||||
Env: PushingEnvironment(doer, repo),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue