From cd90e887fea89445d5fcfc77d694c9ca2e602840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Budnik?= Date: Wed, 3 Feb 2021 09:08:31 +0100 Subject: [PATCH 1/4] switched to gorilla, added out of the box handlers for logging, proxy headers, and recovery --- .gitignore | 2 ++ go.mod | 8 ++++++++ go.sum | 6 ++++++ server.go | 29 ++++++++++++++++++----------- server_test.go | 23 +++++++++++++++++++++++ 5 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 server_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..871eb4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +debug.test +yosoy \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0ca6259 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/lukaszbudnik/yosoy + +go 1.15 + +require ( + github.com/gorilla/handlers v1.5.1 + github.com/gorilla/mux v1.8.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..daba3c0 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= diff --git a/server.go b/server.go index eb706e6..3a5bd99 100644 --- a/server.go +++ b/server.go @@ -3,11 +3,14 @@ package main import ( "fmt" "io/ioutil" + "log" "net/http" "os" "sort" "strings" - "time" + + "github.com/gorilla/handlers" + "github.com/gorilla/mux" ) var counter = 0 @@ -16,16 +19,11 @@ var showEnvs = os.Getenv("YOSOY_SHOW_ENVS") var showFiles = os.Getenv("YOSOY_SHOW_FILES") func handler(w http.ResponseWriter, req *http.Request) { - if req.RequestURI == "/favicon.ico" { - w.WriteHeader(http.StatusNotFound) - return - } - remoteAddr := req.RemoteAddr if index := strings.LastIndex(remoteAddr, ":"); index > 0 { remoteAddr = remoteAddr[0:index] } - fmt.Printf("[%v] - %v - %v - \"%v %v\"\n", hostname, time.Now().Format(time.RFC3339), remoteAddr, req.Method, req.RequestURI) + w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "text/plain") fmt.Fprintf(w, "Request URI: %v\n", req.RequestURI) @@ -58,7 +56,7 @@ func handler(w http.ResponseWriter, req *http.Request) { for _, file := range files { bytes, err := ioutil.ReadFile(file) if err != nil { - fmt.Printf("[%v] - %v - could not read file %v: %v\n", hostname, time.Now().Format(time.RFC3339), file, err) + log.Printf("Could not read file %v: %v\n", file, err) continue } fmt.Fprintln(w) @@ -70,7 +68,16 @@ func handler(w http.ResponseWriter, req *http.Request) { } func main() { - fmt.Printf("[%v] - %v - yosoy is up!\n", hostname, time.Now().Format(time.RFC3339)) - http.HandleFunc("/", handler) - http.ListenAndServe(":80", nil) + log.Printf("yosoy is up %v\n", hostname) + + r := mux.NewRouter() + + r.Handle("/favicon.ico", r.NotFoundHandler) + r.PathPrefix("/").HandlerFunc(handler) + + loggingRouter := handlers.CombinedLoggingHandler(os.Stdout, r) + proxyRouter := handlers.ProxyHeaders(loggingRouter) + recoveryRouter := handlers.RecoveryHandler()(proxyRouter) + + http.ListenAndServe(":80", recoveryRouter) } diff --git a/server_test.go b/server_test.go new file mode 100644 index 0000000..ab51a51 --- /dev/null +++ b/server_test.go @@ -0,0 +1,23 @@ +package main + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestHandler(t *testing.T) { + req, err := http.NewRequest("GET", "/", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(handler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } +} From 1a1f4cf14d50f16fbdbb80feb1bdba9e775b1263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Budnik?= Date: Thu, 4 Feb 2021 00:29:22 +0100 Subject: [PATCH 2/4] converted to go modules, added gorilla web toolkit, added test, changed yosoy to respond with JSON rather than plain text, added travis support --- .travis.yml | 4 + Dockerfile | 6 +- README.md | 177 +++++++++++++++---------------------------- TestDockerfile | 15 ++++ go.mod | 1 + go.sum | 10 +++ server.go | 77 ++++++++++--------- server_test.go | 18 ++++- test/deployment.yaml | 53 +++++++++++++ 9 files changed, 207 insertions(+), 154 deletions(-) create mode 100644 .travis.yml create mode 100644 TestDockerfile create mode 100644 test/deployment.yaml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..84a8435 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: go + +go: +- "1.15" diff --git a/Dockerfile b/Dockerfile index 32251c0..c9f0e8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ -FROM golang:1.13.5-alpine3.10 as builder +FROM golang:1.15.7-alpine3.13 as builder LABEL maintainer="Łukasz Budnik lukasz.budnik@gmail.com" # build yosoy -RUN apk add git +RUN apk --update add git RUN git clone https://github.com/lukaszbudnik/yosoy.git RUN cd /go/yosoy && go build -FROM alpine:3.10 +FROM alpine:3.13 COPY --from=builder /go/yosoy/yosoy /bin # register entrypoint diff --git a/README.md b/README.md index aa065c1..007b298 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,24 @@ Typical use cases include: * testing HTTP caching * stubbing and prototyping distributed applications -yosoy will provide information like: +## API -* Request URI -* Hostname -* Remote IP -* How many times it was called -* HTTP headers -* Env variables if `YOSOY_SHOW_ENVS` is set to `true`, `yes`, `on`, or `1` -* Files' contents if `YOSOY_SHOW_FILES` is set to a comma-separated list of (valid) files +yosoy responds to all requests with a JSON containing the information about: + +* HTTP request: + * Host + * Request URI + * Remote IP + * HTTP headers + * HTTP proxy headers +* host: + * Hostname + * How many times it was called + * Env variables if `YOSOY_SHOW_ENVS` is set to `true`, `yes`, `on`, or `1` + * Files' contents if `YOSOY_SHOW_FILES` is set to a comma-separated list of (valid) files See [Kubernetes example](#kubernetes-example) below. - ## Docker image The docker image is available on docker hub: @@ -36,116 +41,58 @@ It exposes HTTP service on port 80. ## Kubernetes example -Let's take a look at a sample Kubernetes deployment file. It uses both `YOSOY_SHOW_ENVS` and `YOSOY_SHOW_FILES`. +There is a sample Kubernetes deployment file in the `test` folder. It uses both `YOSOY_SHOW_ENVS` and `YOSOY_SHOW_FILES`. The deployment uses Kubernetes Downward API to expose labels and annotations as volume files which are then returned by yosoy. -> To illustrate `YOSOY_SHOW_FILES` functionality Kubernetes Downward API is used to expose labels and annotations as volume files which are then returned by yosoy. +Deploy it to minikube and execute curl to the service a couple of times: -``` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: camarero - labels: - app.kubernetes.io/name: camarero -spec: - replicas: 2 - selector: - matchLabels: - app.kubernetes.io/name: camarero - template: - metadata: - labels: - app.kubernetes.io/name: camarero - spec: - containers: - - name: yosoy - image: lukasz/yosoy - env: - - name: YOSOY_SHOW_ENVS - value: "true" - - name: YOSOY_SHOW_FILES - value: "/etc/podinfo/labels,/etc/podinfo/annotations" - ports: - - containerPort: 80 - volumeMounts: - - name: podinfo - mountPath: /etc/podinfo - volumes: - - name: podinfo - downwardAPI: - items: - - path: "labels" - fieldRef: - fieldPath: metadata.labels - - path: "annotations" - fieldRef: - fieldPath: metadata.annotations ---- -apiVersion: v1 -kind: Service -metadata: - name: camarero - labels: - app.kubernetes.io/name: camarero -spec: - type: NodePort - selector: - app.kubernetes.io/name: camarero - ports: - - protocol: TCP - port: 80 -``` - -Deploy above service (with 2 replicas) and execute curl to the service a couple of times: - -``` -kubectl apply -f test-deployment.yaml -export NODE_PORT=$(kubectl get services/camarero -o go-template='{{(index .spec.ports 0).nodePort}}') -curl $(minikube ip):$NODE_PORT -curl $(minikube ip):$NODE_PORT -curl $(minikube ip):$NODE_PORT -curl $(minikube ip):$NODE_PORT +```bash +# start minikube +minikube start +# deploy test service +kubectl apply -f test/deployment.yaml +# tunnel to it and copy the URL as $URL variable +minikube service --url camarero +# call it a few times +curl $URL +curl $URL +curl $URL +curl $URL ``` A sample response looks like this: -``` -Request URI: / -Hostname: camarero-859d7c6d6b-kb5s5 -Remote IP: 172.18.0.1 -Called: 2 - -HTTP headers: -Accept: */* -User-Agent: curl/7.64.1 - -Env variables: -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -HOSTNAME=camarero-859d7c6d6b-kb5s5 -YOSOY_SHOW_ENVS=true -YOSOY_SHOW_FILES=/etc/podinfo/labels,/etc/podinfo/annotations -CAMARERO_PORT_80_TCP_PORT=80 -CAMARERO_PORT_80_TCP_ADDR=10.105.203.131 -KUBERNETES_PORT=tcp://10.96.0.1:443 -KUBERNETES_PORT_443_TCP_PORT=443 -CAMARERO_SERVICE_HOST=10.105.203.131 -KUBERNETES_PORT_443_TCP_PROTO=tcp -KUBERNETES_SERVICE_HOST=10.96.0.1 -KUBERNETES_SERVICE_PORT=443 -KUBERNETES_SERVICE_PORT_HTTPS=443 -KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443 -KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1 -CAMARERO_PORT=tcp://10.105.203.131:80 -CAMARERO_SERVICE_PORT=80 -CAMARERO_PORT_80_TCP=tcp://10.105.203.131:80 -CAMARERO_PORT_80_TCP_PROTO=tcp -HOME=/root - -File /etc/podinfo/labels: -app.kubernetes.io/name="camarero" -pod-template-hash="859d7c6d6b" - -File /etc/podinfo/annotations: -kubernetes.io/config.seen="2020-11-17T07:38:15.374049163Z" -kubernetes.io/config.source="api" +```json +{ + "host": "127.0.0.1:53366", + "requestUri": "/", + "remoteAddr": "172.17.0.1", + "counter": 4, + "headers": { + "Accept": [ + "*/*" + ], + "User-Agent": [ + "curl/7.64.1" + ] + }, + "hostname": "camarero-77787464ff-hjdkq", + "envVariables": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOSTNAME=camarero-77787464ff-hjdkq", + "YOSOY_SHOW_ENVS=true", + "YOSOY_SHOW_FILES=/etc/podinfo/labels,/etc/podinfo/annotations", + "CAMARERO_SERVICE_HOST=10.97.113.33", + "CAMARERO_PORT=tcp://10.97.113.33:80", + "CAMARERO_PORT_80_TCP=tcp://10.97.113.33:80", + "CAMARERO_PORT_80_TCP_ADDR=10.97.113.33", + "CAMARERO_SERVICE_PORT=80", + "CAMARERO_PORT_80_TCP_PROTO=tcp", + "CAMARERO_PORT_80_TCP_PORT=80", + "HOME=/root" + ], + "files": { + "/etc/podinfo/annotations": "kubernetes.io/config.seen=\"2021-02-03T13:18:34.563751030Z\"\nkubernetes.io/config.source=\"api\"", + "/etc/podinfo/labels": "app.kubernetes.io/name=\"camarero\"\npod-template-hash=\"77787464ff\"" + } +} ``` diff --git a/TestDockerfile b/TestDockerfile new file mode 100644 index 0000000..c2c8a93 --- /dev/null +++ b/TestDockerfile @@ -0,0 +1,15 @@ +FROM golang:1.15.7-alpine3.13 as builder + +LABEL maintainer="Łukasz Budnik lukasz.budnik@gmail.com" + +# build yosoy +ADD . /go/yosoy +RUN cd /go/yosoy && go build + +FROM alpine:3.13 +COPY --from=builder /go/yosoy/yosoy /bin + +# register entrypoint +ENTRYPOINT ["yosoy"] + +EXPOSE 80 diff --git a/go.mod b/go.mod index 0ca6259..7bb8178 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.15 require ( github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 + github.com/stretchr/testify v1.7.0 ) diff --git a/go.sum b/go.sum index daba3c0..60bf2d5 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,16 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server.go b/server.go index 3a5bd99..5be35c2 100644 --- a/server.go +++ b/server.go @@ -1,57 +1,54 @@ package main import ( - "fmt" + "encoding/json" "io/ioutil" "log" "net/http" "os" - "sort" "strings" "github.com/gorilla/handlers" "github.com/gorilla/mux" ) +type response struct { + Host string `json:"host"` + RequestURI string `json:"requestUri"` + RemoteAddr string `json:"remoteAddr"` + Counter int `json:"counter"` + Headers map[string][]string `json:"headers"` + Hostname string `json:"hostname"` + EnvVariables []string `json:"envVariables,omitempty"` + Files map[string]string `json:"files,omitempty"` +} + var counter = 0 var hostname = os.Getenv("HOSTNAME") -var showEnvs = os.Getenv("YOSOY_SHOW_ENVS") -var showFiles = os.Getenv("YOSOY_SHOW_FILES") func handler(w http.ResponseWriter, req *http.Request) { - remoteAddr := req.RemoteAddr - if index := strings.LastIndex(remoteAddr, ":"); index > 0 { - remoteAddr = remoteAddr[0:index] - } + showEnvs := os.Getenv("YOSOY_SHOW_ENVS") + showFiles := os.Getenv("YOSOY_SHOW_FILES") + + response := &response{} - w.WriteHeader(http.StatusOK) - w.Header().Add("Content-Type", "text/plain") - fmt.Fprintf(w, "Request URI: %v\n", req.RequestURI) - fmt.Fprintf(w, "Hostname: %v\n", hostname) - fmt.Fprintf(w, "Remote IP: %v\n", remoteAddr) counter++ - fmt.Fprintf(w, "Called: %v\n", counter) - fmt.Fprintln(w) - fmt.Fprintf(w, "HTTP headers:\n") - headers := make([]string, 0, len(req.Header)) - for k := range req.Header { - headers = append(headers, k) - } - sort.Strings(headers) - for _, header := range headers { - headers := req.Header[header] - for _, h := range headers { - fmt.Fprintf(w, "%v: %v\n", header, h) - } - } + response.Counter = counter + + remoteAddr := remoteAddrWithoutPort(req) + response.RemoteAddr = remoteAddr + + response.RequestURI = req.RequestURI + response.Host = req.Host + response.Headers = req.Header + + response.Hostname = hostname + if strings.ToLower(showEnvs) == "true" || strings.ToLower(showEnvs) == "yes" || strings.ToLower(showEnvs) == "on" || showEnvs == "1" { - fmt.Fprintln(w) - fmt.Fprintf(w, "Env variables:\n") - for _, e := range os.Environ() { - fmt.Fprintln(w, e) - } + response.EnvVariables = os.Environ() } if len(showFiles) > 0 { + response.Files = make(map[string]string) files := strings.Split(showFiles, ",") for _, file := range files { bytes, err := ioutil.ReadFile(file) @@ -59,12 +56,22 @@ func handler(w http.ResponseWriter, req *http.Request) { log.Printf("Could not read file %v: %v\n", file, err) continue } - fmt.Fprintln(w) - fmt.Fprintf(w, "File %v:\n", file) contents := string(bytes) - fmt.Fprintln(w, contents) + response.Files[file] = contents } } + + w.Header().Add("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(response) +} + +func remoteAddrWithoutPort(req *http.Request) string { + remoteAddr := req.RemoteAddr + if index := strings.LastIndex(remoteAddr, ":"); index > 0 { + remoteAddr = remoteAddr[0:index] + } + return remoteAddr } func main() { diff --git a/server_test.go b/server_test.go index ab51a51..7bdefda 100644 --- a/server_test.go +++ b/server_test.go @@ -1,16 +1,24 @@ package main import ( + "encoding/json" "net/http" "net/http/httptest" + "os" "testing" + + "github.com/stretchr/testify/assert" ) func TestHandler(t *testing.T) { - req, err := http.NewRequest("GET", "/", nil) + os.Setenv("YOSOY_SHOW_ENVS", "true") + os.Setenv("YOSOY_SHOW_FILES", ".gitignore") + + req, err := http.NewRequest("GET", "https://example.org/sample/path", nil) if err != nil { t.Fatal(err) } + req.Header.Set("Accept", "*/*") rr := httptest.NewRecorder() handler := http.HandlerFunc(handler) @@ -20,4 +28,12 @@ func TestHandler(t *testing.T) { if status := rr.Code; status != http.StatusOK { t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) } + + var response response + json.Unmarshal(rr.Body.Bytes(), &response) + + assert.Equal(t, 1, response.Counter) + assert.Equal(t, "example.org", response.Host) + assert.NotEmpty(t, response.EnvVariables) + assert.NotEmpty(t, response.Files[".gitignore"]) } diff --git a/test/deployment.yaml b/test/deployment.yaml new file mode 100644 index 0000000..1b672e7 --- /dev/null +++ b/test/deployment.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: camarero + labels: + app.kubernetes.io/name: camarero +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: camarero + template: + metadata: + labels: + app.kubernetes.io/name: camarero + spec: + containers: + - name: yosoy + image: lukasz/yosoy + env: + - name: YOSOY_SHOW_ENVS + value: "true" + - name: YOSOY_SHOW_FILES + value: "/etc/podinfo/labels,/etc/podinfo/annotations" + ports: + - containerPort: 80 + volumeMounts: + - name: podinfo + mountPath: /etc/podinfo + volumes: + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations +--- +apiVersion: v1 +kind: Service +metadata: + name: camarero + labels: + app.kubernetes.io/name: camarero +spec: + type: NodePort + selector: + app.kubernetes.io/name: camarero + ports: + - protocol: TCP + port: 80 From 908f01df4b827c080cea7f5ac7a3679b28275625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Budnik?= Date: Thu, 4 Feb 2021 00:43:12 +0100 Subject: [PATCH 3/4] Create go.yml --- .github/workflows/go.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..6f6cfd5 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,25 @@ +name: Go + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.15 + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v ./... From a2a3c4f9489a4898e71ed0d3c306460f722234d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Budnik?= Date: Thu, 4 Feb 2021 00:50:07 +0100 Subject: [PATCH 4/4] dropping support for Travis - GitHub Actions are faster --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 84a8435..0000000 --- a/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: go - -go: -- "1.15"