Skip to content

Commit

Permalink
Support OS specific extensions (#76)
Browse files Browse the repository at this point in the history
This scores assets higher which contain an OS specific extension in the
name or URL.

At the same time, refactored the test Linux/Windows resolvers to avoid
duplication when no special cases are needed.

To support extensions such as `.AppImage`, now keeps the asset's
original casing while still scoring based on lowercase comparisons.
Test cases have been updated accordingly.

Signed-off-by: Sune Keller <sune.keller+gitlab.com@gmail.com>

Co-authored-by: Sune Keller <sune.keller+gitlab.com@gmail.com>
  • Loading branch information
sirlatrom and sirlatrom authored Mar 21, 2021
1 parent ef69b01 commit 4bd5e82
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 30 deletions.
26 changes: 20 additions & 6 deletions pkg/assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import (
"github.com/xi2/xz"
)

var (
msiType = filetype.AddType("msi", "application/octet-stream")
ascType = filetype.AddType("asc", "text/plain")
)

type Asset struct {
Name string
DisplayName string
Expand All @@ -50,6 +55,7 @@ type FilteredAsset struct {
type platformResolver interface {
GetOS() []string
GetArch() []string
GetOSSpecificExtensions() []string
}

type runtimeResolver struct{}
Expand All @@ -62,6 +68,10 @@ func (runtimeResolver) GetArch() []string {
return config.GetArch()
}

func (runtimeResolver) GetOSSpecificExtensions() []string {
return config.GetOSSpecificExtensions()
}

var resolver platformResolver = runtimeResolver{}

func (g FilteredAsset) String() string {
Expand All @@ -84,21 +94,23 @@ func FilterAssets(repoName string, as []*Asset) (*FilteredAsset, error) {
for _, arch := range resolver.GetArch() {
scores[arch] = 5
}
for _, osSpecificExtension := range resolver.GetOSSpecificExtensions() {
scores[osSpecificExtension] = 15
}
scoreKeys := []string{}
for key := range scores {
scoreKeys = append(scoreKeys, key)
scoreKeys = append(scoreKeys, strings.ToLower(key))
}
for _, a := range as {
lowerName := strings.ToLower(a.Name)
lowerURLPathBasename := path.Base(strings.ToLower(a.URL))
urlPathBasename := path.Base(a.URL)
highestScoreForAsset := 0
gf := &FilteredAsset{RepoName: repoName, Name: a.Name, DisplayName: a.DisplayName, URL: a.URL, score: 0}
for _, candidate := range []string{lowerName, lowerURLPathBasename} {
for _, candidate := range []string{a.Name, urlPathBasename} {
candidateScore := 0
if bstrings.ContainsAny(candidate, scoreKeys) &&
if bstrings.ContainsAny(strings.ToLower(candidate), scoreKeys) &&
isSupportedExt(candidate) {
for toMatch, score := range scores {
if strings.Contains(candidate, strings.ToLower(toMatch)) {
if strings.Contains(strings.ToLower(candidate), strings.ToLower(toMatch)) {
candidateScore += score
}
}
Expand Down Expand Up @@ -361,6 +373,8 @@ func processZip(name string, r io.Reader) (string, io.Reader, error) {
func isSupportedExt(filename string) bool {
if ext := strings.TrimPrefix(filepath.Ext(filename), "."); len(ext) > 0 {
switch filetype.GetType(ext) {
case msiType, matchers.TypeDeb, matchers.TypeRpm, ascType:
return false
case matchers.TypeGz, types.Unknown, matchers.TypeZip, matchers.TypeXz, matchers.TypeTar, matchers.TypeExe:
break
default:
Expand Down
92 changes: 68 additions & 24 deletions pkg/assets/assets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (
)

type mockOSResolver struct {
OS []string
Arch []string
OS []string
Arch []string
OSSpecificExtensions []string
}

func (m *mockOSResolver) GetOS() []string {
Expand All @@ -19,23 +20,30 @@ func (m *mockOSResolver) GetArch() []string {
return m.Arch
}

func (m *mockOSResolver) GetOSSpecificExtensions() []string {
return m.OSSpecificExtensions
}

var (
testLinuxAMDResolver = &mockOSResolver{OS: []string{"linux"}, Arch: []string{"amd64", "x86_64", "x64", "64"}, OSSpecificExtensions: []string{"AppImage"}}
testWindowsAMDResolver = &mockOSResolver{OS: []string{"windows", "win"}, Arch: []string{"amd64", "x86_64", "x64", "64"}, OSSpecificExtensions: []string{"exe"}}
)

func TestSanitizeName(t *testing.T) {
linuxAMDResolver := &mockOSResolver{OS: []string{"linux"}, Arch: []string{"amd64", "x86_64", "x64", "64"}}
windowsAMDResolver := &mockOSResolver{OS: []string{"windows", "win"}, Arch: []string{"amd64", "x86_64", "x64", "64"}}
cases := []struct {
in string
v string
out string
resolver platformResolver
}{
{"bin_amd64_linux", "v0.0.1", "bin", linuxAMDResolver},
{"bin_0.0.1_amd64_linux", "0.0.1", "bin", linuxAMDResolver},
{"bin_0.0.1_amd64_linux", "v0.0.1", "bin", linuxAMDResolver},
{"gitlab-runner-linux-amd64", "v13.2.1", "gitlab-runner", linuxAMDResolver},
{"jq-linux64", "jq-1.5", "jq", linuxAMDResolver},
{"launchpad-linux-x64", "1.2.0-rc.1", "launchpad", linuxAMDResolver},
{"launchpad-win-x64.exe", "1.2.0-rc.1", "launchpad.exe", windowsAMDResolver},
{"bin_0.0.1_Windows_x86_64.exe", "0.0.1", "bin.exe", windowsAMDResolver},
{"bin_amd64_linux", "v0.0.1", "bin", testLinuxAMDResolver},
{"bin_0.0.1_amd64_linux", "0.0.1", "bin", testLinuxAMDResolver},
{"bin_0.0.1_amd64_linux", "v0.0.1", "bin", testLinuxAMDResolver},
{"gitlab-runner-linux-amd64", "v13.2.1", "gitlab-runner", testLinuxAMDResolver},
{"jq-linux64", "jq-1.5", "jq", testLinuxAMDResolver},
{"launchpad-linux-x64", "1.2.0-rc.1", "launchpad", testLinuxAMDResolver},
{"launchpad-win-x64.exe", "1.2.0-rc.1", "launchpad.exe", testWindowsAMDResolver},
{"bin_0.0.1_Windows_x86_64.exe", "0.0.1", "bin.exe", testWindowsAMDResolver},
}

for _, c := range cases {
Expand All @@ -61,8 +69,6 @@ func (a args) String() string {
}

func TestFilterAssets(t *testing.T) {
linuxAMDResolver := &mockOSResolver{OS: []string{"linux"}, Arch: []string{"amd64", "x86_64", "x64", "64"}}
windowsAMDResolver := &mockOSResolver{OS: []string{"windows", "win"}, Arch: []string{"amd64", "x86_64", "x64", "64"}}
cases := []struct {
in args
out string
Expand All @@ -72,48 +78,62 @@ func TestFilterAssets(t *testing.T) {
{Name: "bin_0.0.1_Linux_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.0.1_Linux_x86_64"},
{Name: "bin_0.0.1_Linux_i386", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.0.1_Linux_i386"},
{Name: "bin_0.0.1_Darwin_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.0.1_Darwin_x86_64"},
}}, "bin_0.0.1_linux_x86_64", linuxAMDResolver},
}}, "bin_0.0.1_Linux_x86_64", testLinuxAMDResolver},
{args{"bin", []*Asset{
{Name: "bin_0.1.0_Windows_i386.exe", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Windows_i386.exe"},
{Name: "bin_0.1.0_Linux_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Linux_x86_64"},
{Name: "bin_0.1.0_Darwin_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Darwin_x86_64"},
}}, "bin_0.1.0_linux_x86_64", linuxAMDResolver},
}}, "bin_0.1.0_Linux_x86_64", testLinuxAMDResolver},
{args{"bin", []*Asset{
{Name: "bin_0.1.0_Windows_i386.exe", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Windows_i386.exe"},
{Name: "bin_0.1.0_Linux_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Linux_x86_64"},
{Name: "bin_0.1.0_Darwin_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Darwin_x86_64"},
}}, "bin_0.1.0_linux_x86_64", linuxAMDResolver},
}}, "bin_0.1.0_Linux_x86_64", testLinuxAMDResolver},
{args{"gitlab-runner", []*Asset{
{Name: "Windows 64 bits", URL: "https://gitlab-runner-downloads.s3.amazonaws.com/v13.2.1/binaries/gitlab-runner-windows-amd64.zip"},
{Name: "linux amd64", URL: "https://gitlab-runner-downloads.s3.amazonaws.com/v13.2.1/binaries/gitlab-runner-linux-amd64"},
{Name: "macOS", URL: "https://gitlab-runner-downloads.s3.amazonaws.com/v13.2.1/binaries/gitlab-runner-darwin-amd64"},
}}, "gitlab-runner-linux-amd64", linuxAMDResolver},
}}, "gitlab-runner-linux-amd64", testLinuxAMDResolver},
{args{"yq", []*Asset{
{Name: "yq_freebsd_amd64", URL: "https://github.com/mikefarah/yq/releases/download/3.3.2/yq_freebsd_amd64"},
{Name: "yq_linux_amd64", URL: "https://github.com/mikefarah/yq/releases/download/3.3.2/yq_linux_amd64"},
{Name: "yq_windows_amd64.exe", URL: "https://github.com/mikefarah/yq/releases/download/3.3.2/yq_windows_amd64.exe"},
}}, "yq_linux_amd64", linuxAMDResolver},
}}, "yq_linux_amd64", testLinuxAMDResolver},
{args{"jq", []*Asset{
{Name: "jq-win64.exe", URL: "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-win64.exe"},
{Name: "jq-linux64", URL: "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64"},
{Name: "jq-osx-amd64", URL: "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64"},
}}, "jq-linux64", linuxAMDResolver},
}}, "jq-linux64", testLinuxAMDResolver},
{args{"bin", []*Asset{
{Name: "bin_0.0.1_Windows_x86_64.exe", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.0.1_Windows_x86_64.exe"},
{Name: "bin_0.1.0_Linux_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Linux_x86_64"},
{Name: "bin_0.1.0_Darwin_x86_64", URL: "https://github.com/marcosnils/bin/releases/download/v0.0.1/bin_0.1.0_Darwin_x86_64"},
}}, "bin_0.0.1_windows_x86_64.exe", windowsAMDResolver},
}}, "bin_0.0.1_Windows_x86_64.exe", testWindowsAMDResolver},
{args{"tezos", []*Asset{
{Name: "x86_64-linux-tezos-binaries.tar.gz", URL: "https://gitlab.com/api/v4/projects/3836952/packages/generic/tezos/8.2.0/x86_64-linux-tezos-binaries.tar.gz"},
}}, "x86_64-linux-tezos-binaries.tar.gz", linuxAMDResolver},
}}, "x86_64-linux-tezos-binaries.tar.gz", testLinuxAMDResolver},
{args{"launchpad", []*Asset{
{Name: "launchpad-linux-x64", URL: "https://github.com/Mirantis/launchpad/releases/download/1.2.0-rc.1/launchpad-linux-x64"},
{Name: "launchpad-win-x64.exe", URL: "https://github.com/Mirantis/launchpad/releases/download/1.2.0-rc.1/launchpad-win-x64.exe"},
}}, "launchpad-linux-x64", linuxAMDResolver},
}}, "launchpad-linux-x64", testLinuxAMDResolver},
{args{"launchpad", []*Asset{
{Name: "launchpad-linux-x64", URL: "https://github.com/Mirantis/launchpad/releases/download/1.2.0-rc.1/launchpad-linux-x64"},
{Name: "launchpad-win-x64.exe", URL: "https://github.com/Mirantis/launchpad/releases/download/1.2.0-rc.1/launchpad-win-x64.exe"},
}}, "launchpad-win-x64.exe", windowsAMDResolver},
}}, "launchpad-win-x64.exe", testWindowsAMDResolver},
{args{"Cura", []*Asset{
{Name: "Ultimaker_Cura-4.7.1-Darwin.dmg", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1-Darwin.dmg"},
{Name: "Ultimaker_Cura-4.7.1-win64.exe", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1-win64.exe"},
{Name: "Ultimaker_Cura-4.7.1-win64.msi", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1-win64.msi"},
{Name: "Ultimaker_Cura-4.7.1.AppImage", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1.AppImage"},
{Name: "Ultimaker_Cura-4.7.1.AppImage.asc", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1.AppImage.asc"},
}}, "Ultimaker_Cura-4.7.1.AppImage", testLinuxAMDResolver},
{args{"Cura", []*Asset{
{Name: "Ultimaker_Cura-4.7.1-Darwin.dmg", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1-Darwin.dmg"},
{Name: "Ultimaker_Cura-4.7.1-win64.exe", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1-win64.exe"},
{Name: "Ultimaker_Cura-4.7.1-win64.msi", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1-win64.msi"},
{Name: "Ultimaker_Cura-4.7.1.AppImage", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1.AppImage"},
{Name: "Ultimaker_Cura-4.7.1.AppImage.asc", URL: "https://github.com/Ultimaker/Cura/releases/download/4.7.1/Ultimaker_Cura-4.7.1.AppImage.asc"},
}}, "Ultimaker_Cura-4.7.1-win64.exe", testWindowsAMDResolver},
}

for _, c := range cases {
Expand All @@ -126,3 +146,27 @@ func TestFilterAssets(t *testing.T) {
}

}

func TestIsSupportedExt(t *testing.T) {
cases := []struct {
in string
out bool
}{
{
"Ultimaker_Cura-4.8.0.AppImage",
true,
},
{
"Ultimaker_Cura-4.7.1-win64.msi",
false,
},
}

for _, c := range cases {
result := isSupportedExt(c.in)
if result != c.out {
t.Fatalf("Expected result for extension %v to be %v, but got result %v", c.in, c.out, result)
}
}

}
11 changes: 11 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,14 @@ func GetOS() []string {
}
return res
}

func GetOSSpecificExtensions() []string {
switch runtime.GOOS {
case "linux":
return []string{"AppImage"}
case "windows":
return []string{"exe"}
default:
return nil
}
}

0 comments on commit 4bd5e82

Please sign in to comment.