Merge remote-tracking branch 'upstream/main' into feat/api-project-boards
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
47
services/repository/setting.go
Normal file
47
services/repository/setting.go
Normal 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()
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user