func TestCLIConfirmation(t *testing.T) { Convey("Given a buffer", t, func() { w := &bytes.Buffer{} r := &bytes.Buffer{} Convey("AskForConfirmation should respond correctly to all cases", func() { // Yes case var wg sync.WaitGroup wg.Add(1) var ( resp bool cerr error ) go func() { resp, cerr = utils.AskForConfirmation(w, r, "hello: ") wg.Done() }() r.WriteString("yes\n") wg.Wait() So(cerr, ShouldBeNil) So(w.String(), ShouldEqual, "hello: ") So(resp, ShouldBeTrue) // Clean up w.Reset() r.Reset() // No case wg.Add(1) go func() { resp, cerr = utils.AskForConfirmation(w, r, "hello: ") wg.Done() }() r.WriteString("no\n") wg.Wait() So(cerr, ShouldBeNil) So(w.String(), ShouldEqual, "hello: ") So(resp, ShouldBeFalse) // Clean up for the second time w.Reset() r.Reset() // Retry case wg.Add(1) go func() { resp, cerr = utils.AskForConfirmation(w, r, "hello: ") wg.Done() }() r.WriteString("invalid\n") r.WriteString("yes\n") wg.Wait() So(cerr, ShouldBeNil) So(w.String(), ShouldEqual, "hello: hello: ") So(resp, ShouldBeTrue) // Closed stdin case w.Reset() r2 := &dumbReader{} resp, err := utils.AskForConfirmation(w, r2, "hello: ") So(err, ShouldNotBeNil) So(w.String(), ShouldEqual, "hello: ") So(resp, ShouldBeFalse) }) }) }
func databaseMigrate(c *cli.Context) int { // Connect to RethinkDB opts, session, connected := connectToRethinkDB(c) if !connected { return 1 } // Get the migration status from the database version, err := getDatabaseVersion(opts, session) if err != nil { writeError(c, err) return 1 } // Show the current migration's status fmt.Fprintf(c.App.Writer, "Current database schema's version is %d.\n", version) fmt.Fprintf(c.App.Writer, "Latest migration's version is %d.\n", len(migrations)-1) // Only proceed if the schema is outdated if version >= len(migrations)-1 { fmt.Fprintln(c.App.Writer, "Your schema is up to date.") return 0 } // I don't know why would anyone use it, but it's here if c.Bool("no") { fmt.Fprintln(c.App.Writer, "Aborting the command because of the --no option.") return 1 } // Ask for confirmations if !c.Bool("yes") { want, err := utils.AskForConfirmation( c.App.Writer, c.App.Env["reader"].(io.Reader), "Would you like to run "+strconv.Itoa(len(migrations)-1-version)+" migrations? [y/n]: ", ) if err != nil { writeError(c, err) return 1 } if !want { fmt.Fprintln(c.App.Writer, "Aborting the command.") return 1 } } // Collect all queries queries := []r.Term{} for _, migration := range migrations[version+1:] { queries = append(queries, migration.Migrate(opts)...) queries = append(queries, r.Table("migration_status").Get("revision").Update(map[string]interface{}{ "value": migration.Revision, })) } // Create a new progress bar bar := pb.StartNew(len(queries)) for i, query := range queries { if c.Bool("dry") { fmt.Fprintf(c.App.Writer, "Executing %s\n", query.String()) } else { if err := query.Exec(session); err != nil { bar.FinishPrint("Failed to execute migration #" + strconv.Itoa(i) + ":") fmt.Fprintf(c.App.Writer, "\tQuery: %s\n", query.String()) fmt.Fprintf(c.App.Writer, "\tError: %v\n", err) return 1 } } bar.Increment() } // Show a "finished" message bar.FinishPrint("Migration completed. " + strconv.Itoa(len(queries)) + " queries executed.") return 0 }