a985ccdf4622d86a55ab987c9730197abdd5ebb7

Author
Ayman Bagabas <ayman.bagabas@gmail.com>
Committer
Ayman Bagabas <ayman.bagabas@gmail.com>
Date

Message

feat: test ssh ui output

Still wip

wip

feat(tests): run against ssh ui

Diff

  1diff --git a/cmd/soft/browse/browse.go b/cmd/soft/browse/browse.go
  2index ff1a1d06178a3c6775f3da7d6f1127c0bfa45c56..c430630cf1de1a958b9871dca27e5f32ad2cbde2 100644
  3--- a/cmd/soft/browse/browse.go
  4+++ b/cmd/soft/browse/browse.go
  5@@ -13,7 +13,6 @@ import (
  6 	"github.com/charmbracelet/soft-serve/pkg/ui/common"
  7 	"github.com/charmbracelet/soft-serve/pkg/ui/components/footer"
  8 	"github.com/charmbracelet/soft-serve/pkg/ui/pages/repo"
  9-	"github.com/muesli/termenv"
 10 	"github.com/spf13/cobra"
 11 )
 12 
 13@@ -40,7 +39,7 @@ var Command = &cobra.Command{
 14 
 15 		// Bubble Tea uses Termenv default output so we have to use the same
 16 		// thing here.
 17-		output := termenv.DefaultOutput()
 18+		output := lipgloss.DefaultRenderer()
 19 		ctx := cmd.Context()
 20 		c := common.NewCommon(ctx, output, 0, 0)
 21 		c.HideCloneCmd = true
 22diff --git a/cmd/soft/main.go b/cmd/soft/main.go
 23index 8264abee8666d1d7424a3139be750a601f5d7f7b..9849e8a268f22fba46644af33b1ee140f79f16a2 100644
 24--- a/cmd/soft/main.go
 25+++ b/cmd/soft/main.go
 26@@ -5,6 +5,7 @@ import (
 27 	"fmt"
 28 	"os"
 29 	"runtime/debug"
 30+	"strconv"
 31 
 32 	"github.com/charmbracelet/log"
 33 	"github.com/charmbracelet/soft-serve/cmd/soft/admin"
 34@@ -13,9 +14,11 @@ import (
 35 	"github.com/charmbracelet/soft-serve/cmd/soft/serve"
 36 	"github.com/charmbracelet/soft-serve/pkg/config"
 37 	logr "github.com/charmbracelet/soft-serve/pkg/log"
 38+	"github.com/charmbracelet/soft-serve/pkg/ui/common"
 39 	"github.com/charmbracelet/soft-serve/pkg/version"
 40 	mcobra "github.com/muesli/mango-cobra"
 41 	"github.com/muesli/roff"
 42+	"github.com/muesli/termenv"
 43 	"github.com/spf13/cobra"
 44 	"go.uber.org/automaxprocs/maxprocs"
 45 )
 46@@ -63,6 +66,10 @@ var (
 47 )
 48 
 49 func init() {
 50+	if noColor, _ := strconv.ParseBool(os.Getenv("SOFT_SERVE_NO_COLOR")); noColor {
 51+		common.DefaultColorProfile = termenv.Ascii
 52+	}
 53+
 54 	rootCmd.AddCommand(
 55 		manCmd,
 56 		serve.Command,
 57diff --git a/pkg/ssh/session.go b/pkg/ssh/session.go
 58index 5ccd9062b8d946f1b22edf0321a2fbfc28a2b3eb..99c8489eff56380b0d3b910b4856dc04cc5c11ec 100644
 59--- a/pkg/ssh/session.go
 60+++ b/pkg/ssh/session.go
 61@@ -5,6 +5,7 @@ import (
 62 	"time"
 63 
 64 	tea "github.com/charmbracelet/bubbletea"
 65+	"github.com/charmbracelet/lipgloss"
 66 	"github.com/charmbracelet/soft-serve/pkg/access"
 67 	"github.com/charmbracelet/soft-serve/pkg/backend"
 68 	"github.com/charmbracelet/soft-serve/pkg/config"
 69@@ -54,7 +55,7 @@ func SessionHandler(s ssh.Session) *tea.Program {
 70 	}
 71 
 72 	envs := &sessionEnv{s}
 73-	output := termenv.NewOutput(s, termenv.WithColorCache(true), termenv.WithEnvironment(envs))
 74+	output := lipgloss.NewRenderer(s, termenv.WithColorCache(true), termenv.WithEnvironment(envs))
 75 	c := common.NewCommon(ctx, output, pty.Window.Width, pty.Window.Height)
 76 	c.SetValue(common.ConfigKey, cfg)
 77 	m := NewUI(c, initialRepo)
 78diff --git a/pkg/ui/common/common.go b/pkg/ui/common/common.go
 79index ceee1f58ef0cee0ae55bf61299a6286da003d66e..3c3eddd303e638f5e509f2575689e6c130d95524 100644
 80--- a/pkg/ui/common/common.go
 81+++ b/pkg/ui/common/common.go
 82@@ -4,6 +4,7 @@ import (
 83 	"context"
 84 	"fmt"
 85 
 86+	"github.com/charmbracelet/lipgloss"
 87 	"github.com/charmbracelet/log"
 88 	"github.com/charmbracelet/soft-serve/git"
 89 	"github.com/charmbracelet/soft-serve/pkg/backend"
 90@@ -38,7 +39,7 @@ type Common struct {
 91 }
 92 
 93 // NewCommon returns a new Common struct.
 94-func NewCommon(ctx context.Context, out *termenv.Output, width, height int) Common {
 95+func NewCommon(ctx context.Context, out *lipgloss.Renderer, width, height int) Common {
 96 	if ctx == nil {
 97 		ctx = context.TODO()
 98 	}
 99@@ -46,7 +47,7 @@ func NewCommon(ctx context.Context, out *termenv.Output, width, height int) Comm
100 		ctx:    ctx,
101 		Width:  width,
102 		Height: height,
103-		Output: out,
104+		Output: out.Output(),
105 		Styles: styles.DefaultStyles(),
106 		KeyMap: keymap.DefaultKeyMap(),
107 		Zone:   zone.New(),
108diff --git a/testscript/script_test.go b/testscript/script_test.go
109index f7dd22eec65b699667e357bf2bbd348e9cae17fd..0b1b619e28d656363afe56e28dc6336a969e8e2d 100644
110--- a/testscript/script_test.go
111+++ b/testscript/script_test.go
112@@ -15,6 +15,7 @@ import (
113 	"os/exec"
114 	"path/filepath"
115 	"runtime"
116+	"strconv"
117 	"strings"
118 	"testing"
119 	"time"
120@@ -92,6 +93,8 @@ func TestScript(t *testing.T) {
121 			"new-webhook":   cmdNewWebhook,
122 			"waitforserver": cmdWaitforserver,
123 			"stopserver":    cmdStopserver,
124+			"ui":            cmdUI(admin1.Signer()),
125+			"uui":           cmdUI(user1.Signer()),
126 		},
127 		Setup: func(e *testscript.Env) error {
128 			// Add binPath to PATH
129@@ -120,6 +123,9 @@ func TestScript(t *testing.T) {
130 			// This is used to set up test specific configuration and http endpoints
131 			e.Setenv("SOFT_SERVE_TESTRUN", "1")
132 
133+			// This will disable the default lipgloss renderer colors
134+			e.Setenv("SOFT_SERVE_NO_COLOR", "1")
135+
136 			// Soft Serve debug environment variables
137 			for _, env := range []string{
138 				"SOFT_SERVE_DEBUG",
139@@ -199,6 +205,64 @@ func cmdSoft(key ssh.Signer) func(ts *testscript.TestScript, neg bool, args []st
140 	}
141 }
142 
143+func cmdUI(key ssh.Signer) func(ts *testscript.TestScript, neg bool, args []string) {
144+	return func(ts *testscript.TestScript, neg bool, args []string) {
145+		if len(args) < 1 {
146+			ts.Fatalf("usage: ui <quoted string input>")
147+			return
148+		}
149+
150+		cli, err := ssh.Dial(
151+			"tcp",
152+			net.JoinHostPort("localhost", ts.Getenv("SSH_PORT")),
153+			&ssh.ClientConfig{
154+				User:            "git",
155+				Auth:            []ssh.AuthMethod{ssh.PublicKeys(key)},
156+				HostKeyCallback: ssh.InsecureIgnoreHostKey(),
157+			},
158+		)
159+		check(ts, err, neg)
160+		defer cli.Close()
161+
162+		sess, err := cli.NewSession()
163+		check(ts, err, neg)
164+		defer sess.Close()
165+
166+		// XXX: this is a hack to make the UI tests work
167+		// cmp command always complains about an extra newline
168+		// in the output
169+		defer ts.Stdout().Write([]byte("\n"))
170+
171+		sess.Stdout = ts.Stdout()
172+		sess.Stderr = ts.Stderr()
173+
174+		stdin, err := sess.StdinPipe()
175+		check(ts, err, neg)
176+
177+		in, err := strconv.Unquote(args[0])
178+		check(ts, err, neg)
179+		reader := strings.NewReader(in)
180+		go func() {
181+			defer stdin.Close()
182+			for {
183+				r, _, err := reader.ReadRune()
184+				if err == io.EOF {
185+					break
186+				}
187+				check(ts, err, neg)
188+				stdin.Write([]byte(string(r))) // nolint: errcheck
189+
190+				// Wait for the UI to process the input
191+				time.Sleep(100 * time.Millisecond)
192+			}
193+		}()
194+
195+		err = sess.RequestPty("dumb", 40, 80, ssh.TerminalModes{})
196+		check(ts, err, neg)
197+		check(ts, sess.Run(""), neg)
198+	}
199+}
200+
201 // P.S. Windows sucks!
202 func cmdDos2Unix(ts *testscript.TestScript, neg bool, args []string) {
203 	if neg {
204diff --git a/testscript/testdata/repo-blob.txtar b/testscript/testdata/repo-blob.txtar
205index 040160b17a9b9a29c020cb07502a534b5f2d0db6..e2712acfe6638c9c2eed5f98d08fbbb4c880ec3e 100644
206--- a/testscript/testdata/repo-blob.txtar
207+++ b/testscript/testdata/repo-blob.txtar
208@@ -54,6 +54,6 @@ stderr 'revision does not exist'
209 -- blob1.txt --
210 # Hello\n\nwelcome
211 -- blob2.txt --
212- 1 │ package main\nconst foo = 2\n
213+ 1 │ package main\nconst foo = 2\n
214 -- blob3.txt --
215  1 │ //#include <stdio.h>
216diff --git a/testscript/testdata/ui-home.txtar b/testscript/testdata/ui-home.txtar
217new file mode 100644
218index 0000000000000000000000000000000000000000..e7203fb0d969c98b958eb1d34d36289e9367a235
219--- /dev/null
220+++ b/testscript/testdata/ui-home.txtar
221@@ -0,0 +1,53 @@
222+# vi: set ft=conf
223+
224+# start soft serve
225+exec soft serve &
226+# wait for server to start
227+waitforserver
228+
229+# test repositories tab
230+ui '"    q"'
231+cp stdout home.txt
232+grep 'Test Soft Serve' home.txt
233+grep '• Repositories' home.txt
234+grep 'No items found' home.txt
235+
236+# test about tab
237+ui '"\t    q"'
238+cp stdout about.txt
239+grep 'Create a `.soft-serve` repository and add a `README.md` file' about.txt
240+
241+# add a new repo
242+soft repo create .soft-serve -n 'Config' -d '"Test Soft Serve"'
243+soft repo description .soft-serve
244+stdout 'Test Soft Serve'
245+soft repo project-name .soft-serve
246+stdout 'Config'
247+
248+# clone repo
249+git clone ssh://localhost:$SSH_PORT/.soft-serve config
250+
251+# create readme file
252+mkfile ./config/README.md '# Hello World\nTest Soft Serve'
253+git -C config add -A
254+git -C config commit -m 'Initial commit'
255+git -C config push origin HEAD
256+
257+# test repositories tab
258+ui '"    q"'
259+cp stdout home2.txt
260+grep 'Config' home2.txt
261+grep 'Test Soft Serve' home2.txt
262+grep 'git clone ssh://localhost:.*/.soft-serve' home2.txt
263+
264+# test about tab
265+ui '"\t      q"'
266+cp stdout about2.txt
267+grep '• About' about2.txt
268+grep 'Hello World' about2.txt
269+grep 'Test Soft Serve' about2.txt
270+
271+# stop the server
272+[windows] stopserver
273+[windows] ! stderr .
274+