Skip to content

Commit

Permalink
Refactor to use babyapi CLI
Browse files Browse the repository at this point in the history
- The main thing here is that the API resources need to exist without
  all external integrations
- This required creating all API resources and then adding clients
  as a separate step after starting the server
  • Loading branch information
calvinmclean committed May 6, 2024
1 parent f151c64 commit 03bdb5b
Show file tree
Hide file tree
Showing 30 changed files with 355 additions and 408 deletions.
6 changes: 3 additions & 3 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ tasks:
aliases: [rs]
dir: ./garden-app
cmds:
- go run main.go server --config config.yaml
- go run main.go serve --config config.yaml

run-dev:
desc: Run backend Go app server and read UI templates from local FS
aliases: [dev]
dir: ./garden-app
cmds:
- DEV_TEMPLATE=server/templates/* go run main.go server --config config.yaml
- DEV_TEMPLATE=server/templates/* go run main.go serve --config config.yaml

run-controller:
desc: Run mock controller
Expand All @@ -77,7 +77,7 @@ tasks:
-v ./gardens.yaml:/gardens.yaml \
-v ./config.yaml:/config.yaml \
ghcr.io/calvinmclean/garden-app:{{.CLI_ARGS | default "latest"}} \
server --config /config.yaml
serve --config /config.yaml
generate-mocks:
desc: Use mockery to generate mocks from Go interfaces
Expand Down
2 changes: 1 addition & 1 deletion deploy/base/garden_app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ spec:
- name: config
mountPath: /config
args:
- server
- serve
- --config=/config/config.yaml
volumes:
- name: config
Expand Down
2 changes: 1 addition & 1 deletion deploy/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ services:
volumes:
- "./configs/garden-app:/app/configs"
command:
- "server"
- "serve"
- "--config=/app/configs/config.yaml"
profiles:
- demo
Expand Down
4 changes: 2 additions & 2 deletions docs/app_advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This section goes into additional details of the main functionality of the `gard

### Usage
```shell
garden-app server --help
garden-app --help
```

### Configuration
Expand Down Expand Up @@ -128,7 +128,7 @@ storage:
```

## Controller
The `controller` command behaves as a mock `garden-controller` that makes it easier to develop, test, and debug the `garden-app server` without using a standalone microcontroller. This has extensive options using flags to control different behaviors. In most cases, the defaults will work perfectly fine.
The `controller` command behaves as a mock `garden-controller` that makes it easier to develop, test, and debug the `garden-app serve` without using a standalone microcontroller. This has extensive options using flags to control different behaviors. In most cases, the defaults will work perfectly fine.

### Usage
```shell
Expand Down
2 changes: 1 addition & 1 deletion docs/rest_api.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# REST API
The `garden-app server` provides a robust REST API for interacting with the application.
The `garden-app serve` provides a robust REST API for interacting with the application.

The OpenAPI specification can be found [here](https://github.com/calvinmclean/automated-garden/blob/main/garden-app/api/openapi.yaml).
Use [this link](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/calvinmclean/automated-garden/main/garden-app/api/openapi.yaml) to open in Swagger UI.
Expand Down
2 changes: 1 addition & 1 deletion garden-app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ WORKDIR /app
COPY --from=build /build/garden-app .
COPY gardens.yaml.example /app/gardens.yaml
COPY config.yaml.example /app/config.yaml
ENTRYPOINT ["/app/garden-app", "server", "--readonly"]
ENTRYPOINT ["/app/garden-app", "serve", "--readonly"]

FROM alpine:latest AS production
RUN mkdir /app
Expand Down
2 changes: 1 addition & 1 deletion garden-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This is a Go application with a CLI and web backend for working with the garden
```
1. Run the server:
```shell
go run main.go server --config config.yaml
go run main.go serve --config config.yaml
```

To run this in a more long-term setup, I recommend using [K3s](https://k3s.io) and deploying the manifests from `/deploy/k8s`.
Expand Down
3 changes: 0 additions & 3 deletions garden-app/cmd/README.md

This file was deleted.

70 changes: 0 additions & 70 deletions garden-app/cmd/completion.go

This file was deleted.

14 changes: 8 additions & 6 deletions garden-app/cmd/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var (
Aliases: []string{"controller run"},
Short: "Run a mock garden-controller",
Long: `Subscribes on a MQTT topic to act as a mock garden-controller for testing purposes`,
Run: Controller,
Run: runController,
}
)

Expand All @@ -40,9 +40,13 @@ func init() {
viper.BindPFlag("controller.num_zones", controllerCommand.PersistentFlags().Lookup("zones"))

controllerCommand.PersistentFlags().StringVar(&moistureStrategy, "moisture-strategy", "random", "Strategy for creating moisture data")
controllerCommand.RegisterFlagCompletionFunc("moisture-strategy", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
err := controllerCommand.RegisterFlagCompletionFunc("moisture-strategy", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
return []string{"random", "constant", "increasing", "decreasing"}, cobra.ShellCompDirectiveDefault
})
if err != nil {
panic(err)

Check warning on line 47 in garden-app/cmd/controller.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/controller.go#L47

Added line #L47 was not covered by tests
}

viper.BindPFlag("controller.moisture_strategy", controllerCommand.PersistentFlags().Lookup("moisture-strategy"))

controllerCommand.PersistentFlags().IntVar(&moistureValue, "moisture-value", 100, "The value, or starting value, to use for moisture data publishing")
Expand Down Expand Up @@ -74,12 +78,10 @@ func init() {

controllerCommand.PersistentFlags().Float64Var(&humidityValue, "humidity-value", 100, "The value to use for humidity data publishing")
viper.BindPFlag("controller.humidity_value", controllerCommand.PersistentFlags().Lookup("humidity-value"))

rootCommand.AddCommand(controllerCommand)
}

// Controller will start up the mock garden-controller
func Controller(cmd *cobra.Command, _ []string) {
// runController will start up the mock garden-controller
func runController(cmd *cobra.Command, _ []string) {

Check warning on line 84 in garden-app/cmd/controller.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/controller.go#L84

Added line #L84 was not covered by tests
var config controller.Config
if err := viper.Unmarshal(&config); err != nil {
cmd.PrintErrln("unable to read config from file:", err)
Expand Down
75 changes: 59 additions & 16 deletions garden-app/cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,89 @@
package cmd

import (
"fmt"
"log/slog"
"strings"

"github.com/calvinmclean/automated-garden/garden-app/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
// Used for flags.
configFilename string
logLevel string

rootCommand = &cobra.Command{
Use: "garden-app",
Short: "A command line application for the automated home garden",
Long: `This CLI is used to run and interact with this webserver application for your automated home garden`,
}
)

// Execute executes the root command.
func Execute() error {
return rootCommand.Execute()
}
func Execute() {
api := server.NewAPI()
command := api.Command()

Check warning on line 20 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L18-L20

Added lines #L18 - L20 were not covered by tests

command.AddCommand(controllerCommand)

Check warning on line 22 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L22

Added line #L22 was not covered by tests

func init() {
viper.SetEnvPrefix("GARDEN_APP")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()

cobra.OnInitialize(initConfig)

rootCommand.PersistentFlags().StringVar(&configFilename, "config", "config.yaml", "path to config file")
command.PersistentFlags().StringVar(&configFilename, "config", "config.yaml", "path to config file")

Check warning on line 30 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L30

Added line #L30 was not covered by tests

rootCommand.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "level of logging to display")
rootCommand.RegisterFlagCompletionFunc("log-level", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
command.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "level of logging to display")
err := command.RegisterFlagCompletionFunc("log-level", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {

Check warning on line 33 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L32-L33

Added lines #L32 - L33 were not covered by tests
return []string{
"debug", "info", "warn", "error",
}, cobra.ShellCompDirectiveDefault
})
viper.BindPFlag("log.level", rootCommand.PersistentFlags().Lookup("log-level"))
if err != nil {
panic(err)

Check warning on line 39 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L38-L39

Added lines #L38 - L39 were not covered by tests
}

viper.BindPFlag("log.level", command.PersistentFlags().Lookup("log-level"))

Check warning on line 42 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L42

Added line #L42 was not covered by tests

command.PersistentPreRunE = func(c *cobra.Command, _ []string) error {
if c.Name() != "serve" {
return nil

Check warning on line 46 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L44-L46

Added lines #L44 - L46 were not covered by tests
}

var config server.Config
err := viper.Unmarshal(&config)
if err != nil {
return fmt.Errorf("unable to read config from file: %w", err)

Check warning on line 52 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L49-L52

Added lines #L49 - L52 were not covered by tests
}

err = api.Setup(config, true)
if err != nil {
return fmt.Errorf("error setting up API: %w", err)

Check warning on line 57 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L55-L57

Added lines #L55 - L57 were not covered by tests
}

return nil

Check warning on line 60 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L60

Added line #L60 was not covered by tests
}

for _, c := range command.Commands() {
if c.Name() != "serve" {
continue

Check warning on line 65 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L63-L65

Added lines #L63 - L65 were not covered by tests
}

c.Flags().Int("port", 80, "port to run Application server on")
viper.BindPFlag("web_server.port", c.Flags().Lookup("port"))

Check warning on line 69 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L68-L69

Added lines #L68 - L69 were not covered by tests

c.Flags().Bool("readonly", false, "run in read-only mode so server will only allow GET requests")
viper.BindPFlag("web_server.readonly", c.Flags().Lookup("readonly"))

Check warning on line 72 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L71-L72

Added lines #L71 - L72 were not covered by tests
}

err = command.Execute()
if err != nil {
fmt.Printf("error: %v\n", err)

Check warning on line 77 in garden-app/cmd/root.go

View check run for this annotation

Codecov / codecov/patch

garden-app/cmd/root.go#L75-L77

Added lines #L75 - L77 were not covered by tests
}
}

func init() {
viper.SetEnvPrefix("GARDEN_APP")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()

cobra.OnInitialize(initConfig)
}

func initConfig() {
Expand Down
42 changes: 0 additions & 42 deletions garden-app/cmd/server.go

This file was deleted.

12 changes: 9 additions & 3 deletions garden-app/integration_tests/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,23 @@ func TestIntegration(t *testing.T) {

serverConfig, controllerConfig := getConfigs(t)

s, err := server.NewServer(serverConfig, true)
api := server.NewAPI()
err := api.Setup(serverConfig, true)
require.NoError(t, err)

c, err = controller.NewController(controllerConfig)
require.NoError(t, err)

go c.Start()
go s.Start()
go func() {
serveErr := api.Serve(":8080")
if serveErr != nil {
panic(serveErr.Error())
}
}()

defer c.Stop()
defer s.Stop()
defer api.Stop()

time.Sleep(500 * time.Millisecond)

Expand Down
6 changes: 1 addition & 5 deletions garden-app/main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package main

import (
"os"

"github.com/calvinmclean/automated-garden/garden-app/cmd"
)

func main() {
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
cmd.Execute()
}
3 changes: 0 additions & 3 deletions garden-app/pkg/README.md

This file was deleted.

3 changes: 0 additions & 3 deletions garden-app/server/README.md

This file was deleted.

Loading

0 comments on commit 03bdb5b

Please sign in to comment.