Skip to content

Commit

Permalink
Merge pull request #178 from ccremer/dist-ui
Browse files Browse the repository at this point in the history
Bundle the UI in the Go binary
  • Loading branch information
ccremer authored Sep 17, 2022
2 parents 690ce0a + 10c14c5 commit b4d20ef
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 21 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,18 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Run build
run: make build
run: make build-docker

vite:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: 16
cache: npm
cache-dependency-path: ui/package-lock.json

- name: Run build
run: make build-ui
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- uses: actions/setup-node@v3
with:
node-version: 16
cache: npm
cache-dependency-path: ui/package-lock.json

- name: Import GPG signing key
uses: crazy-max/ghaction-import-gpg@v5
with:
Expand Down
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/dist/
/.github/release-notes.md
/.github/crds.yaml
/.github/ui.tar.gz

# Build
/clustercode
Expand All @@ -19,7 +20,3 @@
/data/intermediate/**
/data/source/**
/data/target/**

# e2e
/e2e/node_modules/
/e2e/debug/
3 changes: 3 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ builds:
- linux
goarm:
- 8
flags:
- -tags=ui

checksum:
name_template: 'checksums.txt'
Expand Down Expand Up @@ -64,3 +66,4 @@ release:
prerelease: auto
extra_files:
- glob: ./.github/crds.yaml
- glob: ./.github/ui.tar.gz
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ help: ## Show this help
@grep -E -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

.PHONY: build
build: build-docker ## All-in-one build
build: build-ui build-docker ## All-in-one build

.PHONY: build-bin
build-bin: export CGO_ENABLED = 0
build-bin: fmt vet ## Build binary
@go build -o $(BIN_FILENAME) .
@go build $(go_build_args) -o $(BIN_FILENAME) .

.PHONY: build-docker
build-docker: build-bin ## Build docker image
Expand Down Expand Up @@ -107,5 +107,6 @@ run-operator: ## Run in Operator mode against your current kube context
clean: $(clean_targets) ## All-in-one target to cleanup local artifacts

.PHONY: release-prepare
release-prepare: generate-go ## Prepares artifacts for releases
release-prepare: build-ui generate-go ## Prepares artifacts for releases
@cat package/crds/*.yaml | yq > .github/crds.yaml
@tar -czf .github/ui.tar.gz ui/dist
10 changes: 8 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/ccremer/go-command-pipeline v0.20.0
github.com/go-logr/logr v1.2.3
github.com/go-logr/zapr v1.2.3
github.com/labstack/echo/v4 v4.9.0
github.com/stretchr/testify v1.8.0
github.com/urfave/cli/v2 v2.11.1
go.uber.org/zap v1.23.0
Expand Down Expand Up @@ -33,6 +34,7 @@ require (
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gobuffalo/flect v0.2.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
Expand All @@ -43,9 +45,10 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand All @@ -59,9 +62,12 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
Expand Down
21 changes: 19 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ github.com/gobuffalo/flect v0.2.5/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOR
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
Expand Down Expand Up @@ -204,14 +206,20 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
Expand Down Expand Up @@ -286,6 +294,10 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/urfave/cli/v2 v2.11.1 h1:UKK6SP7fV3eKOefbS87iT9YHefv7iB/53ih6e+GNAsE=
github.com/urfave/cli/v2 v2.11.1/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand All @@ -312,6 +324,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -432,6 +446,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
Expand Down
12 changes: 4 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import (
"context"
"fmt"
"os"
"os/signal"
"sync/atomic"
"syscall"
"time"

"github.com/go-logr/logr"
Expand All @@ -32,19 +30,17 @@ func init() {
}

func main() {
ctx, stop, app := newApp()
defer stop()
ctx, app := newApp()
err := app.RunContext(ctx, os.Args)
// If required flags aren't set, it will return with error before we could set up logging
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
stop()
os.Exit(1)
}

}

func newApp() (context.Context, context.CancelFunc, *cli.App) {
func newApp() (context.Context, *cli.App) {
logInstance := &atomic.Value{}
logInstance.Store(logr.Discard())
app := &cli.App{
Expand All @@ -65,6 +61,7 @@ func newApp() (context.Context, context.CancelFunc, *cli.App) {
Commands: []*cli.Command{
newOperatorCommand(),
newWebhookCommand(),
newWebuiCommand(),
newScanCommand(),
newCountCommand(),
newCleanupCommand(),
Expand All @@ -82,8 +79,7 @@ func newApp() (context.Context, context.CancelFunc, *cli.App) {
// However, since we are configuring and replacing this logger after starting up and parsing the flags,
// we'll store a thread-safe atomic reference.
parentCtx := context.WithValue(context.Background(), loggerContextKey{}, logInstance)
ctx, stop := signal.NotifyContext(parentCtx, syscall.SIGINT, syscall.SIGTERM)
return ctx, stop, app
return parentCtx, app
}

func rootAction(hasSubcommands bool) func(context *cli.Context) error {
Expand Down
106 changes: 106 additions & 0 deletions pkg/webui/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package webui

import (
"context"
"io/fs"
"net/http"
"os"

"github.com/ccremer/clustercode/pkg/internal/pipe"
"github.com/ccremer/clustercode/ui"
pipeline "github.com/ccremer/go-command-pipeline"
"github.com/go-logr/logr"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)

type Command struct {
Log logr.Logger
}

type commandContext struct {
context.Context
dependencyResolver pipeline.DependencyResolver[*commandContext]

echo *echo.Echo
}

// Execute runs the command and returns an error, if any.
func (c *Command) Execute(ctx context.Context) error {

pctx := &commandContext{
dependencyResolver: pipeline.NewDependencyRecorder[*commandContext](),
Context: ctx,
}

p := pipeline.NewPipeline[*commandContext]().WithBeforeHooks(pipe.DebugLogger[*commandContext](c.Log), pctx.dependencyResolver.Record)
p.WithSteps(
p.NewStep("create server", c.createServer),
p.NewStep("setup routes", c.setupRoutes),
p.NewStep("run server", c.startServer),
)
return p.RunWithContext(pctx)
}

func (c *Command) createServer(ctx *commandContext) error {
ctx.echo = echo.New()
ctx.echo.Pre(middleware.RemoveTrailingSlash())
ctx.echo.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Skipper: skipAccessLogs,
Format: middleware.DefaultLoggerConfig.Format,
CustomTimeFormat: middleware.DefaultLoggerConfig.CustomTimeFormat,
}))
return nil
}

func (c *Command) setupRoutes(ctx *commandContext) error {
ctx.dependencyResolver.MustRequireDependencyByFuncName(c.createServer)
assetHandler := http.FileServer(c.getFileSystem())
ctx.echo.GET("/", echo.WrapHandler(assetHandler))
ctx.echo.GET("/vite.svg", echo.WrapHandler(assetHandler))
ctx.echo.GET("/assets/*", echo.WrapHandler(assetHandler))
ctx.echo.GET("/healthz", healthz)
return nil
}

func (c *Command) getFileSystem() http.FileSystem {
dir := "ui/dist"
if ui.IsEmbedded() {
c.Log.Info("Using embedded assets")
fsys, err := fs.Sub(ui.PublicFs, "dist")
if err == nil {
return http.FS(fsys)
}
c.Log.Info("Cannot use embedded assets, resort to live assets", "error", err.Error())
} else {
c.Log.Info("This release was built without embedding UI assets. Build or download the assets separately.")
}
c.Log.Info("Serving assets from local filesystem", "dir", dir)
return http.FS(os.DirFS(dir))
}

func (c *Command) startServer(ctx *commandContext) error {
ctx.dependencyResolver.MustRequireDependencyByFuncName(c.createServer)
return ctx.echo.Start(":8080")
}

var publicRoutes = []string{
"/favicon.ico",
"/robots.txt",
"/vite.svg",
"/assets/*",
"/healthz",
}

func skipAccessLogs(ctx echo.Context) bool {
for _, path := range publicRoutes {
if path == ctx.Path() {
return true
}
}
return false
}

func healthz(c echo.Context) error {
return c.String(http.StatusNoContent, "")
}
13 changes: 13 additions & 0 deletions ui/Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# These make target are generally only needed by CI/CD
# Use npm directly for local development

clean_targets += clean-ui

npm = npm --prefix ./ui
npm_run = $(npm) run

ui/node_modules:
$(npm) install

ui/dist:
mkdir -p $@/assets

.PHONY: lint-ui
lint-ui: ui/node_modules ## Runs linters for the UI code
$(npm_run) lint
Expand All @@ -15,3 +20,11 @@ lint-ui: ui/node_modules ## Runs linters for the UI code
.PHONY: test-ui
test-ui: ui/node_modules ## Runs tests for the UI code
$(npm_run) cy:run

.PHONY: build-ui
build-ui: ui/node_modules ## Builds the UI for packaging
$(npm_run) build

.PHONY: clean-ui
clean-ui: ## Removes all UI-related artifacts (node_modules, dist)
rm -rf ui/node_modules ui/dist
15 changes: 15 additions & 0 deletions ui/embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build ui

package ui

import (
"embed"
)

//go:embed dist/*
//go:embed dist/assets
var publicFs embed.FS

func init() {
PublicFs = publicFs
}
Loading

0 comments on commit b4d20ef

Please sign in to comment.