Skip to content

Commit

Permalink
feat: compare version to relay, extract latest version in install scr…
Browse files Browse the repository at this point in the history
…ipt (#45)
  • Loading branch information
ZinoKader authored Feb 21, 2023
1 parent b7e946a commit ededb8a
Show file tree
Hide file tree
Showing 15 changed files with 130 additions and 126 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ jobs:

- name: E2E Test
if: github.event_name == 'pull_request'
env:
PORTAL_VERSION: 'v1.1.1' # version does not matter for outcome of test, just for building image
run: make test-e2e

- name: Upload code coverage to Codecov
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Mutli-stage build.
FROM golang:1.18-alpine3.14 as build-stage

ARG version
# Copy source code and build binary
RUN mkdir /usr/app
COPY . /usr/app
WORKDIR /usr/app
RUN go build -o app ./cmd/portal/*.go

RUN CGO=0 go build -ldflags="-s -X main.version=${version}" -o app ./cmd/portal/
# Copy binary from build container and build image.
FROM alpine:3.14
RUN mkdir /usr/app
Expand Down
18 changes: 9 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ LINKER_FLAGS = '-s -X main.version=${PORTAL_VERSION}'
lint:
golangci-lint run --timeout 5m ./...

build:
go build -o portal-bin ./cmd/portal/
build:
go build -ldflags=${LINKER_FLAGS} -o portal-bin ./cmd/portal/

build-production:
CGO=0 go build -ldflags=${LINKER_FLAGS} -o portal ./cmd/portal/

image:
docker build --tag rendezvous:latest .
build-wasm:
GOOS=js GOARCH=wasm go build -o portal.wasm ./cmd/wasm/main.go

image:
docker build --build-arg version=${PORTAL_VERSION} --tag rendezvous:latest .

serve: image
docker run -dp 8080:8080 rendezvous:latest

build-wasm:
GOOS=js GOARCH=wasm go build -o portal.wasm ./cmd/wasm/main.go

test:
go test -v -race -covermode=atomic -coverprofile=coverage.out -failfast -short ./...
go test -ldflags=${LINKER_FLAGS} -v -race -covermode=atomic -coverprofile=coverage.out -failfast -short ./...

test-e2e: image
go test -v -race -covermode=atomic -coverprofile=coverage.out -failfast ./...
go test -ldflags=${LINKER_FLAGS} -v -race -covermode=atomic -coverprofile=coverage.out -failfast ./...
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ brew install SpatiumPortae/homebrew-portal/portal

### Manual

Either get the [latest release](https://github.com/ZinoKader/portal/releases/latest) and install it manually, _or_ run
Either get the [latest release](https://github.com/SpatiumPortae/portal/releases/latest) and install it manually, _or_ run

```bash
curl -s https://raw.githubusercontent.com/ZinoKader/portal/master/scripts/install.sh | bash
curl -s https://raw.githubusercontent.com/SpatiumPortae/portal/master/scripts/install.sh | bash
```

> if permission denied for moving the files to /../bin, replace _" | bash"_ with _" | sudo bash"_ <br>
> if permission is denied for moving the files to /../bin, replace the trailing _"bash"_ with _"sudo bash"_ <br>
(the script is in the repo, so you can check it out before you blindly trust in it!)

## The application
Expand Down
14 changes: 11 additions & 3 deletions cmd/portal/serve.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package main

import (
"fmt"

"github.com/SpatiumPortae/portal/internal/rendezvous"
"github.com/SpatiumPortae/portal/internal/semver"
"github.com/spf13/cobra"
)

Expand All @@ -11,16 +14,21 @@ var serveCmd = &cobra.Command{
Short: "Serve the rendezvous-server",
Long: "The serve command serves the rendezvous-server locally.",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
RunE: func(cmd *cobra.Command, args []string) error {
port, _ := cmd.Flags().GetInt("port")
server := rendezvous.NewServer(port)
ver, err := semver.Parse(version)
if err != nil {
return fmt.Errorf("server requires version to be set: %w", err)
}
server := rendezvous.NewServer(port, ver)
server.Start()
return nil
},
}

// Add `port` flag.
// NOTE: The `port` flag is required and not managed through viper.
func init() {
serveCmd.Flags().IntP("port", "p", 0, "Port to run the portal rendezvous server on")
serveCmd.Flags().IntP("port", "p", 0, "port to run the portal rendezvous server on")
_ = serveCmd.MarkFlagRequired("port")
}
21 changes: 21 additions & 0 deletions internal/rendezvous/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ func (s *Server) handleEstablishReceiver() http.HandlerFunc {
if err != nil {
w.WriteHeader(http.StatusBadRequest)
logger.Error("exchanging salt", zap.Error(err))
return
}

// Start forwarder and relay
Expand All @@ -231,6 +232,26 @@ func (s *Server) handleEstablishReceiver() http.HandlerFunc {
}
}

//nolint:errcheck
func (s *Server) handleVersionCheck() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger, err := logger.FromContext(ctx)
if err != nil {
return
}

response, err := json.Marshal(s.version)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
logger.Error("failed to marshal server version", zap.Error(err))
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(response)
}
}

//nolint:errcheck
func (s *Server) ping() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
Expand Down
5 changes: 4 additions & 1 deletion internal/rendezvous/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (
)

func (s *Server) routes() {
s.router.Use(logger.Middleware(s.logger))
s.router.HandleFunc("/ping", s.ping())
s.router.HandleFunc("/version", s.handleVersionCheck())

portal := s.router.PathPrefix("").Subrouter()
portal.Use(logger.Middleware(s.logger), conn.Middleware())
portal.Use(conn.Middleware())
portal.HandleFunc("/establish-sender", s.handleEstablishSender())
portal.HandleFunc("/establish-receiver", s.handleEstablishReceiver())
}
10 changes: 8 additions & 2 deletions internal/rendezvous/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/SpatiumPortae/portal/internal/logger"
"github.com/SpatiumPortae/portal/internal/semver"
"github.com/gorilla/mux"
"go.uber.org/zap"
)
Expand All @@ -21,10 +22,11 @@ type Server struct {
ids *IDs
signal chan os.Signal
logger *zap.Logger
version *semver.Version
}

// NewServer constructs a new Server struct and setups the routes.
func NewServer(port int) *Server {
func NewServer(port int, version semver.Version) *Server {
router := &mux.Router{}
lgr := logger.New()
stdLoggerWrapper, _ := zap.NewStdLogAt(lgr, zap.ErrorLevel)
Expand All @@ -40,6 +42,7 @@ func NewServer(port int) *Server {
mailboxes: &Mailboxes{&sync.Map{}},
ids: &IDs{&sync.Map{}},
logger: lgr,
version: &version,
}
s.routes()
return s
Expand Down Expand Up @@ -68,7 +71,10 @@ func serve(s *Server, ctx context.Context) (err error) {
}
}()

s.logger.Info(fmt.Sprintf("serving rendezvous server at: %s", s.httpServer.Addr))
s.logger.
With(zap.String("version", s.version.String())).
With(zap.String("address", s.httpServer.Addr)).
Info("serving rendezvous server")
<-ctx.Done()

ctxShutdown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
Expand Down
71 changes: 23 additions & 48 deletions internal/semver/semver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package semver

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand All @@ -12,7 +13,7 @@ import (

const pattern = `^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$`

var ParseError = errors.New("provided string cannot be parsed into semver")
var ErrParse = errors.New("could not parse provided string into semantic version")

type Comparsion int

Expand All @@ -27,7 +28,9 @@ const (
)

type Version struct {
major, minor, patch int
Major int `json:"major,omitempty"`
Minor int `json:"minor,omitempty"`
Patch int `json:"patch,omitempty"`
}

// Parse parses the the provided string into a semver representation.
Expand All @@ -37,19 +40,19 @@ func Parse(s string) (Version, error) {
return Version{}, fmt.Errorf("compiling regex: %w", err)
}
if !re.MatchString(s) {
return Version{}, ParseError
return Version{}, ErrParse
}
split := strings.Split(s[1:], ".")
ver := Version{}
ver.major, err = strconv.Atoi(split[0])
ver.Major, err = strconv.Atoi(split[0])
if err != nil {
return Version{}, fmt.Errorf("parsing Major to int: %w", err)
}
ver.minor, err = strconv.Atoi(split[1])
ver.Minor, err = strconv.Atoi(split[1])
if err != nil {
return Version{}, fmt.Errorf("parsing Minor to int: %w", err)
}
ver.patch, err = strconv.Atoi(split[2])
ver.Patch, err = strconv.Atoi(split[2])
if err != nil {
return Version{}, fmt.Errorf("parsing Patch to int: %w", err)
}
Expand All @@ -59,65 +62,37 @@ func Parse(s string) (Version, error) {

// String returns a string representation of the semver.
func (sv Version) String() string {
return fmt.Sprintf("v%d.%d.%d", sv.major, sv.minor, sv.patch)
return fmt.Sprintf("v%d.%d.%d", sv.Major, sv.Minor, sv.Patch)
}

// Compare compares the semver against the provided oracle statement.
// Return -1 if the semver is less than the oracle statement, 1 if
// the oracle statement is larger than the semver and 0 if they are equal.
func (sv Version) Compare(oracle Version) Comparsion {
switch {
case sv.major < oracle.major:
case sv.Major < oracle.Major:
return CompareOldMajor
case sv.major > oracle.major:
case sv.Major > oracle.Major:
return CompareNewMajor
case sv.minor < oracle.minor:
case sv.Minor < oracle.Minor:
return CompareOldMinor
case sv.minor > oracle.minor:
case sv.Minor > oracle.Minor:
return CompareNewMinor
case sv.patch < oracle.patch:
case sv.Patch < oracle.Patch:
return CompareOldPatch
case sv.patch > oracle.patch:
case sv.Patch > oracle.Patch:
return CompareNewPatch
default:
return CompareEqual
}
}

func (sv Version) Major() int {
return sv.major
}

func (sv Version) Minor() int {
return sv.minor
}

func (sv Version) Patch() int {
return sv.patch
}

func GetPortalLatest() (Version, error) {
r, err := http.Get("https://api.github.com/repos/SpatiumPortae/portal/releases?per_page=1")
func GetRendezvousVersion(ctx context.Context, addr string) (Version, error) {
r, err := http.Get(fmt.Sprintf("http://%s/version", addr))
if err != nil {
return Version{}, fmt.Errorf("fetching the latest tag from github: %w", err)
}
type tag struct {
Name string `json:"tag_name"`
}
var tags []tag
if err := json.NewDecoder(r.Body).Decode(&tags); err != nil {
return Version{}, fmt.Errorf("decoding response from github: %w", err)
}
if len(tags) < 1 {
return Version{}, fmt.Errorf("no tags returned from github: %w", err)
return Version{}, fmt.Errorf("fetching the latest version from relay: %w", err)
}
vers := make([]Version, len(tags))
for i := range tags {
v, err := Parse(tags[i].Name)
if err != nil {
return Version{}, fmt.Errorf("unable to parse tag to semver: %w", err)
}
vers[i] = v
var version Version
if err := json.NewDecoder(r.Body).Decode(&version); err != nil {
return Version{}, fmt.Errorf("decoding version response from relay: %w", err)
}
return vers[0], nil
return version, nil
}
8 changes: 4 additions & 4 deletions internal/semver/semver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ func TestParse(t *testing.T) {
t.Run("no leading v", func(t *testing.T) {
s := "0.0.1"
_, err := semver.Parse(s)
assert.Equal(t, semver.ParseError, err)
assert.Equal(t, semver.ErrParse, err)
})
t.Run("major leading 0", func(t *testing.T) {
s := "v01.0.1"
_, err := semver.Parse(s)
assert.Equal(t, semver.ParseError, err)
assert.Equal(t, semver.ErrParse, err)
})
t.Run("minor leading 0", func(t *testing.T) {
s := "v0.01.1"
_, err := semver.Parse(s)
assert.Equal(t, semver.ParseError, err)
assert.Equal(t, semver.ErrParse, err)
})
t.Run("patch leading 0", func(t *testing.T) {
s := "v0.1.01"
_, err := semver.Parse(s)
assert.Equal(t, semver.ParseError, err)
assert.Equal(t, semver.ErrParse, err)
})
})
}
Expand Down
Loading

0 comments on commit ededb8a

Please sign in to comment.