Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
42641daf
Commit
42641daf
authored
Jan 21, 2021
by
Nick Thomas
Browse files
Options
Browse Files
Download
Plain Diff
Update vendored workhorse to v8.61.0
parents
0180dd49
42e7b65b
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
21 additions
and
296 deletions
+21
-296
workhorse/CHANGELOG
workhorse/CHANGELOG
+6
-0
workhorse/VERSION
workhorse/VERSION
+1
-1
workhorse/gitaly_test.go
workhorse/gitaly_test.go
+0
-169
workhorse/internal/git/info-refs.go
workhorse/internal/git/info-refs.go
+0
-5
workhorse/internal/git/info-refs_test.go
workhorse/internal/git/info-refs_test.go
+0
-33
workhorse/internal/upstream/routes.go
workhorse/internal/upstream/routes.go
+12
-12
workhorse/main_test.go
workhorse/main_test.go
+0
-6
workhorse/upload_test.go
workhorse/upload_test.go
+2
-70
No files found.
workhorse/CHANGELOG
View file @
42641daf
# Changelog for gitlab-workhorse
## v8.61.0
### Fixed
- Revert "Support Git HTTP on toplevel repositories"
https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/681
## v8.60.0
### Added
...
...
workhorse/VERSION
View file @
42641daf
8.6
0
.0
8.6
1
.0
workhorse/gitaly_test.go
View file @
42641daf
...
...
@@ -169,57 +169,6 @@ func TestGetInfoRefsProxiedToGitalyInterruptedStream(t *testing.T) {
waitDone
(
t
,
done
)
}
func
TestGetInfoRefsRouting
(
t
*
testing
.
T
)
{
gitalyServer
,
socketPath
:=
startGitalyServer
(
t
,
codes
.
OK
)
defer
gitalyServer
.
GracefulStop
()
apiResponse
:=
gitOkBody
(
t
)
apiResponse
.
GitalyServer
.
Address
=
"unix:"
+
socketPath
ts
:=
testAuthServer
(
t
,
nil
,
nil
,
200
,
apiResponse
)
defer
ts
.
Close
()
ws
:=
startWorkhorseServer
(
ts
.
URL
)
defer
ws
.
Close
()
testCases
:=
[]
struct
{
method
string
path
string
match
bool
}{
{
"GET"
,
"/toplevel.git/info/refs?service=git-receive-pack"
,
true
},
{
"GET"
,
"/toplevel.wiki.git/info/refs?service=git-upload-pack"
,
true
},
{
"GET"
,
"/toplevel/child/project.git/info/refs?service=git-receive-pack"
,
true
},
{
"GET"
,
"/toplevel/child/project.wiki.git/info/refs?service=git-upload-pack"
,
true
},
{
"GET"
,
"/toplevel/child/project/snippets/123.git/info/refs?service=git-receive-pack"
,
true
},
{
"GET"
,
"/snippets/123.git/info/refs?service=git-upload-pack"
,
true
},
{
"GET"
,
"/foo/bar.git/info/refs"
,
false
},
{
"GET"
,
"/foo/bar.git/info/refs?service=git-zzz-pack"
,
false
},
{
"GET"
,
"/.git/info/refs?service=git-upload-pack"
,
false
},
{
"POST"
,
"/toplevel.git/info/refs?service=git-receive-pack"
,
false
},
}
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
path
,
func
(
t
*
testing
.
T
)
{
req
,
err
:=
http
.
NewRequest
(
tc
.
method
,
ws
.
URL
+
tc
.
path
,
nil
)
require
.
NoError
(
t
,
err
)
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
require
.
NoError
(
t
,
err
)
defer
resp
.
Body
.
Close
()
body
:=
string
(
testhelper
.
ReadAll
(
t
,
resp
.
Body
))
if
tc
.
match
{
require
.
Equal
(
t
,
200
,
resp
.
StatusCode
)
require
.
Contains
(
t
,
body
,
"
\x00
"
,
"expect response generated by test gitaly server"
)
}
else
{
require
.
Equal
(
t
,
204
,
resp
.
StatusCode
)
require
.
Empty
(
t
,
body
,
"normal request has empty response body"
)
}
})
}
}
func
waitDone
(
t
*
testing
.
T
,
done
chan
struct
{})
{
t
.
Helper
()
select
{
...
...
@@ -310,65 +259,6 @@ func TestPostReceivePackProxiedToGitalyInterrupted(t *testing.T) {
waitDone
(
t
,
done
)
}
func
TestPostReceivePackRouting
(
t
*
testing
.
T
)
{
gitalyServer
,
socketPath
:=
startGitalyServer
(
t
,
codes
.
OK
)
defer
gitalyServer
.
GracefulStop
()
apiResponse
:=
gitOkBody
(
t
)
apiResponse
.
GitalyServer
.
Address
=
"unix:"
+
socketPath
ts
:=
testAuthServer
(
t
,
nil
,
nil
,
200
,
apiResponse
)
defer
ts
.
Close
()
ws
:=
startWorkhorseServer
(
ts
.
URL
)
defer
ws
.
Close
()
testCases
:=
[]
struct
{
method
string
path
string
contentType
string
match
bool
}{
{
"POST"
,
"/toplevel.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
true
},
{
"POST"
,
"/toplevel.wiki.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
true
},
{
"POST"
,
"/toplevel/child/project.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
true
},
{
"POST"
,
"/toplevel/child/project.wiki.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
true
},
{
"POST"
,
"/toplevel/child/project/snippets/123.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
true
},
{
"POST"
,
"/snippets/123.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
true
},
{
"POST"
,
"/foo/bar/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
false
},
{
"POST"
,
"/foo/bar.git/git-zzz-pack"
,
"application/x-git-receive-pack-request"
,
false
},
{
"POST"
,
"/.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
false
},
{
"POST"
,
"/toplevel.git/git-receive-pack"
,
"application/x-git-upload-pack-request"
,
false
},
{
"GET"
,
"/toplevel.git/git-receive-pack"
,
"application/x-git-receive-pack-request"
,
false
},
}
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
path
,
func
(
t
*
testing
.
T
)
{
req
,
err
:=
http
.
NewRequest
(
tc
.
method
,
ws
.
URL
+
tc
.
path
,
bytes
.
NewReader
(
testhelper
.
GitalyReceivePackResponseMock
),
)
require
.
NoError
(
t
,
err
)
req
.
Header
.
Set
(
"Content-Type"
,
tc
.
contentType
)
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
require
.
NoError
(
t
,
err
)
defer
resp
.
Body
.
Close
()
body
:=
string
(
testhelper
.
ReadAll
(
t
,
resp
.
Body
))
if
tc
.
match
{
require
.
Equal
(
t
,
200
,
resp
.
StatusCode
)
require
.
Contains
(
t
,
body
,
"
\x00
"
,
"expect response generated by test gitaly server"
)
}
else
{
require
.
Equal
(
t
,
204
,
resp
.
StatusCode
)
require
.
Empty
(
t
,
body
,
"normal request has empty response body"
)
}
})
}
}
// ReaderFunc is an adapter to turn a conforming function into an io.Reader.
type
ReaderFunc
func
(
b
[]
byte
)
(
int
,
error
)
...
...
@@ -486,65 +376,6 @@ func TestPostUploadPackProxiedToGitalyInterrupted(t *testing.T) {
waitDone
(
t
,
done
)
}
func
TestPostUploadPackRouting
(
t
*
testing
.
T
)
{
gitalyServer
,
socketPath
:=
startGitalyServer
(
t
,
codes
.
OK
)
defer
gitalyServer
.
GracefulStop
()
apiResponse
:=
gitOkBody
(
t
)
apiResponse
.
GitalyServer
.
Address
=
"unix:"
+
socketPath
ts
:=
testAuthServer
(
t
,
nil
,
nil
,
200
,
apiResponse
)
defer
ts
.
Close
()
ws
:=
startWorkhorseServer
(
ts
.
URL
)
defer
ws
.
Close
()
testCases
:=
[]
struct
{
method
string
path
string
contentType
string
match
bool
}{
{
"POST"
,
"/toplevel.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
true
},
{
"POST"
,
"/toplevel.wiki.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
true
},
{
"POST"
,
"/toplevel/child/project.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
true
},
{
"POST"
,
"/toplevel/child/project.wiki.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
true
},
{
"POST"
,
"/toplevel/child/project/snippets/123.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
true
},
{
"POST"
,
"/snippets/123.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
true
},
{
"POST"
,
"/foo/bar/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
false
},
{
"POST"
,
"/foo/bar.git/git-zzz-pack"
,
"application/x-git-upload-pack-request"
,
false
},
{
"POST"
,
"/.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
false
},
{
"POST"
,
"/toplevel.git/git-upload-pack"
,
"application/x-git-receive-pack-request"
,
false
},
{
"GET"
,
"/toplevel.git/git-upload-pack"
,
"application/x-git-upload-pack-request"
,
false
},
}
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
path
,
func
(
t
*
testing
.
T
)
{
req
,
err
:=
http
.
NewRequest
(
tc
.
method
,
ws
.
URL
+
tc
.
path
,
bytes
.
NewReader
(
testhelper
.
GitalyReceivePackResponseMock
),
)
require
.
NoError
(
t
,
err
)
req
.
Header
.
Set
(
"Content-Type"
,
tc
.
contentType
)
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
require
.
NoError
(
t
,
err
)
defer
resp
.
Body
.
Close
()
body
:=
string
(
testhelper
.
ReadAll
(
t
,
resp
.
Body
))
if
tc
.
match
{
require
.
Equal
(
t
,
200
,
resp
.
StatusCode
)
require
.
Contains
(
t
,
body
,
"
\x00
"
,
"expect response generated by test gitaly server"
)
}
else
{
require
.
Equal
(
t
,
204
,
resp
.
StatusCode
)
require
.
Empty
(
t
,
body
,
"normal request has empty response body"
)
}
})
}
}
func
TestGetDiffProxiedToGitalySuccessfully
(
t
*
testing
.
T
)
{
gitalyServer
,
socketPath
:=
startGitalyServer
(
t
,
codes
.
OK
)
defer
gitalyServer
.
GracefulStop
()
...
...
workhorse/internal/git/info-refs.go
View file @
42641daf
...
...
@@ -20,11 +20,6 @@ func GetInfoRefsHandler(a *api.API) http.Handler {
return
repoPreAuthorizeHandler
(
a
,
handleGetInfoRefs
)
}
func
IsSmartInfoRefs
(
r
*
http
.
Request
)
bool
{
service
:=
r
.
URL
.
Query
()
.
Get
(
"service"
)
return
r
.
Method
==
"GET"
&&
(
service
==
"git-upload-pack"
||
service
==
"git-receive-pack"
)
}
func
handleGetInfoRefs
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
,
a
*
api
.
Response
)
{
responseWriter
:=
NewHttpResponseWriter
(
rw
)
// Log 0 bytes in because we ignore the request body (and there usually is none anyway).
...
...
workhorse/internal/git/info-refs_test.go
deleted
100644 → 0
View file @
0180dd49
package
git
import
(
"net/http"
"net/url"
"testing"
"github.com/stretchr/testify/require"
)
func
TestIsSmartInfoRefs
(
t
*
testing
.
T
)
{
testCases
:=
[]
struct
{
method
string
url
string
match
bool
}{
{
"GET"
,
"?service=git-upload-pack"
,
true
},
{
"GET"
,
"?service=git-receive-pack"
,
true
},
{
"GET"
,
""
,
false
},
{
"GET"
,
"?service="
,
false
},
{
"GET"
,
"?service=foo"
,
false
},
{
"POST"
,
"?service=git-upload-pack"
,
false
},
{
"POST"
,
"?service=git-receive-pack"
,
false
},
}
for
_
,
tc
:=
range
testCases
{
url
,
err
:=
url
.
Parse
(
tc
.
url
)
require
.
NoError
(
t
,
err
)
r
:=
http
.
Request
{
Method
:
tc
.
method
,
URL
:
url
}
require
.
Equal
(
t
,
tc
.
match
,
IsSmartInfoRefs
(
&
r
))
}
}
workhorse/internal/upstream/routes.go
View file @
42641daf
...
...
@@ -53,13 +53,13 @@ type uploadPreparers struct {
}
const
(
apiPattern
=
`
\A
/api/`
ciAPIPattern
=
`
\A
/ci/api/`
git
RepositoryPattern
=
`\A/.
+\.git/`
projectPattern
=
`
\A
/([^/]+/){1,}[^/]+/`
snippetUploadPattern
=
`
\A
/uploads/personal_snippet`
userUploadPattern
=
`
\A
/uploads/user`
importPattern
=
`
\A
/import/`
apiPattern
=
`
^
/api/`
ciAPIPattern
=
`
^
/ci/api/`
git
ProjectPattern
=
`^/([^/]+/){1,}[^/]
+\.git/`
projectPattern
=
`
^
/([^/]+/){1,}[^/]+/`
snippetUploadPattern
=
`
^
/uploads/personal_snippet`
userUploadPattern
=
`
^
/uploads/user`
importPattern
=
`
^
/import/`
)
func
compileRegexp
(
regexpStr
string
)
*
regexp
.
Regexp
{
...
...
@@ -222,10 +222,10 @@ func (u *upstream) configureRoutes() {
u
.
Routes
=
[]
routeEntry
{
// Git Clone
u
.
route
(
"GET"
,
git
RepositoryPattern
+
`info/refs\z`
,
git
.
GetInfoRefsHandler
(
api
),
withMatcher
(
git
.
IsSmartInfoRefs
)),
u
.
route
(
"POST"
,
git
Repository
Pattern
+
`git-upload-pack\z`
,
contentEncodingHandler
(
git
.
UploadPack
(
api
)),
withMatcher
(
isContentType
(
"application/x-git-upload-pack-request"
))),
u
.
route
(
"POST"
,
git
Repository
Pattern
+
`git-receive-pack\z`
,
contentEncodingHandler
(
git
.
ReceivePack
(
api
)),
withMatcher
(
isContentType
(
"application/x-git-receive-pack-request"
))),
u
.
route
(
"PUT"
,
git
Repository
Pattern
+
`gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`
,
lfs
.
PutStore
(
api
,
signingProxy
,
preparers
.
lfs
),
withMatcher
(
isContentType
(
"application/octet-stream"
))),
u
.
route
(
"GET"
,
git
ProjectPattern
+
`info/refs\z`
,
git
.
GetInfoRefsHandler
(
api
)),
u
.
route
(
"POST"
,
git
Project
Pattern
+
`git-upload-pack\z`
,
contentEncodingHandler
(
git
.
UploadPack
(
api
)),
withMatcher
(
isContentType
(
"application/x-git-upload-pack-request"
))),
u
.
route
(
"POST"
,
git
Project
Pattern
+
`git-receive-pack\z`
,
contentEncodingHandler
(
git
.
ReceivePack
(
api
)),
withMatcher
(
isContentType
(
"application/x-git-receive-pack-request"
))),
u
.
route
(
"PUT"
,
git
Project
Pattern
+
`gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`
,
lfs
.
PutStore
(
api
,
signingProxy
,
preparers
.
lfs
),
withMatcher
(
isContentType
(
"application/octet-stream"
))),
// CI Artifacts
u
.
route
(
"POST"
,
apiPattern
+
`v4/jobs/[0-9]+/artifacts\z`
,
contentEncodingHandler
(
artifacts
.
UploadArtifacts
(
api
,
signingProxy
,
preparers
.
artifacts
))),
...
...
@@ -262,7 +262,7 @@ func (u *upstream) configureRoutes() {
u
.
route
(
"POST"
,
apiPattern
+
`v4/projects/[0-9]+/packages/pypi`
,
upload
.
Accelerate
(
api
,
signingProxy
,
preparers
.
packages
)),
// Debian Artifact Repository
u
.
route
(
"PUT"
,
apiPattern
+
`v4/projects/[0-9]+/
-/packages/debian/incoming
/`
,
upload
.
BodyUploader
(
api
,
signingProxy
,
preparers
.
packages
)),
u
.
route
(
"PUT"
,
apiPattern
+
`v4/projects/[0-9]+/
packages/debian
/`
,
upload
.
BodyUploader
(
api
,
signingProxy
,
preparers
.
packages
)),
// We are porting API to disk acceleration
// we need to declare each routes until we have fixed all the routes on the rails codebase.
...
...
workhorse/main_test.go
View file @
42641daf
...
...
@@ -694,12 +694,6 @@ func testAuthServer(t *testing.T, url *regexp.Regexp, params url.Values, code in
return
testhelper
.
TestServerWithHandler
(
url
,
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
require
.
NotEmpty
(
t
,
r
.
Header
.
Get
(
"X-Request-Id"
))
// return a 204 No Content response if we don't receive the JWT header
if
r
.
Header
.
Get
(
secret
.
RequestHeader
)
==
""
{
w
.
WriteHeader
(
204
)
return
}
w
.
Header
()
.
Set
(
"Content-Type"
,
api
.
ResponseContentType
)
logEntry
:=
log
.
WithFields
(
log
.
Fields
{
...
...
workhorse/upload_test.go
View file @
42641daf
...
...
@@ -234,7 +234,7 @@ func TestLfsUpload(t *testing.T) {
reqBody
:=
"test data"
rspBody
:=
"test success"
oid
:=
"916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9"
resource
:=
fmt
.
Sprintf
(
"/
gitlab-org/gitlab-test.git/gitlab-lfs/objects/%s/%d"
,
oid
,
len
(
reqBody
))
resource
:=
fmt
.
Sprintf
(
"/
%s/gitlab-lfs/objects/%s/%d"
,
testRepo
,
oid
,
len
(
reqBody
))
lfsApiResponse
:=
fmt
.
Sprintf
(
`{"TempPath":%q, "LfsOid":%q, "LfsSize": %d}`
,
...
...
@@ -292,74 +292,6 @@ func TestLfsUpload(t *testing.T) {
require
.
Equal
(
t
,
rspBody
,
string
(
rspData
))
}
func
TestLfsUploadRouting
(
t
*
testing
.
T
)
{
reqBody
:=
"test data"
rspBody
:=
"test success"
oid
:=
"916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9"
ts
:=
testhelper
.
TestServerWithHandler
(
regexp
.
MustCompile
(
`.`
),
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
r
.
Header
.
Get
(
secret
.
RequestHeader
)
==
""
{
w
.
WriteHeader
(
204
)
}
else
{
fmt
.
Fprint
(
w
,
rspBody
)
}
})
defer
ts
.
Close
()
ws
:=
startWorkhorseServer
(
ts
.
URL
)
defer
ws
.
Close
()
testCases
:=
[]
struct
{
method
string
path
string
contentType
string
match
bool
}{
{
"PUT"
,
"/toplevel.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
true
},
{
"PUT"
,
"/toplevel.wiki.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
true
},
{
"PUT"
,
"/toplevel/child/project.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
true
},
{
"PUT"
,
"/toplevel/child/project.wiki.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
true
},
{
"PUT"
,
"/toplevel/child/project/snippets/123.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
true
},
{
"PUT"
,
"/snippets/123.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
true
},
{
"PUT"
,
"/foo/bar/gitlab-lfs/objects"
,
"application/octet-stream"
,
false
},
{
"PUT"
,
"/foo/bar.git/gitlab-lfs/objects/zzz"
,
"application/octet-stream"
,
false
},
{
"PUT"
,
"/.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
false
},
{
"PUT"
,
"/toplevel.git/gitlab-lfs/objects"
,
"application/zzz"
,
false
},
{
"POST"
,
"/toplevel.git/gitlab-lfs/objects"
,
"application/octet-stream"
,
false
},
}
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
path
,
func
(
t
*
testing
.
T
)
{
resource
:=
fmt
.
Sprintf
(
tc
.
path
+
"/%s/%d"
,
oid
,
len
(
reqBody
))
req
,
err
:=
http
.
NewRequest
(
tc
.
method
,
ws
.
URL
+
resource
,
strings
.
NewReader
(
reqBody
),
)
require
.
NoError
(
t
,
err
)
req
.
Header
.
Set
(
"Content-Type"
,
tc
.
contentType
)
req
.
ContentLength
=
int64
(
len
(
reqBody
))
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
require
.
NoError
(
t
,
err
)
defer
resp
.
Body
.
Close
()
rspData
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
require
.
NoError
(
t
,
err
)
if
tc
.
match
{
require
.
Equal
(
t
,
200
,
resp
.
StatusCode
)
require
.
Equal
(
t
,
rspBody
,
string
(
rspData
),
"expect response generated by test upstream server"
)
}
else
{
require
.
Equal
(
t
,
204
,
resp
.
StatusCode
)
require
.
Empty
(
t
,
rspData
,
"normal request has empty response body"
)
}
})
}
}
func
packageUploadTestServer
(
t
*
testing
.
T
,
resource
string
,
reqBody
string
,
rspBody
string
)
*
httptest
.
Server
{
return
testhelper
.
TestServerWithHandler
(
regexp
.
MustCompile
(
`.`
),
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
require
.
Equal
(
t
,
r
.
Method
,
"PUT"
)
...
...
@@ -428,7 +360,7 @@ func TestPackageFilesUpload(t *testing.T) {
"/api/v4/projects/2412/packages/conan/v1/files"
,
"/api/v4/projects/2412/packages/maven/v1/files"
,
"/api/v4/projects/2412/packages/generic/mypackage/0.0.1/myfile.tar.gz"
,
"/api/v4/projects/2412/
-/packages/debian/incoming
/libsample0_1.2.3~alpha2-1_amd64.deb"
,
"/api/v4/projects/2412/
packages/debian
/libsample0_1.2.3~alpha2-1_amd64.deb"
,
}
for
_
,
r
:=
range
routes
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment