Skip to content

Commit

Permalink
Windows cache CLI support (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucaspin authored Apr 1, 2022
1 parent 3b4c301 commit 92ea5f8
Show file tree
Hide file tree
Showing 36 changed files with 371 additions and 188 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
on: [push]
name: Unit tests
jobs:
unit-testing:
runs-on: windows-latest
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.16.x
- name: Check out repository code
uses: actions/checkout@v2
- name: Install gotestsum
run: go install gotest.tools/gotestsum@latest
- name: Run tests
env:
SEMAPHORE_CACHE_S3_URL: "http://127.0.0.1:9000"
run: |
New-Item C:\minio -ItemType Directory > $null
Invoke-WebRequest "https://dl.min.io/server/minio/release/windows-amd64/minio.exe" -OutFile C:\minio\minio.exe
New-Item C:\minio\data\semaphore-cache -ItemType Directory > $null
Start-Process C:\minio\minio.exe -ArgumentList 'server','C:\minio\data' -RedirectStandardOutput C:\minio\logs -RedirectStandardError C:\minio\errors
cd cache-cli
gotestsum --format short-verbose --packages="./..." -- -p 1
1 change: 1 addition & 0 deletions .semaphore/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ blocks:
- checkout
- artifact pull workflow bin/linux/cache -d cache-cli/bin/linux/cache
- artifact pull workflow bin/darwin/cache -d cache-cli/bin/darwin/cache
- artifact pull workflow bin/windows/cache.exe -d cache-cli/bin/windows/cache.exe
- bash release/create.sh -a
- bash release/upload.sh
6 changes: 4 additions & 2 deletions .semaphore/semaphore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ blocks:
- name: Build cache CLI
commands:
- cd cache-cli
- make build OS=linux
- make build OS=darwin
- make build.linux
- make build.darwin
- make build.windows
- artifact push workflow bin/linux/cache -d bin/linux/cache
- artifact push workflow bin/darwin/cache -d bin/darwin/cache
- artifact push workflow bin/windows/cache.exe -d bin/windows/cache.exe

- name: Static Code Analysis
dependencies: []
Expand Down
10 changes: 8 additions & 2 deletions cache-cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,14 @@ test:
test.watch:
docker-compose run --rm cli gotestsum --watch --format short-verbose --junitfile junit-report.xml --packages="./..." -- -p 1

build:
CGO_ENABLED=0 GOOS=$(OS) go build -o bin/$(OS)/cache main.go
build.darwin:
CGO_ENABLED=0 GOOS=darwin go build -o bin/darwin/cache main.go

build.linux:
CGO_ENABLED=0 GOOS=linux go build -o bin/linux/cache main.go

build.windows:
CGO_ENABLED=0 GOOS=windows go build -o bin/windows/cache.exe main.go

lint:
revive -formatter friendly -config lint.toml ./...
3 changes: 2 additions & 1 deletion cache-cli/cmd/clear_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/semaphoreci/toolbox/cache-cli/pkg/storage"
Expand All @@ -27,7 +28,7 @@ func Test__Clear(t *testing.T) {
err := storage.Clear()
assert.Nil(t, err)

tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
storage.Store("abc001", tempFile.Name())

capturer := utils.CreateOutputCapturer()
Expand Down
5 changes: 3 additions & 2 deletions cache-cli/cmd/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/semaphoreci/toolbox/cache-cli/pkg/storage"
Expand All @@ -22,7 +23,7 @@ func Test__Delete(t *testing.T) {

t.Run(fmt.Sprintf("%s key is present", backend), func(*testing.T) {
storage.Clear()
tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
storage.Store("abc001", tempFile.Name())

capturer := utils.CreateOutputCapturer()
Expand All @@ -34,7 +35,7 @@ func Test__Delete(t *testing.T) {

t.Run(fmt.Sprintf("%s normalizes key", backend), func(*testing.T) {
storage.Clear()
tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
RunStore(storeCmd, []string{"abc/00/33", tempFile.Name()})

capturer := utils.CreateOutputCapturer()
Expand Down
5 changes: 3 additions & 2 deletions cache-cli/cmd/has_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/semaphoreci/toolbox/cache-cli/pkg/storage"
Expand All @@ -22,7 +23,7 @@ func Test__HasKey(t *testing.T) {

t.Run(fmt.Sprintf("%s key is present", backend), func(*testing.T) {
storage.Clear()
tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
storage.Store("abc001", tempFile.Name())

capturer := utils.CreateOutputCapturer()
Expand All @@ -34,7 +35,7 @@ func Test__HasKey(t *testing.T) {

t.Run(fmt.Sprintf("%s normalizes key", backend), func(*testing.T) {
storage.Clear()
tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
RunStore(storeCmd, []string{"abc/00/33", tempFile.Name()})

capturer := utils.CreateOutputCapturer()
Expand Down
3 changes: 2 additions & 1 deletion cache-cli/cmd/is_not_empty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/semaphoreci/toolbox/cache-cli/pkg/storage"
Expand All @@ -18,7 +19,7 @@ func Test__IsNotEmpty(t *testing.T) {

t.Run(fmt.Sprintf("%s cache is not empty", backend), func(*testing.T) {
storage.Clear()
tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
storage.Store("abc001", tempFile.Name())

assert.True(t, RunIsNotEmpty(isNotEmptyCmd, []string{}))
Expand Down
3 changes: 2 additions & 1 deletion cache-cli/cmd/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/semaphoreci/toolbox/cache-cli/pkg/storage"
Expand All @@ -24,7 +25,7 @@ func Test__List(t *testing.T) {

t.Run(fmt.Sprintf("%s with keys", backend), func(*testing.T) {
storage.Clear()
tempFile, _ := ioutil.TempFile("/tmp", "*")
tempFile, _ := ioutil.TempFile(os.TempDir(), "*")
storage.Store("abc001", tempFile.Name())
storage.Store("abc002", tempFile.Name())
storage.Store("abc003", tempFile.Name())
Expand Down
38 changes: 25 additions & 13 deletions cache-cli/cmd/restore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,19 @@ func Test__Restore(t *testing.T) {
t.Run(fmt.Sprintf("%s using single exact key", backend), func(*testing.T) {
storage.Clear()

tempDir, _ := ioutil.TempDir("/tmp", "*")
tempDir, _ := ioutil.TempDir(os.TempDir(), "*")
tempFile, _ := ioutil.TempFile(tempDir, "*")
_ = tempFile.Close()

compressAndStore(storage, "abc-001", tempDir)

capturer := utils.CreateOutputCapturer()
RunRestore(restoreCmd, []string{"abc-001"})
output := capturer.Done()

restoredPath := filepath.FromSlash(fmt.Sprintf("%s/", tempDir))
assert.Contains(t, output, "HIT: 'abc-001', using key 'abc-001'.")
assert.Contains(t, output, fmt.Sprintf("Restored: %s/.", tempDir))
assert.Contains(t, output, fmt.Sprintf("Restored: %s.", restoredPath))

os.Remove(tempFile.Name())
os.Remove(tempDir)
Expand All @@ -56,18 +58,20 @@ func Test__Restore(t *testing.T) {
t.Run(fmt.Sprintf("%s normalizes key", backend), func(*testing.T) {
storage.Clear()

tempDir, _ := ioutil.TempDir("/tmp", "*")
tempDir, _ := ioutil.TempDir(os.TempDir(), "*")
tempFile, _ := ioutil.TempFile(tempDir, "*")
_ = tempFile.Close()

compressAndStore(storage, "abc/00/22", tempDir)

capturer := utils.CreateOutputCapturer()
RunRestore(restoreCmd, []string{"abc/00/22"})
output := capturer.Done()

restoredPath := filepath.FromSlash(fmt.Sprintf("%s/", tempDir))
assert.Contains(t, output, "Key 'abc/00/22' is normalized to 'abc-00-22'")
assert.Contains(t, output, "HIT: 'abc-00-22', using key 'abc-00-22'.")
assert.Contains(t, output, fmt.Sprintf("Restored: %s/.", tempDir))
assert.Contains(t, output, fmt.Sprintf("Restored: %s.", restoredPath))

os.Remove(tempFile.Name())
os.Remove(tempDir)
Expand All @@ -76,17 +80,19 @@ func Test__Restore(t *testing.T) {
t.Run(fmt.Sprintf("%s using single matching key", backend), func(*testing.T) {
storage.Clear()

tempDir, _ := ioutil.TempDir("/tmp", "*")
tempDir, _ := ioutil.TempDir(os.TempDir(), "*")
tempFile, _ := ioutil.TempFile(tempDir, "*")
_ = tempFile.Close()

compressAndStore(storage, "abc-001", tempDir)

capturer := utils.CreateOutputCapturer()
RunRestore(restoreCmd, []string{"abc"})
output := capturer.Done()

restoredPath := filepath.FromSlash(fmt.Sprintf("%s/", tempDir))
assert.Contains(t, output, "HIT: 'abc', using key 'abc-001'.")
assert.Contains(t, output, fmt.Sprintf("Restored: %s/.", tempDir))
assert.Contains(t, output, fmt.Sprintf("Restored: %s.", restoredPath))

os.Remove(tempFile.Name())
os.Remove(tempDir)
Expand All @@ -95,8 +101,9 @@ func Test__Restore(t *testing.T) {
t.Run(fmt.Sprintf("%s only first matching key is used", backend), func(*testing.T) {
storage.Clear()

tempDir, _ := ioutil.TempDir("/tmp", "*")
tempDir, _ := ioutil.TempDir(os.TempDir(), "*")
tempFile, _ := ioutil.TempFile(tempDir, "*")
_ = tempFile.Close()

compressAndStore(storage, "abc-001", tempDir)
compressAndStore(storage, "abc-002", tempDir)
Expand All @@ -105,8 +112,9 @@ func Test__Restore(t *testing.T) {
RunRestore(restoreCmd, []string{"abc-001,abc-002"})
output := capturer.Done()

restoredPath := filepath.FromSlash(fmt.Sprintf("%s/", tempDir))
assert.Contains(t, output, "HIT: 'abc-001', using key 'abc-001'.")
assert.Contains(t, output, fmt.Sprintf("Restored: %s/.", tempDir))
assert.Contains(t, output, fmt.Sprintf("Restored: %s.", restoredPath))
assert.NotContains(t, output, "HIT: 'abc-002', using key 'abc-002'.")

os.Remove(tempFile.Name())
Expand All @@ -116,18 +124,20 @@ func Test__Restore(t *testing.T) {
t.Run(fmt.Sprintf("%s using fallback key", backend), func(*testing.T) {
storage.Clear()

tempDir, _ := ioutil.TempDir("/tmp", "*")
tempDir, _ := ioutil.TempDir(os.TempDir(), "*")
tempFile, _ := ioutil.TempFile(tempDir, "*")
_ = tempFile.Close()

compressAndStore(storage, "abc", tempDir)

capturer := utils.CreateOutputCapturer()
RunRestore(restoreCmd, []string{"abc-001,abc"})
output := capturer.Done()

restoredPath := filepath.FromSlash(fmt.Sprintf("%s/", tempDir))
assert.Contains(t, output, "MISS: 'abc-001'.")
assert.Contains(t, output, "HIT: 'abc', using key 'abc'.")
assert.Contains(t, output, fmt.Sprintf("Restored: %s/.", tempDir))
assert.Contains(t, output, fmt.Sprintf("Restored: %s.", restoredPath))

os.Remove(tempFile.Name())
os.Remove(tempDir)
Expand All @@ -136,17 +146,19 @@ func Test__Restore(t *testing.T) {
t.Run(fmt.Sprintf("%s using regex key", backend), func(*testing.T) {
storage.Clear()

tempDir, _ := ioutil.TempDir("/tmp", "*")
tempDir, _ := ioutil.TempDir(os.TempDir(), "*")
tempFile, _ := ioutil.TempFile(tempDir, "*")
_ = tempFile.Close()

compressAndStore(storage, "abc", tempDir)

capturer := utils.CreateOutputCapturer()
RunRestore(restoreCmd, []string{"^abc"})
output := capturer.Done()

restoredPath := filepath.FromSlash(fmt.Sprintf("%s/", tempDir))
assert.Contains(t, output, "HIT: '^abc', using key 'abc'.")
assert.Contains(t, output, fmt.Sprintf("Restored: %s/.", tempDir))
assert.Contains(t, output, fmt.Sprintf("Restored: %s.", restoredPath))

os.Remove(tempFile.Name())
os.Remove(tempDir)
Expand Down Expand Up @@ -191,7 +203,7 @@ func Test__AutomaticRestore(t *testing.T) {

assert.Contains(t, output, "Detected Gemfile.lock")
assert.Contains(t, output, fmt.Sprintf("Downloading key '%s'", key))
assert.Contains(t, output, "Restored: vendor/bundle")
assert.Contains(t, output, fmt.Sprintf("Restored: %s", filepath.FromSlash("vendor/bundle")))

os.RemoveAll("vendor")
os.Remove(compressedFile)
Expand Down
41 changes: 28 additions & 13 deletions cache-cli/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,51 @@ package cmd

import (
"os"
"runtime"
"testing"

"github.com/semaphoreci/toolbox/cache-cli/pkg/storage"
assert "github.com/stretchr/testify/assert"
)

var testBackend = map[string]map[string]string{
type TestBackend struct {
envVars map[string]string
runInWindows bool
}

var testBackends = map[string]TestBackend{
"s3": {
"SEMAPHORE_PROJECT_NAME": "cache-cli",
"SEMAPHORE_CACHE_BACKEND": "s3",
"SEMAPHORE_CACHE_S3_URL": "http://s3:9000",
"SEMAPHORE_CACHE_S3_BUCKET": "semaphore-cache",
runInWindows: true,
envVars: map[string]string{
"SEMAPHORE_PROJECT_NAME": "cache-cli",
"SEMAPHORE_CACHE_BACKEND": "s3",
"SEMAPHORE_CACHE_S3_URL": os.Getenv("SEMAPHORE_CACHE_S3_URL"),
"SEMAPHORE_CACHE_S3_BUCKET": "semaphore-cache",
},
},
"sftp": {
"SEMAPHORE_CACHE_BACKEND": "sftp",
"SEMAPHORE_CACHE_URL": "sftp-server:22",
"SEMAPHORE_CACHE_USERNAME": "tester",
"SEMAPHORE_CACHE_PRIVATE_KEY_PATH": "/root/.ssh/semaphore_cache_key",
runInWindows: false,
envVars: map[string]string{
"SEMAPHORE_CACHE_BACKEND": "sftp",
"SEMAPHORE_CACHE_URL": "sftp-server:22",
"SEMAPHORE_CACHE_USERNAME": "tester",
"SEMAPHORE_CACHE_PRIVATE_KEY_PATH": "/root/.ssh/semaphore_cache_key",
},
},
}

func runTestForAllBackends(t *testing.T, test func(string, storage.Storage)) {
for backend, envVars := range testBackend {
for envVarName, envVarValue := range envVars {
for backendType, testBackend := range testBackends {
if runtime.GOOS == "windows" && !testBackend.runInWindows {
continue
}

for envVarName, envVarValue := range testBackend.envVars {
os.Setenv(envVarName, envVarValue)
}

storage, err := storage.InitStorage()
assert.Nil(t, err)

test(backend, storage)
test(backendType, storage)
}
}
4 changes: 3 additions & 1 deletion cache-cli/cmd/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

Expand Down Expand Up @@ -52,7 +53,8 @@ func RunStore(cmd *cobra.Command, args []string) {
}
}
} else {
compressAndStore(storage, args[0], args[1])
path := filepath.FromSlash(args[1])
compressAndStore(storage, args[0], path)
}
}

Expand Down
Loading

0 comments on commit 92ea5f8

Please sign in to comment.