Esempio n. 1
0
func runLogin(cmd *cobra.Command, args []string) {
	if loginInfo := login.SavedLoginInfo(); loginInfo != nil {
		color.Red("You are already logged in as %s. To logout, type \"nestor logout\"\n", loginInfo.Email)
		os.Exit(1)
	}

	email := getEmail()
	password := getPassword()

	loginInfo, err := login.Login(email, password)
	if err != nil {
		color.Red(err.Error())
		os.Exit(1)
	}

	err = loginInfo.Save()
	if err != nil {
		color.Red(unexpectedErrorWhileLoggingInErr.Error())
		os.Exit(1)
	}

	color.Green("Successfully logged in as %s\n", email)

	// Make user pick a default team right at the beginning
	runTeam(cmd, args)
}
Esempio n. 2
0
func runTeam(cmd *cobra.Command, args []string) {
	var l *login.LoginInfo

	if l = login.SavedLoginInfo(); l == nil {
		color.Red("You are not logged in. To login, type \"nestor login\"\n")
		os.Exit(1)
	}

	teams, err := team.GetTeams(l)
	if err != nil {
		fmt.Println(unexpectedErrorWhileLoggingInErr.Error())
		os.Exit(1)
	}

	if len(teams) == 1 {
		team := teams[0]
		err := team.Save(l)
		if err != nil {
			color.Red("Error saving default team\n")
			os.Exit(1)
		} else {
			color.Green("Saved %s as your default team\n", team.Name)
		}
	} else {
		table := team.TableizeTeams(teams, l.DefaultTeamId)
		fmt.Printf("\n")
		table.Render()
		fmt.Printf("\n")

		ok := false
		intIndex := 0

		for !ok {
			index, promptErr := prompt.Basic(fmt.Sprintf("Pick which team you want to set as your default (1-%d): ", len(teams)), true)
			if promptErr != nil {
				os.Exit(1)
			}

			intIndex, err = strconv.Atoi(index)
			if err == nil && intIndex > 0 && intIndex <= len(teams) {
				ok = true
			}
		}

		team := teams[intIndex-1]
		err := team.Save(l)
		if err != nil {
			color.Red("Unexpected error saving your default team. Please try updating the app with `nestor update` or raise an issue at https://github.com/zerobotlabs/nestor-cli\n")
			os.Exit(1)
		} else {
			color.Green("Saved %s as your default team\n", team.Name)
		}
	}
}
Esempio n. 3
0
func runUpdate(cmd *cobra.Command, args []string) {
	newVersion, err := update.Update()
	switch {
	case err == update.NotAvailableErr:
		color.Green("No update available\n")
		os.Exit(0)
	case err != nil:
		color.Red("There was an error updating nestor. Please try again later or contact [email protected]\n")
		os.Exit(1)
	}

	color.Green("Updated nestor to new version: %s!\n", newVersion)
}
Esempio n. 4
0
func (a *App) CompileCoffeescript() error {
	coffeeFiles := []string{}

	if a.ArtifactPath == "" {
		return fmt.Errorf("ArtifactPath not set")
	}

	err := filepath.Walk(a.ArtifactPath, func(p string, info os.FileInfo, err error) error {
		if info.Mode().IsRegular() && strings.HasSuffix(p, ".coffee") {
			coffeeFiles = append(coffeeFiles, p)
		}
		return err
	})

	if err != nil {
		return err
	}

	if len(coffeeFiles) == 0 {
		return nil
	}

	color.Green("+ Compiling Coffeescript...\n")

	binary, lookErr := exec.LookPath("coffee")
	if lookErr != nil {
		color.Red("- Could not find coffee in your $PATH. Please install coffee-script with 'npm install -g coffee-script'\n")
		return lookErr
	}

	for _, coffeeFile := range coffeeFiles {
		_, err := exec.Command(binary, "-c", coffeeFile).Output()
		if err != nil {
			return err
		}

		err = os.Remove(coffeeFile)
		if err != nil {
			return err
		}
	}

	return nil
}
Esempio n. 5
0
func runLogout(cmd *cobra.Command, args []string) {
	var l *login.LoginInfo

	if l = login.SavedLoginInfo(); l == nil {
		color.Red("You are not logged in. To login, type \"nestor login\"\n")
		os.Exit(1)
	}

	shouldLogout, err := prompt.Ask(fmt.Sprintf("Are you sure you want to log out as %s", l.Email))
	if err != nil {
		os.Exit(1)
	}

	if shouldLogout {
		err = login.Delete()
		if err != nil {
			fmt.Println(unexpectedErrorWhileLoggingOutErr)
			os.Exit(1)
		}
		color.Green("Successfully logged out as %s\n", l.Email)
	} else {
		os.Exit(1)
	}
}
Esempio n. 6
0
func runSave(cmd *cobra.Command, args []string) {
	var l *login.LoginInfo
	var a app.App

	// Check if you are logged in first
	if l = login.SavedLoginInfo(); l == nil {
		color.Red("You are not logged in. To login, type \"nestor login\"\n")
		os.Exit(1)
	}

	// Check if you have a valid nestor.json file
	nestorJsonPath, err := pathToNestorJson(args)
	if err != nil {
		color.Red("Could not find nestor.json in the path specified\n")
		os.Exit(1)
	}

	a.ManifestPath = nestorJsonPath

	err = a.ParseManifest()
	if err != nil {
		color.Red("%s\n", err.Error())
		os.Exit(1)
	}

	// Check if existing app exists and if so, then we should be making calls to the "UPDATE" function
	// We are ignoring the error for now but at some point we will have to show an error that is not annoying
	err = a.Hydrate(l)
	if err != nil {
		color.Red("- Error fetching details for power\n")
	}

	color.Green("+ Building deployment artifact...\n")
	err = a.BuildArtifact()
	if err != nil {
		color.Red("- Error while building deployment artifact for your power\n")
	}

	// Check if you need to do coffee compilation
	err = a.CompileCoffeescript()
	if err != nil {
		color.Red("- There was an error compiling coffeescript in your power\n")
		os.Exit(1)
	}

	err = a.CalculateLocalSha256()
	if err != nil {
		color.Red("- There was an error calculating whether your power needs to be uploaded\n")
		os.Exit(1)
	}

	if a.LocalSha256 != a.RemoteSha256 {
		color.Green("+ Generating zip...\n")
		zip, err := a.ZipBytes()
		if err != nil {
			color.Red("- Error creating a zip of your power's deployment artifact\n")
			os.Exit(1)
		}

		color.Green("+ Uploading zip...\n")
		// Upload app contents
		buffer := bytes.NewBuffer(zip)
		err = a.Upload(buffer, l)
		if err != nil {
			color.Red("- Error while uploading deployment artifact: %+v\n", err)
			os.Exit(1)
		}
	}

	// Make API call to Nestor with contents from JSON file along with S3 URL so that the API can create a functioning bot app
	color.Green("+ Saving power to Nestor...\n")
	err = a.SaveToNestor(l)
	if err != nil {
		color.Red("- Error while saving power to nestor: %+v\n", err)
		os.Exit(1)
	}

	color.Green("+ Successfully saved power to Nestor!\n")

	fmt.Printf("\nYou can test your power by running `nestor shell`\n")
	fmt.Printf("To deploy your power to Slack, run `nestor deploy --latest`\n")
}
Esempio n. 7
0
func runShell(cmd *cobra.Command, args []string) {
	var l *login.LoginInfo
	var a app.App

	// Check if you are logged in first
	if l = login.SavedLoginInfo(); l == nil {
		color.Red("You are not logged in. To login, type \"nestor login\"\n")
		os.Exit(1)
	}

	// Check if you have a valid nestor.json file
	nestorJsonPath, err := pathToNestorJson(args)
	if err != nil {
		color.Red("Could not find nestor.json in the path specified\n")
		os.Exit(1)
	}

	a.ManifestPath = nestorJsonPath

	err = a.ParseManifest()
	if err != nil {
		color.Red("%s\n", err.Error())
		os.Exit(1)
	}

	// Check if existing app exists and if so, then we should be making calls to the "UPDATE" function
	// We are ignoring the error for now but at some point we will have to show an error that is not annoying
	err = a.Hydrate(l)
	if err != nil {
		color.Red("Error fetching details for power\n")
	}

	if a.Id == 0 {
		color.Red("You haven't saved your power yet. Run `nestor save` before you can test your power\n")
		os.Exit(1)
	}

	ok := false

	line := liner.NewLiner()

	line.SetCtrlCAborts(true)
	hf, err := os.OpenFile(historyFile, os.O_RDWR, 0644)
	if err != nil {
		color.Red("Unexpected error opening shell\n")
		line.Close()
		os.Exit(1)
	}

	line.ReadHistory(hf)

	for !ok {
		if command, err := line.Prompt("nestor> "); err == nil {
			command = strings.TrimSpace(command)

			if command != "" {
				line.AppendHistory(command)
			}
			switch {
			case quitPattern.MatchString(command):
				fmt.Println("Goodbye!")
				saveHistory(line, hf)
				os.Exit(1)
			case setEnvPattern.MatchString(command):
				matches := setEnvPattern.FindAllStringSubmatch(command, -1)
				resp, err := a.UpdateEnv(l, matches[0][1], matches[0][2])
				if err != nil {
					color.Red("There was an error setting environment variable %s for your power", matches[0][1])
				} else {
					fmt.Printf("Set %s to %s\n", matches[0][1], resp)
				}
			case getEnvPattern.MatchString(command):
				matches := getEnvPattern.FindAllStringSubmatch(command, -1)
				table, err := a.GetEnv(l, matches[0][1])
				if err != nil {
					color.Red("There was an error getting environment variable %s for your power", matches[0][1])
				} else {
					table.Render()
					fmt.Printf("\n")
				}
			case command == "":
				continue
			default:
				output := exec.Output{}
				err := output.Exec(&a, l, command)
				if err != nil {
					color.Red("unexpected error while running your power. Please try again later or contact [email protected]\n", err)
				}
				if output.Logs != "" {
					color.Yellow(output.Logs)
				}
				if len(output.ToSuggest) > 0 {
					suggestion := output.ToSuggest[0]
					fmt.Println("Oops, did you mean `" + suggestion + "`?")
				} else {
					for _, send := range output.ToSend {
						fmt.Println(send.ToString())
					}
				}
			}
		}
	}

	saveHistory(line, hf)
}
Esempio n. 8
0
func runDeploy(cmd *cobra.Command, args []string) {
	var l *login.LoginInfo
	var a app.App

	// Check if you are logged in first
	if l = login.SavedLoginInfo(); l == nil {
		color.Red("You are not logged in. To login, type \"nestor login\"\n")
		os.Exit(1)
	}

	// Check if you have a valid nestor.json file
	nestorJsonPath, err := pathToNestorJson(args)
	if err != nil {
		color.Red("Could not find nestor.json in the path specified\n")
		os.Exit(1)
	}

	a.ManifestPath = nestorJsonPath

	err = a.ParseManifest()
	if err != nil {
		color.Red("%s\n", err.Error())
		os.Exit(1)
	}

	// Check if existing app exists and if so, then we should be making calls to the "UPDATE" function
	// We are ignoring the error for now but at some point we will have to show an error that is not annoying
	err = a.Hydrate(l)
	if err != nil {
		color.Red("Error fetching details for this power\n")
	}

	if a.Id == 0 {
		color.Red("You haven't saved your power yet. Run `nestor save` before you can deploy your power\n")
		os.Exit(1)
	}

	versions, err := version.FetchVersions(a, l)
	if err != nil {
		color.Red("Error fetching versions for your power\n")
		os.Exit(1)
	}

	if latestDeploy {
		pickedVersion := versions[0]
		if pickedVersion.CurrentlyDeployed {
			color.Green("Version %s already deployed. Nothing to do here\n", pickedVersion.Ref)
		} else {
			err = pickedVersion.Deploy(a, l)

			if err != nil {
				color.Red(err.Error())
				os.Exit(1)
			}

			color.Green("Deployed version %s successfully\n", pickedVersion.Ref)
		}
	} else {
		table := version.TableizeVersions(versions)
		fmt.Printf("\n")
		table.Render()
		fmt.Printf("\n")

		ok := false
		intIndex := 0

		for !ok {
			index, promptErr := prompt.Basic(fmt.Sprintf("Pick a version to deploy (1-%d): ", len(versions)), true)
			if promptErr != nil {
				os.Exit(1)
			}

			intIndex, err = strconv.Atoi(index)
			if err == nil && intIndex > 0 && intIndex <= len(versions) {
				ok = true
			}
		}

		pickedVersion := versions[intIndex-1]
		if pickedVersion.CurrentlyDeployed {
			color.Green("Version %s already deployed. Nothing to do here\n", pickedVersion.Ref)
		} else {
			err = pickedVersion.Deploy(a, l)

			if err != nil {
				color.Red("Error deploying %s. Please try again later or contact [email protected]\n", pickedVersion.Ref)
				os.Exit(1)
			}

			color.Green("Deployed version %s successfully\n", pickedVersion.Ref)
		}
	}
}
Esempio n. 9
0
func runNew(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		color.Red("Usage: nestor new <power-name>")
		os.Exit(1)
	}

	appName := strings.TrimSpace(args[0])
	permalink := strings.ToLower(strings.Replace(appName, " ", "-", -1))
	permalink = strings.ToLower(strings.Replace(permalink, ".", "-", -1))

	currentDir, err := os.Getwd()
	if err != nil {
		color.Red("Unexpected error occurred while creating your power: %+v", err)
		os.Exit(1)
	}

	base := path.Join(currentDir, permalink)
	if _, err = os.Stat(base); err == nil {
		color.Red("A power with this name already exists in this directory, pick another name or another directory to create your power")
		os.Exit(1)
	}

	color.Green("+ Creating directory...")
	err = os.Mkdir(base, 0755)
	if err != nil {
		color.Red("- Unexpected error occurred while creating your power: %+v", err)
		os.Exit(1)
	}

	binary, lookErr := exec.LookPath("npm")
	if lookErr != nil {
		color.Red("- Could not find npm in your $PATH. Please install nodejs from https://nodejs.org")
		os.Exit(1)
	}

	color.Green("+ Running npm init...")
	npmInitCommand := exec.Command(binary, "init", "-y")
	npmInitCommand.Dir = base
	err = npmInitCommand.Run()
	if err != nil {
		color.Red("- Unexpected Error while creating package.json for your power")
		os.Exit(1)
	}

	color.Green("+ Running npm install nestorbot...")
	npmInstallCommand := exec.Command(binary, "install", "nestorbot", "--save")
	npmInstallCommand.Dir = base
	err = npmInstallCommand.Run()
	if err != nil {
		color.Red("- Unexpected Error while downloading nestorbot")
		os.Exit(1)
	}

	color.Green("+ Creating nestor.json...")
	var app AppNestorJson
	app.Name = appName
	app.Description = appName
	app.Permalink = permalink

	marshaledApp, err := json.MarshalIndent(app, "", "  ")
	if err != nil {
		color.Red("- Unexpected Error while creating nestor.json")
		os.Exit(1)
	}

	nestorJsonPath := path.Join(base, "nestor.json")
	err = ioutil.WriteFile(nestorJsonPath, marshaledApp, 0644)
	if err != nil {
		color.Red("- Unexpected Error while creating nestor.json: %+v", err)
		os.Exit(1)
	}

	color.Green("+ Creating example at index.js...")
	indexFilePath := path.Join(base, "index.js")
	err = ioutil.WriteFile(indexFilePath, []byte(defaultAppFile), 0644)
	if err != nil {
		color.Red("- Unexpected Error while creating index.js: %+v", err)
		os.Exit(1)
	}

	color.Green("+ Downloading README...")
	resp, err := http.Get(readmeUrl)
	if err != nil {
		color.Red("- Unexpected Error while fetching README: %+v", err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	readmePath := path.Join(base, "README.md")
	readme, err := os.Create(readmePath)
	if err != nil {
		color.Red("- Unexpected Error while creating README: %+v", err)
		os.Exit(1)
	}
	defer readme.Close()

	_, err = io.Copy(readme, resp.Body)
	if err != nil {
		color.Red("- Unexpected Error while creating README: %+v", err)
		os.Exit(1)
	}

	color.Green("Successfully created power %s here: %s", appName, base)
	fmt.Printf("\ncd %s and run `nestor save` and `nestor shell` to start working on your power\n", base)
}