mirror of https://github.com/go-gitea/gitea.git
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)"`
|
||||
TargetURL string `xorm:"TEXT"`
|
||||
Description string `xorm:"TEXT"`
|
||||
ContextHash string `xorm:"char(40) index"`
|
||||
ContextHash string `xorm:"VARCHAR(64) index"`
|
||||
Context string `xorm:"TEXT"`
|
||||
Creator *user_model.User `xorm:"-"`
|
||||
CreatorID int64
|
||||
|
|
|
@ -270,7 +270,7 @@ type Comment struct {
|
|||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
|
||||
// Reference issue in commit message
|
||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
||||
CommitSHA string `xorm:"VARCHAR(64)"`
|
||||
|
||||
Attachments []*repo_model.Attachment `xorm:"-"`
|
||||
Reactions ReactionList `xorm:"-"`
|
||||
|
|
|
@ -171,11 +171,11 @@ type PullRequest struct {
|
|||
HeadBranch string
|
||||
HeadCommitID string `xorm:"-"`
|
||||
BaseBranch string
|
||||
MergeBase string `xorm:"VARCHAR(40)"`
|
||||
MergeBase string `xorm:"VARCHAR(64)"`
|
||||
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`
|
||||
|
||||
HasMerged bool `xorm:"INDEX"`
|
||||
MergedCommitID string `xorm:"VARCHAR(40)"`
|
||||
MergedCommitID string `xorm:"VARCHAR(64)"`
|
||||
MergerID int64 `xorm:"INDEX"`
|
||||
Merger *user_model.User `xorm:"-"`
|
||||
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
|
||||
|
|
|
@ -116,7 +116,7 @@ type Review struct {
|
|||
Content string `xorm:"TEXT"`
|
||||
// Official is a review made by an assigned approver (counts towards approval)
|
||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CommitID string `xorm:"VARCHAR(40)"`
|
||||
CommitID string `xorm:"VARCHAR(64)"`
|
||||
Stale 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),
|
||||
// v285 -> v286
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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"`
|
||||
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?
|
||||
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
|
||||
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)"`
|
||||
Type git.ArchiveType `xorm:"unique(s)"`
|
||||
Status ArchiverStatus
|
||||
CommitID string `xorm:"VARCHAR(40) unique(s)"`
|
||||
CommitID string `xorm:"VARCHAR(64) unique(s)"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ type Release struct {
|
|||
Target string
|
||||
TargetBehind string `xorm:"-"` // to handle non-existing or empty target
|
||||
Title string
|
||||
Sha1 string `xorm:"VARCHAR(40)"`
|
||||
Sha1 string `xorm:"VARCHAR(64)"`
|
||||
NumCommits int64
|
||||
NumCommitsBehind int64 `xorm:"-"`
|
||||
Note string `xorm:"TEXT"`
|
||||
|
|
|
@ -180,7 +180,7 @@ type Repository struct {
|
|||
IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"`
|
||||
CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Topics []string `xorm:"TEXT JSON"`
|
||||
ObjectFormatName string `xorm:"-"`
|
||||
ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"`
|
||||
|
||||
TrustModel TrustModelType
|
||||
|
||||
|
@ -276,10 +276,6 @@ func (repo *Repository) AfterLoad() {
|
|||
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
||||
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
|
||||
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.
|
||||
|
|
|
@ -27,7 +27,7 @@ const (
|
|||
type RepoIndexerStatus struct { //revive:disable-line:exported
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"INDEX(s)"`
|
||||
CommitSha string `xorm:"VARCHAR(40)"`
|
||||
CommitSha string `xorm:"VARCHAR(64)"`
|
||||
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
_, _ = payloadSB.Write(line)
|
||||
case "gpgsig":
|
||||
fallthrough
|
||||
case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
|
||||
_, _ = signatureSB.Write(data)
|
||||
_ = signatureSB.WriteByte('\n')
|
||||
pgpsig = true
|
||||
|
|
|
@ -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=")
|
||||
}
|
||||
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 CheckGitVersionAtLeast("2.1.2") != nil {
|
||||
return errors.New("LFS server support requires Git >= 2.1.2")
|
||||
|
|
|
@ -5,6 +5,7 @@ package git
|
|||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
@ -12,6 +13,9 @@ import (
|
|||
// sha1Pattern can be used to determine if a string is an valid sha
|
||||
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 {
|
||||
// Name returns the name of the object format
|
||||
Name() string
|
||||
|
@ -29,11 +33,12 @@ type ObjectFormat interface {
|
|||
ComputeHash(t ObjectType, content []byte) ObjectID
|
||||
}
|
||||
|
||||
/* SHA1 Type */
|
||||
type Sha1ObjectFormatImpl struct{}
|
||||
|
||||
var (
|
||||
emptyObjectID = &Sha1Hash{}
|
||||
emptyTree = &Sha1Hash{
|
||||
emptySha1ObjectID = &Sha1Hash{}
|
||||
emptySha1Tree = &Sha1Hash{
|
||||
0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
|
||||
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
|
||||
}
|
||||
|
@ -41,11 +46,11 @@ var (
|
|||
|
||||
func (Sha1ObjectFormatImpl) Name() string { return "sha1" }
|
||||
func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID {
|
||||
return emptyObjectID
|
||||
return emptySha1ObjectID
|
||||
}
|
||||
|
||||
func (Sha1ObjectFormatImpl) EmptyTree() ObjectID {
|
||||
return emptyTree
|
||||
return emptySha1Tree
|
||||
}
|
||||
func (Sha1ObjectFormatImpl) FullLength() int { return 40 }
|
||||
func (Sha1ObjectFormatImpl) IsValid(input string) bool {
|
||||
|
@ -72,11 +77,59 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID
|
|||
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{
|
||||
Sha1ObjectFormat,
|
||||
// TODO: add sha256
|
||||
}
|
||||
|
||||
func ObjectFormatFromName(name string) ObjectFormat {
|
||||
|
|
|
@ -16,6 +16,7 @@ type ObjectID interface {
|
|||
Type() ObjectFormat
|
||||
}
|
||||
|
||||
/* SHA1 */
|
||||
type Sha1Hash [20]byte
|
||||
|
||||
func (h *Sha1Hash) String() string {
|
||||
|
@ -39,6 +40,21 @@ func MustIDFromString(hexHash string) ObjectID {
|
|||
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) {
|
||||
var theObjectFormat ObjectFormat
|
||||
for _, objectFormat := range SupportedObjectFormats {
|
||||
|
|
|
@ -13,6 +13,8 @@ func ParseGogitHash(h plumbing.Hash) ObjectID {
|
|||
switch hash.Size {
|
||||
case 20:
|
||||
return Sha1ObjectFormat.MustID(h[:])
|
||||
case 32:
|
||||
return Sha256ObjectFormat.MustID(h[:])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -97,15 +97,12 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
|
|||
}
|
||||
|
||||
cmd := NewCommand(ctx, "init")
|
||||
if SupportHashSha256 {
|
||||
if objectFormatName == "" {
|
||||
objectFormatName = Sha1ObjectFormat.Name()
|
||||
}
|
||||
if !IsValidObjectFormat(objectFormatName) {
|
||||
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
||||
}
|
||||
cmd.AddOptionValues("--object-format", objectFormatName)
|
||||
|
||||
if !IsValidObjectFormat(objectFormatName) {
|
||||
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
||||
}
|
||||
cmd.AddOptionValues("--object-format", objectFormatName)
|
||||
|
||||
if bare {
|
||||
cmd.AddArguments("--bare")
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
var isGogit bool
|
||||
|
||||
// contextKey is a value for use with context.WithValue.
|
||||
type contextKey struct {
|
||||
name string
|
||||
|
|
|
@ -21,6 +21,10 @@ import (
|
|||
"github.com/go-git/go-git/v5/storage/filesystem"
|
||||
)
|
||||
|
||||
func init() {
|
||||
isGogit = true
|
||||
}
|
||||
|
||||
// Repository represents a Git repository.
|
||||
type Repository struct {
|
||||
Path string
|
||||
|
|
|
@ -15,6 +15,10 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
isGogit = false
|
||||
}
|
||||
|
||||
// Repository represents a Git repository.
|
||||
type Repository struct {
|
||||
Path string
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/main
|
|
@ -0,0 +1,6 @@
|
|||
[core]
|
||||
repositoryformatversion = 1
|
||||
filemode = true
|
||||
bare = true
|
||||
[extensions]
|
||||
objectformat = sha256
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -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]
|
||||
# *~
|
|
@ -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.
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/main
|
|
@ -0,0 +1,6 @@
|
|||
[core]
|
||||
repositoryformatversion = 1
|
||||
filemode = true
|
||||
bare = true
|
||||
[extensions]
|
||||
objectformat = sha256
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -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.
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/main
|
|
@ -0,0 +1,6 @@
|
|||
[core]
|
||||
repositoryformatversion = 1
|
||||
filemode = true
|
||||
bare = true
|
||||
[extensions]
|
||||
objectformat = sha256
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -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]
|
||||
# *~
|
|
@ -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.
|
@ -0,0 +1,2 @@
|
|||
# pack-refs with: peeled fully-peeled sorted
|
||||
e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 refs/heads/main
|
|
@ -0,0 +1 @@
|
|||
e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/main
|
|
@ -0,0 +1,6 @@
|
|||
[core]
|
||||
repositoryformatversion = 1
|
||||
filemode = true
|
||||
bare = true
|
||||
[extensions]
|
||||
objectformat = sha256
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -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]
|
||||
# *~
|
|
@ -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.
|
@ -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/]
|
||||
|
||||
// sha1CurrentPattern 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
|
||||
// hashCurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
|
||||
// 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.
|
||||
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 = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`)
|
||||
|
||||
// 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 = 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-]+://`)
|
||||
|
||||
|
@ -171,13 +171,13 @@ type processor func(ctx *RenderContext, node *html.Node)
|
|||
var defaultProcessors = []processor{
|
||||
fullIssuePatternProcessor,
|
||||
comparePatternProcessor,
|
||||
fullSha1PatternProcessor,
|
||||
fullHashPatternProcessor,
|
||||
shortLinkProcessor,
|
||||
linkProcessor,
|
||||
mentionProcessor,
|
||||
issueIndexPatternProcessor,
|
||||
commitCrossReferencePatternProcessor,
|
||||
sha1CurrentPatternProcessor,
|
||||
hashCurrentPatternProcessor,
|
||||
emailAddressProcessor,
|
||||
emojiProcessor,
|
||||
emojiShortCodeProcessor,
|
||||
|
@ -199,12 +199,12 @@ func PostProcess(
|
|||
var commitMessageProcessors = []processor{
|
||||
fullIssuePatternProcessor,
|
||||
comparePatternProcessor,
|
||||
fullSha1PatternProcessor,
|
||||
fullHashPatternProcessor,
|
||||
linkProcessor,
|
||||
mentionProcessor,
|
||||
issueIndexPatternProcessor,
|
||||
commitCrossReferencePatternProcessor,
|
||||
sha1CurrentPatternProcessor,
|
||||
hashCurrentPatternProcessor,
|
||||
emailAddressProcessor,
|
||||
emojiProcessor,
|
||||
emojiShortCodeProcessor,
|
||||
|
@ -231,12 +231,12 @@ func RenderCommitMessage(
|
|||
var commitMessageSubjectProcessors = []processor{
|
||||
fullIssuePatternProcessor,
|
||||
comparePatternProcessor,
|
||||
fullSha1PatternProcessor,
|
||||
fullHashPatternProcessor,
|
||||
linkProcessor,
|
||||
mentionProcessor,
|
||||
issueIndexPatternProcessor,
|
||||
commitCrossReferencePatternProcessor,
|
||||
sha1CurrentPatternProcessor,
|
||||
hashCurrentPatternProcessor,
|
||||
emojiShortCodeProcessor,
|
||||
emojiProcessor,
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ func RenderIssueTitle(
|
|||
return renderProcessString(ctx, []processor{
|
||||
issueIndexPatternProcessor,
|
||||
commitCrossReferencePatternProcessor,
|
||||
sha1CurrentPatternProcessor,
|
||||
hashCurrentPatternProcessor,
|
||||
emojiShortCodeProcessor,
|
||||
emojiProcessor,
|
||||
}, title)
|
||||
|
@ -946,15 +946,15 @@ func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||
}
|
||||
}
|
||||
|
||||
// fullSha1PatternProcessor renders SHA containing URLs
|
||||
func fullSha1PatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||
// fullHashPatternProcessor renders SHA containing URLs
|
||||
func fullHashPatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||
if ctx.Metas == nil {
|
||||
return
|
||||
}
|
||||
|
||||
next := node.NextSibling
|
||||
for node != nil && node != next {
|
||||
m := anySHA1Pattern.FindStringSubmatchIndex(node.Data)
|
||||
m := anyHashPattern.FindStringSubmatchIndex(node.Data)
|
||||
if m == nil {
|
||||
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.
|
||||
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"] == "" {
|
||||
return
|
||||
}
|
||||
|
@ -1124,7 +1124,7 @@ func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||
ctx.ShaExistCache = make(map[string]bool)
|
||||
}
|
||||
for node != nil && node != next && start < len(node.Data) {
|
||||
m := sha1CurrentPattern.FindStringSubmatchIndex(node.Data[start:])
|
||||
m := hashCurrentPattern.FindStringSubmatchIndex(node.Data[start:])
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -390,10 +390,10 @@ func TestRegExp_sha1CurrentPattern(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, testCase := range trueTestCases {
|
||||
assert.True(t, sha1CurrentPattern.MatchString(testCase))
|
||||
assert.True(t, hashCurrentPattern.MatchString(testCase))
|
||||
}
|
||||
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 {
|
||||
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|[:;,.?!]$)`)
|
||||
// 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)
|
||||
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 = regexp.MustCompile(`(?:.*[0-9a-zA-Z-_])\s`)
|
||||
// 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,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -105,6 +105,9 @@ type Repository struct {
|
|||
AvatarURL string `json:"avatar_url"`
|
||||
Internal bool `json:"internal"`
|
||||
MirrorInterval string `json:"mirror_interval"`
|
||||
// ObjectFormatName of the underlying git repository
|
||||
// enum: sha1,sha256
|
||||
ObjectFormatName string `json:"object_format_name"`
|
||||
// swagger:strfmt date-time
|
||||
MirrorUpdated time.Time `json:"mirror_updated,omitempty"`
|
||||
RepoTransfer *RepoTransfer `json:"repo_transfer"`
|
||||
|
@ -139,6 +142,9 @@ type CreateRepoOption struct {
|
|||
// TrustModel of the repository
|
||||
// enum: default,collaborator,committer,collaboratorcommitter
|
||||
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
|
||||
|
|
|
@ -41,3 +41,7 @@ func (su *StringUtils) Cut(s, sep string) []any {
|
|||
func (su *StringUtils) EllipsisString(s string, max int) string {
|
||||
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_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>
|
||||
object_format = Object Format
|
||||
object_format_helper = Object format of the repository. Cannot be changed later. SHA1 is most compatible.
|
||||
readme = README
|
||||
readme_helper = Select a README file template.
|
||||
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.internal = Internal
|
||||
desc.archived = Archived
|
||||
desc.sha256 = SHA256
|
||||
|
||||
template.items = Template Items
|
||||
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,
|
||||
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
||||
IsTemplate: opt.Template,
|
||||
ObjectFormatName: git.Sha1ObjectFormat.Name(),
|
||||
ObjectFormatName: opt.ObjectFormatName,
|
||||
})
|
||||
if err != nil {
|
||||
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/packs", repo.GetInfoPacks)
|
||||
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/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
||||
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
||||
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,64}}.pack", repo.GetPackFile)
|
||||
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())
|
||||
}
|
||||
|
|
|
@ -159,7 +159,6 @@ func Create(ctx *context.Context) {
|
|||
ctx.Data["private"] = getRepoPrivate(ctx)
|
||||
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
||||
ctx.Data["default_branch"] = setting.Repository.DefaultBranch
|
||||
ctx.Data["hash_type"] = "sha1"
|
||||
|
||||
ctxUser := checkContextUser(ctx, ctx.FormInt64("org"))
|
||||
if ctx.Written() {
|
||||
|
@ -179,6 +178,8 @@ func Create(ctx *context.Context) {
|
|||
|
||||
ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
|
||||
ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
|
||||
ctx.Data["SupportedObjectFormats"] = git.SupportedObjectFormats
|
||||
ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat
|
||||
|
||||
ctx.HTML(http.StatusOK, tplCreate)
|
||||
}
|
||||
|
|
|
@ -1235,7 +1235,7 @@ func registerRoutes(m *web.Route) {
|
|||
Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost)
|
||||
m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch).
|
||||
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)
|
||||
}, repo.MustBeEditable)
|
||||
m.Group("", func() {
|
||||
|
@ -1377,8 +1377,8 @@ func registerRoutes(m *web.Route) {
|
|||
m.Combo("/*").
|
||||
Get(repo.Wiki).
|
||||
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,40}}.{ext:patch|diff}", repo.RawDiff)
|
||||
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,64}}.{ext:patch|diff}", repo.RawDiff)
|
||||
}, repo.MustEnableWiki, func(ctx *context.Context) {
|
||||
ctx.Data["PageIsWiki"] = true
|
||||
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
|
||||
|
@ -1498,9 +1498,9 @@ func registerRoutes(m *web.Route) {
|
|||
|
||||
m.Group("", func() {
|
||||
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,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
|
||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||
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,64})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
|
||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
|
||||
|
||||
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
||||
|
@ -1517,7 +1517,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Group("", func() {
|
||||
m.Get("/forks", repo.Forks)
|
||||
}, 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())
|
||||
|
||||
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{
|
||||
OwnerID: u.ID,
|
||||
Owner: u,
|
||||
|
|
|
@ -76,17 +76,18 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
|
|||
defaultBranch = opts.SingleBranch
|
||||
}
|
||||
repo := &repo_model.Repository{
|
||||
OwnerID: owner.ID,
|
||||
Owner: owner,
|
||||
OwnerName: owner.Name,
|
||||
Name: opts.Name,
|
||||
LowerName: strings.ToLower(opts.Name),
|
||||
Description: opts.Description,
|
||||
DefaultBranch: defaultBranch,
|
||||
IsPrivate: opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate,
|
||||
IsEmpty: opts.BaseRepo.IsEmpty,
|
||||
IsFork: true,
|
||||
ForkID: opts.BaseRepo.ID,
|
||||
OwnerID: owner.ID,
|
||||
Owner: owner,
|
||||
OwnerName: owner.Name,
|
||||
Name: opts.Name,
|
||||
LowerName: strings.ToLower(opts.Name),
|
||||
Description: opts.Description,
|
||||
DefaultBranch: defaultBranch,
|
||||
IsPrivate: opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate,
|
||||
IsEmpty: opts.BaseRepo.IsEmpty,
|
||||
IsFork: true,
|
||||
ForkID: opts.BaseRepo.ID,
|
||||
ObjectFormatName: opts.BaseRepo.ObjectFormatName,
|
||||
}
|
||||
|
||||
oldRepoPath := opts.BaseRepo.RepoPath()
|
||||
|
|
|
@ -67,6 +67,9 @@
|
|||
{{if .IsTemplate}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
||||
{{end}}
|
||||
{{if eq .ObjectFormatName "sha256"}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
|
||||
{{end}}
|
||||
{{if .IsMirror}}
|
||||
{{svg "octicon-mirror"}}
|
||||
{{else if .IsFork}}
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
{{if .IsTemplate}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span>
|
||||
{{end}}
|
||||
{{if eq .ObjectFormatName "sha256"}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-item-trailing">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<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="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th>
|
||||
<th class="one wide"></th>
|
||||
|
|
|
@ -185,6 +185,19 @@
|
|||
<input id="default_branch" name="default_branch" value="{{.default_branch}}" placeholder="{{.default_branch}}">
|
||||
<span class="help">{{ctx.Locale.Tr "repo.default_branch_helper"}}</span>
|
||||
</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">
|
||||
<label>{{ctx.Locale.Tr "repo.template"}}</label>
|
||||
<div class="ui checkbox">
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
<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>
|
||||
{{end}}
|
||||
{{if eq .ObjectFormatName "sha256"}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if not (or .IsBeingCreated .IsBroken)}}
|
||||
|
|
|
@ -18370,6 +18370,15 @@
|
|||
"uniqueItems": true,
|
||||
"x-go-name": "Name"
|
||||
},
|
||||
"object_format_name": {
|
||||
"description": "ObjectFormatName of the underlying git repository",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"sha1",
|
||||
"sha256"
|
||||
],
|
||||
"x-go-name": "ObjectFormatName"
|
||||
},
|
||||
"private": {
|
||||
"description": "Whether the repository is private",
|
||||
"type": "boolean",
|
||||
|
@ -22185,6 +22194,15 @@
|
|||
"type": "string",
|
||||
"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": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
|
|
Loading…
Reference in New Issue