Merge remote-tracking branch 'upstream/main' into feat/api-project-boards

This commit is contained in:
dineshsalunke
2024-01-17 19:55:54 +05:30
874 changed files with 10728 additions and 7872 deletions

View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
user_model "code.gitea.io/gitea/models/user"
git "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
@@ -114,9 +115,13 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
}
creator := user_model.NewActionsUser()
commitID, err := git.NewIDFromString(sha)
if err != nil {
return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err)
}
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
Repo: repo,
SHA: sha,
SHA: commitID,
Creator: creator,
CommitStatus: &git_model.CommitStatus{
SHA: sha,

View File

@@ -117,6 +117,9 @@ func notify(ctx context.Context, input *notifyInput) error {
return nil
}
if unit_model.TypeActions.UnitGlobalDisabled() {
if err := actions_model.CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
log.Error("CleanRepoScheduleTasks: %v", err)
}
return nil
}
if err := input.Repo.LoadUnits(ctx); err != nil {
@@ -153,7 +156,11 @@ func notify(ctx context.Context, input *notifyInput) error {
var detectedWorkflows []*actions_module.DetectedWorkflow
actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig()
workflows, schedules, err := actions_module.DetectWorkflows(gitRepo, commit, input.Event, input.Payload)
workflows, schedules, err := actions_module.DetectWorkflows(gitRepo, commit,
input.Event,
input.Payload,
input.Event == webhook_module.HookEventPush && input.Ref == input.Repo.DefaultBranch,
)
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
@@ -167,7 +174,7 @@ func notify(ctx context.Context, input *notifyInput) error {
continue
}
if wf.TriggerEvent != actions_module.GithubEventPullRequestTarget {
if wf.TriggerEvent.Name != actions_module.GithubEventPullRequestTarget {
detectedWorkflows = append(detectedWorkflows, wf)
}
}
@@ -180,7 +187,7 @@ func notify(ctx context.Context, input *notifyInput) error {
if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %w", err)
}
baseWorkflows, _, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload)
baseWorkflows, _, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload, false)
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
@@ -188,14 +195,14 @@ func notify(ctx context.Context, input *notifyInput) error {
log.Trace("repo %s with commit %s couldn't find pull_request_target workflows", input.Repo.RepoPath(), baseCommit.ID)
} else {
for _, wf := range baseWorkflows {
if wf.TriggerEvent == actions_module.GithubEventPullRequestTarget {
if wf.TriggerEvent.Name == actions_module.GithubEventPullRequestTarget {
detectedWorkflows = append(detectedWorkflows, wf)
}
}
}
}
if err := handleSchedules(ctx, schedules, commit, input); err != nil {
if err := handleSchedules(ctx, schedules, commit, input, ref); err != nil {
return err
}
@@ -265,7 +272,7 @@ func handleWorkflows(
IsForkPullRequest: isForkPullRequest,
Event: input.Event,
EventPayload: string(p),
TriggerEvent: dwf.TriggerEvent,
TriggerEvent: dwf.TriggerEvent.Name,
Status: actions_model.StatusWaiting,
}
if need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer); err != nil {
@@ -289,6 +296,7 @@ func handleWorkflows(
run.RepoID,
run.Ref,
run.WorkflowID,
run.Event,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
@@ -399,6 +407,7 @@ func handleSchedules(
detectedWorkflows []*actions_module.DetectedWorkflow,
commit *git.Commit,
input *notifyInput,
ref string,
) error {
branch, err := commit.GetBranchName()
if err != nil {
@@ -413,8 +422,8 @@ func handleSchedules(
log.Error("CountSchedules: %v", err)
return err
} else if count > 0 {
if err := actions_model.DeleteScheduleTaskByRepo(ctx, input.Repo.ID); err != nil {
log.Error("DeleteCronTaskByRepo: %v", err)
if err := actions_model.CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
log.Error("CleanRepoScheduleTasks: %v", err)
}
}
@@ -448,26 +457,13 @@ func handleSchedules(
OwnerID: input.Repo.OwnerID,
WorkflowID: dwf.EntryName,
TriggerUserID: input.Doer.ID,
Ref: input.Ref,
Ref: ref,
CommitSHA: commit.ID.String(),
Event: input.Event,
EventPayload: string(p),
Specs: schedules,
Content: dwf.Content,
}
// cancel running jobs if the event is push
if run.Event == webhook_module.HookEventPush {
// cancel running jobs of the same workflow
if err := actions_model.CancelRunningJobs(
ctx,
run.RepoID,
run.Ref,
run.WorkflowID,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
}
crons = append(crons, run)
}

View File

@@ -59,6 +59,7 @@ func startTasks(ctx context.Context) error {
row.RepoID,
row.Schedule.Ref,
row.Schedule.WorkflowID,
webhook_module.HookEventSchedule,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
@@ -113,6 +114,7 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule)
CommitSHA: cron.CommitSHA,
Event: cron.Event,
EventPayload: cron.EventPayload,
TriggerEvent: string(webhook_module.HookEventSchedule),
ScheduleID: cron.ID,
Status: actions_model.StatusWaiting,
}

View File

@@ -36,9 +36,10 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
topicBranch = opts.GitPushOptions["topic"]
_, forcePush = opts.GitPushOptions["force-push"]
objectFormat, _ := gitRepo.GetObjectFormat()
for i := range opts.OldCommitIDs {
if opts.NewCommitIDs[i] == git.EmptySHA {
if opts.NewCommitIDs[i] == objectFormat.EmptyObjectID().String() {
results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i],
@@ -148,10 +149,11 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
objectFormat, _ := gitRepo.GetObjectFormat()
results = append(results, private.HookProcReceiveRefResult{
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
OldOID: git.EmptySHA,
OldOID: objectFormat.EmptyObjectID().String(),
NewOID: opts.NewCommitIDs[i],
})
continue

View File

@@ -143,7 +143,10 @@ Loop:
case always:
break Loop
case pubkey:
keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
OwnerID: u.ID,
IncludeSubKeys: true,
})
if err != nil {
return false, "", nil, err
}
@@ -179,7 +182,10 @@ Loop:
case always:
break Loop
case pubkey:
keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
OwnerID: u.ID,
IncludeSubKeys: true,
})
if err != nil {
return false, "", nil, err
}
@@ -232,7 +238,10 @@ Loop:
case always:
break Loop
case pubkey:
keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
OwnerID: u.ID,
IncludeSubKeys: true,
})
if err != nil {
return false, "", nil, err
}
@@ -294,7 +303,10 @@ Loop:
case always:
break Loop
case pubkey:
keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
OwnerID: u.ID,
IncludeSubKeys: true,
})
if err != nil {
return false, "", nil, err
}

View File

@@ -33,7 +33,7 @@ func DeletePublicKey(ctx context.Context, doer *user_model.User, id int64) (err
}
defer committer.Close()
if err = asymkey_model.DeletePublicKeys(dbCtx, id); err != nil {
if _, err = db.DeleteByID[asymkey_model.PublicKey](dbCtx, id); err != nil {
return err
}

View File

@@ -37,14 +37,14 @@ func TestCheckAuthToken(t *testing.T) {
})
t.Run("Expired", func(t *testing.T) {
timeutil.Set(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
assert.NoError(t, err)
assert.NotNil(t, at)
assert.NotEmpty(t, token)
timeutil.Unset()
timeutil.MockUnset()
at2, err := CheckAuthToken(db.DefaultContext, at.ID+":"+token)
assert.ErrorIs(t, err, ErrAuthTokenExpired)
@@ -83,15 +83,15 @@ func TestCheckAuthToken(t *testing.T) {
func TestRegenerateAuthToken(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
timeutil.Set(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
defer timeutil.Unset()
timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
defer timeutil.MockUnset()
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
assert.NoError(t, err)
assert.NotNil(t, at)
assert.NotEmpty(t, token)
timeutil.Set(time.Date(2023, 1, 1, 0, 0, 1, 0, time.UTC))
timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 1, 0, time.UTC))
at2, token2, err := RegenerateAuthToken(db.DefaultContext, at)
assert.NoError(t, err)

View File

@@ -14,6 +14,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/auth/source/oauth2"
@@ -62,14 +63,19 @@ func (o *OAuth2) Name() string {
// representing whether the token exists or not
func parseToken(req *http.Request) (string, bool) {
_ = req.ParseForm()
// Check token.
if token := req.Form.Get("token"); token != "" {
return token, true
}
// Check access token.
if token := req.Form.Get("access_token"); token != "" {
return token, true
if !setting.DisableQueryAuthToken {
// Check token.
if token := req.Form.Get("token"); token != "" {
return token, true
}
// Check access token.
if token := req.Form.Get("access_token"); token != "" {
return token, true
}
} else if req.Form.Get("token") != "" || req.Form.Get("access_token") != "" {
log.Warn("API token sent in query string but DISABLE_QUERY_AUTH_TOKEN=true")
}
// check header token
if auHead := req.Header.Get("Authorization"); auHead != "" {
auths := strings.Fields(auHead)

View File

@@ -158,6 +158,7 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api
BlockOnOfficialReviewRequests: bp.BlockOnOfficialReviewRequests,
BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch,
DismissStaleApprovals: bp.DismissStaleApprovals,
IgnoreStaleApprovals: bp.IgnoreStaleApprovals,
RequireSignedCommits: bp.RequireSignedCommits,
ProtectedFilePatterns: bp.ProtectedFilePatterns,
UnprotectedFilePatterns: bp.UnprotectedFilePatterns,
@@ -308,40 +309,38 @@ func ToTeam(ctx context.Context, team *organization.Team, loadOrg ...bool) (*api
// ToTeams convert models.Team list to api.Team list
func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([]*api.Team, error) {
if len(teams) == 0 || teams[0] == nil {
return nil, nil
}
cache := make(map[int64]*api.Organization)
apiTeams := make([]*api.Team, len(teams))
for i := range teams {
if err := teams[i].LoadUnits(ctx); err != nil {
apiTeams := make([]*api.Team, 0, len(teams))
for _, t := range teams {
if err := t.LoadUnits(ctx); err != nil {
return nil, err
}
apiTeams[i] = &api.Team{
ID: teams[i].ID,
Name: teams[i].Name,
Description: teams[i].Description,
IncludesAllRepositories: teams[i].IncludesAllRepositories,
CanCreateOrgRepo: teams[i].CanCreateOrgRepo,
Permission: teams[i].AccessMode.String(),
Units: teams[i].GetUnitNames(),
UnitsMap: teams[i].GetUnitsMap(),
apiTeam := &api.Team{
ID: t.ID,
Name: t.Name,
Description: t.Description,
IncludesAllRepositories: t.IncludesAllRepositories,
CanCreateOrgRepo: t.CanCreateOrgRepo,
Permission: t.AccessMode.String(),
Units: t.GetUnitNames(),
UnitsMap: t.GetUnitsMap(),
}
if loadOrgs {
apiOrg, ok := cache[teams[i].OrgID]
apiOrg, ok := cache[t.OrgID]
if !ok {
org, err := organization.GetOrgByID(ctx, teams[i].OrgID)
org, err := organization.GetOrgByID(ctx, t.OrgID)
if err != nil {
return nil, err
}
apiOrg = ToOrganization(ctx, org)
cache[teams[i].OrgID] = apiOrg
cache[t.OrgID] = apiOrg
}
apiTeams[i].Organization = apiOrg
apiTeam.Organization = apiOrg
}
apiTeams = append(apiTeams, apiTeam)
}
return apiTeams, nil
}

View File

@@ -19,12 +19,12 @@ import (
func TestToCommitMeta(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
sha1, _ := git.NewIDFromString("0000000000000000000000000000000000000000")
sha1 := git.Sha1ObjectFormat
signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)}
tag := &git.Tag{
Name: "Test Tag",
ID: sha1,
Object: sha1,
ID: sha1.EmptyObjectID(),
Object: sha1.EmptyObjectID(),
Type: "Test Type",
Tagger: signature,
Message: "Test Message",
@@ -34,8 +34,8 @@ func TestToCommitMeta(t *testing.T) {
assert.NotNil(t, commitMeta)
assert.EqualValues(t, &api.CommitMeta{
SHA: "0000000000000000000000000000000000000000",
URL: util.URLJoin(headRepo.APIURL(), "git/commits", "0000000000000000000000000000000000000000"),
SHA: sha1.EmptyObjectID().String(),
URL: util.URLJoin(headRepo.APIURL(), "git/commits", sha1.EmptyObjectID().String()),
Created: time.Unix(0, 0),
}, commitMeta)
}

View File

@@ -21,15 +21,9 @@ func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model.
r.Reviewer = user_model.NewGhostUser()
}
apiTeam, err := ToTeam(ctx, r.ReviewerTeam)
if err != nil {
return nil, err
}
result := &api.PullReview{
ID: r.ID,
Reviewer: ToUser(ctx, r.Reviewer, doer),
ReviewerTeam: apiTeam,
State: api.ReviewStateUnknown,
Body: r.Content,
CommitID: r.CommitID,
@@ -43,6 +37,14 @@ func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model.
HTMLPullURL: r.Issue.HTMLURL(),
}
if r.ReviewerTeam != nil {
var err error
result.ReviewerTeam, err = ToTeam(ctx, r.ReviewerTeam)
if err != nil {
return nil, err
}
}
switch r.Type {
case issues_model.ReviewTypeApprove:
result.State = api.ReviewStateApproved

View File

@@ -8,6 +8,7 @@ import (
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
@@ -133,7 +134,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
return nil
}
numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false})
numReleases, _ := db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{
IncludeDrafts: false,
IncludeTags: false,
RepoID: repo.ID,
})
mirrorInterval := ""
var mirrorUpdated time.Time

View File

@@ -84,13 +84,15 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
t.lock.Unlock()
defer func() {
taskStatusTable.Stop(t.Name)
if err := recover(); err != nil {
// Recover a panic within the
combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
log.Error("PANIC whilst running task: %s Value: %v", t.Name, combinedErr)
}
}()
graceful.GetManager().RunWithShutdownContext(func(baseCtx context.Context) {
defer func() {
if err := recover(); err != nil {
// Recover a panic within the execution of the task.
combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
log.Error("PANIC whilst running task: %s Value: %v", t.Name, combinedErr)
}
}()
// Store the time of this run, before the function is executed, so it
// matches the behavior of what the cron library does.
t.lock.Lock()

View File

@@ -4,6 +4,7 @@
package cron
import (
"sort"
"strconv"
"testing"
@@ -22,9 +23,10 @@ func TestAddTaskToScheduler(t *testing.T) {
},
})
assert.NoError(t, err)
assert.Len(t, scheduler.Jobs(), 1)
assert.Equal(t, "task 1", scheduler.Jobs()[0].Tags()[0])
assert.Equal(t, "5 4 * * *", scheduler.Jobs()[0].Tags()[1])
jobs := scheduler.Jobs()
assert.Len(t, jobs, 1)
assert.Equal(t, "task 1", jobs[0].Tags()[0])
assert.Equal(t, "5 4 * * *", jobs[0].Tags()[1])
// with seconds
err = addTaskToScheduler(&Task{
@@ -34,9 +36,13 @@ func TestAddTaskToScheduler(t *testing.T) {
},
})
assert.NoError(t, err)
assert.Len(t, scheduler.Jobs(), 2)
assert.Equal(t, "task 2", scheduler.Jobs()[1].Tags()[0])
assert.Equal(t, "30 5 4 * * *", scheduler.Jobs()[1].Tags()[1])
jobs = scheduler.Jobs() // the item order is not guaranteed, so we need to sort it before "assert"
sort.Slice(jobs, func(i, j int) bool {
return jobs[i].Tags()[0] < jobs[j].Tags()[0]
})
assert.Len(t, jobs, 2)
assert.Equal(t, "task 2", jobs[1].Tags()[0])
assert.Equal(t, "30 5 4 * * *", jobs[1].Tags()[1])
}
func TestScheduleHasSeconds(t *testing.T) {

View File

@@ -21,13 +21,6 @@ import (
"gitea.com/go-chi/binding"
)
// _______________________________________ _________.______________________ _______________.___.
// \______ \_ _____/\______ \_____ \ / _____/| \__ ___/\_____ \\______ \__ | |
// | _/| __)_ | ___// | \ \_____ \ | | | | / | \| _// | |
// | | \| \ | | / | \/ \| | | | / | \ | \\____ |
// |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
// \/ \/ \/ \/ \/ \/ \/
// CreateRepoForm form for creating repository
type CreateRepoForm struct {
UID int64 `binding:"Required"`
@@ -50,9 +43,9 @@ type CreateRepoForm struct {
Avatar bool
Labels bool
ProtectedBranch bool
TrustModel string
ForkSingleBranch string
ObjectFormatName string
}
// Validate validates the fields
@@ -211,6 +204,7 @@ type ProtectBranchForm struct {
BlockOnOfficialReviewRequests bool
BlockOnOutdatedBranch bool
DismissStaleApprovals bool
IgnoreStaleApprovals bool
RequireSignedCommits bool
ProtectedFilePatterns string
UnprotectedFilePatterns string

View File

@@ -365,7 +365,7 @@ func (f *EditVariableForm) Validate(req *http.Request, errs binding.Errors) bind
// NewAccessTokenForm form for creating access token
type NewAccessTokenForm struct {
Name string `binding:"Required;MaxSize(255)"`
Name string `binding:"Required;MaxSize(255)" locale:"settings.token_name"`
Scope []string
}

View File

@@ -285,15 +285,15 @@ type DiffInline struct {
// DiffInlineWithUnicodeEscape makes a DiffInline with hidden unicode characters escaped
func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) DiffInline {
status, content := charset.EscapeControlHTML(string(s), locale)
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
status, content := charset.EscapeControlHTML(s, locale)
return DiffInline{EscapeStatus: status, Content: content}
}
// DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped
func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline {
highlighted, _ := highlight.Code(fileName, language, code)
status, content := charset.EscapeControlHTML(highlighted, locale)
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
return DiffInline{EscapeStatus: status, Content: content}
}
// GetComputedInlineDiffFor computes inline diff for the given line.
@@ -1115,10 +1115,15 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
}
cmdDiff := git.NewCommand(gitRepo.Ctx)
if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return nil, err
}
if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String()) && commit.ParentCount() == 0 {
cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M").
AddArguments(opts.WhitespaceBehavior...).
AddArguments("4b825dc642cb6eb9a060e54bf8d69288fbee4904"). // append empty tree ref
AddDynamicArguments(objectFormat.EmptyTree().String()).
AddDynamicArguments(opts.AfterCommitID)
} else {
actualBeforeCommitID := opts.BeforeCommitID
@@ -1224,8 +1229,8 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
}
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA {
diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() {
diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
if err != nil && strings.Contains(err.Error(), "no merge base") {
@@ -1256,12 +1261,15 @@ func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStat
separator = ".."
}
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA {
diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID}
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return nil, err
}
var err error
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() {
diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
}
_, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
if err != nil && strings.Contains(err.Error(), "no merge base") {

View File

@@ -93,10 +93,10 @@ func (hcd *highlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB
highlightCodeA, _ := highlight.Code(filename, language, codeA)
highlightCodeB, _ := highlight.Code(filename, language, codeB)
highlightCodeA = hcd.convertToPlaceholders(highlightCodeA)
highlightCodeB = hcd.convertToPlaceholders(highlightCodeB)
convertedCodeA := hcd.convertToPlaceholders(string(highlightCodeA))
convertedCodeB := hcd.convertToPlaceholders(string(highlightCodeB))
diffs := diffMatchPatch.DiffMain(highlightCodeA, highlightCodeB, true)
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
for i := range diffs {

View File

@@ -130,3 +130,25 @@ func (r *indexerNotifier) IssueChangeTitle(ctx context.Context, doer *user_model
func (r *indexerNotifier) IssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}
func (r *indexerNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}
func (r *indexerNotifier) IssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}
func (r *indexerNotifier) IssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}
func (r *indexerNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
addedLabels, removedLabels []*issues_model.Label,
) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}
func (r *indexerNotifier) IssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}

View File

@@ -18,8 +18,12 @@ func TestDeleteNotPassedAssignee(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// Fake issue with assignees
issue, err := issues_model.GetIssueWithAttrsByID(db.DefaultContext, 1)
issue, err := issues_model.GetIssueByID(db.DefaultContext, 1)
assert.NoError(t, err)
err = issue.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.Len(t, issue.Assignees, 1)
user1, err := user_model.GetUserByID(db.DefaultContext, 1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him

View File

@@ -232,7 +232,7 @@ func BatchHandler(ctx *context.Context) {
return
}
if accessible {
_, err := git_model.NewLFSMetaObject(ctx, &git_model.LFSMetaObject{Pointer: p, RepositoryID: repository.ID})
_, err := git_model.NewLFSMetaObject(ctx, repository.ID, p)
if err != nil {
log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err)
writeStatus(ctx, http.StatusInternalServerError)
@@ -325,7 +325,7 @@ func UploadHandler(ctx *context.Context) {
log.Error("Error putting LFS MetaObject [%s] into content store. Error: %v", p.Oid, err)
return err
}
_, err := git_model.NewLFSMetaObject(ctx, &git_model.LFSMetaObject{Pointer: p, RepositoryID: repository.ID})
_, err := git_model.NewLFSMetaObject(ctx, repository.ID, p)
return err
}

View File

@@ -220,9 +220,11 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
// This is the body of the new issue or comment, not the mail body
body, err := markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
URLPrefix: ctx.Issue.Repo.HTMLURL(),
Metas: ctx.Issue.Repo.ComposeMetas(ctx),
Ctx: ctx,
Links: markup.Links{
Base: ctx.Issue.Repo.HTMLURL(),
},
Metas: ctx.Issue.Repo.ComposeMetas(ctx),
}, ctx.Content)
if err != nil {
return nil, err

View File

@@ -57,9 +57,11 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo
var err error
rel.RenderedNote, err = markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
URLPrefix: rel.Repo.Link(),
Metas: rel.Repo.ComposeMetas(ctx),
Ctx: ctx,
Links: markup.Links{
Base: rel.Repo.HTMLURL(),
},
Metas: rel.Repo.ComposeMetas(ctx),
}, rel.Note)
if err != nil {
log.Error("markdown.RenderString(%d): %v", rel.RepoID, err)

View File

@@ -48,16 +48,18 @@ func CheckAndEnsureSafePR(pr *base.PullRequest, commonCloneBaseURL string, g bas
}
// SECURITY: SHAs Must be a SHA
if pr.MergeCommitSHA != "" && !git.IsValidSHAPattern(pr.MergeCommitSHA) {
// FIXME: hash only a SHA1
CommitType := git.Sha1ObjectFormat
if pr.MergeCommitSHA != "" && !CommitType.IsValid(pr.MergeCommitSHA) {
WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA)
pr.MergeCommitSHA = ""
}
if pr.Head.SHA != "" && !git.IsValidSHAPattern(pr.Head.SHA) {
if pr.Head.SHA != "" && !CommitType.IsValid(pr.Head.SHA) {
WarnAndNotice("PR #%d in %s has invalid HeadSHA: %s", pr.Number, g, pr.Head.SHA)
pr.Head.SHA = ""
valid = false
}
if pr.Base.SHA != "" && !git.IsValidSHAPattern(pr.Base.SHA) {
if pr.Base.SHA != "" && !CommitType.IsValid(pr.Base.SHA) {
WarnAndNotice("PR #%d in %s has invalid BaseSHA: %s", pr.Number, g, pr.Base.SHA)
pr.Base.SHA = ""
valid = false

View File

@@ -7,7 +7,7 @@ package migrations
import (
"errors"
"github.com/google/go-github/v53/github"
"github.com/google/go-github/v57/github"
)
// ErrRepoNotCreated returns the error that repository not created

View File

@@ -862,7 +862,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
line := comment.Line
if line != 0 {
comment.Position = 1
} else {
} else if comment.DiffHunk != "" {
_, _, line, _ = git.ParseDiffHunkString(comment.DiffHunk)
}
@@ -892,7 +892,8 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
comment.UpdatedAt = comment.CreatedAt
}
if !git.IsValidSHAPattern(comment.CommitID) {
objectFormat, _ := g.gitRepo.GetObjectFormat()
if !objectFormat.IsValid(comment.CommitID) {
log.Warn("Invalid comment CommitID[%s] on comment[%d] in PR #%d of %s/%s replaced with %s", comment.CommitID, pr.Index, g.repoOwner, g.repoName, headCommitID)
comment.CommitID = headCommitID
}

View File

@@ -65,16 +65,16 @@ func TestGiteaUploadRepo(t *testing.T) {
assert.True(t, repo.HasWiki())
assert.EqualValues(t, repo_model.RepositoryReady, repo.Status)
milestones, _, err := issues_model.GetMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
RepoID: repo.ID,
State: structs.StateOpen,
milestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: repo.ID,
IsClosed: util.OptionalBoolFalse,
})
assert.NoError(t, err)
assert.Len(t, milestones, 1)
milestones, _, err = issues_model.GetMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
RepoID: repo.ID,
State: structs.StateClosed,
milestones, err = db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: repo.ID,
IsClosed: util.OptionalBoolTrue,
})
assert.NoError(t, err)
assert.Empty(t, milestones)
@@ -83,22 +83,24 @@ func TestGiteaUploadRepo(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, labels, 12)
releases, err := repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{
releases, err := db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{
ListOptions: db.ListOptions{
PageSize: 10,
Page: 0,
},
IncludeTags: true,
RepoID: repo.ID,
})
assert.NoError(t, err)
assert.Len(t, releases, 8)
releases, err = repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{
releases, err = db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{
ListOptions: db.ListOptions{
PageSize: 10,
Page: 0,
},
IncludeTags: false,
RepoID: repo.ID,
})
assert.NoError(t, err)
assert.Len(t, releases, 1)
@@ -232,7 +234,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
//
fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
baseRef := "master"
assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false))
assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName))
err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644))

View File

@@ -20,7 +20,7 @@ import (
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/structs"
"github.com/google/go-github/v53/github"
"github.com/google/go-github/v57/github"
"golang.org/x/oauth2"
)
@@ -135,7 +135,7 @@ func (g *GithubDownloaderV3) LogString() string {
func (g *GithubDownloaderV3) addClient(client *http.Client, baseURL string) {
githubClient := github.NewClient(client)
if baseURL != "https://github.com" {
githubClient, _ = github.NewEnterpriseClient(baseURL, baseURL, client)
githubClient, _ = github.NewClient(client).WithEnterpriseURLs(baseURL, baseURL)
}
g.clients = append(g.clients, githubClient)
g.rates = append(g.rates, nil)
@@ -168,14 +168,14 @@ func (g *GithubDownloaderV3) waitAndPickClient() {
err := g.RefreshRate()
if err != nil {
log.Error("g.getClient().RateLimits: %s", err)
log.Error("g.getClient().RateLimit.Get: %s", err)
}
}
}
// RefreshRate update the current rate (doesn't count in rate limit)
func (g *GithubDownloaderV3) RefreshRate() error {
rates, _, err := g.getClient().RateLimits(g.ctx)
rates, _, err := g.getClient().RateLimit.Get(g.ctx)
if err != nil {
// if rate limit is not enabled, ignore it
if strings.Contains(err.Error(), "404") {

View File

@@ -55,19 +55,36 @@ func (f *GitlabDownloaderFactory) GitServiceType() structs.GitServiceType {
return structs.GitlabService
}
type gitlabIIDResolver struct {
maxIssueIID int64
frozen bool
}
func (r *gitlabIIDResolver) recordIssueIID(issueIID int) {
if r.frozen {
panic("cannot record issue IID after pull request IID generation has started")
}
r.maxIssueIID = max(r.maxIssueIID, int64(issueIID))
}
func (r *gitlabIIDResolver) generatePullRequestNumber(mrIID int) int64 {
r.frozen = true
return r.maxIssueIID + int64(mrIID)
}
// GitlabDownloader implements a Downloader interface to get repository information
// from gitlab via go-gitlab
// - issueCount is incremented in GetIssues() to ensure PR and Issue numbers do not overlap,
// because Gitlab has individual Issue and Pull Request numbers.
type GitlabDownloader struct {
base.NullDownloader
ctx context.Context
client *gitlab.Client
baseURL string
repoID int
repoName string
issueCount int64
maxPerPage int
ctx context.Context
client *gitlab.Client
baseURL string
repoID int
repoName string
iidResolver gitlabIIDResolver
maxPerPage int
}
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
@@ -450,8 +467,8 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er
Context: gitlabIssueContext{IsMergeRequest: false},
})
// increment issueCount, to be used in GetPullRequests()
g.issueCount++
// record the issue IID, to be used in GetPullRequests()
g.iidResolver.recordIssueIID(issue.IID)
}
return allIssues, len(issues) < perPage, nil
@@ -607,8 +624,8 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
awardPage++
}
// Add the PR ID to the Issue Count because PR and Issues share ID space in Gitea
newPRNumber := g.issueCount + int64(pr.IID)
// Generate new PR Numbers by the known Issue Numbers, because they share the same number space in Gitea, but they are independent in Gitlab
newPRNumber := g.iidResolver.generatePullRequestNumber(pr.IID)
allPRs = append(allPRs, &base.PullRequest{
Title: pr.Title,

View File

@@ -516,3 +516,20 @@ func TestAwardsToReactions(t *testing.T) {
},
}, reactions)
}
func TestGitlabIIDResolver(t *testing.T) {
r := gitlabIIDResolver{}
r.recordIssueIID(1)
r.recordIssueIID(2)
r.recordIssueIID(3)
r.recordIssueIID(2)
assert.EqualValues(t, 4, r.generatePullRequestNumber(1))
assert.EqualValues(t, 13, r.generatePullRequestNumber(10))
assert.Panics(t, func() {
r := gitlabIIDResolver{}
r.recordIssueIID(1)
assert.EqualValues(t, 2, r.generatePullRequestNumber(1))
r.recordIssueIID(3) // the generation procedure has been started, it shouldn't accept any new issue IID, so it panics
})
}

View File

@@ -478,9 +478,13 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err)
continue
}
objectFormat, err := git.GetObjectFormatOfRepo(ctx, m.Repo.RepoPath())
if err != nil {
log.Error("SyncMirrors [repo: %-v]: unable to GetHashTypeOfRepo: %v", m.Repo, err)
}
notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{
RefFullName: result.refName,
OldCommitID: git.EmptySHA,
OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: commitID,
}, repo_module.NewPushCommits())
notify_service.SyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName, commitID)

View File

@@ -12,6 +12,7 @@ import (
"strings"
"time"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/lfs"
@@ -93,8 +94,9 @@ func SyncPushMirror(ctx context.Context, mirrorID int64) bool {
log.Error("PANIC whilst syncPushMirror[%d] Panic: %v\nStacktrace: %s", mirrorID, err, log.Stack(2))
}()
m, err := repo_model.GetPushMirror(ctx, repo_model.PushMirrorOptions{ID: mirrorID})
if err != nil {
// TODO: Handle "!exist" better
m, exist, err := db.GetByID[repo_model.PushMirror](ctx, mirrorID)
if err != nil || !exist {
log.Error("GetPushMirrorByID [%d]: %v", mirrorID, err)
return false
}

View File

@@ -82,10 +82,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error {
}
for _, pf := range pfs {
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -157,12 +154,11 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, IndexFilename, fmt.Sprintf("%s|%s|%s", branch, repository, architecture))
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
} else if pf == nil {
return nil
}
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
return packages_model.DeleteFileByID(ctx, pf.ID)
return packages_service.DeletePackageFile(ctx, pf)
}
// Cache data needed for all repository files

View File

@@ -267,11 +267,11 @@ func alterRepositoryContent(ctx context.Context, doer *user_model.User, repo *re
defer t.Close()
var lastCommitID string
if err := t.Clone(repo.DefaultBranch); err != nil {
if err := t.Clone(repo.DefaultBranch, true); err != nil {
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return err
}
if err := t.Init(); err != nil {
if err := t.Init(repo.ObjectFormatName); err != nil {
return err
}
} else {

View File

@@ -15,6 +15,7 @@ import (
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
alpine_service "code.gitea.io/gitea/services/packages/alpine"
cargo_service "code.gitea.io/gitea/services/packages/cargo"
container_service "code.gitea.io/gitea/services/packages/container"
debian_service "code.gitea.io/gitea/services/packages/debian"
@@ -122,6 +123,10 @@ func ExecuteCleanupRules(outerCtx context.Context) error {
if err := debian_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
return fmt.Errorf("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
}
} else if pcr.Type == packages_model.TypeAlpine {
if err := alpine_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
return fmt.Errorf("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
}
}
}
return nil

View File

@@ -11,6 +11,7 @@ import (
container_model "code.gitea.io/gitea/models/packages/container"
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
digest "github.com/opencontainers/go-digest"
)
@@ -47,10 +48,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e
}
for _, pf := range pfs {
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}

View File

@@ -67,7 +67,7 @@ func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, err
}
func generateKeypair() (string, string, error) {
e, err := openpgp.NewEntity(setting.AppName, "Debian Registry", "", nil)
e, err := openpgp.NewEntity("", "Debian Registry", "", nil)
if err != nil {
return "", "", err
}
@@ -110,10 +110,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error {
}
for _, pf := range pfs {
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -181,12 +178,11 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, key)
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
} else if pf == nil {
continue
}
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -286,12 +282,11 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, distribution)
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
} else if pf == nil {
continue
}
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}

View File

@@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/json"
packages_module "code.gitea.io/gitea/modules/packages"
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
@@ -68,7 +67,7 @@ func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, err
}
func generateKeypair() (string, string, error) {
e, err := openpgp.NewEntity(setting.AppName, "RPM Registry", "", nil)
e, err := openpgp.NewEntity("", "RPM Registry", "", nil)
if err != nil {
return "", "", err
}
@@ -127,16 +126,17 @@ type packageData struct {
type packageCache = map[*packages_model.PackageFile]*packageData
// BuildSpecificRepositoryFiles builds metadata files for the repository
func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
func BuildRepositoryFiles(ctx context.Context, ownerID int64, compositeKey string) error {
pv, err := GetOrCreateRepositoryVersion(ctx, ownerID)
if err != nil {
return err
}
pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
OwnerID: ownerID,
PackageType: packages_model.TypeRpm,
Query: "%.rpm",
OwnerID: ownerID,
PackageType: packages_model.TypeRpm,
Query: "%.rpm",
CompositeKey: compositeKey,
})
if err != nil {
return err
@@ -149,10 +149,7 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
return err
}
for _, pf := range pfs {
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
return err
}
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -198,15 +195,15 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
cache[pf] = pd
}
primary, err := buildPrimary(ctx, pv, pfs, cache)
primary, err := buildPrimary(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
filelists, err := buildFilelists(ctx, pv, pfs, cache)
filelists, err := buildFilelists(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
other, err := buildOther(ctx, pv, pfs, cache)
other, err := buildOther(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
@@ -220,11 +217,12 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
filelists,
other,
},
compositeKey,
)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#repomd-xml
func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData) error {
func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData, compositeKey string) error {
type Repomd struct {
XMLName xml.Name `xml:"repomd"`
Xmlns string `xml:"xmlns,attr"`
@@ -279,7 +277,8 @@ func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
Filename: file.Name,
Filename: file.Name,
CompositeKey: compositeKey,
},
Creator: user_model.NewGhostUser(),
Data: file.Data,
@@ -296,7 +295,7 @@ func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#primary-xml
func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) {
func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) {
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -376,7 +375,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
files = append(files, f)
}
}
packageVersion := fmt.Sprintf("%s-%s", pd.FileMetadata.Version, pd.FileMetadata.Release)
packages = append(packages, &Package{
Type: "rpm",
Name: pd.Package.Name,
@@ -405,7 +404,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
Archive: pd.FileMetadata.ArchiveSize,
},
Location: Location{
Href: fmt.Sprintf("package/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(pd.Version.Version), url.PathEscape(pd.FileMetadata.Architecture)),
Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(packageVersion), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, packageVersion, pd.FileMetadata.Architecture))),
},
Format: Format{
License: pd.VersionMetadata.License,
@@ -435,11 +434,11 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
PackageCount: len(pfs),
Packages: packages,
})
}, compositeKey)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#filelists-xml
func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl
func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -482,11 +481,12 @@ func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pfs),
Packages: packages,
})
},
compositeKey)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#other-xml
func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl
func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -529,7 +529,7 @@ func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*p
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pfs),
Packages: packages,
})
}, compositeKey)
}
// writtenCounter counts all written bytes
@@ -549,10 +549,8 @@ func (wc *writtenCounter) Written() int64 {
return wc.written
}
func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) {
func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any, compositeKey string) (*repoData, error) {
content, _ := packages_module.NewHashedBuffer()
defer content.Close()
gzw := gzip.NewWriter(content)
wc := &writtenCounter{}
h := sha256.New()
@@ -575,7 +573,8 @@ func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion,
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
Filename: filename,
Filename: filename,
CompositeKey: compositeKey,
},
Creator: user_model.NewGhostUser(),
Data: content,

View File

@@ -215,24 +215,29 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com
return nil, fmt.Errorf("GetFullCommitID(%s) in %s: %w", prHeadRef, pr.BaseRepo.FullName(), err)
}
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
if err != nil {
return nil, fmt.Errorf("%-v OpenRepository: %w", pr.BaseRepo, err)
}
defer gitRepo.Close()
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return nil, fmt.Errorf("%-v GetObjectFormat: %w", pr.BaseRepo, err)
}
// Get the commit from BaseBranch where the pull request got merged
mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse").
AddDynamicArguments(prHeadCommitID + ".." + pr.BaseBranch).
RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
if err != nil {
return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %w", err)
} else if len(mergeCommit) < git.SHAFullLength {
} else if len(mergeCommit) < objectFormat.FullLength() {
// PR was maybe fast-forwarded, so just use last commit of PR
mergeCommit = prHeadCommitID
}
mergeCommit = strings.TrimSpace(mergeCommit)
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
if err != nil {
return nil, fmt.Errorf("%-v OpenRepository: %w", pr.BaseRepo, err)
}
defer gitRepo.Close()
commit, err := gitRepo.GetCommit(mergeCommit)
if err != nil {
return nil, fmt.Errorf("GetMergeCommit[%s]: %w", mergeCommit, err)

View File

@@ -127,9 +127,7 @@ func createLFSMetaObjectsFromCatFileBatch(ctx context.Context, catFileBatchReade
// OK we have a pointer that is associated with the head repo
// and is actually a file in the LFS
// Therefore it should be associated with the base repo
meta := &git_model.LFSMetaObject{Pointer: pointer}
meta.RepositoryID = pr.BaseRepoID
if _, err := git_model.NewLFSMetaObject(ctx, meta); err != nil {
if _, err := git_model.NewLFSMetaObject(ctx, pr.BaseRepoID, pointer); err != nil {
_ = catFileBatchReader.CloseWithError(err)
break
}

View File

@@ -486,7 +486,8 @@ func MergedManually(ctx context.Context, pr *issues_model.PullRequest, doer *use
return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged}
}
if len(commitID) < git.SHAFullLength {
objectFormat, _ := baseGitRepo.GetObjectFormat()
if len(commitID) != objectFormat.FullLength() {
return fmt.Errorf("Wrong commit ID")
}

View File

@@ -129,6 +129,7 @@ func (e *errMergeConflict) Error() string {
func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, gitRepo *git.Repository) error {
log.Trace("Attempt to merge:\n%v", file)
switch {
case file.stage1 != nil && (file.stage2 == nil || file.stage3 == nil):
// 1. Deleted in one or both:

View File

@@ -4,6 +4,7 @@
package pull
import (
"bytes"
"context"
"fmt"
"io"
@@ -327,7 +328,8 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
}
if err == nil {
for _, pr := range prs {
if newCommitID != "" && newCommitID != git.EmptySHA {
objectFormat, _ := git.GetObjectFormatOfRepo(ctx, pr.BaseRepo.RepoPath())
if newCommitID != "" && newCommitID != objectFormat.EmptyObjectID().String() {
changed, err := checkIfPRContentChanged(ctx, pr, oldCommitID, newCommitID)
if err != nil {
log.Error("checkIfPRContentChanged: %v", err)
@@ -421,9 +423,11 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest,
return false, fmt.Errorf("unable to open pipe for to run diff: %w", err)
}
stderr := new(bytes.Buffer)
if err := cmd.Run(&git.RunOpts{
Dir: prCtx.tmpBasePath,
Stdout: stdoutWriter,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
defer func() {
@@ -435,6 +439,7 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest,
if err == util.ErrNotEmpty {
return true, nil
}
err = git.ConcatenateError(err, stderr.String())
log.Error("Unable to run diff on %s %s %s in tempRepo for PR[%d]%s/%s...%s/%s: Error: %v",
newCommitID, oldCommitID, base,
@@ -541,6 +546,43 @@ func (errs errlist) Error() string {
return ""
}
// RetargetChildrenOnMerge retarget children pull requests on merge if possible
func RetargetChildrenOnMerge(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) error {
if setting.Repository.PullRequest.RetargetChildrenOnMerge && pr.BaseRepoID == pr.HeadRepoID {
return RetargetBranchPulls(ctx, doer, pr.HeadRepoID, pr.HeadBranch, pr.BaseBranch)
}
return nil
}
// RetargetBranchPulls change target branch for all pull requests whose base branch is the branch
// Both branch and targetBranch must be in the same repo (for security reasons)
func RetargetBranchPulls(ctx context.Context, doer *user_model.User, repoID int64, branch, targetBranch string) error {
prs, err := issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, repoID, branch)
if err != nil {
return err
}
if err := issues_model.PullRequestList(prs).LoadAttributes(ctx); err != nil {
return err
}
var errs errlist
for _, pr := range prs {
if err = pr.Issue.LoadRepo(ctx); err != nil {
errs = append(errs, err)
} else if err = ChangeTargetBranch(ctx, pr, doer, targetBranch); err != nil &&
!issues_model.IsErrIssueIsClosed(err) && !models.IsErrPullRequestHasMerged(err) &&
!issues_model.IsErrPullRequestAlreadyExists(err) {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errs
}
return nil
}
// CloseBranchPulls close all the pull requests who's head branch is the branch
func CloseBranchPulls(ctx context.Context, doer *user_model.User, repoID int64, branch string) error {
prs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(ctx, repoID, branch)

View File

@@ -94,7 +94,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
baseRepoPath := pr.BaseRepo.RepoPath()
headRepoPath := pr.HeadRepo.RepoPath()
if err := git.InitRepository(ctx, tmpBasePath, false); err != nil {
if err := git.InitRepository(ctx, tmpBasePath, false, pr.BaseRepo.ObjectFormatName); err != nil {
log.Error("Unable to init tmpBasePath for %-v: %v", pr, err)
cancel()
return nil, nil, err
@@ -168,11 +168,12 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
}
trackingBranch := "tracking"
objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName)
// Fetch head branch
var headBranch string
if pr.Flow == issues_model.PullRequestFlowGithub {
headBranch = git.BranchPrefix + pr.HeadBranch
} else if len(pr.HeadCommitID) == git.SHAFullLength { // for not created pull request
} else if len(pr.HeadCommitID) == objectFormat.FullLength() { // for not created pull request
headBranch = pr.HeadCommitID
} else {
headBranch = pr.GetGitRefName()

View File

@@ -86,16 +86,17 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel
created = true
rel.LowerTagName = strings.ToLower(rel.TagName)
objectFormat, _ := gitRepo.GetObjectFormat()
commits := repository.NewPushCommits()
commits.HeadCommit = repository.CommitToPushCommit(commit)
commits.CompareURL = rel.Repo.ComposeCompareURL(git.EmptySHA, commit.ID.String())
commits.CompareURL = rel.Repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), commit.ID.String())
refFullName := git.RefNameFromTag(rel.TagName)
notify_service.PushCommits(
ctx, rel.Publisher, rel.Repo,
&repository.PushUpdateOptions{
RefFullName: refFullName,
OldCommitID: git.EmptySHA,
OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: commit.ID.String(),
}, commits)
notify_service.CreateRef(ctx, rel.Publisher, rel.Repo, refFullName, commit.ID.String())
@@ -301,17 +302,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo
}
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, delTag bool) error {
rel, err := repo_model.GetReleaseByID(ctx, id)
if err != nil {
return fmt.Errorf("GetReleaseByID: %w", err)
}
repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID: %w", err)
}
func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *repo_model.Release, doer *user_model.User, delTag bool) error {
if delTag {
protectedTags, err := git_model.GetProtectedTags(ctx, rel.RepoID)
if err != nil {
@@ -335,28 +326,32 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del
}
refName := git.RefNameFromTag(rel.TagName)
objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath())
if err != nil {
return err
}
notify_service.PushCommits(
ctx, doer, repo,
&repository.PushUpdateOptions{
RefFullName: refName,
OldCommitID: rel.Sha1,
NewCommitID: git.EmptySHA,
NewCommitID: objectFormat.EmptyObjectID().String(),
}, repository.NewPushCommits())
notify_service.DeleteRef(ctx, doer, repo, refName)
if err := repo_model.DeleteReleaseByID(ctx, id); err != nil {
if _, err := db.DeleteByID[repo_model.Release](ctx, rel.ID); err != nil {
return fmt.Errorf("DeleteReleaseByID: %w", err)
}
} else {
rel.IsTag = true
if err = repo_model.UpdateRelease(ctx, rel); err != nil {
if err := repo_model.UpdateRelease(ctx, rel); err != nil {
return fmt.Errorf("Update: %w", err)
}
}
rel.Repo = repo
if err = rel.LoadAttributes(ctx); err != nil {
if err := rel.LoadAttributes(ctx); err != nil {
return fmt.Errorf("LoadAttributes: %w", err)
}

View File

@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"os"
"regexp"
"strings"
"time"
@@ -36,10 +35,6 @@ type ArchiveRequest struct {
CommitID string
}
// SHA1 hashes will only go up to 40 characters, but SHA256 hashes will go all
// the way to 64.
var shaRegex = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
// ErrUnknownArchiveFormat request archive format is not supported
type ErrUnknownArchiveFormat struct {
RequestFormat string
@@ -96,30 +91,13 @@ func NewRequest(repoID int64, repo *git.Repository, uri string) (*ArchiveRequest
r.refName = strings.TrimSuffix(uri, ext)
var err error
// Get corresponding commit.
if repo.IsBranchExist(r.refName) {
r.CommitID, err = repo.GetBranchCommitID(r.refName)
if err != nil {
return nil, err
}
} else if repo.IsTagExist(r.refName) {
r.CommitID, err = repo.GetTagCommitID(r.refName)
if err != nil {
return nil, err
}
} else if shaRegex.MatchString(r.refName) {
if repo.IsCommitExist(r.refName) {
r.CommitID = r.refName
} else {
return nil, git.ErrNotExist{
ID: r.refName,
}
}
} else {
commitID, err := repo.ConvertToGitID(r.refName)
if err != nil {
return nil, RepoRefNotFoundError{RefName: r.refName}
}
r.CommitID = commitID.String()
return r, nil
}
@@ -199,7 +177,7 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
CommitID: r.CommitID,
Status: repo_model.ArchiverGenerating,
}
if err := repo_model.AddRepoArchiver(ctx, archiver); err != nil {
if err := db.Insert(ctx, archiver); err != nil {
return nil, err
}
}
@@ -331,7 +309,7 @@ func StartArchive(request *ArchiveRequest) error {
}
func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error {
if err := repo_model.DeleteRepoArchiver(ctx, archiver); err != nil {
if _, err := db.DeleteByID[repo_model.RepoArchiver](ctx, archiver.ID); err != nil {
return err
}
p := archiver.RelativePath()
@@ -346,7 +324,7 @@ func DeleteOldRepositoryArchives(ctx context.Context, olderThan time.Duration) e
log.Trace("Doing: ArchiveCleanup")
for {
archivers, err := repo_model.FindRepoArchives(ctx, repo_model.FindRepoArchiversOption{
archivers, err := db.Find[repo_model.RepoArchiver](ctx, repo_model.FindRepoArchiversOption{
ListOptions: db.ListOptions{
PageSize: 100,
Page: 1,

View File

@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
@@ -20,7 +21,9 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/queue"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
notify_service "code.gitea.io/gitea/services/notify"
files_service "code.gitea.io/gitea/services/repository/files"
@@ -28,35 +31,13 @@ import (
)
// CreateNewBranch creates a new repository branch
func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldBranchName, branchName string) (err error) {
err = repo.MustNotBeArchived()
func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, oldBranchName, branchName string) (err error) {
branch, err := git_model.GetBranch(ctx, repo.ID, oldBranchName)
if err != nil {
return err
}
// Check if branch name can be used
if err := checkBranchName(ctx, repo, branchName); err != nil {
return err
}
if !git.IsBranchExist(ctx, repo.RepoPath(), oldBranchName) {
return git_model.ErrBranchNotExist{
BranchName: oldBranchName,
}
}
if err := git.Push(ctx, repo.RepoPath(), git.PushOptions{
Remote: repo.RepoPath(),
Branch: fmt.Sprintf("%s%s:%s%s", git.BranchPrefix, oldBranchName, git.BranchPrefix, branchName),
Env: repo_module.PushingEnvironment(doer, repo),
}); err != nil {
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
return err
}
return fmt.Errorf("push: %w", err)
}
return nil
return CreateNewBranchFromCommit(ctx, doer, repo, gitRepo, branch.CommitID, branchName)
}
// Branch contains the branch information
@@ -87,22 +68,17 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git
Keyword: keyword,
}
totalNumOfBranches, err := git_model.CountBranches(ctx, branchOpts)
dbBranches, totalNumOfBranches, err := db.FindAndCount[git_model.Branch](ctx, branchOpts)
if err != nil {
return nil, nil, 0, err
}
branchOpts.ExcludeBranchNames = []string{repo.DefaultBranch}
dbBranches, err := git_model.FindBranches(ctx, branchOpts)
if err != nil {
if err := git_model.BranchList(dbBranches).LoadDeletedBy(ctx); err != nil {
return nil, nil, 0, err
}
if err := dbBranches.LoadDeletedBy(ctx); err != nil {
return nil, nil, 0, err
}
if err := dbBranches.LoadPusher(ctx); err != nil {
if err := git_model.BranchList(dbBranches).LoadPusher(ctx); err != nil {
return nil, nil, 0, err
}
@@ -249,8 +225,49 @@ func checkBranchName(ctx context.Context, repo *repo_model.Repository, name stri
return err
}
// syncBranchToDB sync the branch information in the database. It will try to update the branch first,
// if updated success with affect records > 0, then all are done. Because that means the branch has been in the database.
// If no record is affected, that means the branch does not exist in database. So there are two possibilities.
// One is this is a new branch, then we just need to insert the record. Another is the branches haven't been synced,
// then we need to sync all the branches into database.
func syncBranchToDB(ctx context.Context, repoID, pusherID int64, branchName string, commit *git.Commit) error {
cnt, err := git_model.UpdateBranch(ctx, repoID, pusherID, branchName, commit)
if err != nil {
return fmt.Errorf("git_model.UpdateBranch %d:%s failed: %v", repoID, branchName, err)
}
if cnt > 0 { // This means branch does exist, so it's a normal update. It also means the branch has been synced.
return nil
}
// if user haven't visit UI but directly push to a branch after upgrading from 1.20 -> 1.21,
// we cannot simply insert the branch but need to check we have branches or not
hasBranch, err := db.Exist[git_model.Branch](ctx, git_model.FindBranchOptions{
RepoID: repoID,
IsDeletedBranch: util.OptionalBoolFalse,
}.ToConds())
if err != nil {
return err
}
if !hasBranch {
if _, err = repo_module.SyncRepoBranches(ctx, repoID, pusherID); err != nil {
return fmt.Errorf("repo_module.SyncRepoBranches %d:%s failed: %v", repoID, branchName, err)
}
return nil
}
// if database have branches but not this branch, it means this is a new branch
return db.Insert(ctx, &git_model.Branch{
RepoID: repoID,
Name: branchName,
CommitID: commit.ID.String(),
CommitMessage: commit.Summary(),
PusherID: pusherID,
CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()),
})
}
// CreateNewBranchFromCommit creates a new repository branch
func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, branchName string) (err error) {
func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, commitID, branchName string) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
@@ -263,7 +280,7 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
if err := git.Push(ctx, repo.RepoPath(), git.PushOptions{
Remote: repo.RepoPath(),
Branch: fmt.Sprintf("%s:%s%s", commit, git.BranchPrefix, branchName),
Branch: fmt.Sprintf("%s:%s%s", commitID, git.BranchPrefix, branchName),
Env: repo_module.PushingEnvironment(doer, repo),
}); err != nil {
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
@@ -271,7 +288,6 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
}
return fmt.Errorf("push: %w", err)
}
return nil
}
@@ -294,13 +310,28 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m
return "from_not_exist", nil
}
if err := git_model.RenameBranch(ctx, repo, from, to, func(isDefault bool) error {
if err := git_model.RenameBranch(ctx, repo, from, to, func(ctx context.Context, isDefault bool) error {
err2 := gitRepo.RenameBranch(from, to)
if err2 != nil {
return err2
}
if isDefault {
// if default branch changed, we need to delete all schedules and cron jobs
if err := actions_model.DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
log.Error("DeleteCronTaskByRepo: %v", err)
}
// cancel running cron jobs of this repository and delete old schedules
if err := actions_model.CancelRunningJobs(
ctx,
repo.ID,
from,
"",
webhook_module.HookEventSchedule,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
err2 = gitRepo.SetDefaultBranch(to)
if err2 != nil {
return err2
@@ -352,6 +383,11 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
return fmt.Errorf("GetBranch: %vc", err)
}
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return err
}
if rawBranch.IsDeleted {
return nil
}
@@ -378,7 +414,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
&repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromBranch(branchName),
OldCommitID: commit.ID.String(),
NewCommitID: git.EmptySHA,
NewCommitID: objectFormat.EmptyObjectID().String(),
PusherID: doer.ID,
PusherName: doer.Name,
RepoUserName: repo.OwnerName,
@@ -431,3 +467,50 @@ func AddAllRepoBranchesToSyncQueue(ctx context.Context, doerID int64) error {
}
return nil
}
func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, newBranchName string) error {
if repo.DefaultBranch == newBranchName {
return nil
}
if !gitRepo.IsBranchExist(newBranchName) {
return git_model.ErrBranchNotExist{
BranchName: newBranchName,
}
}
oldDefaultBranchName := repo.DefaultBranch
repo.DefaultBranch = newBranchName
if err := db.WithTx(ctx, func(ctx context.Context) error {
if err := repo_model.UpdateDefaultBranch(ctx, repo); err != nil {
return err
}
if err := actions_model.DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
log.Error("DeleteCronTaskByRepo: %v", err)
}
// cancel running cron jobs of this repository and delete old schedules
if err := actions_model.CancelRunningJobs(
ctx,
repo.ID,
oldDefaultBranchName,
"",
webhook_module.HookEventSchedule,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
if err := gitRepo.SetDefaultBranch(newBranchName); err != nil {
if !git.IsErrUnsupportedVersion(err) {
return err
}
}
return nil
}); err != nil {
return err
}
notify_service.ChangeDefaultBranch(ctx, repo)
return nil
}

View File

@@ -9,15 +9,10 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
)
// CacheRef cachhe last commit information of the branch or the tag
func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName git.RefName) error {
if !setting.CacheService.LastCommit.Enabled {
return nil
}
commit, err := gitRepo.GetCommit(fullRefName.String())
if err != nil {
return err

View File

@@ -192,7 +192,7 @@ func ReinitMissingRepositories(ctx context.Context) error {
default:
}
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
if err := git.InitRepository(ctx, repo.RepoPath(), true); err != nil {
if err := git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormatName); err != nil {
log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
if err2 := system_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
log.Error("CreateRepositoryNotice: %v", err2)

View File

@@ -27,22 +27,23 @@ import (
// CreateRepoOptions contains the create repository options
type CreateRepoOptions struct {
Name string
Description string
OriginalURL string
GitServiceType api.GitServiceType
Gitignores string
IssueLabels string
License string
Readme string
DefaultBranch string
IsPrivate bool
IsMirror bool
IsTemplate bool
AutoInit bool
Status repo_model.RepositoryStatus
TrustModel repo_model.TrustModelType
MirrorInterval string
Name string
Description string
OriginalURL string
GitServiceType api.GitServiceType
Gitignores string
IssueLabels string
License string
Readme string
DefaultBranch string
IsPrivate bool
IsMirror bool
IsTemplate bool
AutoInit bool
Status repo_model.RepositoryStatus
TrustModel repo_model.TrustModelType
MirrorInterval string
ObjectFormatName string
}
func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
@@ -134,7 +135,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
// InitRepository initializes README and .gitignore if needed.
func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name); err != nil {
if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name, opts.ObjectFormatName); err != nil {
return err
}
@@ -234,6 +235,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
TrustModel: opts.TrustModel,
IsMirror: opts.IsMirror,
DefaultBranch: opts.DefaultBranch,
ObjectFormatName: opts.ObjectFormatName,
}
var rollbackRepo *repo_model.Repository

View File

@@ -31,12 +31,15 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
log.Error("%v", err)
}
defer t.Close()
if err := t.Clone(opts.OldBranch); err != nil {
if err := t.Clone(opts.OldBranch, false); err != nil {
return nil, err
}
if err := t.SetDefaultIndex(); err != nil {
return nil, err
}
if err := t.RefreshIndex(); err != nil {
return nil, err
}
// Get the commit of the original branch
commit, err := t.GetBranchCommit(opts.OldBranch)
@@ -48,7 +51,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("CherryPick: Invalid last commit ID: %w", err)
}
@@ -67,7 +70,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
}
parent, err := commit.ParentID(0)
if err != nil {
parent = git.MustIDFromString(git.EmptyTreeSHA)
parent = git.ObjectFormatFromName(repo.ObjectFormatName).EmptyTree()
}
base, right := parent.String(), commit.ID.String()

View File

@@ -29,10 +29,15 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
}
defer closer.Close()
if commit, err := gitRepo.GetCommit(sha); err != nil {
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return fmt.Errorf("GetObjectFormat[%s]: %w", repoPath, err)
}
commit, err := gitRepo.GetCommit(sha)
if err != nil {
gitRepo.Close()
return fmt.Errorf("GetCommit[%s]: %w", sha, err)
} else if len(sha) != git.SHAFullLength {
} else if len(sha) != objectFormat.FullLength() {
// use complete commit sha
sha = commit.ID.String()
}
@@ -41,7 +46,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
Repo: repo,
Creator: creator,
SHA: sha,
SHA: commit.ID,
CommitStatus: status,
}); err != nil {
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)

View File

@@ -21,7 +21,7 @@ func GetDiffPreview(ctx context.Context, repo *repo_model.Repository, branch, tr
return nil, err
}
defer t.Close()
if err := t.Clone(branch); err != nil {
if err := t.Clone(branch, true); err != nil {
return nil, err
}
if err := t.SetDefaultIndex(); err != nil {

View File

@@ -113,7 +113,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
log.Error("%v", err)
}
defer t.Close()
if err := t.Clone(opts.OldBranch); err != nil {
if err := t.Clone(opts.OldBranch, true); err != nil {
return nil, err
}
if err := t.SetDefaultIndex(); err != nil {
@@ -130,7 +130,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("ApplyPatch: Invalid last commit ID: %w", err)
}

View File

@@ -51,8 +51,13 @@ func (t *TemporaryUploadRepository) Close() {
}
// Clone the base repository to our path and set branch as the HEAD
func (t *TemporaryUploadRepository) Clone(branch string) error {
if _, _, err := git.NewCommand(t.ctx, "clone", "-s", "--bare", "-b").AddDynamicArguments(branch, t.repo.RepoPath(), t.basePath).RunStdString(nil); err != nil {
func (t *TemporaryUploadRepository) Clone(branch string, bare bool) error {
cmd := git.NewCommand(t.ctx, "clone", "-s", "-b").AddDynamicArguments(branch, t.repo.RepoPath(), t.basePath)
if bare {
cmd.AddArguments("--bare")
}
if _, _, err := cmd.RunStdString(nil); err != nil {
stderr := err.Error()
if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched {
return git.ErrBranchNotExist{
@@ -77,8 +82,8 @@ func (t *TemporaryUploadRepository) Clone(branch string) error {
}
// Init the repository
func (t *TemporaryUploadRepository) Init() error {
if err := git.InitRepository(t.ctx, t.basePath, false); err != nil {
func (t *TemporaryUploadRepository) Init(objectFormatName string) error {
if err := git.InitRepository(t.ctx, t.basePath, false, objectFormatName); err != nil {
return err
}
gitRepo, err := git.OpenRepository(t.ctx, t.basePath)
@@ -97,6 +102,14 @@ func (t *TemporaryUploadRepository) SetDefaultIndex() error {
return nil
}
// RefreshIndex looks at the current index and checks to see if merges or updates are needed by checking stat() information.
func (t *TemporaryUploadRepository) RefreshIndex() error {
if _, _, err := git.NewCommand(t.ctx, "update-index", "--refresh").RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil {
return fmt.Errorf("RefreshIndex: %w", err)
}
return nil
}
// LsFiles checks if the given filename arguments are in the index
func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, error) {
stdOut := new(bytes.Buffer)

View File

@@ -37,19 +37,21 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
}
apiURL := repo.APIURL()
apiURLLen := len(apiURL)
objectFormat, _ := gitRepo.GetObjectFormat()
hashLen := objectFormat.FullLength()
// 51 is len(sha1) + len("/git/blobs/"). 40 + 11.
blobURL := make([]byte, apiURLLen+51)
const gitBlobsPath = "/git/blobs/"
blobURL := make([]byte, apiURLLen+hashLen+len(gitBlobsPath))
copy(blobURL, apiURL)
copy(blobURL[apiURLLen:], "/git/blobs/")
copy(blobURL[apiURLLen:], []byte(gitBlobsPath))
// 51 is len(sha1) + len("/git/trees/"). 40 + 11.
treeURL := make([]byte, apiURLLen+51)
const gitTreePath = "/git/trees/"
treeURL := make([]byte, apiURLLen+hashLen+len(gitTreePath))
copy(treeURL, apiURL)
copy(treeURL[apiURLLen:], "/git/trees/")
copy(treeURL[apiURLLen:], []byte(gitTreePath))
// 40 is the size of the sha1 hash in hexadecimal format.
copyPos := len(treeURL) - git.SHAFullLength
// copyPos is at the start of the hash
copyPos := len(treeURL) - hashLen
if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage {
perPage = setting.API.DefaultGitTreesPerPage

View File

@@ -146,7 +146,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
}
defer t.Close()
hasOldBranch := true
if err := t.Clone(opts.OldBranch); err != nil {
if err := t.Clone(opts.OldBranch, true); err != nil {
for _, file := range opts.Files {
if file.Operation == "delete" {
return nil, err
@@ -155,7 +155,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return nil, err
}
if err := t.Init(); err != nil {
if err := t.Init(repo.ObjectFormatName); err != nil {
return nil, err
}
hasOldBranch = false
@@ -202,7 +202,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("ConvertToSHA1: Invalid last commit ID: %w", err)
}
@@ -438,7 +438,7 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file
if lfsMetaObject != nil {
// We have an LFS object - create it
lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, lfsMetaObject)
lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, lfsMetaObject.RepositoryID, lfsMetaObject.Pointer)
if err != nil {
return err
}

View File

@@ -87,11 +87,11 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
defer t.Close()
hasOldBranch := true
if err = t.Clone(opts.OldBranch); err != nil {
if err = t.Clone(opts.OldBranch, true); err != nil {
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return err
}
if err = t.Init(); err != nil {
if err = t.Init(repo.ObjectFormatName); err != nil {
return err
}
hasOldBranch = false
@@ -143,7 +143,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if infos[i].lfsMetaObject == nil {
continue
}
infos[i].lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, infos[i].lfsMetaObject)
infos[i].lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, infos[i].lfsMetaObject.RepositoryID, infos[i].lfsMetaObject.Pointer)
if err != nil {
// OK Now we need to cleanup
return cleanUpAfterFailure(ctx, &infos, t, err)

View File

@@ -78,13 +78,14 @@ func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.R
store := lfs.NewContentStore()
errStop := errors.New("STOPERR")
objectFormat, _ := gitRepo.GetObjectFormat()
err = git_model.IterateLFSMetaObjectsForRepo(ctx, repo.ID, func(ctx context.Context, metaObject *git_model.LFSMetaObject, count int64) error {
if opts.NumberToCheckPerRepo > 0 && total > opts.NumberToCheckPerRepo {
return errStop
}
total++
pointerSha := git.ComputeBlobHash([]byte(metaObject.Pointer.StringContent()))
pointerSha := git.ComputeBlobHash(objectFormat, []byte(metaObject.Pointer.StringContent()))
if gitRepo.IsObjectExist(pointerSha.String()) {
return git_model.MarkLFSMetaObject(ctx, metaObject.ID)

View File

@@ -52,7 +52,7 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string
pointer, err := lfs.GeneratePointer(bytes.NewReader(*content))
assert.NoError(t, err)
_, err = git_model.NewLFSMetaObject(db.DefaultContext, &git_model.LFSMetaObject{Pointer: pointer, RepositoryID: repositoryID})
_, err = git_model.NewLFSMetaObject(db.DefaultContext, repositoryID, pointer)
assert.NoError(t, err)
contentStore := lfs.NewContentStore()
exist, err := contentStore.Exists(pointer)

View File

@@ -35,7 +35,9 @@ var pushQueue *queue.WorkerPoolQueue[[]*repo_module.PushUpdateOptions]
func handler(items ...[]*repo_module.PushUpdateOptions) [][]*repo_module.PushUpdateOptions {
for _, opts := range items {
if err := pushUpdates(opts); err != nil {
log.Error("pushUpdate failed: %v", err)
// Username and repository stays the same between items in opts.
pushUpdate := opts[0]
log.Error("pushUpdate[%s/%s] failed: %v", pushUpdate.RepoUserName, pushUpdate.RepoName, err)
}
}
return nil
@@ -63,7 +65,7 @@ func PushUpdates(opts []*repo_module.PushUpdateOptions) error {
for _, opt := range opts {
if opt.IsNewRef() && opt.IsDelRef() {
return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
return fmt.Errorf("Old and new revisions are both NULL")
}
}
@@ -92,6 +94,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
defer gitRepo.Close()
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return fmt.Errorf("unknown repository ObjectFormat [%s]: %w", repoPath, err)
}
if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
return fmt.Errorf("Failed to update size for repository: %v", err)
}
@@ -104,7 +111,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName)
if opts.IsNewRef() && opts.IsDelRef() {
return fmt.Errorf("old and new revisions are both %s", git.EmptySHA)
return fmt.Errorf("old and new revisions are both %s", objectFormat.EmptyObjectID())
}
if opts.RefFullName.IsTag() {
if pusher == nil || pusher.ID != opts.PusherID {
@@ -124,7 +131,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
&repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromTag(tagName),
OldCommitID: opts.OldCommitID,
NewCommitID: git.EmptySHA,
NewCommitID: objectFormat.EmptyObjectID().String(),
}, repo_module.NewPushCommits())
delTags = append(delTags, tagName)
@@ -137,13 +144,13 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
commits := repo_module.NewPushCommits()
commits.HeadCommit = repo_module.CommitToPushCommit(newCommit)
commits.CompareURL = repo.ComposeCompareURL(git.EmptySHA, opts.NewCommitID)
commits.CompareURL = repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), opts.NewCommitID)
notify_service.PushCommits(
ctx, pusher, repo,
&repo_module.PushUpdateOptions{
RefFullName: opts.RefFullName,
OldCommitID: git.EmptySHA,
OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: opts.NewCommitID,
}, commits)
@@ -227,7 +234,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
oldCommitID := opts.OldCommitID
if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 {
if oldCommitID == objectFormat.EmptyObjectID().String() && len(commits.Commits) > 0 {
oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1)
if err != nil && !git.IsErrNotExist(err) {
log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err)
@@ -243,11 +250,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
}
if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch {
if oldCommitID == objectFormat.EmptyObjectID().String() && repo.DefaultBranch != branch {
oldCommitID = repo.DefaultBranch
}
if oldCommitID != git.EmptySHA {
if oldCommitID != objectFormat.EmptyObjectID().String() {
commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID)
} else {
commits.CompareURL = ""
@@ -257,7 +264,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
}
if err = git_model.UpdateBranch(ctx, repo.ID, opts.PusherID, branch, newCommit); err != nil {
if err = syncBranchToDB(ctx, repo.ID, opts.PusherID, branch, newCommit); err != nil {
return fmt.Errorf("git_model.UpdateBranch %s:%s failed: %v", repo.FullName(), branch, err)
}
@@ -320,9 +327,12 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
lowerTags = append(lowerTags, strings.ToLower(tag))
}
releases, err := repo_model.GetReleasesByRepoIDAndNames(ctx, repo.ID, lowerTags)
releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
RepoID: repo.ID,
TagNames: lowerTags,
})
if err != nil {
return fmt.Errorf("GetReleasesByRepoIDAndNames: %w", err)
return fmt.Errorf("db.Find[repo_model.Release]: %w", err)
}
relMap := make(map[string]*repo_model.Release)
for _, rel := range releases {

View File

@@ -0,0 +1,47 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repository
import (
"context"
"slices"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/log"
)
// UpdateRepositoryUnits updates a repository's units
func UpdateRepositoryUnits(ctx context.Context, repo *repo_model.Repository, units []repo_model.RepoUnit, deleteUnitTypes []unit.Type) (err error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
// Delete existing settings of units before adding again
for _, u := range units {
deleteUnitTypes = append(deleteUnitTypes, u.Type)
}
if slices.Contains(deleteUnitTypes, unit.TypeActions) {
if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
log.Error("CleanRepoScheduleTasks: %v", err)
}
}
if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil {
return err
}
if len(units) > 0 {
if err = db.Insert(ctx, units); err != nil {
return err
}
}
return committer.Commit()
}

View File

@@ -76,7 +76,7 @@ func DeleteSecretByName(ctx context.Context, ownerID, repoID int64, name string)
}
func deleteSecret(ctx context.Context, s *secret_model.Secret) error {
if _, err := db.DeleteByID(ctx, s.ID, s); err != nil {
if _, err := db.DeleteByID[secret_model.Secret](ctx, s.ID); err != nil {
return err
}
return nil

View File

@@ -159,7 +159,9 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
// ***** END: PublicKey *****
// ***** START: GPGPublicKey *****
keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
OwnerID: u.ID,
})
if err != nil {
return fmt.Errorf("ListGPGKeys: %w", err)
}
@@ -185,7 +187,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
}
// ***** END: ExternalLoginUser *****
if _, err = db.DeleteByID(ctx, u.ID, new(user_model.User)); err != nil {
if _, err = db.DeleteByID[user_model.User](ctx, u.ID); err != nil {
return fmt.Errorf("delete: %w", err)
}

View File

@@ -129,6 +129,10 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
return fmt.Errorf("%s is an organization not a user", u.Name)
}
if user_model.IsLastAdminUser(ctx, u) {
return models.ErrDeleteLastAdminUser{UID: u.ID}
}
if purge {
// Disable the user first
// NOTE: This is deliberately not within a transaction as it must disable the user immediately to prevent any further action by the user to be purged.
@@ -295,7 +299,8 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error {
}
if err := DeleteUser(ctx, u, false); err != nil {
// Ignore users that were set inactive by admin.
if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || models.IsErrUserOwnPackages(err) {
if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) ||
models.IsErrUserOwnPackages(err) || models.IsErrDeleteLastAdminUser(err) {
continue
}
return err

View File

@@ -92,6 +92,7 @@ func SlackLinkFormatter(url, text string) string {
// SlackLinkToRef slack-formatter link to a repo ref
func SlackLinkToRef(repoURL, ref string) string {
// FIXME: SHA1 hardcoded here
url := git.RefURL(repoURL, ref)
refName := git.RefName(ref).ShortName()
return SlackLinkFormatter(url, refName)

View File

@@ -19,6 +19,7 @@ import (
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/sync"
asymkey_service "code.gitea.io/gitea/services/asymkey"
repo_service "code.gitea.io/gitea/services/repository"
)
// TODO: use clustered lock (unique queue? or *abuse* cache)
@@ -36,7 +37,7 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error {
return nil
}
if err := git.InitRepository(ctx, repo.WikiPath(), true); err != nil {
if err := git.InitRepository(ctx, repo.WikiPath(), true, repo.ObjectFormatName); err != nil {
return fmt.Errorf("InitRepository: %w", err)
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
@@ -350,7 +351,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
// DeleteWiki removes the actual and local copy of repository wiki.
func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error {
if err := repo_model.UpdateRepositoryUnits(ctx, repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
if err := repo_service.UpdateRepositoryUnits(ctx, repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
return err
}

View File

@@ -302,7 +302,7 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) {
// Now create a temporaryDirectory
tmpDir := t.TempDir()
err := git.InitRepository(git.DefaultContext, tmpDir, true)
err := git.InitRepository(git.DefaultContext, tmpDir, true, git.Sha1ObjectFormat.Name())
assert.NoError(t, err)
gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir)