detached cd460cf

Refactor deployment flow, improve version check and HTTP validation, optimize commands

- Rename push command/payload to deploy command/payload
- Enhance version checking and purge extraneous string normalization
- Fix HTTP server endpoints to align with deployment operations
- Update NewPingCommand to validate HTTP status and Content-Type more robustly
- Update CLI documentation
- Re-use of docker.IsRunningInContainer() where needed
- Optimize NewUpdateCommand with concise flags and options
- Enhance HTTP handler response to include detailed request outcomes
commit
cd460cf29bf67699f85c3f71d137513f65a2c7cb
author
bnema · · 2023-11-07 09:13 UTC
parent
7eee03d
signature
unsigned
14 files · +105 -100
M cmd/cli/main.go +2 -6
@@ -23,7 +23,7 @@ var rootCmd = &cobra.Command{Use: "gordon"}
2323 func InitializeCommands(client *cli.App, server *server.App) {
2424 rootCmd.AddCommand(cmd.NewServeCommand(server))
2525 rootCmd.AddCommand(cmd.NewPingCommand(client))
26- rootCmd.AddCommand(cmd.NewPushCommand(client))
26+ rootCmd.AddCommand(cmd.NewDeployCommand(client))
2727 rootCmd.AddCommand(cmd.NewUpdateCommand(client))
2828 }
2929
@@ -34,17 +34,13 @@ func Execute(client *cli.App, server *server.App) {
3434
3535 func main() {
3636 build = regexp.MustCompile(`\d+\.\d+\.\d+`).FindString(build)
37- buildInfo := common.BuildConfig{
37+ buildInfo := &common.BuildConfig{
3838 BuildVersion: build,
3939 BuildCommit: commit,
4040 BuildDate: date,
4141 ProxyURL: "https://gordon-proxy.bnema.dev",
4242 }
4343
44- if buildInfo.BuildVersion != "" {
45- fmt.Printf("Gordon version %s\n", build)
46- }
47-
4844 a, err := cli.NewClientApp(buildInfo)
4945 if err != nil {
5046 fmt.Println("Error initializing app:", err)
@@ -23,7 +23,7 @@ var rootCmd = &cobra.Command{Use: "gordon"}
23 func InitializeCommands(client *cli.App, server *server.App) {23 func InitializeCommands(client *cli.App, server *server.App) {
24 rootCmd.AddCommand(cmd.NewServeCommand(server))24 rootCmd.AddCommand(cmd.NewServeCommand(server))
25 rootCmd.AddCommand(cmd.NewPingCommand(client))25 rootCmd.AddCommand(cmd.NewPingCommand(client))
26- rootCmd.AddCommand(cmd.NewPushCommand(client))26+ rootCmd.AddCommand(cmd.NewDeployCommand(client))
27 rootCmd.AddCommand(cmd.NewUpdateCommand(client))27 rootCmd.AddCommand(cmd.NewUpdateCommand(client))
28 }28 }
29 29
@@ -34,17 +34,13 @@ func Execute(client *cli.App, server *server.App) {
34 34
35 func main() {35 func main() {
36 build = regexp.MustCompile(`\d+\.\d+\.\d+`).FindString(build)36 build = regexp.MustCompile(`\d+\.\d+\.\d+`).FindString(build)
37- buildInfo := common.BuildConfig{37+ buildInfo := &common.BuildConfig{
38 BuildVersion: build,38 BuildVersion: build,
39 BuildCommit: commit,39 BuildCommit: commit,
40 BuildDate: date,40 BuildDate: date,
41 ProxyURL: "https://gordon-proxy.bnema.dev",41 ProxyURL: "https://gordon-proxy.bnema.dev",
42 }42 }
43 43
44- if buildInfo.BuildVersion != "" {
45- fmt.Printf("Gordon version %s\n", build)
46- }
47-
48 a, err := cli.NewClientApp(buildInfo)44 a, err := cli.NewClientApp(buildInfo)
49 if err != nil {45 if err != nil {
50 fmt.Println("Error initializing app:", err)46 fmt.Println("Error initializing app:", err)
M internal/cli/cmd/ping.go +13 -0
@@ -3,6 +3,7 @@ package cmd
33 import (
44 "encoding/json"
55 "fmt"
6+ "net/http"
67 "os"
78 "time"
89
@@ -51,6 +52,18 @@ func NewPingCommand(a *cli.App) *cobra.Command {
5152 return
5253 }
5354
55+ // Check for non-200 status codes
56+ if resp.StatusCode != http.StatusOK {
57+ fmt.Printf("Received non-OK response from server: %s\n", resp.StatusCode)
58+ return
59+ }
60+
61+ // Check for the correct Content-Type header
62+ if contentType := resp.Header.Get("Content-Type"); contentType != "application/json" {
63+ fmt.Printf("Expected application/json response, got %s\n", contentType)
64+ return
65+ }
66+
5467 if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 {
5568 fmt.Println("Login incorrect, edit your config file and try again")
5669 return
@@ -3,6 +3,7 @@ package cmd
3 import (3 import (
4 "encoding/json"4 "encoding/json"
5 "fmt"5 "fmt"
6+ "net/http"
6 "os"7 "os"
7 "time"8 "time"
8 9
@@ -51,6 +52,18 @@ func NewPingCommand(a *cli.App) *cobra.Command {
51 return52 return
52 }53 }
53 54
55+ // Check for non-200 status codes
56+ if resp.StatusCode != http.StatusOK {
57+ fmt.Printf("Received non-OK response from server: %s\n", resp.StatusCode)
58+ return
59+ }
60+
61+ // Check for the correct Content-Type header
62+ if contentType := resp.Header.Get("Content-Type"); contentType != "application/json" {
63+ fmt.Printf("Expected application/json response, got %s\n", contentType)
64+ return
65+ }
66+
54 if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 {67 if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 {
55 fmt.Println("Login incorrect, edit your config file and try again")68 fmt.Println("Login incorrect, edit your config file and try again")
56 return69 return
M internal/cli/cmd/push.go +9 -9
@@ -17,13 +17,13 @@ import (
1717 "github.com/spf13/cobra"
1818 )
1919
20-func NewPushCommand(a *cli.App) *cobra.Command {
20+func NewDeployCommand(a *cli.App) *cobra.Command {
2121 var port string
2222 var targetDomain string
2323
24- pushCmd := &cobra.Command{
25- Use: "push [image:tag]",
26- Short: "Push an image to the server, if no tag is specified, latest is used",
24+ deployCmd := &cobra.Command{
25+ Use: "deploy [image:tag]",
26+ Short: "Deploy an image to the server, if no tag is specified, latest is used",
2727 Args: cobra.ExactArgs(1),
2828 PreRun: func(cmd *cobra.Command, args []string) {
2929 if err := handler.FieldCheck(a); err != nil {
@@ -87,8 +87,8 @@ func NewPushCommand(a *cli.App) *cobra.Command {
8787
8888 // Create a RequestPayload and populate it
8989 reqPayload := common.RequestPayload{
90- Type: "push",
91- Payload: common.PushPayload{
90+ Type: "deploy",
91+ Payload: common.DeployPayload{
9292 Ports: port,
9393 TargetDomain: targetDomain,
9494 ImageName: imageName,
@@ -171,8 +171,8 @@ func NewPushCommand(a *cli.App) *cobra.Command {
171171 }
172172
173173 // Add flags
174- pushCmd.Flags().StringVarP(&port, "port", "p", "", "Port mapping for the container")
175- pushCmd.Flags().StringVarP(&targetDomain, "target", "t", "", "Target domain for Traefik")
174+ deployCmd.Flags().StringVarP(&port, "port", "p", "", "Port mapping for the container")
175+ deployCmd.Flags().StringVarP(&targetDomain, "target", "t", "", "Target domain for Traefik")
176176
177- return pushCmd
177+ return deployCmd
178178 }
@@ -17,13 +17,13 @@ import (
17 "github.com/spf13/cobra"17 "github.com/spf13/cobra"
18 )18 )
19 19
20-func NewPushCommand(a *cli.App) *cobra.Command {20+func NewDeployCommand(a *cli.App) *cobra.Command {
21 var port string21 var port string
22 var targetDomain string22 var targetDomain string
23 23
24- pushCmd := &cobra.Command{24+ deployCmd := &cobra.Command{
25- Use: "push [image:tag]",25+ Use: "deploy [image:tag]",
26- Short: "Push an image to the server, if no tag is specified, latest is used",26+ Short: "Deploy an image to the server, if no tag is specified, latest is used",
27 Args: cobra.ExactArgs(1),27 Args: cobra.ExactArgs(1),
28 PreRun: func(cmd *cobra.Command, args []string) {28 PreRun: func(cmd *cobra.Command, args []string) {
29 if err := handler.FieldCheck(a); err != nil {29 if err := handler.FieldCheck(a); err != nil {
@@ -87,8 +87,8 @@ func NewPushCommand(a *cli.App) *cobra.Command {
87 87
88 // Create a RequestPayload and populate it88 // Create a RequestPayload and populate it
89 reqPayload := common.RequestPayload{89 reqPayload := common.RequestPayload{
90- Type: "push",90+ Type: "deploy",
91- Payload: common.PushPayload{91+ Payload: common.DeployPayload{
92 Ports: port,92 Ports: port,
93 TargetDomain: targetDomain,93 TargetDomain: targetDomain,
94 ImageName: imageName,94 ImageName: imageName,
@@ -171,8 +171,8 @@ func NewPushCommand(a *cli.App) *cobra.Command {
171 }171 }
172 172
173 // Add flags173 // Add flags
174- pushCmd.Flags().StringVarP(&port, "port", "p", "", "Port mapping for the container")174+ deployCmd.Flags().StringVarP(&port, "port", "p", "", "Port mapping for the container")
175- pushCmd.Flags().StringVarP(&targetDomain, "target", "t", "", "Target domain for Traefik")175+ deployCmd.Flags().StringVarP(&targetDomain, "target", "t", "", "Target domain for Traefik")
176 176
177- return pushCmd177+ return deployCmd
178 }178 }
M internal/cli/cmd/root.go +1 -1
@@ -3,6 +3,6 @@ package cmd
33
44 // if no command selected print all commands
55 // available commands for now are:
6-// - push
6+// - deploy
77 // - serve
88 // - version
@@ -3,6 +3,6 @@ package cmd
3 3
4 // if no command selected print all commands4 // if no command selected print all commands
5 // available commands for now are:5 // available commands for now are:
6-// - push6+// - deploy
7 // - serve7 // - serve
8 // - version8 // - version
M internal/cli/cmd/serve.go +2 -1
@@ -5,6 +5,7 @@ package cmd
55 import (
66 "github.com/bnema/gordon/internal/cli/handler"
77 "github.com/bnema/gordon/internal/server"
8+ "github.com/bnema/gordon/pkg/docker"
89 "github.com/spf13/cobra"
910 )
1011
@@ -14,7 +15,7 @@ func NewServeCommand(a *server.App) *cobra.Command {
1415 var port string
1516
1617 // if the server is running in a docker container, the default port is 80
17- if isMaybeRunningInDocker() {
18+ if docker.IsRunningInContainer() {
1819 defaultport = "80"
1920 }
2021
@@ -5,6 +5,7 @@ package cmd
5 import (5 import (
6 "github.com/bnema/gordon/internal/cli/handler"6 "github.com/bnema/gordon/internal/cli/handler"
7 "github.com/bnema/gordon/internal/server"7 "github.com/bnema/gordon/internal/server"
8+ "github.com/bnema/gordon/pkg/docker"
8 "github.com/spf13/cobra"9 "github.com/spf13/cobra"
9 )10 )
10 11
@@ -14,7 +15,7 @@ func NewServeCommand(a *server.App) *cobra.Command {
14 var port string15 var port string
15 16
16 // if the server is running in a docker container, the default port is 8017 // if the server is running in a docker container, the default port is 80
17- if isMaybeRunningInDocker() {18+ if docker.IsRunningInContainer() {
18 defaultport = "80"19 defaultport = "80"
19 }20 }
20 21
M internal/cli/cmd/update.go +2 -17
@@ -19,6 +19,7 @@ import (
1919
2020 "github.com/AlecAivazis/survey/v2"
2121 "github.com/bnema/gordon/internal/cli"
22+ "github.com/bnema/gordon/pkg/docker"
2223 "github.com/fatih/color"
2324 "github.com/pocketbase/pocketbase/tools/archive"
2425 "github.com/spf13/cobra"
@@ -75,7 +76,7 @@ func NewUpdateCommand(a *cli.App) *cobra.Command {
7576 SilenceUsage: true,
7677 RunE: func(command *cobra.Command, args []string) error {
7778 var needConfirm bool
78- if isMaybeRunningInDocker() {
79+ if docker.IsRunningInContainer() {
7980 needConfirm = true
8081 color.Yellow("NB! It seems that you are in a Docker container.")
8182 color.Yellow("The update command may not work as expected in this context because usually the version of the app is managed by the container image itself.")
@@ -96,14 +97,6 @@ func NewUpdateCommand(a *cli.App) *cobra.Command {
9697 return pluginInstance.update(withBackup)
9798 },
9899 }
99-
100- command.PersistentFlags().BoolVar(
101- &withBackup,
102- "backup",
103- true,
104- "Creates a pb_data backup at the end of the update process",
105- )
106-
107100 return command
108101 }
109102
@@ -120,9 +113,6 @@ func (p *plugin) update(withBackup bool) error {
120113 return err
121114 }
122115
123- fmt.Println("Latest version:", latest.Tag)
124- fmt.Println("Current version:", p.currentVersion)
125-
126116 if compareVersions(strings.TrimPrefix(p.currentVersion, "v"), strings.TrimPrefix(latest.Tag, "v")) <= 0 {
127117 color.Green("You already have the latest version %s.", p.currentVersion)
128118 return nil
@@ -367,8 +357,3 @@ func compareVersions(a, b string) int {
367357
368358 return 0 // equal
369359 }
370-
371-func isMaybeRunningInDocker() bool {
372- _, err := os.Stat("/.iscontainer")
373- return err == nil
374-}
@@ -19,6 +19,7 @@ import (
19 19
20 "github.com/AlecAivazis/survey/v2"20 "github.com/AlecAivazis/survey/v2"
21 "github.com/bnema/gordon/internal/cli"21 "github.com/bnema/gordon/internal/cli"
22+ "github.com/bnema/gordon/pkg/docker"
22 "github.com/fatih/color"23 "github.com/fatih/color"
23 "github.com/pocketbase/pocketbase/tools/archive"24 "github.com/pocketbase/pocketbase/tools/archive"
24 "github.com/spf13/cobra"25 "github.com/spf13/cobra"
@@ -75,7 +76,7 @@ func NewUpdateCommand(a *cli.App) *cobra.Command {
75 SilenceUsage: true,76 SilenceUsage: true,
76 RunE: func(command *cobra.Command, args []string) error {77 RunE: func(command *cobra.Command, args []string) error {
77 var needConfirm bool78 var needConfirm bool
78- if isMaybeRunningInDocker() {79+ if docker.IsRunningInContainer() {
79 needConfirm = true80 needConfirm = true
80 color.Yellow("NB! It seems that you are in a Docker container.")81 color.Yellow("NB! It seems that you are in a Docker container.")
81 color.Yellow("The update command may not work as expected in this context because usually the version of the app is managed by the container image itself.")82 color.Yellow("The update command may not work as expected in this context because usually the version of the app is managed by the container image itself.")
@@ -96,14 +97,6 @@ func NewUpdateCommand(a *cli.App) *cobra.Command {
96 return pluginInstance.update(withBackup)97 return pluginInstance.update(withBackup)
97 },98 },
98 }99 }
99-
100- command.PersistentFlags().BoolVar(
101- &withBackup,
102- "backup",
103- true,
104- "Creates a pb_data backup at the end of the update process",
105- )
106-
107 return command100 return command
108 }101 }
109 102
@@ -120,9 +113,6 @@ func (p *plugin) update(withBackup bool) error {
120 return err113 return err
121 }114 }
122 115
123- fmt.Println("Latest version:", latest.Tag)
124- fmt.Println("Current version:", p.currentVersion)
125-
126 if compareVersions(strings.TrimPrefix(p.currentVersion, "v"), strings.TrimPrefix(latest.Tag, "v")) <= 0 {116 if compareVersions(strings.TrimPrefix(p.currentVersion, "v"), strings.TrimPrefix(latest.Tag, "v")) <= 0 {
127 color.Green("You already have the latest version %s.", p.currentVersion)117 color.Green("You already have the latest version %s.", p.currentVersion)
128 return nil118 return nil
@@ -367,8 +357,3 @@ func compareVersions(a, b string) int {
367 357
368 return 0 // equal358 return 0 // equal
369 }359 }
370-
371-func isMaybeRunningInDocker() bool {
372- _, err := os.Stat("/.iscontainer")
373- return err == nil
374-}
M internal/cli/handler/http.go +11 -9
@@ -34,6 +34,8 @@ func SendRequest(req *http.Request) (*http.Response, error) {
3434 }
3535
3636 type Response struct {
37+ Http *http.Response
38+ Header http.Header
3739 Body []byte
3840 StatusCode int
3941 }
@@ -46,23 +48,23 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
4648 var req *http.Request
4749 var err error
4850
49- // Handle push type payload
50- if rp.Type == "push" {
51- pushPayload, ok := rp.Payload.(common.PushPayload)
51+ // Handle deploy type payload
52+ if rp.Type == "deploy" {
53+ deployPayload, ok := rp.Payload.(common.DeployPayload)
5254 if !ok {
53- return nil, fmt.Errorf("invalid payload type for push")
55+ return nil, fmt.Errorf("invalid payload type for deploy")
5456 }
5557
56- req, err = http.NewRequest(method, apiUrl+endpoint, pushPayload.Data)
58+ req, err = http.NewRequest(method, apiUrl+endpoint, deployPayload.Data)
5759 if err != nil {
5860 return nil, fmt.Errorf("failed to create new streaming request: %w", err)
5961 }
6062
6163 setAuthRequestHeaders(req, token)
6264 req.Header.Set("Content-Type", "application/octet-stream")
63- req.Header.Set("X-Ports", pushPayload.Ports)
64- req.Header.Set("X-Target-Domain", pushPayload.TargetDomain)
65- req.Header.Set("X-Image-Name", pushPayload.ImageName)
65+ req.Header.Set("X-Ports", deployPayload.Ports)
66+ req.Header.Set("X-Target-Domain", deployPayload.TargetDomain)
67+ req.Header.Set("X-Image-Name", deployPayload.ImageName)
6668
6769 client := &http.Client{}
6870 resp, err := client.Do(req)
@@ -103,5 +105,5 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
103105 if err != nil {
104106 return nil, fmt.Errorf("failed to read response body: %w", err)
105107 }
106- return &Response{Body: body}, nil
108+ return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil
107109 }
@@ -34,6 +34,8 @@ func SendRequest(req *http.Request) (*http.Response, error) {
34 }34 }
35 35
36 type Response struct {36 type Response struct {
37+ Http *http.Response
38+ Header http.Header
37 Body []byte39 Body []byte
38 StatusCode int40 StatusCode int
39 }41 }
@@ -46,23 +48,23 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
46 var req *http.Request48 var req *http.Request
47 var err error49 var err error
48 50
49- // Handle push type payload51+ // Handle deploy type payload
50- if rp.Type == "push" {52+ if rp.Type == "deploy" {
51- pushPayload, ok := rp.Payload.(common.PushPayload)53+ deployPayload, ok := rp.Payload.(common.DeployPayload)
52 if !ok {54 if !ok {
53- return nil, fmt.Errorf("invalid payload type for push")55+ return nil, fmt.Errorf("invalid payload type for deploy")
54 }56 }
55 57
56- req, err = http.NewRequest(method, apiUrl+endpoint, pushPayload.Data)58+ req, err = http.NewRequest(method, apiUrl+endpoint, deployPayload.Data)
57 if err != nil {59 if err != nil {
58 return nil, fmt.Errorf("failed to create new streaming request: %w", err)60 return nil, fmt.Errorf("failed to create new streaming request: %w", err)
59 }61 }
60 62
61 setAuthRequestHeaders(req, token)63 setAuthRequestHeaders(req, token)
62 req.Header.Set("Content-Type", "application/octet-stream")64 req.Header.Set("Content-Type", "application/octet-stream")
63- req.Header.Set("X-Ports", pushPayload.Ports)65+ req.Header.Set("X-Ports", deployPayload.Ports)
64- req.Header.Set("X-Target-Domain", pushPayload.TargetDomain)66+ req.Header.Set("X-Target-Domain", deployPayload.TargetDomain)
65- req.Header.Set("X-Image-Name", pushPayload.ImageName)67+ req.Header.Set("X-Image-Name", deployPayload.ImageName)
66 68
67 client := &http.Client{}69 client := &http.Client{}
68 resp, err := client.Do(req)70 resp, err := client.Do(req)
@@ -103,5 +105,5 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
103 if err != nil {105 if err != nil {
104 return nil, fmt.Errorf("failed to read response body: %w", err)106 return nil, fmt.Errorf("failed to read response body: %w", err)
105 }107 }
106- return &Response{Body: body}, nil108+ return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil
107 }109 }
M internal/cli/newclient.go +2 -2
@@ -11,10 +11,10 @@ type App struct {
1111 }
1212
1313 // NewClientApp initializes a new App with configuration.
14-func NewClientApp(buildConfig common.BuildConfig) (*App, error) {
14+func NewClientApp(buildConfig *common.BuildConfig) (*App, error) {
1515 // Initialize AppConfig
1616 config := common.Config{
17- Build: buildConfig,
17+ Build: *buildConfig,
1818 }
1919 _, err := config.LoadConfig()
2020 if err != nil {
@@ -11,10 +11,10 @@ type App struct {
11 }11 }
12 12
13 // NewClientApp initializes a new App with configuration.13 // NewClientApp initializes a new App with configuration.
14-func NewClientApp(buildConfig common.BuildConfig) (*App, error) {14+func NewClientApp(buildConfig *common.BuildConfig) (*App, error) {
15 // Initialize AppConfig15 // Initialize AppConfig
16 config := common.Config{16 config := common.Config{
17- Build: buildConfig,17+ Build: *buildConfig,
18 }18 }
19 _, err := config.LoadConfig()19 _, err := config.LoadConfig()
20 if err != nil {20 if err != nil {
M internal/common/payload.go +6 -6
@@ -34,8 +34,8 @@ func (p *RequestPayload) UnmarshalJSON(data []byte) error {
3434 return err
3535 }
3636 p.Payload = payload
37- case "push":
38- var payload PushPayload
37+ case "deploy":
38+ var payload DeployPayload
3939 if err := json.Unmarshal(raw["payload"], &payload); err != nil {
4040 return err
4141 }
@@ -52,8 +52,8 @@ func (p PingPayload) GetType() string {
5252 return "ping"
5353 }
5454
55-func (p PushPayload) GetType() string {
56- return "push"
55+func (p DeployPayload) GetType() string {
56+ return "deploy"
5757 }
5858
5959 func NewPingPayload(data map[string]interface{}) (PingPayload, error) {
@@ -64,12 +64,12 @@ func NewPingPayload(data map[string]interface{}) (PingPayload, error) {
6464 return PingPayload{Message: message}, nil
6565 }
6666
67-// What do we need inside the push payload :
67+// What do we need inside the deploy payload :
6868 // the ports as a string (80:80/tcp, 443:443/tcp)
6969 // the image+tag as a string (nginx:latest)
7070 // the .tar container image as a byte array
7171
72-type PushPayload struct {
72+type DeployPayload struct {
7373 Ports string `json:"ports"`
7474 TargetDomain string `json:"targetdomain"`
7575 ImageName string `json:"imagename"`
@@ -34,8 +34,8 @@ func (p *RequestPayload) UnmarshalJSON(data []byte) error {
34 return err34 return err
35 }35 }
36 p.Payload = payload36 p.Payload = payload
37- case "push":37+ case "deploy":
38- var payload PushPayload38+ var payload DeployPayload
39 if err := json.Unmarshal(raw["payload"], &payload); err != nil {39 if err := json.Unmarshal(raw["payload"], &payload); err != nil {
40 return err40 return err
41 }41 }
@@ -52,8 +52,8 @@ func (p PingPayload) GetType() string {
52 return "ping"52 return "ping"
53 }53 }
54 54
55-func (p PushPayload) GetType() string {55+func (p DeployPayload) GetType() string {
56- return "push"56+ return "deploy"
57 }57 }
58 58
59 func NewPingPayload(data map[string]interface{}) (PingPayload, error) {59 func NewPingPayload(data map[string]interface{}) (PingPayload, error) {
@@ -64,12 +64,12 @@ func NewPingPayload(data map[string]interface{}) (PingPayload, error) {
64 return PingPayload{Message: message}, nil64 return PingPayload{Message: message}, nil
65 }65 }
66 66
67-// What do we need inside the push payload :67+// What do we need inside the deploy payload :
68 // the ports as a string (80:80/tcp, 443:443/tcp)68 // the ports as a string (80:80/tcp, 443:443/tcp)
69 // the image+tag as a string (nginx:latest)69 // the image+tag as a string (nginx:latest)
70 // the .tar container image as a byte array70 // the .tar container image as a byte array
71 71
72-type PushPayload struct {72+type DeployPayload struct {
73 Ports string `json:"ports"`73 Ports string `json:"ports"`
74 TargetDomain string `json:"targetdomain"`74 TargetDomain string `json:"targetdomain"`
75 ImageName string `json:"imagename"`75 ImageName string `json:"imagename"`
M internal/common/version.go +49 -43
@@ -7,7 +7,6 @@ import (
77 "log"
88 "net/http"
99 "runtime"
10- "strings"
1110 "time"
1211
1312 "github.com/bnema/gordon/pkg/docker"
@@ -27,84 +26,90 @@ type VersionInfo struct {
2726 }
2827
2928 type VersionsResponse struct {
29+ Name string `json:"name"`
3030 AMD64 VersionInfo `json:"amd64"`
3131 ARM64 VersionInfo `json:"arm64"`
3232 }
3333
3434 func GetCurrentBuildVersionInfo(c *Config) CurrentVersion {
35-
3635 return CurrentVersion{
3736 isContainer: docker.IsRunningInContainer(),
38- Version: c.Build.BuildVersion,
37+ Version: c.GetVersion(),
38+ }
39+}
40+
41+func CheckForNewVersion(localVersion, remoteVersion string) string {
42+ if localVersion != remoteVersion {
43+ return "A new version is available"
3944 }
45+ return ""
46+}
47+
48+func getArch() string {
49+ return runtime.GOARCH
4050 }
4151
42-// CheckForNewVersion compares the local and remote version.
43-// If the remote version is newer, it returns a message stating that a new version is available.
44-func CheckForNewVersion(local CurrentVersion, remote VersionsResponse) string {
45- arch := getArch()
52+func checkAndUpdateVersion(c *Config) (string, error) {
53+ localVersion := GetCurrentBuildVersionInfo(c)
54+ remoteVersions, err := getRemoteVersion(c)
55+ if err != nil {
56+ return "", err
57+ }
4658
47- var remoteVersionInfo VersionInfo
48- switch arch {
59+ var remoteVersion string
60+ switch getArch() {
4961 case "amd64":
50- remoteVersionInfo = remote.AMD64
62+ remoteVersion = remoteVersions.AMD64.Name
5163 case "arm64":
52- remoteVersionInfo = remote.ARM64
64+ remoteVersion = remoteVersions.ARM64.Name
5365 default:
54- log.Printf("Unknown architecture: %s", arch)
55- return ""
66+ remoteVersion = remoteVersions.Name
5667 }
5768
58- localVersion := normalizeVersion(local.Version, arch)
59- remoteVersion := normalizeVersion(remoteVersionInfo.Name, arch)
60-
61- // Compare the normalized local version with the remote version
62- if localVersion != remoteVersion {
63- return "A new version is available"
69+ message := CheckForNewVersion(localVersion.Version, remoteVersion)
70+ if message != "" {
71+ return fmt.Sprintf("New version %s is available", remoteVersion), nil
6472 }
65- return ""
73+ return "", nil
6674 }
6775
68-// normalizeVersion ensures that the version strings are comparable.
69-func normalizeVersion(version, arch string) string {
70- // Assuming the version string might not contain the architecture.
71- if !strings.Contains(version, arch) {
72- version = fmt.Sprintf("%s-%s", version, arch)
76+func CheckVersionPeriodically(c *Config) (string, error) {
77+ // Perform an immediate check.
78+ newVersionMessage, err := checkAndUpdateVersion(c)
79+
80+ if err != nil {
81+ return "", err
7382 }
74- return version
75-}
7683
77-func getArch() string {
78- return runtime.GOARCH
79-}
84+ if newVersionMessage != "" {
85+ fmt.Println(newVersionMessage)
86+ return "", nil
87+ }
8088
81-func CheckVersionPeriodically(c *Config) (string, error) {
82- timer := time.NewTicker(1 * time.Minute)
89+ // Set up a ticker to check every 5 minutes.
90+ timer := time.NewTicker(5 * time.Minute)
8391 defer timer.Stop()
8492
8593 for range timer.C {
86- localVersion := getLocalVersion(c)
87- remoteVersion, err := getRemoteVersion(c)
94+ newVersionMessage, err = checkAndUpdateVersion(c)
8895 if err != nil {
8996 log.Printf("Error fetching remote version: %s", err)
9097 continue
9198 }
9299
93- message := CheckForNewVersion(localVersion, remoteVersion)
94- if message != "" {
95- log.Print(message)
96- // TODO: Add a notification
100+ if newVersionMessage != "" {
101+ fmt.Println(newVersionMessage)
102+ return "", nil //We return so the loop stops in case of a new version
97103 }
98104 }
99105
100106 return "", nil
101107 }
102108
103-func getLocalVersion(c *Config) CurrentVersion {
104- return CurrentVersion{
105- Version: c.Build.BuildVersion,
106- }
107-}
109+// func getLocalVersion(c *Config) CurrentVersion {
110+// // Dummy implementation, replace with your actual logic
111+// return CurrentVersion{Version: "0.0.970"} // Example version
112+// }
108113
109114 func getRemoteVersion(c *Config) (VersionsResponse, error) {
110115 proxyURL := c.Build.ProxyURL
@@ -132,4 +137,5 @@ func getRemoteVersion(c *Config) (VersionsResponse, error) {
132137 }
133138
134139 return remoteVersionInfo, nil
140+
135141 }
@@ -7,7 +7,6 @@ import (
7 "log"7 "log"
8 "net/http"8 "net/http"
9 "runtime"9 "runtime"
10- "strings"
11 "time"10 "time"
12 11
13 "github.com/bnema/gordon/pkg/docker"12 "github.com/bnema/gordon/pkg/docker"
@@ -27,84 +26,90 @@ type VersionInfo struct {
27 }26 }
28 27
29 type VersionsResponse struct {28 type VersionsResponse struct {
29+ Name string `json:"name"`
30 AMD64 VersionInfo `json:"amd64"`30 AMD64 VersionInfo `json:"amd64"`
31 ARM64 VersionInfo `json:"arm64"`31 ARM64 VersionInfo `json:"arm64"`
32 }32 }
33 33
34 func GetCurrentBuildVersionInfo(c *Config) CurrentVersion {34 func GetCurrentBuildVersionInfo(c *Config) CurrentVersion {
35-
36 return CurrentVersion{35 return CurrentVersion{
37 isContainer: docker.IsRunningInContainer(),36 isContainer: docker.IsRunningInContainer(),
38- Version: c.Build.BuildVersion,37+ Version: c.GetVersion(),
38+ }
39+}
40+
41+func CheckForNewVersion(localVersion, remoteVersion string) string {
42+ if localVersion != remoteVersion {
43+ return "A new version is available"
39 }44 }
45+ return ""
46+}
47+
48+func getArch() string {
49+ return runtime.GOARCH
40 }50 }
41 51
42-// CheckForNewVersion compares the local and remote version.52+func checkAndUpdateVersion(c *Config) (string, error) {
43-// If the remote version is newer, it returns a message stating that a new version is available.53+ localVersion := GetCurrentBuildVersionInfo(c)
44-func CheckForNewVersion(local CurrentVersion, remote VersionsResponse) string {54+ remoteVersions, err := getRemoteVersion(c)
45- arch := getArch()55+ if err != nil {
56+ return "", err
57+ }
46 58
47- var remoteVersionInfo VersionInfo59+ var remoteVersion string
48- switch arch {60+ switch getArch() {
49 case "amd64":61 case "amd64":
50- remoteVersionInfo = remote.AMD6462+ remoteVersion = remoteVersions.AMD64.Name
51 case "arm64":63 case "arm64":
52- remoteVersionInfo = remote.ARM6464+ remoteVersion = remoteVersions.ARM64.Name
53 default:65 default:
54- log.Printf("Unknown architecture: %s", arch)66+ remoteVersion = remoteVersions.Name
55- return ""
56 }67 }
57 68
58- localVersion := normalizeVersion(local.Version, arch)69+ message := CheckForNewVersion(localVersion.Version, remoteVersion)
59- remoteVersion := normalizeVersion(remoteVersionInfo.Name, arch)70+ if message != "" {
60-71+ return fmt.Sprintf("New version %s is available", remoteVersion), nil
61- // Compare the normalized local version with the remote version
62- if localVersion != remoteVersion {
63- return "A new version is available"
64 }72 }
65- return ""73+ return "", nil
66 }74 }
67 75
68-// normalizeVersion ensures that the version strings are comparable.76+func CheckVersionPeriodically(c *Config) (string, error) {
69-func normalizeVersion(version, arch string) string {77+ // Perform an immediate check.
70- // Assuming the version string might not contain the architecture.78+ newVersionMessage, err := checkAndUpdateVersion(c)
71- if !strings.Contains(version, arch) {79+
72- version = fmt.Sprintf("%s-%s", version, arch)80+ if err != nil {
81+ return "", err
73 }82 }
74- return version
75-}
76 83
77-func getArch() string {84+ if newVersionMessage != "" {
78- return runtime.GOARCH85+ fmt.Println(newVersionMessage)
79-}86+ return "", nil
87+ }
80 88
81-func CheckVersionPeriodically(c *Config) (string, error) {89+ // Set up a ticker to check every 5 minutes.
82- timer := time.NewTicker(1 * time.Minute)90+ timer := time.NewTicker(5 * time.Minute)
83 defer timer.Stop()91 defer timer.Stop()
84 92
85 for range timer.C {93 for range timer.C {
86- localVersion := getLocalVersion(c)94+ newVersionMessage, err = checkAndUpdateVersion(c)
87- remoteVersion, err := getRemoteVersion(c)
88 if err != nil {95 if err != nil {
89 log.Printf("Error fetching remote version: %s", err)96 log.Printf("Error fetching remote version: %s", err)
90 continue97 continue
91 }98 }
92 99
93- message := CheckForNewVersion(localVersion, remoteVersion)100+ if newVersionMessage != "" {
94- if message != "" {101+ fmt.Println(newVersionMessage)
95- log.Print(message)102+ return "", nil //We return so the loop stops in case of a new version
96- // TODO: Add a notification
97 }103 }
98 }104 }
99 105
100 return "", nil106 return "", nil
101 }107 }
102 108
103-func getLocalVersion(c *Config) CurrentVersion {109+// func getLocalVersion(c *Config) CurrentVersion {
104- return CurrentVersion{110+// // Dummy implementation, replace with your actual logic
105- Version: c.Build.BuildVersion,111+// return CurrentVersion{Version: "0.0.970"} // Example version
106- }112+// }
107-}
108 113
109 func getRemoteVersion(c *Config) (VersionsResponse, error) {114 func getRemoteVersion(c *Config) (VersionsResponse, error) {
110 proxyURL := c.Build.ProxyURL115 proxyURL := c.Build.ProxyURL
@@ -132,4 +137,5 @@ func getRemoteVersion(c *Config) (VersionsResponse, error) {
132 }137 }
133 138
134 return remoteVersionInfo, nil139 return remoteVersionInfo, nil
140+
135 }141 }
M internal/httpserve/handler/clientendpoins.go +2 -2
@@ -56,10 +56,10 @@ func GetInfos(c echo.Context, a *server.App) error {
5656
5757 }
5858
59-func PostPush(c echo.Context, a *server.App) error {
59+func PostDeploy(c echo.Context, a *server.App) error {
6060
6161 // Initialize pushPayload object
62- payload := &common.PushPayload{
62+ payload := &common.DeployPayload{
6363 Ports: c.Request().Header.Get("X-Ports"),
6464 ImageName: c.Request().Header.Get("X-Image-Name"),
6565 TargetDomain: c.Request().Header.Get("X-Target-Domain"),
@@ -56,10 +56,10 @@ func GetInfos(c echo.Context, a *server.App) error {
56 56
57 }57 }
58 58
59-func PostPush(c echo.Context, a *server.App) error {59+func PostDeploy(c echo.Context, a *server.App) error {
60 60
61 // Initialize pushPayload object61 // Initialize pushPayload object
62- payload := &common.PushPayload{62+ payload := &common.DeployPayload{
63 Ports: c.Request().Header.Get("X-Ports"),63 Ports: c.Request().Header.Get("X-Ports"),
64 ImageName: c.Request().Header.Get("X-Image-Name"),64 ImageName: c.Request().Header.Get("X-Image-Name"),
65 TargetDomain: c.Request().Header.Get("X-Target-Domain"),65 TargetDomain: c.Request().Header.Get("X-Target-Domain"),
M internal/httpserve/router.go +1 -1
@@ -55,7 +55,7 @@ func bindAPIEndpoints(e *echo.Echo, a *server.App) {
5555 return handler.GetInfos(c, a)
5656 })
5757 apiGroup.POST("/push", func(c echo.Context) error {
58- return handler.PostPush(c, a)
58+ return handler.PostDeploy(c, a)
5959 })
6060 }
6161
@@ -55,7 +55,7 @@ func bindAPIEndpoints(e *echo.Echo, a *server.App) {
55 return handler.GetInfos(c, a)55 return handler.GetInfos(c, a)
56 })56 })
57 apiGroup.POST("/push", func(c echo.Context) error {57 apiGroup.POST("/push", func(c echo.Context) error {
58- return handler.PostPush(c, a)58+ return handler.PostDeploy(c, a)
59 })59 })
60 }60 }
61 61
M internal/server/newserver.go +4 -2
@@ -10,9 +10,11 @@ import (
1010 "github.com/bnema/gordon/internal/webui"
1111 )
1212
13-func NewServerApp(common.BuildConfig) (*App, error) {
13+func NewServerApp(buildConfig *common.BuildConfig) (*App, error) {
1414 // Initialize AppConfig
15- config := common.Config{}
15+ config := common.Config{
16+ Build: *buildConfig,
17+ }
1618 _, err := config.LoadConfig()
1719 if err != nil {
1820 log.Fatalf("Failed to load configuration: %v", err)
@@ -10,9 +10,11 @@ import (
10 "github.com/bnema/gordon/internal/webui"10 "github.com/bnema/gordon/internal/webui"
11 )11 )
12 12
13-func NewServerApp(common.BuildConfig) (*App, error) {13+func NewServerApp(buildConfig *common.BuildConfig) (*App, error) {
14 // Initialize AppConfig14 // Initialize AppConfig
15- config := common.Config{}15+ config := common.Config{
16+ Build: *buildConfig,
17+ }
16 _, err := config.LoadConfig()18 _, err := config.LoadConfig()
17 if err != nil {19 if err != nil {
18 log.Fatalf("Failed to load configuration: %v", err)20 log.Fatalf("Failed to load configuration: %v", err)
M internal/templating/cmdparams/fromcli.go +1 -1
@@ -11,7 +11,7 @@ import (
1111 )
1212
1313 // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct
14-func FromPayloadStructToCmdParams(ppl *common.PushPayload, a *server.App) (docker.ContainerCommandParams, error) {
14+func FromPayloadStructToCmdParams(ppl *common.DeployPayload, a *server.App) (docker.ContainerCommandParams, error) {
1515
1616 imageID, err := docker.GetImageID(ppl.ImageName)
1717 if err != nil {
@@ -11,7 +11,7 @@ import (
11 )11 )
12 12
13 // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct13 // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct
14-func FromPayloadStructToCmdParams(ppl *common.PushPayload, a *server.App) (docker.ContainerCommandParams, error) {14+func FromPayloadStructToCmdParams(ppl *common.DeployPayload, a *server.App) (docker.ContainerCommandParams, error) {
15 15
16 imageID, err := docker.GetImageID(ppl.ImageName)16 imageID, err := docker.GetImageID(ppl.ImageName)
17 if err != nil {17 if err != nil {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close