Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
drewsilcock committed Jan 31, 2020
0 parents commit b254a99
Show file tree
Hide file tree
Showing 26 changed files with 2,034 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Dockerfile

# Application output
hbaas-server

# Auto-generated Swagger docs
docs

# Generated files
gen-*.go

# Binary data generated with go-bindata
bindata.go

.env
.go-pkg
.go-bin

.idea
.vscode

*.swp
*.swo
.*.swp
.*.swo
*~
.*~

.git
.gitignore
.dockerignore
.env.example
.gitlab-ci.yml
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HBAAS_POSTGRES_URL="postgres://{ps_user}:{ps_password}@localhost:5432/{ps_database}?sslmode=disable"
30 changes: 30 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Application output
hbaas-server

# Excel spreadsheet for creating the seed people data.
seed-data.xlsx

# Generated files
gen-*.go

# Auto-generated Swagger docs
docs

# Binary data generated with go-bindata
bindata.go

.env
.go-pkg
.go-bin

# IDE files
.idea
.vscode

# Vim files
*.swp
*.swo
.*.swp
.*.swo
*~
.*~
27 changes: 27 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
image: golang

cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .go-bin
- .go-pkg

stages:
- build
- lint
# No testing implemented currently.

build-code:
stage: build
script:
- make compile

lint:
stage: lint
before_script:
- wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /go/bin v1.21.0
- make install
# We need to run the code-gen scripts for the linting to work.
- make code-gen
script:
- golangci-lint run .
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Builder stage
FROM golang AS builder

ENV GO111MODULE=on

ARG version
ARG build

ENV VERSION=$version
ENV BUILD=$build
ENV OUTBINDIR=/app

WORKDIR /app

# Enable Docker cache for go modules.
COPY go.mod .
COPY go.sum .
RUN GOPATH=/app/.go-pkg:/app GOBIN=/app/.go-bin go mod download

COPY Makefile .
RUN make install

COPY . .

RUN make compile-linux

# Runner stage
FROM scratch
# If we need the config.toml in the future that'll need to be copied over too.
COPY --from=builder /app/hbaas-server /app/

# Document that the service listens on port 8080.
EXPOSE 8000
EXPOSE 4443

# Run the outyet command by default when the container starts.
CMD ["/app/hbaas-server", "run-server"]
166 changes: 166 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
-include .env

SHELL := /bin/bash

PROJECTNAME := hbaas-server

VERSION?=$(shell git describe --tags --always)
BUILDTIME=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")

# Go related variables.
GOBASE := $(shell pwd)
GOPATH := $(GOBASE)/.go-pkg:$(GOBASE)
GOBIN := $(GOBASE)/.go-bin
GOFILES := $(wildcard *.go)

# Directory in which to put the output executable.
OUTBINDIR?=$(GOBASE)

PACKAGENAME=$(shell go list)

# Use linker flags to provide version/build settings
LDFLAGS=-ldflags "-X '$(PACKAGENAME)/version.Version=$(VERSION)' -X '$(PACKAGENAME)/version.BuildTime=$(BUILDTIME)'"

LINUXBUILD=CGO_ENABLED=0 GOOS=linux GOARCH=amd64

# Make is verbose in Linux. Make it silent.
MAKEFLAGS += --silent

IS_INTERACTIVE:=$(shell [ -t 0 ] && echo 1)

ifdef IS_INTERACTIVE
LOG_INFO := $(shell tput setaf 12)
LOG_ERROR := $(shell tput setaf 9)
LOG_END := $(shell tput sgr0)
endif

define log
echo -e "$(LOG_INFO)$(1)$(LOG_END)"
endef

define log-error
echo -e "$(LOG_ERROR)$(1)$(LOG_END)"
endef

default: help

## install: Install missing dependencies. Runs `go get` internally. e.g; make install get=github.com/foo/bar
install: go-get-build-deps go-mod-download

## start: Start in development mode. Auto-starts when code changes.
start: clean compile start-server

start-server:
@test -e $(OUTBINDIR)/$(PROJECTNAME) || (\
$(call log-error,Unable to find $(PROJECTNAME) executable.) \
&& false\
)
@$(call log,Starting $(PROJECTNAME)...)
@-$(OUTBINDIR)/$(PROJECTNAME) run-server

## run: Run server with specified args, e.g. `make run args=version`
run:
@$(OUTBINDIR)/$(PROJECTNAME) $(args)

## compile: Compile the binary.
compile: go-get-build-deps go-mod-download code-gen go-build

## compile-linux: Compile the binary for Linux.
compile-linux: go-get-build-deps go-mod-download code-gen go-build-linux

## exec: Run given command, wrapped with custom GOPATH. e.g; make exec run="go test ./..."
exec:
@GOPATH=$(GOPATH) GOBIN=$(GOBIN) $(run)

## build-image: Build Docker image for project.
build-image:
@$(call log,Building Docker image...)
docker build \
--build-arg version=$(VERSION) \
--build-arg build=$(BUILD) \
-t $(PROJECTNAME):latest . || \
(\
$(call log-error,Unable to build Docker image.) \
&& false \
)

## clean: Clean build files. Runs `go clean` internally.
clean:
@-rm $(OUTBINDIR)/$(PROJECTNAME) 2> /dev/null
@-$(MAKE) go-clean
@-rm ./**/bindata.go 2> /dev/null
@-rm ./**/gen-*.go 2> /dev/null

code-gen:
@$(call log,Running pre-build code generation...)
@cd migrations && $(GOBIN)/go-bindata -pkg migrations . || (\
$(call log-error,Unable to generate binary migration data.) \
&& false \
)
@cd seeddata && $(GOBIN)/go-bindata -pkg seeddata . || (\
$(call log-error,Unable to generate binary database seed data.) \
&& false \
)
# If there's no docs package, the docs generation fails. Because of this
# bug, we need to put a stub package in so that Swag can replace it.
@mkdir -p docs
@echo "package docs" > docs/docs.go
@$(GOBIN)/swag init --parseDependency || (\
$(call log-error,Unable to generate Swagger docs.) \
&& false \
)

go-build:
@$(call log,Building binary...)

# Uncomment line below for debugging build arguments.
#@echo Building $(PROJECTNAME): GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(OUTBINDIR)/$(PROJECTNAME) $(GOFILES)

@GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(OUTBINDIR)/$(PROJECTNAME) $(GOFILES) || (\
$(call log-error,Failed to build $(PROJECTNAME).) \
&& false \
)

go-build-linux:
@$(call log,Building binary...)

# Uncomment line below for debugging build arguments.
#@echo Linux build command: "GOPATH=$(GOPATH) GOBIN=$(GOBIN) $(LINUXBUILD) go build $(LDFLAGS) -o $(OUTBINDIR)/$(PROJECTNAME) $(GOFILES)"

@GOPATH=$(GOPATH) GOBIN=$(GOBIN) $(LINUXBUILD) go build $(LDFLAGS) -o $(OUTBINDIR)/$(PROJECTNAME) $(GOFILES) || (\
$(call log-error,Failed to build $(PROJECTNAME).) \
&& false \
)

go-generate:
@$(call log,Generating dependency files...)
@GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate)

go-get-build-deps:
@$(call log,Checking if there are any missing build-time dependencies...)
@make go-get bin=go-bindata pkg=github.com/kevinburke/go-bindata/...
@make go-get bin=swag pkg=github.com/swaggo/swag/cmd/swag

go-get:
@test -e $(GOBIN)/$(bin) || \
GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(pkg)

go-mod-download:
@$(call log,Checking if there are any missing modules...)
@GOPATH=$(GOPATH) GOBIN=$(GOBIN) go mod download

go-install:
@GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES)

go-clean:
@$(call log,Cleaning build cache)
@GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean

.PHONY: help
all: help
help: Makefile
@echo
@echo "Choose a command run in "$(PROJECTNAME)":"
@echo
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
@echo
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# HBaaS Server

This is a fun demo API for saying happy birthday to people for the purposes of demonstrating server containerisation and deployment.

## Software Stack

This project uses the [Go programming language](https://go.dev/) for rapid prototype development and easy containerisation.

For the RESTful API, we are using the [Echo](https://echo.labstack.com/) framework due to its ease-of-use, minimalism, extensability but also performance.

For persistence, GORM is used to interact with a PostgreSQL database.

## Running

There are multiple commands available to the application for seeding the database with test values, auto-migrating the database schema and running the main server.

The main command for the server is:

```sh
./hbaas-server run-server
```

For information on all command-line options, run:

```sh
./hbaas-server --help
```

In order to connect to your local PostgreSQL database, you must specify the `POSTGRES_URL` environment variable. See the `.env.example` file for what this should look like.
59 changes: 59 additions & 0 deletions cmd/auto_migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"github.com/drewsilcock/hbaas-server/migrations"
"github.com/golang-migrate/migrate/v4"
bindata "github.com/golang-migrate/migrate/v4/source/go_bindata"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"log"
)

func init() {
rootCmd.AddCommand(autoMigrateCmd)
}

var autoMigrateCmd = &cobra.Command{
Use: "auto-migrate",
Short: "Migrate DB schema",
Long: "Automatically migrate database schema to the latest version.",
Run: autoMigrate,
}

func autoMigrate(cmd *cobra.Command, args []string) {
assetSource := bindata.Resource(migrations.AssetNames(),
func(name string) ([]byte, error) {
return migrations.Asset(name)
})
migrationData, err := bindata.WithInstance(assetSource)
if err != nil {
log.Fatal("Unable to read migration data:", err)
}
migrator, err := migrate.NewWithSourceInstance(
"go-bindata",
migrationData,
viper.GetString("POSTGRES_URL"),
)
if err != nil {
log.Fatal("Unable to read create migrator:", err)
}
currentVersion, isDirty, err := migrator.Version()
if err == migrate.ErrNilVersion {
log.Println("No migrations currently applied.")
} else if err != nil {
log.Fatal("Unable to get migration status:", err)
} else {
var status string
if isDirty {
status = "dirty"
} else {
status = "clean"
}
log.Println("Currently", status, "on version", currentVersion)
}
log.Println("Migrating database up to latest...")
if err := migrator.Up(); err != nil {
log.Fatal("Unable to perform 'up' migrations:", err)
}
log.Println("Done")
}
Loading

0 comments on commit b254a99

Please sign in to comment.