Add support for sha256 repositories (#23894)
Currently only SHA1 repositories are supported by Gitea. This adds support for alternate SHA256 with the additional aim of easier support for additional hash types in the future. Fixes: #13794 Limited by: https://github.com/go-git/go-git/issues/899 Depend on: #28138 <img width="776" alt="图片" src="https://github.com/go-gitea/gitea/assets/81045/5448c9a7-608e-4341-a149-5dd0069c9447"> --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
parent
07ba4d9f87
commit
d68a613ba8
|
@ -37,7 +37,7 @@ type CommitStatus struct {
|
||||||
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
|
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
|
||||||
TargetURL string `xorm:"TEXT"`
|
TargetURL string `xorm:"TEXT"`
|
||||||
Description string `xorm:"TEXT"`
|
Description string `xorm:"TEXT"`
|
||||||
ContextHash string `xorm:"char(40) index"`
|
ContextHash string `xorm:"VARCHAR(64) index"`
|
||||||
Context string `xorm:"TEXT"`
|
Context string `xorm:"TEXT"`
|
||||||
Creator *user_model.User `xorm:"-"`
|
Creator *user_model.User `xorm:"-"`
|
||||||
CreatorID int64
|
CreatorID int64
|
||||||
|
|
|
@ -270,7 +270,7 @@ type Comment struct {
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
|
|
||||||
// Reference issue in commit message
|
// Reference issue in commit message
|
||||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
CommitSHA string `xorm:"VARCHAR(64)"`
|
||||||
|
|
||||||
Attachments []*repo_model.Attachment `xorm:"-"`
|
Attachments []*repo_model.Attachment `xorm:"-"`
|
||||||
Reactions ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
|
|
|
@ -171,11 +171,11 @@ type PullRequest struct {
|
||||||
HeadBranch string
|
HeadBranch string
|
||||||
HeadCommitID string `xorm:"-"`
|
HeadCommitID string `xorm:"-"`
|
||||||
BaseBranch string
|
BaseBranch string
|
||||||
MergeBase string `xorm:"VARCHAR(40)"`
|
MergeBase string `xorm:"VARCHAR(64)"`
|
||||||
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`
|
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
|
||||||
HasMerged bool `xorm:"INDEX"`
|
HasMerged bool `xorm:"INDEX"`
|
||||||
MergedCommitID string `xorm:"VARCHAR(40)"`
|
MergedCommitID string `xorm:"VARCHAR(64)"`
|
||||||
MergerID int64 `xorm:"INDEX"`
|
MergerID int64 `xorm:"INDEX"`
|
||||||
Merger *user_model.User `xorm:"-"`
|
Merger *user_model.User `xorm:"-"`
|
||||||
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
|
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
|
||||||
|
|
|
@ -116,7 +116,7 @@ type Review struct {
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
// Official is a review made by an assigned approver (counts towards approval)
|
// Official is a review made by an assigned approver (counts towards approval)
|
||||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
CommitID string `xorm:"VARCHAR(40)"`
|
CommitID string `xorm:"VARCHAR(64)"`
|
||||||
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
|
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# type Repository struct {
|
||||||
|
# ID int64 `xorm:"pk autoincr"`
|
||||||
|
# }
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
-
|
||||||
|
id: 3
|
||||||
|
-
|
||||||
|
id: 10
|
|
@ -556,6 +556,8 @@ var migrations = []Migration{
|
||||||
NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable),
|
NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable),
|
||||||
// v285 -> v286
|
// v285 -> v286
|
||||||
NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
|
NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
|
||||||
|
// v286 -> v287
|
||||||
|
NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
104
models/migrations/v1_22/v286.go
Normal file
104
models/migrations/v1_22/v286.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func expandHashReferencesToSha256(x *xorm.Engine) error {
|
||||||
|
alteredTables := [][2]string{
|
||||||
|
{"commit_status", "context_hash"},
|
||||||
|
{"comment", "commit_sha"},
|
||||||
|
{"pull_request", "merge_base"},
|
||||||
|
{"pull_request", "merged_commit_id"},
|
||||||
|
{"review", "commit_id"},
|
||||||
|
{"review_state", "commit_sha"},
|
||||||
|
{"repo_archiver", "commit_id"},
|
||||||
|
{"release", "sha1"},
|
||||||
|
{"repo_indexer_status", "commit_sha"},
|
||||||
|
}
|
||||||
|
|
||||||
|
db := x.NewSession()
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
if err := db.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !setting.Database.Type.IsSQLite3() {
|
||||||
|
if setting.Database.Type.IsMSSQL() {
|
||||||
|
// drop indexes that need to be re-created afterwards
|
||||||
|
droppedIndexes := []string{
|
||||||
|
"DROP INDEX commit_status.IDX_commit_status_context_hash",
|
||||||
|
"DROP INDEX review_state.UQE_review_state_pull_commit_user",
|
||||||
|
"DROP INDEX repo_archiver.UQE_repo_archiver_s",
|
||||||
|
}
|
||||||
|
for _, s := range droppedIndexes {
|
||||||
|
_, err := db.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(s + " " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, alts := range alteredTables {
|
||||||
|
var err error
|
||||||
|
if setting.Database.Type.IsMySQL() {
|
||||||
|
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
|
||||||
|
} else if setting.Database.Type.IsMSSQL() {
|
||||||
|
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
|
||||||
|
} else {
|
||||||
|
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1]))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("alter column '%s' of table '%s' failed: %w", alts[1], alts[0], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if setting.Database.Type.IsMSSQL() {
|
||||||
|
recreateIndexes := []string{
|
||||||
|
"CREATE INDEX IDX_commit_status_context_hash ON commit_status(context_hash)",
|
||||||
|
"CREATE UNIQUE INDEX UQE_review_state_pull_commit_user ON review_state(user_id, pull_id, commit_sha)",
|
||||||
|
"CREATE UNIQUE INDEX UQE_repo_archiver_s ON repo_archiver(repo_id, type, commit_id)",
|
||||||
|
}
|
||||||
|
for _, s := range recreateIndexes {
|
||||||
|
_, err := db.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(s + " " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("Updated database tables to hold SHA256 git hash references")
|
||||||
|
|
||||||
|
return db.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func addObjectFormatNameToRepository(x *xorm.Engine) error {
|
||||||
|
type Repository struct {
|
||||||
|
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := x.Sync(new(Repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here to catch weird edge-cases where column constraints above are
|
||||||
|
// not applied by the DB backend
|
||||||
|
_, err := x.Exec("UPDATE repository set object_format_name = 'sha1' WHERE object_format_name = '' or object_format_name IS NULL")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AdjustDBForSha256(x *xorm.Engine) error {
|
||||||
|
if err := expandHashReferencesToSha256(x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return addObjectFormatNameToRepository(x)
|
||||||
|
}
|
62
models/migrations/v1_22/v286_test.go
Normal file
62
models/migrations/v1_22/v286_test.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1_22 //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/migrations/base"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrepareOldRepository(t *testing.T) (*xorm.Engine, func()) {
|
||||||
|
type Repository struct { // old struct
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare and load the testing database
|
||||||
|
return base.PrepareTestEnv(t, 0, new(Repository))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_RepositoryFormat(t *testing.T) {
|
||||||
|
x, deferable := PrepareOldRepository(t)
|
||||||
|
defer deferable()
|
||||||
|
|
||||||
|
type Repository struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
ObjectFormatName string `xorg:"not null default('sha1')"`
|
||||||
|
}
|
||||||
|
|
||||||
|
repo := new(Repository)
|
||||||
|
|
||||||
|
// check we have some records to migrate
|
||||||
|
count, err := x.Count(new(Repository))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 4, count)
|
||||||
|
|
||||||
|
assert.NoError(t, AdjustDBForSha256(x))
|
||||||
|
|
||||||
|
repo.ID = 20
|
||||||
|
repo.ObjectFormatName = "sha256"
|
||||||
|
_, err = x.Insert(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
count, err = x.Count(new(Repository))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 5, count)
|
||||||
|
|
||||||
|
repo = new(Repository)
|
||||||
|
ok, err := x.ID(2).Get(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, true, ok)
|
||||||
|
assert.EqualValues(t, "sha1", repo.ObjectFormatName)
|
||||||
|
|
||||||
|
repo = new(Repository)
|
||||||
|
ok, err = x.ID(20).Get(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, true, ok)
|
||||||
|
assert.EqualValues(t, "sha256", repo.ObjectFormatName)
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ type ReviewState struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
|
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
|
||||||
PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on?
|
PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on?
|
||||||
CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review?
|
CommitSHA string `xorm:"NOT NULL VARCHAR(64) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review?
|
||||||
UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed
|
UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits
|
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ type RepoArchiver struct { //revive:disable-line:exported
|
||||||
RepoID int64 `xorm:"index unique(s)"`
|
RepoID int64 `xorm:"index unique(s)"`
|
||||||
Type git.ArchiveType `xorm:"unique(s)"`
|
Type git.ArchiveType `xorm:"unique(s)"`
|
||||||
Status ArchiverStatus
|
Status ArchiverStatus
|
||||||
CommitID string `xorm:"VARCHAR(40) unique(s)"`
|
CommitID string `xorm:"VARCHAR(64) unique(s)"`
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ type Release struct {
|
||||||
Target string
|
Target string
|
||||||
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
||||||
Title string
|
Title string
|
||||||
Sha1 string `xorm:"VARCHAR(40)"`
|
Sha1 string `xorm:"VARCHAR(64)"`
|
||||||
NumCommits int64
|
NumCommits int64
|
||||||
NumCommitsBehind int64 `xorm:"-"`
|
NumCommitsBehind int64 `xorm:"-"`
|
||||||
Note string `xorm:"TEXT"`
|
Note string `xorm:"TEXT"`
|
||||||
|
|
|
@ -180,7 +180,7 @@ type Repository struct {
|
||||||
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
|
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
|
||||||
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
|
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
Topics []string `xorm:"TEXT JSON"`
|
Topics []string `xorm:"TEXT JSON"`
|
||||||
ObjectFormatName string `xorm:"-"`
|
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
|
||||||
|
|
||||||
TrustModel TrustModelType
|
TrustModel TrustModelType
|
||||||
|
|
||||||
|
@ -276,10 +276,6 @@ func (repo *Repository) AfterLoad() {
|
||||||
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
||||||
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
|
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
|
||||||
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
|
repo.NumOpenActionRuns = repo.NumActionRuns - repo.NumClosedActionRuns
|
||||||
|
|
||||||
// this is a temporary behaviour to support old repos, next step is to store the object format in the database
|
|
||||||
// and read from database so this line could be removed. To not depend on git module, we use a constant variable here
|
|
||||||
repo.ObjectFormatName = "sha1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAttributes loads attributes of the repository.
|
// LoadAttributes loads attributes of the repository.
|
||||||
|
|
|
@ -27,7 +27,7 @@ const (
|
||||||
type RepoIndexerStatus struct { //revive:disable-line:exported
|
type RepoIndexerStatus struct { //revive:disable-line:exported
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
RepoID int64 `xorm:"INDEX(s)"`
|
RepoID int64 `xorm:"INDEX(s)"`
|
||||||
CommitSha string `xorm:"VARCHAR(40)"`
|
CommitSha string `xorm:"VARCHAR(64)"`
|
||||||
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
|
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
144
modules/git/blame_sha256_test.go
Normal file
144
modules/git/blame_sha256_test.go
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadingBlameOutputSha256(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
t.Run("Without .git-blame-ignore-revs", func(t *testing.T) {
|
||||||
|
repo, err := OpenRepository(ctx, "./tests/repos/repo5_pulls_sha256")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
commit, err := repo.GetCommit("0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
parts := []*BlamePart{
|
||||||
|
{
|
||||||
|
Sha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
|
||||||
|
Lines: []string{
|
||||||
|
"# test_repo",
|
||||||
|
"Test repository for testing migration from github to gitea",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Sha: "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345",
|
||||||
|
Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"},
|
||||||
|
PreviousSha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca",
|
||||||
|
PreviousPath: "README.md",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, bypass := range []bool{false, true} {
|
||||||
|
blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, blameReader)
|
||||||
|
defer blameReader.Close()
|
||||||
|
|
||||||
|
assert.False(t, blameReader.UsesIgnoreRevs())
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, part, actualPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure all parts have been read
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.Nil(t, actualPart)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("With .git-blame-ignore-revs", func(t *testing.T) {
|
||||||
|
repo, err := OpenRepository(ctx, "./tests/repos/repo6_blame_sha256")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
full := []*BlamePart{
|
||||||
|
{
|
||||||
|
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
Lines: []string{"line", "line"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Sha: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
|
||||||
|
Lines: []string{"changed line"},
|
||||||
|
PreviousSha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
PreviousPath: "blame.txt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
Lines: []string{"line", "line", ""},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
CommitID string
|
||||||
|
UsesIgnoreRevs bool
|
||||||
|
Bypass bool
|
||||||
|
Parts []*BlamePart
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
|
||||||
|
UsesIgnoreRevs: true,
|
||||||
|
Bypass: false,
|
||||||
|
Parts: []*BlamePart{
|
||||||
|
{
|
||||||
|
Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc",
|
||||||
|
Lines: []string{"line", "line", "changed line", "line", "line", ""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3",
|
||||||
|
UsesIgnoreRevs: false,
|
||||||
|
Bypass: true,
|
||||||
|
Parts: full,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
|
||||||
|
UsesIgnoreRevs: false,
|
||||||
|
Bypass: false,
|
||||||
|
Parts: full,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe",
|
||||||
|
UsesIgnoreRevs: false,
|
||||||
|
Bypass: false,
|
||||||
|
Parts: full,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
commit, err := repo.GetCommit(c.CommitID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
blameReader, err := CreateBlameReader(ctx, repo.objectFormat, "./tests/repos/repo6_blame_sha256", commit, "blame.txt", c.Bypass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, blameReader)
|
||||||
|
defer blameReader.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs())
|
||||||
|
|
||||||
|
for _, part := range c.Parts {
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, part, actualPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure all parts have been read
|
||||||
|
actualPart, err := blameReader.NextPart()
|
||||||
|
assert.Nil(t, actualPart)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -85,6 +85,8 @@ readLoop:
|
||||||
commit.Committer.Decode(data)
|
commit.Committer.Decode(data)
|
||||||
_, _ = payloadSB.Write(line)
|
_, _ = payloadSB.Write(line)
|
||||||
case "gpgsig":
|
case "gpgsig":
|
||||||
|
fallthrough
|
||||||
|
case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
|
||||||
_, _ = signatureSB.Write(data)
|
_, _ = signatureSB.Write(data)
|
||||||
_ = signatureSB.WriteByte('\n')
|
_ = signatureSB.WriteByte('\n')
|
||||||
pgpsig = true
|
pgpsig = true
|
||||||
|
|
195
modules/git/commit_sha256_test.go
Normal file
195
modules/git/commit_sha256_test.go
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build !gogit
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommitsCountSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
commitsCount, err := CommitsCount(DefaultContext,
|
||||||
|
CommitsCountOptions{
|
||||||
|
RepoPath: bareRepo1Path,
|
||||||
|
Revision: []string{"f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc"},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(3), commitsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitsCountWithoutBaseSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
commitsCount, err := CommitsCount(DefaultContext,
|
||||||
|
CommitsCountOptions{
|
||||||
|
RepoPath: bareRepo1Path,
|
||||||
|
Not: "main",
|
||||||
|
Revision: []string{"branch1"},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(2), commitsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFullCommitIDSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "f004f4")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFullCommitIDErrorSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "unknown")
|
||||||
|
assert.Empty(t, id)
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitFromReaderSha256(t *testing.T) {
|
||||||
|
commitString := `9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 commit 1114
|
||||||
|
tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
|
||||||
|
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
|
||||||
|
author Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
committer Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
|
||||||
|
` + " " + `
|
||||||
|
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
|
||||||
|
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
|
||||||
|
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
|
||||||
|
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
|
||||||
|
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
|
||||||
|
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
|
||||||
|
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
|
||||||
|
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
|
||||||
|
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
|
||||||
|
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
|
||||||
|
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
|
||||||
|
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
|
||||||
|
=xybZ
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
|
||||||
|
signed commit`
|
||||||
|
|
||||||
|
sha := &Sha256Hash{
|
||||||
|
0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59,
|
||||||
|
0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0,
|
||||||
|
}
|
||||||
|
gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare_sha256"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, gitRepo)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.NotNil(t, commitFromReader) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.EqualValues(t, sha, commitFromReader.ID)
|
||||||
|
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz
|
||||||
|
dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd
|
||||||
|
aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK
|
||||||
|
WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx
|
||||||
|
1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4
|
||||||
|
JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP
|
||||||
|
oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6
|
||||||
|
U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy
|
||||||
|
zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI
|
||||||
|
VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
|
||||||
|
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
|
||||||
|
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
|
||||||
|
=xybZ
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
`, commitFromReader.Signature.Signature)
|
||||||
|
assert.EqualValues(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
|
||||||
|
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
|
||||||
|
author Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
committer Adam Majer <amajer@suse.de> 1698676906 +0100
|
||||||
|
|
||||||
|
signed commit`, commitFromReader.Signature.Payload)
|
||||||
|
assert.EqualValues(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
|
||||||
|
|
||||||
|
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
commitFromReader.CommitMessage += "\n\n"
|
||||||
|
commitFromReader.Signature.Payload += "\n\n"
|
||||||
|
assert.EqualValues(t, commitFromReader, commitFromReader2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasPreviousCommitSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256")
|
||||||
|
|
||||||
|
repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer repo.Close()
|
||||||
|
|
||||||
|
commit, err := repo.GetCommit("f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
parentSHA := MustIDFromString("b0ec7af4547047f12d5093e37ef8f1b3b5415ed8ee17894d43a34d7d34212e9c")
|
||||||
|
notParentSHA := MustIDFromString("42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236")
|
||||||
|
assert.Equal(t, repo.objectFormat, parentSHA.Type())
|
||||||
|
assert.Equal(t, repo.objectFormat.Name(), "sha256")
|
||||||
|
|
||||||
|
haz, err := commit.HasPreviousCommit(parentSHA)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, haz)
|
||||||
|
|
||||||
|
hazNot, err := commit.HasPreviousCommit(notParentSHA)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, hazNot)
|
||||||
|
|
||||||
|
selfNot, err := commit.HasPreviousCommit(commit.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, selfNot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCommitFileStatusMergesSha256(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo6_merge_sha256")
|
||||||
|
|
||||||
|
commitFileStatus, err := GetCommitFileStatus(DefaultContext, bareRepo1Path, "d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
expected := CommitFileStatus{
|
||||||
|
[]string{
|
||||||
|
"add_file.txt",
|
||||||
|
},
|
||||||
|
[]string{},
|
||||||
|
[]string{
|
||||||
|
"to_modify.txt",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expected.Added, commitFileStatus.Added)
|
||||||
|
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
|
||||||
|
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
|
||||||
|
|
||||||
|
expected = CommitFileStatus{
|
||||||
|
[]string{},
|
||||||
|
[]string{
|
||||||
|
"to_remove.txt",
|
||||||
|
},
|
||||||
|
[]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
commitFileStatus, err = GetCommitFileStatus(DefaultContext, bareRepo1Path, "da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expected.Added, commitFileStatus.Added)
|
||||||
|
assert.Equal(t, expected.Removed, commitFileStatus.Removed)
|
||||||
|
assert.Equal(t, expected.Modified, commitFileStatus.Modified)
|
||||||
|
}
|
|
@ -185,7 +185,13 @@ func InitFull(ctx context.Context) (err error) {
|
||||||
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
|
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
|
||||||
}
|
}
|
||||||
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
|
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
|
||||||
SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil
|
SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit
|
||||||
|
if SupportHashSha256 {
|
||||||
|
SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat)
|
||||||
|
} else {
|
||||||
|
log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
if setting.LFS.StartServer {
|
if setting.LFS.StartServer {
|
||||||
if CheckGitVersionAtLeast("2.1.2") != nil {
|
if CheckGitVersionAtLeast("2.1.2") != nil {
|
||||||
return errors.New("LFS server support requires Git >= 2.1.2")
|
return errors.New("LFS server support requires Git >= 2.1.2")
|
||||||
|
|
|
@ -5,6 +5,7 @@ package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
@ -12,6 +13,9 @@ import (
|
||||||
// sha1Pattern can be used to determine if a string is an valid sha
|
// sha1Pattern can be used to determine if a string is an valid sha
|
||||||
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
||||||
|
|
||||||
|
// sha256Pattern can be used to determine if a string is an valid sha
|
||||||
|
var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
|
||||||
|
|
||||||
type ObjectFormat interface {
|
type ObjectFormat interface {
|
||||||
// Name returns the name of the object format
|
// Name returns the name of the object format
|
||||||
Name() string
|
Name() string
|
||||||
|
@ -29,11 +33,12 @@ type ObjectFormat interface {
|
||||||
ComputeHash(t ObjectType, content []byte) ObjectID
|
ComputeHash(t ObjectType, content []byte) ObjectID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SHA1 Type */
|
||||||
type Sha1ObjectFormatImpl struct{}
|
type Sha1ObjectFormatImpl struct{}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
emptyObjectID = &Sha1Hash{}
|
emptySha1ObjectID = &Sha1Hash{}
|
||||||
emptyTree = &Sha1Hash{
|
emptySha1Tree = &Sha1Hash{
|
||||||
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
||||||
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
||||||
}
|
}
|
||||||
|
@ -41,11 +46,11 @@ var (
|
||||||
|
|
||||||
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
||||||
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
|
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
|
||||||
return emptyObjectID
|
return emptySha1ObjectID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
|
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
|
||||||
return emptyTree
|
return emptySha1Tree
|
||||||
}
|
}
|
||||||
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
|
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
|
||||||
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
|
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
|
||||||
|
@ -72,11 +77,59 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID
|
||||||
return &sha1
|
return &sha1
|
||||||
}
|
}
|
||||||
|
|
||||||
var Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
|
/* SHA256 Type */
|
||||||
|
type Sha256ObjectFormatImpl struct{}
|
||||||
|
|
||||||
|
var (
|
||||||
|
emptySha256ObjectID = &Sha256Hash{}
|
||||||
|
emptySha256Tree = &Sha256Hash{
|
||||||
|
0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1,
|
||||||
|
0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5,
|
||||||
|
0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc,
|
||||||
|
0x53, 0x21,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (Sha256ObjectFormatImpl) Name() string { return "sha256" }
|
||||||
|
func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID {
|
||||||
|
return emptySha256ObjectID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Sha256ObjectFormatImpl) EmptyTree() ObjectID {
|
||||||
|
return emptySha256Tree
|
||||||
|
}
|
||||||
|
func (Sha256ObjectFormatImpl) FullLength() int { return 64 }
|
||||||
|
func (Sha256ObjectFormatImpl) IsValid(input string) bool {
|
||||||
|
return sha256Pattern.MatchString(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID {
|
||||||
|
var id Sha256Hash
|
||||||
|
copy(id[0:32], b)
|
||||||
|
return &id
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeHash compute the hash for a given ObjectType and content
|
||||||
|
func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID {
|
||||||
|
hasher := sha256.New()
|
||||||
|
_, _ = hasher.Write(t.Bytes())
|
||||||
|
_, _ = hasher.Write([]byte(" "))
|
||||||
|
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
|
||||||
|
_, _ = hasher.Write([]byte{0})
|
||||||
|
|
||||||
|
// HashSum generates a SHA256 for the provided hash
|
||||||
|
var sha256 Sha1Hash
|
||||||
|
copy(sha256[:], hasher.Sum(nil))
|
||||||
|
return &sha256
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{}
|
||||||
|
Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
|
||||||
|
)
|
||||||
|
|
||||||
var SupportedObjectFormats = []ObjectFormat{
|
var SupportedObjectFormats = []ObjectFormat{
|
||||||
Sha1ObjectFormat,
|
Sha1ObjectFormat,
|
||||||
// TODO: add sha256
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ObjectFormatFromName(name string) ObjectFormat {
|
func ObjectFormatFromName(name string) ObjectFormat {
|
||||||
|
|
|
@ -16,6 +16,7 @@ type ObjectID interface {
|
||||||
Type() ObjectFormat
|
Type() ObjectFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SHA1 */
|
||||||
type Sha1Hash [20]byte
|
type Sha1Hash [20]byte
|
||||||
|
|
||||||
func (h *Sha1Hash) String() string {
|
func (h *Sha1Hash) String() string {
|
||||||
|
@ -39,6 +40,21 @@ func MustIDFromString(hexHash string) ObjectID {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SHA256 */
|
||||||
|
type Sha256Hash [32]byte
|
||||||
|
|
||||||
|
func (h *Sha256Hash) String() string {
|
||||||
|
return hex.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Sha256Hash) IsZero() bool {
|
||||||
|
empty := Sha256Hash{}
|
||||||
|
return bytes.Equal(empty[:], h[:])
|
||||||
|
}
|
||||||
|
func (h *Sha256Hash) RawValue() []byte { return h[:] }
|
||||||
|
func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat }
|
||||||
|
|
||||||
|
/* utility */
|
||||||
func NewIDFromString(hexHash string) (ObjectID, error) {
|
func NewIDFromString(hexHash string) (ObjectID, error) {
|
||||||
var theObjectFormat ObjectFormat
|
var theObjectFormat ObjectFormat
|
||||||
for _, objectFormat := range SupportedObjectFormats {
|
for _, objectFormat := range SupportedObjectFormats {
|
||||||
|
|
|
@ -13,6 +13,8 @@ func ParseGogitHash(h plumbing.Hash) ObjectID {
|
||||||
switch hash.Size {
|
switch hash.Size {
|
||||||
case 20:
|
case 20:
|
||||||
return Sha1ObjectFormat.MustID(h[:])
|
return Sha1ObjectFormat.MustID(h[:])
|
||||||
|
case 32:
|
||||||
|
return Sha256ObjectFormat.MustID(h[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -97,15 +97,12 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand(ctx, "init")
|
cmd := NewCommand(ctx, "init")
|
||||||
if SupportHashSha256 {
|
|
||||||
if objectFormatName == "" {
|
|
||||||
objectFormatName = Sha1ObjectFormat.Name()
|
|
||||||
}
|
|
||||||
if !IsValidObjectFormat(objectFormatName) {
|
if !IsValidObjectFormat(objectFormatName) {
|
||||||
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
||||||
}
|
}
|
||||||
cmd.AddOptionValues("--object-format", objectFormatName)
|
cmd.AddOptionValues("--object-format", objectFormatName)
|
||||||
}
|
|
||||||
if bare {
|
if bare {
|
||||||
cmd.AddArguments("--bare")
|
cmd.AddArguments("--bare")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var isGogit bool
|
||||||
|
|
||||||
// contextKey is a value for use with context.WithValue.
|
// contextKey is a value for use with context.WithValue.
|
||||||
type contextKey struct {
|
type contextKey struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -21,6 +21,10 @@ import (
|
||||||
"github.com/go-git/go-git/v5/storage/filesystem"
|
"github.com/go-git/go-git/v5/storage/filesystem"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isGogit = true
|
||||||
|
}
|
||||||
|
|
||||||
// Repository represents a Git repository.
|
// Repository represents a Git repository.
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
Path string
|
Path string
|
||||||
|
|
|
@ -15,6 +15,10 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isGogit = false
|
||||||
|
}
|
||||||
|
|
||||||
// Repository represents a Git repository.
|
// Repository represents a Git repository.
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
Path string
|
Path string
|
||||||
|
|
1
modules/git/tests/repos/repo1_bare_sha256/HEAD
Normal file
1
modules/git/tests/repos/repo1_bare_sha256/HEAD
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/main
|
6
modules/git/tests/repos/repo1_bare_sha256/config
Normal file
6
modules/git/tests/repos/repo1_bare_sha256/config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 1
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
|
[extensions]
|
||||||
|
objectformat = sha256
|
1
modules/git/tests/repos/repo1_bare_sha256/description
Normal file
1
modules/git/tests/repos/repo1_bare_sha256/description
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
6
modules/git/tests/repos/repo1_bare_sha256/info/exclude
Normal file
6
modules/git/tests/repos/repo1_bare_sha256/info/exclude
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
7
modules/git/tests/repos/repo1_bare_sha256/info/refs
Normal file
7
modules/git/tests/repos/repo1_bare_sha256/info/refs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236 refs/heads/branch1
|
||||||
|
5bc2249e32e0ba40a08879fba2bd4e97a13cb345831549f4bc5649525da8f6cc refs/heads/branch2
|
||||||
|
9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/heads/main
|
||||||
|
29a82d4fc02e19190fb489cc90d5730ed91970b49f4e39acda2798b3dd4f814e refs/tags/signed-tag
|
||||||
|
9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/tags/signed-tag^{}
|
||||||
|
171822a62559f3aa28a00aa3785dbe915d6a8eb02712682740db44fc8bd2187a refs/tags/test
|
||||||
|
6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1 refs/tags/test^{}
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
P pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.pack
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8
modules/git/tests/repos/repo1_bare_sha256/packed-refs
Normal file
8
modules/git/tests/repos/repo1_bare_sha256/packed-refs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# pack-refs with: peeled fully-peeled sorted
|
||||||
|
42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236 refs/heads/branch1
|
||||||
|
5bc2249e32e0ba40a08879fba2bd4e97a13cb345831549f4bc5649525da8f6cc refs/heads/branch2
|
||||||
|
9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/heads/main
|
||||||
|
29a82d4fc02e19190fb489cc90d5730ed91970b49f4e39acda2798b3dd4f814e refs/tags/signed-tag
|
||||||
|
^9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0
|
||||||
|
171822a62559f3aa28a00aa3785dbe915d6a8eb02712682740db44fc8bd2187a refs/tags/test
|
||||||
|
^6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1
|
|
@ -0,0 +1 @@
|
||||||
|
9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0
|
1
modules/git/tests/repos/repo5_pulls_sha256/HEAD
Normal file
1
modules/git/tests/repos/repo5_pulls_sha256/HEAD
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/main
|
6
modules/git/tests/repos/repo5_pulls_sha256/config
Normal file
6
modules/git/tests/repos/repo5_pulls_sha256/config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 1
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
|
[extensions]
|
||||||
|
objectformat = sha256
|
1
modules/git/tests/repos/repo5_pulls_sha256/description
Normal file
1
modules/git/tests/repos/repo5_pulls_sha256/description
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
4
modules/git/tests/repos/repo5_pulls_sha256/info/refs
Normal file
4
modules/git/tests/repos/repo5_pulls_sha256/info/refs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main
|
||||||
|
35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main-clone
|
||||||
|
7f50a4906503378b0bbb7d61bd2ca8d8d8ff4f7a2474980f99402d742ccc9665 refs/heads/test-patch-1
|
||||||
|
1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca refs/tags/v0.9.99
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
P pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.pack
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5
modules/git/tests/repos/repo5_pulls_sha256/packed-refs
Normal file
5
modules/git/tests/repos/repo5_pulls_sha256/packed-refs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# pack-refs with: peeled fully-peeled sorted
|
||||||
|
35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main
|
||||||
|
35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main-clone
|
||||||
|
7f50a4906503378b0bbb7d61bd2ca8d8d8ff4f7a2474980f99402d742ccc9665 refs/heads/test-patch-1
|
||||||
|
1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca refs/tags/v0.9.99
|
|
@ -0,0 +1 @@
|
||||||
|
35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b
|
1
modules/git/tests/repos/repo6_blame_sha256/HEAD
Normal file
1
modules/git/tests/repos/repo6_blame_sha256/HEAD
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/main
|
6
modules/git/tests/repos/repo6_blame_sha256/config
Normal file
6
modules/git/tests/repos/repo6_blame_sha256/config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 1
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
|
[extensions]
|
||||||
|
objectformat = sha256
|
1
modules/git/tests/repos/repo6_blame_sha256/description
Normal file
1
modules/git/tests/repos/repo6_blame_sha256/description
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
6
modules/git/tests/repos/repo6_blame_sha256/info/exclude
Normal file
6
modules/git/tests/repos/repo6_blame_sha256/info/exclude
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
1
modules/git/tests/repos/repo6_blame_sha256/info/refs
Normal file
1
modules/git/tests/repos/repo6_blame_sha256/info/refs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 refs/heads/main
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
P pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
modules/git/tests/repos/repo6_blame_sha256/packed-refs
Normal file
2
modules/git/tests/repos/repo6_blame_sha256/packed-refs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# pack-refs with: peeled fully-peeled sorted
|
||||||
|
e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 refs/heads/main
|
|
@ -0,0 +1 @@
|
||||||
|
e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3
|
1
modules/git/tests/repos/repo6_merge_sha256/HEAD
Normal file
1
modules/git/tests/repos/repo6_merge_sha256/HEAD
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/main
|
6
modules/git/tests/repos/repo6_merge_sha256/config
Normal file
6
modules/git/tests/repos/repo6_merge_sha256/config
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 1
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
|
[extensions]
|
||||||
|
objectformat = sha256
|
1
modules/git/tests/repos/repo6_merge_sha256/description
Normal file
1
modules/git/tests/repos/repo6_merge_sha256/description
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
6
modules/git/tests/repos/repo6_merge_sha256/info/exclude
Normal file
6
modules/git/tests/repos/repo6_merge_sha256/info/exclude
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
4
modules/git/tests/repos/repo6_merge_sha256/info/refs
Normal file
4
modules/git/tests/repos/repo6_merge_sha256/info/refs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1 refs/heads/main
|
||||||
|
b45258e9823233edea2d40d183742f29630e1e69300479fb4a55eabfe9b1d8bf refs/heads/merge/add_file
|
||||||
|
ff2b996e2fa366146300e4c9e51ccb6818147b360e46fa1437334f4a690955ce refs/heads/merge/modify_file
|
||||||
|
da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172 refs/heads/merge/remove_file
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
P pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.pack
|
||||||
|
P pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
5
modules/git/tests/repos/repo6_merge_sha256/packed-refs
Normal file
5
modules/git/tests/repos/repo6_merge_sha256/packed-refs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# pack-refs with: peeled fully-peeled sorted
|
||||||
|
d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1 refs/heads/main
|
||||||
|
b45258e9823233edea2d40d183742f29630e1e69300479fb4a55eabfe9b1d8bf refs/heads/merge/add_file
|
||||||
|
ff2b996e2fa366146300e4c9e51ccb6818147b360e46fa1437334f4a690955ce refs/heads/merge/modify_file
|
||||||
|
da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172 refs/heads/merge/remove_file
|
|
@ -0,0 +1 @@
|
||||||
|
d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1
|
|
@ -45,19 +45,19 @@ var (
|
||||||
|
|
||||||
// valid chars in encoded path and parameter: [-+~_%.a-zA-Z0-9/]
|
// valid chars in encoded path and parameter: [-+~_%.a-zA-Z0-9/]
|
||||||
|
|
||||||
// sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
|
// hashCurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
|
||||||
// Although SHA1 hashes are 40 chars long, the regex matches the hash from 7 to 40 chars in length
|
// Although SHA1 hashes are 40 chars long, SHA256 are 64, the regex matches the hash from 7 to 64 chars in length
|
||||||
// so that abbreviated hash links can be used as well. This matches git and GitHub usability.
|
// so that abbreviated hash links can be used as well. This matches git and GitHub usability.
|
||||||
sha1CurrentPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-f]{7,40})(?:\s|$|\)|\]|[.,](\s|$))`)
|
hashCurrentPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-f]{7,64})(?:\s|$|\)|\]|[.,](\s|$))`)
|
||||||
|
|
||||||
// shortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax
|
// shortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax
|
||||||
shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`)
|
shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`)
|
||||||
|
|
||||||
// anySHA1Pattern splits url containing SHA into parts
|
// anySHA1Pattern splits url containing SHA into parts
|
||||||
anySHA1Pattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`)
|
anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`)
|
||||||
|
|
||||||
// comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash"
|
// comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash"
|
||||||
comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,40})(\.\.\.?)([0-9a-f]{7,40})?(#[-+~_%.a-zA-Z0-9]+)?`)
|
comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`)
|
||||||
|
|
||||||
validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
|
validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
|
||||||
|
|
||||||
|
@ -171,13 +171,13 @@ type processor func(ctx *RenderContext, node *html.Node)
|
||||||
var defaultProcessors = []processor{
|
var defaultProcessors = []processor{
|
||||||
fullIssuePatternProcessor,
|
fullIssuePatternProcessor,
|
||||||
comparePatternProcessor,
|
comparePatternProcessor,
|
||||||
fullSha1PatternProcessor,
|
fullHashPatternProcessor,
|
||||||
shortLinkProcessor,
|
shortLinkProcessor,
|
||||||
linkProcessor,
|
linkProcessor,
|
||||||
mentionProcessor,
|
mentionProcessor,
|
||||||
issueIndexPatternProcessor,
|
issueIndexPatternProcessor,
|
||||||
commitCrossReferencePatternProcessor,
|
commitCrossReferencePatternProcessor,
|
||||||
sha1CurrentPatternProcessor,
|
hashCurrentPatternProcessor,
|
||||||
emailAddressProcessor,
|
emailAddressProcessor,
|
||||||
emojiProcessor,
|
emojiProcessor,
|
||||||
emojiShortCodeProcessor,
|
emojiShortCodeProcessor,
|
||||||
|
@ -199,12 +199,12 @@ func PostProcess(
|
||||||
var commitMessageProcessors = []processor{
|
var commitMessageProcessors = []processor{
|
||||||
fullIssuePatternProcessor,
|
fullIssuePatternProcessor,
|
||||||
comparePatternProcessor,
|
comparePatternProcessor,
|
||||||
fullSha1PatternProcessor,
|
fullHashPatternProcessor,
|
||||||
linkProcessor,
|
linkProcessor,
|
||||||
mentionProcessor,
|
mentionProcessor,
|
||||||
issueIndexPatternProcessor,
|
issueIndexPatternProcessor,
|
||||||
commitCrossReferencePatternProcessor,
|
commitCrossReferencePatternProcessor,
|
||||||
sha1CurrentPatternProcessor,
|
hashCurrentPatternProcessor,
|
||||||
emailAddressProcessor,
|
emailAddressProcessor,
|
||||||
emojiProcessor,
|
emojiProcessor,
|
||||||
emojiShortCodeProcessor,
|
emojiShortCodeProcessor,
|
||||||
|
@ -231,12 +231,12 @@ func RenderCommitMessage(
|
||||||
var commitMessageSubjectProcessors = []processor{
|
var commitMessageSubjectProcessors = []processor{
|
||||||
fullIssuePatternProcessor,
|
fullIssuePatternProcessor,
|
||||||
comparePatternProcessor,
|
comparePatternProcessor,
|
||||||
fullSha1PatternProcessor,
|
fullHashPatternProcessor,
|
||||||
linkProcessor,
|
linkProcessor,
|
||||||
mentionProcessor,
|
mentionProcessor,
|
||||||
issueIndexPatternProcessor,
|
issueIndexPatternProcessor,
|
||||||
commitCrossReferencePatternProcessor,
|
commitCrossReferencePatternProcessor,
|
||||||
sha1CurrentPatternProcessor,
|
hashCurrentPatternProcessor,
|
||||||
emojiShortCodeProcessor,
|
emojiShortCodeProcessor,
|
||||||
emojiProcessor,
|
emojiProcessor,
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ func RenderIssueTitle(
|
||||||
return renderProcessString(ctx, []processor{
|
return renderProcessString(ctx, []processor{
|
||||||
issueIndexPatternProcessor,
|
issueIndexPatternProcessor,
|
||||||
commitCrossReferencePatternProcessor,
|
commitCrossReferencePatternProcessor,
|
||||||
sha1CurrentPatternProcessor,
|
hashCurrentPatternProcessor,
|
||||||
emojiShortCodeProcessor,
|
emojiShortCodeProcessor,
|
||||||
emojiProcessor,
|
emojiProcessor,
|
||||||
}, title)
|
}, title)
|
||||||
|
@ -946,15 +946,15 @@ func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fullSha1PatternProcessor renders SHA containing URLs
|
// fullHashPatternProcessor renders SHA containing URLs
|
||||||
func fullSha1PatternProcessor(ctx *RenderContext, node *html.Node) {
|
func fullHashPatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
if ctx.Metas == nil {
|
if ctx.Metas == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
next := node.NextSibling
|
next := node.NextSibling
|
||||||
for node != nil && node != next {
|
for node != nil && node != next {
|
||||||
m := anySHA1Pattern.FindStringSubmatchIndex(node.Data)
|
m := anyHashPattern.FindStringSubmatchIndex(node.Data)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1111,9 +1111,9 @@ func emojiProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sha1CurrentPatternProcessor renders SHA1 strings to corresponding links that
|
// hashCurrentPatternProcessor renders SHA1 strings to corresponding links that
|
||||||
// are assumed to be in the same repository.
|
// are assumed to be in the same repository.
|
||||||
func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
|
func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
if ctx.Metas == nil || ctx.Metas["user"] == "" || ctx.Metas["repo"] == "" || ctx.Metas["repoPath"] == "" {
|
if ctx.Metas == nil || ctx.Metas["user"] == "" || ctx.Metas["repo"] == "" || ctx.Metas["repoPath"] == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1124,7 +1124,7 @@ func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
ctx.ShaExistCache = make(map[string]bool)
|
ctx.ShaExistCache = make(map[string]bool)
|
||||||
}
|
}
|
||||||
for node != nil && node != next && start < len(node.Data) {
|
for node != nil && node != next && start < len(node.Data) {
|
||||||
m := sha1CurrentPattern.FindStringSubmatchIndex(node.Data[start:])
|
m := hashCurrentPattern.FindStringSubmatchIndex(node.Data[start:])
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,10 +390,10 @@ func TestRegExp_sha1CurrentPattern(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range trueTestCases {
|
for _, testCase := range trueTestCases {
|
||||||
assert.True(t, sha1CurrentPattern.MatchString(testCase))
|
assert.True(t, hashCurrentPattern.MatchString(testCase))
|
||||||
}
|
}
|
||||||
for _, testCase := range falseTestCases {
|
for _, testCase := range falseTestCases {
|
||||||
assert.False(t, sha1CurrentPattern.MatchString(testCase))
|
assert.False(t, hashCurrentPattern.MatchString(testCase))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +427,7 @@ func TestRegExp_anySHA1Pattern(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range testCases {
|
for k, v := range testCases {
|
||||||
assert.Equal(t, anySHA1Pattern.FindStringSubmatch(k)[1:], v)
|
assert.Equal(t, anyHashPattern.FindStringSubmatch(k)[1:], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ var (
|
||||||
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
||||||
// crossReferenceCommitPattern matches a string that references a commit in a different repository
|
// crossReferenceCommitPattern matches a string that references a commit in a different repository
|
||||||
// e.g. go-gitea/gitea@d8a994ef, go-gitea/gitea@d8a994ef243349f321568f9e36d5c3f444b99cae (7-40 characters)
|
// e.g. go-gitea/gitea@d8a994ef, go-gitea/gitea@d8a994ef243349f321568f9e36d5c3f444b99cae (7-40 characters)
|
||||||
crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,40})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,64})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
||||||
// spaceTrimmedPattern let's find the trailing space
|
// spaceTrimmedPattern let's find the trailing space
|
||||||
spaceTrimmedPattern = regexp.MustCompile(`(?:.*[0-9a-zA-Z-_])\s`)
|
spaceTrimmedPattern = regexp.MustCompile(`(?:.*[0-9a-zA-Z-_])\s`)
|
||||||
// timeLogPattern matches string for time tracking
|
// timeLogPattern matches string for time tracking
|
||||||
|
|
|
@ -343,7 +343,7 @@ func TestFindRenderizableCommitCrossReference(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Input: "go-gitea/gitea@abcd1234abcd1234abcd1234abcd1234abcd12340", // longer than 40 characters
|
Input: "go-gitea/gitea@abcd1234abcd1234abcd1234abcd1234abcd12341234512345123451234512345", // longer than 64 characters
|
||||||
Expected: nil,
|
Expected: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,6 +105,9 @@ type Repository struct {
|
||||||
AvatarURL string `json:"avatar_url"`
|
AvatarURL string `json:"avatar_url"`
|
||||||
Internal bool `json:"internal"`
|
Internal bool `json:"internal"`
|
||||||
MirrorInterval string `json:"mirror_interval"`
|
MirrorInterval string `json:"mirror_interval"`
|
||||||
|
// ObjectFormatName of the underlying git repository
|
||||||
|
// enum: sha1,sha256
|
||||||
|
ObjectFormatName string `json:"object_format_name"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
MirrorUpdated time.Time `json:"mirror_updated,omitempty"`
|
MirrorUpdated time.Time `json:"mirror_updated,omitempty"`
|
||||||
RepoTransfer *RepoTransfer `json:"repo_transfer"`
|
RepoTransfer *RepoTransfer `json:"repo_transfer"`
|
||||||
|
@ -139,6 +142,9 @@ type CreateRepoOption struct {
|
||||||
// TrustModel of the repository
|
// TrustModel of the repository
|
||||||
// enum: default,collaborator,committer,collaboratorcommitter
|
// enum: default,collaborator,committer,collaboratorcommitter
|
||||||
TrustModel string `json:"trust_model"`
|
TrustModel string `json:"trust_model"`
|
||||||
|
// ObjectFormatName of the underlying git repository
|
||||||
|
// enum: sha1,sha256
|
||||||
|
ObjectFormatName string `json:"object_format_name" binding:"MaxSize(6)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditRepoOption options when editing a repository's properties
|
// EditRepoOption options when editing a repository's properties
|
||||||
|
|
|
@ -41,3 +41,7 @@ func (su *StringUtils) Cut(s, sep string) []any {
|
||||||
func (su *StringUtils) EllipsisString(s string, max int) string {
|
func (su *StringUtils) EllipsisString(s string, max int) string {
|
||||||
return base.EllipsisString(s, max)
|
return base.EllipsisString(s, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (su *StringUtils) ToUpper(s string) string {
|
||||||
|
return strings.ToUpper(s)
|
||||||
|
}
|
||||||
|
|
|
@ -970,6 +970,8 @@ issue_labels_helper = Select an issue label set.
|
||||||
license = License
|
license = License
|
||||||
license_helper = Select a license file.
|
license_helper = Select a license file.
|
||||||
license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See <a target="_blank" rel="noopener noreferrer" href="%s">Choose a license.</a>
|
license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See <a target="_blank" rel="noopener noreferrer" href="%s">Choose a license.</a>
|
||||||
|
object_format = Object Format
|
||||||
|
object_format_helper = Object format of the repository. Cannot be changed later. SHA1 is most compatible.
|
||||||
readme = README
|
readme = README
|
||||||
readme_helper = Select a README file template.
|
readme_helper = Select a README file template.
|
||||||
readme_helper_desc = This is the place where you can write a complete description for your project.
|
readme_helper_desc = This is the place where you can write a complete description for your project.
|
||||||
|
@ -1038,6 +1040,7 @@ desc.public = Public
|
||||||
desc.template = Template
|
desc.template = Template
|
||||||
desc.internal = Internal
|
desc.internal = Internal
|
||||||
desc.archived = Archived
|
desc.archived = Archived
|
||||||
|
desc.sha256 = SHA256
|
||||||
|
|
||||||
template.items = Template Items
|
template.items = Template Items
|
||||||
template.git_content = Git Content (Default Branch)
|
template.git_content = Git Content (Default Branch)
|
||||||
|
|
|
@ -253,7 +253,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
||||||
DefaultBranch: opt.DefaultBranch,
|
DefaultBranch: opt.DefaultBranch,
|
||||||
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
||||||
IsTemplate: opt.Template,
|
IsTemplate: opt.Template,
|
||||||
ObjectFormatName: git.Sha1ObjectFormat.Name(),
|
ObjectFormatName: opt.ObjectFormatName,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
|
|
|
@ -36,8 +36,8 @@ func gitHTTPRouters(m *web.Route) {
|
||||||
m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
|
m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
|
||||||
m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks)
|
m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks)
|
||||||
m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile(""))
|
m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile(""))
|
||||||
m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38,62}}", repo.GetLooseObject)
|
||||||
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.pack", repo.GetPackFile)
|
||||||
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.idx", repo.GetIdxFile)
|
||||||
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
|
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,6 @@ func Create(ctx *context.Context) {
|
||||||
ctx.Data["private"] = getRepoPrivate(ctx)
|
ctx.Data["private"] = getRepoPrivate(ctx)
|
||||||
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
||||||
ctx.Data["default_branch"] = setting.Repository.DefaultBranch
|
ctx.Data["default_branch"] = setting.Repository.DefaultBranch
|
||||||
ctx.Data["hash_type"] = "sha1"
|
|
||||||
|
|
||||||
ctxUser := checkContextUser(ctx, ctx.FormInt64("org"))
|
ctxUser := checkContextUser(ctx, ctx.FormInt64("org"))
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
|
@ -179,6 +178,8 @@ func Create(ctx *context.Context) {
|
||||||
|
|
||||||
ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
|
ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
|
||||||
ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
|
ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
|
||||||
|
ctx.Data["SupportedObjectFormats"] = git.SupportedObjectFormats
|
||||||
|
ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplCreate)
|
ctx.HTML(http.StatusOK, tplCreate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1235,7 +1235,7 @@ func registerRoutes(m *web.Route) {
|
||||||
Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost)
|
Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost)
|
||||||
m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch).
|
m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch).
|
||||||
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
|
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
|
||||||
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick).
|
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,64})}/*").Get(repo.CherryPick).
|
||||||
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
|
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
|
||||||
}, repo.MustBeEditable)
|
}, repo.MustBeEditable)
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
|
@ -1377,8 +1377,8 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Combo("/*").
|
m.Combo("/*").
|
||||||
Get(repo.Wiki).
|
Get(repo.Wiki).
|
||||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||||
m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||||
m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
|
m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
|
||||||
}, repo.MustEnableWiki, func(ctx *context.Context) {
|
}, repo.MustEnableWiki, func(ctx *context.Context) {
|
||||||
ctx.Data["PageIsWiki"] = true
|
ctx.Data["PageIsWiki"] = true
|
||||||
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
|
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
|
||||||
|
@ -1498,9 +1498,9 @@ func registerRoutes(m *web.Route) {
|
||||||
|
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Get("/graph", repo.Graph)
|
m.Get("/graph", repo.Graph)
|
||||||
m.Get("/commit/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
m.Get("/commit/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||||
m.Get("/commit/{sha:([a-f0-9]{7,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
|
m.Get("/commit/{sha:([a-f0-9]{7,64})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
|
||||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||||
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
|
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
|
||||||
|
|
||||||
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
||||||
|
@ -1517,7 +1517,7 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Get("/forks", repo.Forks)
|
m.Get("/forks", repo.Forks)
|
||||||
}, context.RepoRef(), reqRepoCodeReader)
|
}, context.RepoRef(), reqRepoCodeReader)
|
||||||
m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
|
m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
|
||||||
}, ignSignIn, context.RepoAssignment, context.UnitTypes())
|
}, ignSignIn, context.RepoAssignment, context.UnitTypes())
|
||||||
|
|
||||||
m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit)
|
m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit)
|
||||||
|
|
|
@ -217,6 +217,10 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.ObjectFormatName == "" {
|
||||||
|
opts.ObjectFormatName = git.Sha1ObjectFormat.Name()
|
||||||
|
}
|
||||||
|
|
||||||
repo := &repo_model.Repository{
|
repo := &repo_model.Repository{
|
||||||
OwnerID: u.ID,
|
OwnerID: u.ID,
|
||||||
Owner: u,
|
Owner: u,
|
||||||
|
|
|
@ -87,6 +87,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
|
||||||
IsEmpty: opts.BaseRepo.IsEmpty,
|
IsEmpty: opts.BaseRepo.IsEmpty,
|
||||||
IsFork: true,
|
IsFork: true,
|
||||||
ForkID: opts.BaseRepo.ID,
|
ForkID: opts.BaseRepo.ID,
|
||||||
|
ObjectFormatName: opts.BaseRepo.ObjectFormatName,
|
||||||
}
|
}
|
||||||
|
|
||||||
oldRepoPath := opts.BaseRepo.RepoPath()
|
oldRepoPath := opts.BaseRepo.RepoPath()
|
||||||
|
|
|
@ -67,6 +67,9 @@
|
||||||
{{if .IsTemplate}}
|
{{if .IsTemplate}}
|
||||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if eq .ObjectFormatName "sha256"}}
|
||||||
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
|
||||||
|
{{end}}
|
||||||
{{if .IsMirror}}
|
{{if .IsMirror}}
|
||||||
{{svg "octicon-mirror"}}
|
{{svg "octicon-mirror"}}
|
||||||
{{else if .IsFork}}
|
{{else if .IsFork}}
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
{{if .IsTemplate}}
|
{{if .IsTemplate}}
|
||||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if eq .ObjectFormatName "sha256"}}
|
||||||
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
|
||||||
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-item-trailing">
|
<div class="flex-item-trailing">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th>
|
<th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th>
|
||||||
<th class="two wide sha">SHA1</th>
|
<th class="two wide sha">{{StringUtils.ToUpper $.Repository.ObjectFormatName}}</th>
|
||||||
<th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th>
|
<th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th>
|
||||||
<th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th>
|
<th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th>
|
||||||
<th class="one wide"></th>
|
<th class="one wide"></th>
|
||||||
|
|
|
@ -185,6 +185,19 @@
|
||||||
<input id="default_branch" name="default_branch" value="{{.default_branch}}" placeholder="{{.default_branch}}">
|
<input id="default_branch" name="default_branch" value="{{.default_branch}}" placeholder="{{.default_branch}}">
|
||||||
<span class="help">{{ctx.Locale.Tr "repo.default_branch_helper"}}</span>
|
<span class="help">{{ctx.Locale.Tr "repo.default_branch_helper"}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.object_format"}}</label>
|
||||||
|
<div class="ui selection owner dropdown">
|
||||||
|
<input type="hidden" id="object_format_name" name="object_format_name" value="{{.DefaultObjectFormat.Name}}" required>
|
||||||
|
<div class="default text">{{.DefaultObjectFormat.Name}}</div>
|
||||||
|
<div class="menu">
|
||||||
|
{{range .SupportedObjectFormats}}
|
||||||
|
<div class="item" data-value="{{.Name}}">{{.Name}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="help">{{ctx.Locale.Tr "repo.object_format_helper"}}</span>
|
||||||
|
</div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{ctx.Locale.Tr "repo.template"}}</label>
|
<label>{{ctx.Locale.Tr "repo.template"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
||||||
<div class="repo-icon" data-tooltip-content="{{ctx.Locale.Tr "repo.desc.template"}}">{{svg "octicon-repo-template" 18}}</div>
|
<div class="repo-icon" data-tooltip-content="{{ctx.Locale.Tr "repo.desc.template"}}">{{svg "octicon-repo-template" 18}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if eq .ObjectFormatName "sha256"}}
|
||||||
|
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{if not (or .IsBeingCreated .IsBroken)}}
|
{{if not (or .IsBeingCreated .IsBroken)}}
|
||||||
|
|
18
templates/swagger/v1_json.tmpl
generated
18
templates/swagger/v1_json.tmpl
generated
|
@ -18370,6 +18370,15 @@
|
||||||
"uniqueItems": true,
|
"uniqueItems": true,
|
||||||
"x-go-name": "Name"
|
"x-go-name": "Name"
|
||||||
},
|
},
|
||||||
|
"object_format_name": {
|
||||||
|
"description": "ObjectFormatName of the underlying git repository",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"sha1",
|
||||||
|
"sha256"
|
||||||
|
],
|
||||||
|
"x-go-name": "ObjectFormatName"
|
||||||
|
},
|
||||||
"private": {
|
"private": {
|
||||||
"description": "Whether the repository is private",
|
"description": "Whether the repository is private",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
@ -22185,6 +22194,15 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Name"
|
"x-go-name": "Name"
|
||||||
},
|
},
|
||||||
|
"object_format_name": {
|
||||||
|
"description": "ObjectFormatName of the underlying git repository",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"sha1",
|
||||||
|
"sha256"
|
||||||
|
],
|
||||||
|
"x-go-name": "ObjectFormatName"
|
||||||
|
},
|
||||||
"open_issues_count": {
|
"open_issues_count": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
|
|
Loading…
Reference in a new issue