mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-25 08:59:31 -05:00
Set repository link based on the url in package.json for npm packages (#20379)
automatically set repository link for package based on the repository url present inside package.json closes #20146
This commit is contained in:
parent
3cab9c6b0c
commit
5cd1d6c93b
3 changed files with 135 additions and 0 deletions
|
@ -658,6 +658,49 @@ func GetRepositoryByName(ownerID int64, name string) (*Repository, error) {
|
||||||
return repo, err
|
return repo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getRepositoryURLPathSegments returns segments (owner, reponame) extracted from a url
|
||||||
|
func getRepositoryURLPathSegments(repoURL string) []string {
|
||||||
|
if strings.HasPrefix(repoURL, setting.AppURL) {
|
||||||
|
return strings.Split(strings.TrimPrefix(repoURL, setting.AppURL), "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
sshURLVariants := [4]string{
|
||||||
|
setting.SSH.Domain + ":",
|
||||||
|
setting.SSH.User + "@" + setting.SSH.Domain + ":",
|
||||||
|
"git+ssh://" + setting.SSH.Domain + "/",
|
||||||
|
"git+ssh://" + setting.SSH.User + "@" + setting.SSH.Domain + "/",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sshURL := range sshURLVariants {
|
||||||
|
if strings.HasPrefix(repoURL, sshURL) {
|
||||||
|
return strings.Split(strings.TrimPrefix(repoURL, sshURL), "/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepositoryByURL returns the repository by given url
|
||||||
|
func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error) {
|
||||||
|
// possible urls for git:
|
||||||
|
// https://my.domain/sub-path/<owner>/<repo>.git
|
||||||
|
// https://my.domain/sub-path/<owner>/<repo>
|
||||||
|
// git+ssh://user@my.domain/<owner>/<repo>.git
|
||||||
|
// git+ssh://user@my.domain/<owner>/<repo>
|
||||||
|
// user@my.domain:<owner>/<repo>.git
|
||||||
|
// user@my.domain:<owner>/<repo>
|
||||||
|
|
||||||
|
pathSegments := getRepositoryURLPathSegments(repoURL)
|
||||||
|
|
||||||
|
if len(pathSegments) != 2 {
|
||||||
|
return nil, fmt.Errorf("unknown or malformed repository URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
ownerName := pathSegments[0]
|
||||||
|
repoName := strings.TrimSuffix(pathSegments[1], ".git")
|
||||||
|
return GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
|
||||||
|
}
|
||||||
|
|
||||||
// GetRepositoryByID returns the repository by given id if exists.
|
// GetRepositoryByID returns the repository by given id if exists.
|
||||||
func GetRepositoryByID(ctx context.Context, id int64) (*Repository, error) {
|
func GetRepositoryByID(ctx context.Context, id int64) (*Repository, error) {
|
||||||
repo := new(Repository)
|
repo := new(Repository)
|
||||||
|
|
|
@ -124,3 +124,65 @@ func TestMetas(t *testing.T) {
|
||||||
assert.Equal(t, "user3", metas["org"])
|
assert.Equal(t, "user3", metas["org"])
|
||||||
assert.Equal(t, ",owners,team1,", metas["teams"])
|
assert.Equal(t, ",owners,team1,", metas["teams"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetRepositoryByURL(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
t.Run("InvalidPath", func(t *testing.T) {
|
||||||
|
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, "something")
|
||||||
|
|
||||||
|
assert.Nil(t, repo)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ValidHttpURL", func(t *testing.T) {
|
||||||
|
test := func(t *testing.T, url string) {
|
||||||
|
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, url)
|
||||||
|
|
||||||
|
assert.NotNil(t, repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, repo.ID, int64(2))
|
||||||
|
assert.Equal(t, repo.OwnerID, int64(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(t, "https://try.gitea.io/user2/repo2")
|
||||||
|
test(t, "https://try.gitea.io/user2/repo2.git")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ValidGitSshURL", func(t *testing.T) {
|
||||||
|
test := func(t *testing.T, url string) {
|
||||||
|
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, url)
|
||||||
|
|
||||||
|
assert.NotNil(t, repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, repo.ID, int64(2))
|
||||||
|
assert.Equal(t, repo.OwnerID, int64(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(t, "git+ssh://sshuser@try.gitea.io/user2/repo2")
|
||||||
|
test(t, "git+ssh://sshuser@try.gitea.io/user2/repo2.git")
|
||||||
|
|
||||||
|
test(t, "git+ssh://try.gitea.io/user2/repo2")
|
||||||
|
test(t, "git+ssh://try.gitea.io/user2/repo2.git")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ValidImplicitSshURL", func(t *testing.T) {
|
||||||
|
test := func(t *testing.T, url string) {
|
||||||
|
repo, err := repo_model.GetRepositoryByURL(db.DefaultContext, url)
|
||||||
|
|
||||||
|
assert.NotNil(t, repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, repo.ID, int64(2))
|
||||||
|
assert.Equal(t, repo.OwnerID, int64(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
test(t, "sshuser@try.gitea.io:user2/repo2")
|
||||||
|
test(t, "sshuser@try.gitea.io:user2/repo2.git")
|
||||||
|
|
||||||
|
test(t, "try.gitea.io:user2/repo2")
|
||||||
|
test(t, "try.gitea.io:user2/repo2.git")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
npm_module "code.gitea.io/gitea/modules/packages/npm"
|
npm_module "code.gitea.io/gitea/modules/packages/npm"
|
||||||
|
@ -166,6 +169,26 @@ func UploadPackage(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repo, err := repo_model.GetRepositoryByURL(ctx, npmPackage.Metadata.Repository.URL)
|
||||||
|
if err == nil {
|
||||||
|
canWrite := repo.OwnerID == ctx.Doer.ID
|
||||||
|
|
||||||
|
if !canWrite {
|
||||||
|
perms, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
|
||||||
|
if err != nil {
|
||||||
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
canWrite = perms.CanWrite(unit.TypePackages)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !canWrite {
|
||||||
|
apiError(ctx, http.StatusForbidden, "no permission to upload this package")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buf, err := packages_module.CreateHashedBufferFromReader(bytes.NewReader(npmPackage.Data), 32*1024*1024)
|
buf, err := packages_module.CreateHashedBufferFromReader(bytes.NewReader(npmPackage.Data), 32*1024*1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
@ -217,6 +240,13 @@ func UploadPackage(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if repo != nil {
|
||||||
|
if err := packages_model.SetRepositoryLink(ctx, pv.PackageID, repo.ID); err != nil {
|
||||||
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusCreated)
|
ctx.Status(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue