dodo: Support Sketch agent

Change-Id: I4dcd6aab7d7a2c2e86aaf1ad8d36d30a649ab31d
diff --git a/apps/app-runner/server.go b/apps/app-runner/server.go
index 1f7fe01..89f621a 100644
--- a/apps/app-runner/server.go
+++ b/apps/app-runner/server.go
@@ -31,6 +31,7 @@
 
 type Server struct {
 	l           sync.Locker
+	agentMode   bool
 	port        int
 	appId       string
 	service     string
@@ -50,9 +51,10 @@
 	status      *Status
 }
 
-func NewServer(port int, appId, service, id, repoAddr, branch, rootDir string, signer ssh.Signer, appDir string, runCommands []Command, self string, manager string) *Server {
+func NewServer(agentMode bool, port int, appId, service, id, repoAddr, branch, rootDir string, signer ssh.Signer, appDir string, runCommands []Command, self string, manager string) *Server {
 	return &Server{
 		l:           &sync.Mutex{},
+		agentMode:   agentMode,
 		port:        port,
 		ready:       false,
 		appId:       appId,
@@ -114,30 +116,80 @@
 	s.l.Unlock()
 }
 
+type command struct {
+	cmd string
+	env []string
+}
+
 func (s *Server) run() error {
-	newDir, err := os.MkdirTemp(s.appDir, "code-*")
-	if err != nil {
-		return err
-	}
-	commit, err := CloneRepositoryBranch(s.repoAddr, s.branch, s.rootDir, s.signer, newDir)
-	if err != nil {
-		fmt.Fprintf(s.logs, "!!! dodo: Failed to clone repository\n")
-		s.status = &Status{
-			Commit: nil,
+	newDir := s.appDir
+	commands := []command{}
+	if !s.agentMode {
+		var err error
+		newDir, err = os.MkdirTemp(s.appDir, "code-*")
+		if err != nil {
+			return err
 		}
-		return err
 	}
-	fmt.Fprintf(s.logs, "!!! dodo: Successfully cloned repository %s\n", commit.Hash)
-	s.status = &Status{
-		Commit:   commit,
-		Commands: []CommandStatus{},
+	if s.repoAddr != "" {
+		commit, err := CloneRepositoryBranch(s.repoAddr, s.branch, s.rootDir, s.signer, newDir)
+		if err != nil {
+			fmt.Fprintf(s.logs, "!!! dodo: Failed to clone repository\n")
+			s.status = &Status{
+				Commit: nil,
+			}
+			return err
+		}
+		fmt.Fprintf(s.logs, "!!! dodo: Successfully cloned repository %s\n", commit.Hash)
+		s.status = &Status{
+			Commit:   commit,
+			Commands: []CommandStatus{},
+		}
+	} else {
+		s.status = &Status{
+			Commit:   nil,
+			Commands: []CommandStatus{},
+		}
 	}
-	commands := []string{}
+	if s.agentMode {
+		if _, err := os.Stat(filepath.Join(newDir, ".git")); err != nil && os.IsNotExist(err) {
+			commands = append(commands, command{cmd: "git config --global user.name dodo"})
+			s.status.Commands = append(s.status.Commands, CommandStatus{
+				Command: commands[len(commands)-1].cmd,
+				State:   "waiting",
+			})
+			commands = append(commands, command{cmd: "git config --global user.email dodo@dodo.cloud"})
+			s.status.Commands = append(s.status.Commands, CommandStatus{
+				Command: commands[len(commands)-1].cmd,
+				State:   "waiting",
+			})
+			commands = append(commands, command{cmd: "git init ."})
+			s.status.Commands = append(s.status.Commands, CommandStatus{
+				Command: commands[len(commands)-1].cmd,
+				State:   "waiting",
+			})
+			commands = append(commands, command{cmd: "echo \"TODO: Describe project\" > README.md"})
+			s.status.Commands = append(s.status.Commands, CommandStatus{
+				Command: commands[len(commands)-1].cmd,
+				State:   "waiting",
+			})
+			commands = append(commands, command{cmd: "git add README.md"})
+			s.status.Commands = append(s.status.Commands, CommandStatus{
+				Command: commands[len(commands)-1].cmd,
+				State:   "waiting",
+			})
+			commands = append(commands, command{cmd: "git commit -m \"init\""})
+			s.status.Commands = append(s.status.Commands, CommandStatus{
+				Command: commands[len(commands)-1].cmd,
+				State:   "waiting",
+			})
+		}
+	}
 	for _, c := range s.runCommands {
 		args := []string{c.Bin}
 		args = append(args, c.Args...)
 		cmd := strings.Join(args, " ")
-		commands = append(commands, cmd)
+		commands = append(commands, command{cmd, c.Env})
 		s.status.Commands = append(s.status.Commands, CommandStatus{
 			Command: cmd,
 			State:   "waiting",
@@ -151,8 +203,8 @@
 		cmd := &exec.Cmd{
 			Dir:    filepath.Join(newDir, s.rootDir),
 			Path:   "/bin/sh",
-			Args:   []string{"/bin/sh", "-c", c},
-			Env:    append(os.Environ(), s.runCommands[i].Env...),
+			Args:   []string{"/bin/sh", "-c", c.cmd},
+			Env:    append(os.Environ(), c.env...),
 			Stdout: logM,
 			Stderr: logM,
 		}
@@ -160,7 +212,7 @@
 		fmt.Printf("Running: %s\n", c)
 		fmt.Fprintf(s.logs, "!!! dodo: Running: %s\n", c)
 		s.status.Commands[i].State = "running"
-		if i < len(s.runCommands)-1 {
+		if i < len(commands)-1 {
 			if err := cmd.Run(); err != nil {
 				return err
 			}
@@ -170,7 +222,7 @@
 				if err := s.kill(); err != nil {
 					return err
 				}
-				if s.currDir != "" {
+				if s.currDir != "" && !s.agentMode {
 					if err := os.RemoveAll(s.currDir); err != nil {
 						return err
 					}