This commit is contained in:
@@ -5,9 +5,12 @@ package lfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
// DownloadCallback gets called for every requested LFS object to process its content
|
||||
@@ -23,10 +26,23 @@ type Client interface {
|
||||
Upload(ctx context.Context, objects []Pointer, callback UploadCallback) error
|
||||
}
|
||||
|
||||
// NewClient creates a LFS client
|
||||
func NewClient(endpoint *url.URL, httpTransport *http.Transport) Client {
|
||||
// newClient creates a LFS client
|
||||
func newClient(endpoint *url.URL, httpTransport *http.Transport) Client {
|
||||
if endpoint.Scheme == "file" {
|
||||
return newFilesystemClient(endpoint)
|
||||
}
|
||||
return newHTTPClient(endpoint, httpTransport)
|
||||
}
|
||||
|
||||
// NewClientFromEndpoint creates a LFS client after resolving its endpoint.
|
||||
func NewClientFromEndpoint(cloneurl, lfsurl string, httpTransport *http.Transport) (Client, error) {
|
||||
endpoint := DetermineEndpoint(cloneurl, lfsurl)
|
||||
if endpoint == nil {
|
||||
source := cloneurl
|
||||
if lfsurl != "" {
|
||||
source = lfsurl
|
||||
}
|
||||
return nil, fmt.Errorf("unable to determine LFS endpoint from %q", util.SanitizeCredentialURLs(source))
|
||||
}
|
||||
return newClient(endpoint, httpTransport), nil
|
||||
}
|
||||
|
||||
@@ -12,10 +12,21 @@ import (
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
u, _ := url.Parse("file:///test")
|
||||
c := NewClient(u, nil)
|
||||
c := newClient(u, nil)
|
||||
assert.IsType(t, &FilesystemClient{}, c)
|
||||
|
||||
u, _ = url.Parse("https://test.com/lfs")
|
||||
c = NewClient(u, nil)
|
||||
c = newClient(u, nil)
|
||||
assert.IsType(t, &HTTPClient{}, c)
|
||||
}
|
||||
|
||||
func TestNewClientFromEndpoint(t *testing.T) {
|
||||
client, err := NewClientFromEndpoint("ssh://git@example.com/owner/repo.git", "", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, client)
|
||||
|
||||
client, err = NewClientFromEndpoint("ftp://example.com/owner/repo.git", "", nil)
|
||||
assert.Nil(t, client)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "unable to determine LFS endpoint")
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -10,8 +10,9 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
giturl "gitea.dev/modules/git/url"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
// DetermineEndpoint determines an endpoint from the clone url or uses the specified LFS url.
|
||||
@@ -44,15 +45,20 @@ func endpointFromCloneURL(rawurl string) *url.URL {
|
||||
}
|
||||
|
||||
func endpointFromURL(rawurl string) *url.URL {
|
||||
if rawurl == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(rawurl, "/") {
|
||||
return endpointFromLocalPath(rawurl)
|
||||
}
|
||||
|
||||
u, err := url.Parse(rawurl)
|
||||
gitURL, err := giturl.ParseGitURL(rawurl)
|
||||
if err != nil {
|
||||
log.Error("lfs.endpointFromUrl: %v", err)
|
||||
return nil
|
||||
}
|
||||
u := gitURL.URL
|
||||
|
||||
switch u.Scheme {
|
||||
case "http", "https":
|
||||
@@ -60,6 +66,12 @@ func endpointFromURL(rawurl string) *url.URL {
|
||||
case "git":
|
||||
u.Scheme = "https"
|
||||
return u
|
||||
case "ssh", "git+ssh":
|
||||
u.Scheme = "https" // is it possible http?
|
||||
u.Host = u.Hostname() // remove ssh port if any
|
||||
u.Path = "/" + strings.TrimPrefix(u.Path, "/")
|
||||
u.User = nil
|
||||
return u
|
||||
case "file":
|
||||
return u
|
||||
default:
|
||||
|
||||
@@ -64,6 +64,24 @@ func TestDetermineEndpoint(t *testing.T) {
|
||||
lfsurl: "git://gitlfs.com/repo",
|
||||
expected: str2url("https://gitlfs.com/repo"),
|
||||
},
|
||||
// case 7
|
||||
{
|
||||
cloneurl: "ssh://git@git.com/owner/repo.git",
|
||||
lfsurl: "",
|
||||
expected: str2url("https://git.com/owner/repo.git/info/lfs"),
|
||||
},
|
||||
// case 8
|
||||
{
|
||||
cloneurl: "git@git.com:owner/repo.git",
|
||||
lfsurl: "",
|
||||
expected: str2url("https://git.com/owner/repo.git/info/lfs"),
|
||||
},
|
||||
// case 9
|
||||
{
|
||||
cloneurl: "",
|
||||
lfsurl: "ssh://git@gitlfs.com/owner/repo.git/info/lfs",
|
||||
expected: str2url("https://gitlfs.com/owner/repo.git/info/lfs"),
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
// FilesystemClient is used to read LFS data from a filesystem path
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/proxy"
|
||||
"gitea.dev/modules/setting"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -249,7 +249,7 @@ func createRequest(ctx context.Context, method, url string, headers map[string]s
|
||||
}
|
||||
|
||||
// performRequest sends a request, optionally performs a callback on the request and returns the response.
|
||||
// If the status code is 200, the response is returned, and it will contain a non-nil Body.
|
||||
// If the status code is in the 2xx range, the response is returned, and it will contain a non-nil Body.
|
||||
// Otherwise, it will return an error, and the Body will be nil or closed.
|
||||
func performRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||
log.Trace("performRequest: %s", req.URL)
|
||||
@@ -264,7 +264,7 @@ func performRequest(ctx context.Context, client *http.Client, req *http.Request)
|
||||
return res, err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
if res.StatusCode < 200 || res.StatusCode >= 300 {
|
||||
defer res.Body.Close()
|
||||
return res, handleErrorResponse(res)
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"gitea.dev/modules/git"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
"code.gitea.io/gitea/modules/git/pipeline"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/git/gitcmd"
|
||||
"gitea.dev/modules/git/pipeline"
|
||||
"gitea.dev/modules/util"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/log"
|
||||
)
|
||||
|
||||
// TransferAdapter represents an adapter for downloading/uploading LFS objects.
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"gitea.dev/modules/json"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -135,6 +135,15 @@ func TestBasicTransferAdapter(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Upload created", func(t *testing.T) {
|
||||
client := &http.Client{Transport: RoundTripFunc(func(req *http.Request) *http.Response {
|
||||
return &http.Response{StatusCode: http.StatusCreated, Body: io.NopCloser(strings.NewReader(""))}
|
||||
})}
|
||||
adapter := &BasicTransferAdapter{client: client}
|
||||
err := adapter.Upload(t.Context(), &Link{Href: "https://upload-created-request.io"}, p, strings.NewReader("dummy"))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Verify", func(t *testing.T) {
|
||||
cases := []struct {
|
||||
link *Link
|
||||
|
||||
Reference in New Issue
Block a user