mirror of https://github.com/harness/drone.git
fix complex file extensions like tar.gz (#2143)
* fix complex file extensions like tar.gzunified-ui
parent
afd24f911b
commit
7c2c732c9f
|
@ -34,7 +34,12 @@ func HandleArchive(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
params, filename := request.ParseArchiveParams(r)
|
params, filename, err := request.ParseArchiveParams(r)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(ctx, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var contentType string
|
var contentType string
|
||||||
switch params.Format {
|
switch params.Format {
|
||||||
case api.ArchiveFormatTar:
|
case api.ArchiveFormatTar:
|
||||||
|
|
|
@ -33,16 +33,26 @@ const (
|
||||||
QueryParamArchiveCompression = "compression"
|
QueryParamArchiveCompression = "compression"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseArchiveParams(r *http.Request) (api.ArchiveParams, string) {
|
func Ext(path string) string {
|
||||||
|
found := ""
|
||||||
|
for _, format := range api.ArchiveFormats {
|
||||||
|
if strings.HasSuffix(path, "."+string(format)) {
|
||||||
|
if len(found) == 0 || len(found) < len(format) {
|
||||||
|
found = string(format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseArchiveParams(r *http.Request) (api.ArchiveParams, string, error) {
|
||||||
// separate rev and ref part from url, for example:
|
// separate rev and ref part from url, for example:
|
||||||
// api/v1/repos/root/demo/+/archive/refs/heads/main.zip
|
// api/v1/repos/root/demo/+/archive/refs/heads/main.zip
|
||||||
// will produce rev=refs/heads and ref=main.zip
|
// will produce rev=refs/heads and ref=main.zip
|
||||||
rev, filename := filepath.Split(PathParamOrEmpty(r, PathParamArchiveGitRef))
|
path := PathParamOrEmpty(r, PathParamArchiveGitRef)
|
||||||
|
rev, filename := filepath.Split(path)
|
||||||
// use ext as format specifier
|
// use ext as format specifier
|
||||||
ext := filepath.Ext(filename)
|
format := Ext(filename)
|
||||||
// get name of the ref from filename
|
|
||||||
name := strings.TrimSuffix(filename, ext)
|
|
||||||
format := strings.Replace(ext, ".", "", 1)
|
|
||||||
// prefix is used for git archive to prefix all paths.
|
// prefix is used for git archive to prefix all paths.
|
||||||
prefix, _ := QueryParam(r, QueryParamArchivePrefix)
|
prefix, _ := QueryParam(r, QueryParamArchivePrefix)
|
||||||
attributes, _ := QueryParam(r, QueryParamArchiveAttributes)
|
attributes, _ := QueryParam(r, QueryParamArchiveAttributes)
|
||||||
|
@ -65,13 +75,20 @@ func ParseArchiveParams(r *http.Request) (api.ArchiveParams, string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
archFormat, err := api.ParseArchiveFormat(format)
|
||||||
|
if err != nil {
|
||||||
|
return api.ArchiveParams{}, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get name from filename
|
||||||
|
name := strings.TrimSuffix(filename, "."+format)
|
||||||
return api.ArchiveParams{
|
return api.ArchiveParams{
|
||||||
Format: api.ArchiveFormat(format),
|
Format: archFormat,
|
||||||
Prefix: prefix,
|
Prefix: prefix,
|
||||||
Attributes: api.ArchiveAttribute(attributes),
|
Attributes: api.ArchiveAttribute(attributes),
|
||||||
Time: mtime,
|
Time: mtime,
|
||||||
Compression: compression,
|
Compression: compression,
|
||||||
Treeish: rev + name,
|
Treeish: rev + name,
|
||||||
Paths: r.URL.Query()[QueryParamArchivePaths],
|
Paths: r.URL.Query()[QueryParamArchivePaths],
|
||||||
}, filename
|
}, filename, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/git/api"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseArchiveParams(t *testing.T) {
|
||||||
|
req := func(param string) *http.Request {
|
||||||
|
rctx := chi.NewRouteContext()
|
||||||
|
rctx.URLParams.Add("*", param)
|
||||||
|
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, rctx)
|
||||||
|
r, err := http.NewRequestWithContext(ctx, http.MethodGet, "", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantParams api.ArchiveParams
|
||||||
|
wantFilename string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "git archive flag is empty returns error",
|
||||||
|
args: args{
|
||||||
|
r: req("refs/heads/main"),
|
||||||
|
},
|
||||||
|
wantParams: api.ArchiveParams{},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "git archive flag is unknown returns error",
|
||||||
|
args: args{
|
||||||
|
r: req("refs/heads/main.7z"),
|
||||||
|
},
|
||||||
|
wantParams: api.ArchiveParams{},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "git archive flag format 'tar'",
|
||||||
|
args: args{
|
||||||
|
r: req("refs/heads/main.tar"),
|
||||||
|
},
|
||||||
|
wantParams: api.ArchiveParams{
|
||||||
|
Format: api.ArchiveFormatTar,
|
||||||
|
Treeish: "refs/heads/main",
|
||||||
|
},
|
||||||
|
wantFilename: "main.tar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "git archive flag format 'zip'",
|
||||||
|
args: args{
|
||||||
|
r: req("refs/heads/main.zip"),
|
||||||
|
},
|
||||||
|
wantParams: api.ArchiveParams{
|
||||||
|
Format: api.ArchiveFormatZip,
|
||||||
|
Treeish: "refs/heads/main",
|
||||||
|
},
|
||||||
|
wantFilename: "main.zip",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "git archive flag format 'gz'",
|
||||||
|
args: args{
|
||||||
|
r: req("refs/heads/main.tar.gz"),
|
||||||
|
},
|
||||||
|
wantParams: api.ArchiveParams{
|
||||||
|
Format: api.ArchiveFormatTarGz,
|
||||||
|
Treeish: "refs/heads/main",
|
||||||
|
},
|
||||||
|
wantFilename: "main.tar.gz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "git archive flag format 'tgz'",
|
||||||
|
args: args{
|
||||||
|
r: req("refs/heads/main.tgz"),
|
||||||
|
},
|
||||||
|
wantParams: api.ArchiveParams{
|
||||||
|
Format: api.ArchiveFormatTgz,
|
||||||
|
Treeish: "refs/heads/main",
|
||||||
|
},
|
||||||
|
wantFilename: "main.tgz",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, gotFilename, err := ParseArchiveParams(tt.args.r)
|
||||||
|
if !tt.wantErr && err != nil {
|
||||||
|
t.Errorf("ParseArchiveParams() expected error but err was nil")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.wantParams) {
|
||||||
|
t.Errorf("ParseArchiveParams() expected = %v, got %v", tt.wantParams, got)
|
||||||
|
}
|
||||||
|
if gotFilename != tt.wantFilename {
|
||||||
|
t.Errorf("ParseArchiveParams() expected filename = %v, got %v", tt.wantFilename, gotFilename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExt(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test file without ext",
|
||||||
|
args: args{
|
||||||
|
path: "./testdata/test",
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test file ext tar",
|
||||||
|
args: args{
|
||||||
|
path: "./testdata/test.tar",
|
||||||
|
},
|
||||||
|
want: "tar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test file ext zip",
|
||||||
|
args: args{
|
||||||
|
path: "./testdata/test.zip",
|
||||||
|
},
|
||||||
|
want: "zip",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test file ext tar.gz",
|
||||||
|
args: args{
|
||||||
|
path: "./testdata/test.tar.gz",
|
||||||
|
},
|
||||||
|
want: "tar.gz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test file ext tgz",
|
||||||
|
args: args{
|
||||||
|
path: "./testdata/test.tgz",
|
||||||
|
},
|
||||||
|
want: "tgz",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := Ext(tt.args.path); got != tt.want {
|
||||||
|
t.Errorf("Ext() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,28 @@ const (
|
||||||
ArchiveFormatTgz ArchiveFormat = "tgz"
|
ArchiveFormatTgz ArchiveFormat = "tgz"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ArchiveFormats = []ArchiveFormat{
|
||||||
|
ArchiveFormatTar,
|
||||||
|
ArchiveFormatZip,
|
||||||
|
ArchiveFormatTarGz,
|
||||||
|
ArchiveFormatTgz,
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseArchiveFormat(format string) (ArchiveFormat, error) {
|
||||||
|
switch format {
|
||||||
|
case "tar":
|
||||||
|
return ArchiveFormatTar, nil
|
||||||
|
case "zip":
|
||||||
|
return ArchiveFormatZip, nil
|
||||||
|
case "tar.gz":
|
||||||
|
return ArchiveFormatTarGz, nil
|
||||||
|
case "tgz":
|
||||||
|
return ArchiveFormatTgz, nil
|
||||||
|
default:
|
||||||
|
return "", errors.InvalidArgument("failed to parse file format '%s' is invalid", format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f ArchiveFormat) Validate() error {
|
func (f ArchiveFormat) Validate() error {
|
||||||
switch f {
|
switch f {
|
||||||
case ArchiveFormatTar, ArchiveFormatZip, ArchiveFormatTarGz, ArchiveFormatTgz:
|
case ArchiveFormatTar, ArchiveFormatZip, ArchiveFormatTarGz, ArchiveFormatTgz:
|
||||||
|
|
Loading…
Reference in New Issue