gitforge/tests/forgery/fs.go
rgon c956dae73d feat: adds option to force overwrite new branch for /contents route (#12663)
Adds an option "force_overwrite_new_branch" when posting to
/repos/{owner}/{repo}/contents to modify multiple files in a repository.
When user provides both "branch" and "new_branch" options, and
"new_branch" already exists, the "force_overwrite_new_branch" option
allows the user to overwrite the existing branch. Under the hood this
amounts to a "git push --force".

[Issue #12600](https://codeberg.org/forgejo/forgejo/issues/12600)

### Tests for Go changes

- I added test coverage for Go changes...
  - [ ] in their respective `*_test.go` for unit tests.
  - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I ran...
  - [x] `make pr-go` before pushing

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [ ] I did not document these changes and I do not expect someone else to do it.
- [x] API swagger docs updated

### Release notes

- [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

Co-authored-by: Rob Gonnella <rob.gonnella@papayapay.com>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12663
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
2026-06-06 16:45:57 +02:00

112 lines
2.4 KiB
Go

// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package forgery
import (
"fmt"
"io"
"io/fs"
"strings"
"testing/fstest"
"time"
repo_model "forgejo.org/models/repo"
user_model "forgejo.org/models/user"
"forgejo.org/modules/git"
files_service "forgejo.org/services/repository/files"
)
type MapFS = fstest.MapFS
// when a file has one of this mode, it needs specific git handling
// other non-zero modes are rejected
const (
modeSubmodule = fs.ModeNamedPipe // hacky, but
modeSymlink = fs.ModeSymlink
)
func MapFile(data string) *fstest.MapFile {
return &fstest.MapFile{
Data: []byte(data),
}
}
func MapSymlink(target string) *fstest.MapFile {
return &fstest.MapFile{
Data: []byte(target),
Mode: modeSymlink,
}
}
func MapSubmodule(sha string) *fstest.MapFile {
return &fstest.MapFile{
Data: []byte(sha),
Mode: modeSubmodule,
}
}
func initRepo(doer *user_model.User, repo *repo_model.Repository, format git.ObjectFormat, fsys fs.FS, commitMessage string) (string, error) {
t, err := files_service.NewTemporaryUploadRepository(git.DefaultContext, repo)
if err != nil {
return "", err
}
defer t.Close()
if err := t.Init(format.Name()); err != nil {
return "", err
}
if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
var content io.Reader
mode := git.EntryModeBlob
switch d.Type() {
case modeSymlink:
target, err := fs.ReadLink(fsys, path)
if err != nil {
return err
}
content = strings.NewReader(target)
mode = git.EntryModeSymlink
case modeSubmodule:
mode = git.EntryModeCommit
fallthrough
case 0:
f, err := fsys.Open(path)
if err != nil {
return err
}
defer f.Close()
content = f
default:
return fmt.Errorf("unexpected file type in forgery.CreateRepository %s: %s", path, d.Type())
}
// add object to the database
objectHash, err := t.HashObject(content)
if err != nil {
return err
}
// Add the object to the index
return t.AddObjectToIndex(mode.String(), objectHash, path)
}); err != nil {
return "", err
}
treeHash, err := t.WriteTree()
if err != nil {
return "", err
}
now := time.Now()
commitHash, err := t.CommitTreeWithDate("", doer, doer, treeHash, commitMessage, false, now, now)
if err != nil {
return "", err
}
return commitHash, t.Push(doer, commitHash, repo.DefaultBranch, false)
}