0.1 5d00907

deploy.go RawHistoryFolder

1package cmd
2
3import (
4	"crypto/tls"
5	"fmt"
6	"io"
7	"net/http"
8	"os"
9	"strings"
10	"time"
11
12	"github.com/bnema/gordon/internal/cli"
13	"github.com/bnema/gordon/internal/cli/handler"
14	"github.com/bnema/gordon/internal/cli/mvu"
15	"github.com/bnema/gordon/internal/common"
16	"github.com/bnema/gordon/pkg/docker"
17	"github.com/fatih/color"
18	"github.com/spf13/cobra"
19)
20
21func NewDeployCommand(a *cli.App) *cobra.Command {
22	var port string
23	var targetDomain string
24
25	deployCmd := &cobra.Command{
26		Use:   "deploy [image:tag]",
27		Short: "Deploy an image to your remote Gordon instance",
28		Args:  cobra.ExactArgs(1),
29		PreRun: func(cmd *cobra.Command, args []string) {
30			if err := handler.FieldCheck(a); err != nil {
31				fmt.Println("Field check failed:", err)
32				os.Exit(1)
33			}
34		},
35		Run: func(cmd *cobra.Command, args []string) {
36			imageName := args[0]
37			color.White("Pushing image: %s", imageName)
38
39			// Validate the image name
40			if err := handler.ValidateImageName(imageName); err != nil {
41				fmt.Println(err)
42				return
43			}
44
45			// Ensure the image has a tag
46			handler.EnsureImageTag(&imageName)
47
48			// Validate the port mapping
49			if err := handler.ValidatePortMapping(port); err != nil {
50				fmt.Println(err)
51				return
52			}
53
54			// Validate the target domain
55			if err := handler.ValidateTargetDomain(targetDomain); err != nil {
56				fmt.Println(err)
57				return
58			}
59
60			// Export the image to a reader and return its true size
61			reader, actualSize, err := exportDockerImage(imageName)
62			if err != nil {
63				fmt.Println("Error exporting image:", err)
64				return
65			}
66
67			progressCh := make(chan mvu.ProgressMsg)
68
69			// Create a progress function to update the progress bar
70			progressReader := &mvu.ProgressReader{
71				Reader:     reader,     // This is the actual reader from exportDockerImage
72				Total:      actualSize, // This is the total size of the data to be read
73				ProgressCh: progressCh, // This is the channel used to send progress updates
74			}
75
76			// Create a RequestPayload and populate it
77			reqPayload := common.RequestPayload{
78				Type: "deploy",
79				Payload: common.DeployPayload{
80					Ports:        port,
81					TargetDomain: targetDomain,
82					ImageName:    imageName,
83					Data:         progressReader,
84				},
85			}
86
87			go func() {
88				resp, err := handler.SendHTTPRequest(a, &reqPayload, "POST", "/push")
89				if err != nil {
90					fmt.Println("Error sending HTTP request:", err)
91					// Don't forget to close the channel if there's an error
92					close(progressCh)
93					return
94				}
95
96				// Check the response
97				targetDomain := string(resp.Body)
98				targetDomain = strings.TrimSpace(targetDomain)  // Remove leading and trailing whitespace
99				targetDomain = strings.Trim(targetDomain, "\"") // Remove leading and trailing quotes
100				// Close the progress channel after the upload is complete
101				// Determine if the target is HTTPS or HTTP
102				isHTTPS := strings.HasPrefix(targetDomain, "https://")
103
104				// Initialize HTTP client
105				client := &http.Client{
106					Timeout: 5 * time.Second,
107				}
108
109				// Only set TLS config if target is HTTPS
110				if isHTTPS {
111					client.Transport = &http.Transport{
112						TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, // set false to ensure certificate is validated
113					}
114				}
115
116				// Run the TUI program
117				finalModel, err := mvu.RunDeploymentTUI(client, imageName, targetDomain, port)
118				if err != nil {
119					fmt.Println("Error running deployment TUI:", err)
120					return
121				}
122
123				// Check if the deployment was successful
124				if !finalModel.DeploymentDone {
125					fmt.Println("Deployment failed check your configuration and try again.")
126					return
127				}
128
129				// Print the final message
130				color.Blue("	Deployment successful!")
131				fmt.Println("	Your application is now available at:", targetDomain)
132				close(progressCh)
133			}()
134
135			// Run the progress bar TUI
136			m, err := mvu.RunProgressBarTUI(progressCh)
137			if err != nil {
138				fmt.Println("Error running progress bar TUI:", err)
139				return
140			}
141
142			// Close the reader
143			err = progressReader.Close()
144			if err != nil {
145				fmt.Println("Error closing reader:", err)
146				return
147			}
148
149			m.Done = true
150
151		},
152	}
153
154	// Add flags
155	deployCmd.Flags().StringVarP(&port, "port", "p", "", "Port mapping for the container")
156	deployCmd.Flags().StringVarP(&targetDomain, "target", "t", "", "Target domain for Traefik")
157
158	return deployCmd
159}
160
161// export the docker image to a reader and return its true size
162func exportDockerImage(imageName string) (io.ReadCloser, int64, error) {
163	imageID, err := docker.GetImageID(imageName)
164	if err != nil {
165		return nil, 0, fmt.Errorf("error getting image ID: %w", err)
166	}
167
168	actualSize, err := docker.GetImageSizeFromReader(imageID)
169	if err != nil {
170		return nil, 0, fmt.Errorf("error getting image size: %w", err)
171	}
172
173	reader, err := docker.ExportImageFromEngine(imageID)
174	if err != nil {
175		return nil, 0, fmt.Errorf("error exporting image: %w", err)
176	}
177
178	// Return the wrapped reader.
179	return reader, actualSize, nil
180}

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