mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08: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:
		@@ -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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user