func run(cmd *gocli.Command, args []string) { if len(args) != 0 { cmd.Usage() os.Exit(2) } upgraded, err := pkg.Upgrade(&pkg.InstallOptions{ GitHubOwner: flagOwner, GitHubRepo: flagRepo, }) if err != nil { if err == pkg.ErrAborted { fmt.Println("\nYour wish is my command, exiting now!") return } errs.Fatal(err) } if upgraded { log.Log("SalsaFlow was upgraded successfully") } else { log.Log("SalsaFlow is up to date") asciiart.PrintThumbsUp() fmt.Println() } }
func Upgrade(opts *InstallOptions) error { // Get GitHub owner and repository names. var ( owner = DefaultGitHubOwner repo = DefaultGitHubRepo ) if opts != nil { if opts.GitHubOwner != "" { owner = opts.GitHubOwner } if opts.GitHubRepo != "" { repo = opts.GitHubRepo } } // Instantiate a GitHub client. task := "Instantiate a GitHub client" client, err := newGitHubClient() if err != nil { return errs.NewError(task, err) } // Fetch the list of available GitHub releases. task = fmt.Sprintf("Fetch GitHub releases for %v/%v", owner, repo) log.Run(task) releases, _, err := client.Repositories.ListReleases(owner, repo, nil) if err != nil { return errs.NewError(task, err) } // Sort the releases by version and get the most recent release. task = "Select the most suitable GitHub release" var rs releaseSlice for i, release := range releases { // Skip drafts and pre-releases. if *release.Draft || *release.Prerelease { continue } // We expect the tag to be "v" + semver version string. version, err := version.Parse((*release.TagName)[1:]) if err != nil { log.Warn(fmt.Sprintf("Tag format invalid for '%v', skipping...", release.TagName)) continue } // Append the release to the list of releases. rs = append(rs, &githubRelease{ version: version, resource: &releases[i], }) } if rs.Len() == 0 { return errs.NewError(task, errors.New("no suitable GitHub releases found")) } sort.Sort(rs) release := rs[len(rs)-1] // Make sure the selected release is more recent than this executable. currentVersion, err := version.Parse(metadata.Version) if err != nil { panic(err) } if release.version.String() == metadata.Version || release.version.LT(currentVersion.Version) { log.Log("SalsaFlow is up to date") asciiart.PrintThumbsUp() fmt.Println() return nil } // Prompt the user to confirm the upgrade. task = "Prompt the user to confirm upgrade" fmt.Println() confirmed, err := prompt.Confirm(fmt.Sprintf( "SalsaFlow version %v is available. Upgrade now?", release.version)) if err != nil { return errs.NewError(task, err) } if !confirmed { return ErrAborted } fmt.Println() // Proceed to actually install the executables. return doInstall(client, owner, repo, release.resource.Assets, release.version.String()) }
func Init(force bool) error { // Check whether the repository has been initialised yet. task := "Check whether the repository has been initialised" versionString, err := git.GetConfigString("salsaflow.initialised") if err != nil { return errs.NewError(task, err) } if versionString == metadata.Version && !force { return errs.NewError(task, ErrInitialised) } log.Log("Initialising the repository for SalsaFlow") // Make sure the user is using the right version of Git. // // The check is here and not in app.Init because it is highly improbable // that the check would pass once and then fail later. Once the right // version of git is installed, it most probably stays. task = "Check the git version being used" log.Run(task) stdout, err := git.Run("--version") if err != nil { return errs.NewError(task, err) } pattern := regexp.MustCompile("^git version (([0-9]+)[.]([0-9]+).*)") parts := pattern.FindStringSubmatch(stdout.String()) if len(parts) != 4 { return errs.NewError(task, errors.New("unexpected git --version output")) } gitVersion := parts[1] // This cannot fail since we matched the regexp. major, _ := strconv.Atoi(parts[2]) minor, _ := strconv.Atoi(parts[3]) // We need Git version 1.8.5.4+, so let's require 1.9+. switch { case major >= 2: // OK case major == 1 && minor >= 9: // OK default: hint := ` You need Git version 1.9.0 or newer. ` return errs.NewErrorWithHint( task, errors.New("unsupported git version detected: "+gitVersion), hint) } // Get hold of a git config instance. gitConfig, err := git.LoadConfig() if err != nil { return err } var ( remoteName = gitConfig.RemoteName trunkBranch = gitConfig.TrunkBranchName stableBranch = gitConfig.StableBranchName ) // Make sure that the stable branch exists. task = fmt.Sprintf("Make sure branch '%v' exists", stableBranch) log.Run(task) err = git.CheckOrCreateTrackingBranch(stableBranch, remoteName) if err != nil { if ex, ok := err.(*git.ErrRefNotFound); ok { hint := fmt.Sprintf( "Make sure that branch '%v' exists and run init again.\n", ex.Ref) return errs.NewErrorWithHint(task, err, hint) } else if _, ok := err.(*git.ErrRefNotInSync); !ok { // We ignore ErrRefNotInSync here, so return the error // in case it is of some other kind. return errs.NewError(task, err) } } // Make sure that the trunk branch exists. task = fmt.Sprintf("Make sure branch '%v' exists", trunkBranch) log.Run(task) err = git.CheckOrCreateTrackingBranch(trunkBranch, remoteName) if err != nil { if _, ok := err.(*git.ErrRefNotFound); ok { task := fmt.Sprintf("Create branch '%v'", trunkBranch) log.Log(fmt.Sprintf( "Branch '%v' not found. Will create one for you for free!", trunkBranch)) if err := git.Branch(trunkBranch, stableBranch); err != nil { return errs.NewError(task, err) } log.NewLine(fmt.Sprintf( "The newly created branch is pointing to '%v'.", stableBranch)) task = fmt.Sprintf("Push branch '%v' to remote '%v'", trunkBranch, remoteName) log.Run(task) if err := git.Push(remoteName, trunkBranch+":"+trunkBranch); err != nil { return errs.NewError(task, err) } } else if _, ok := err.(*git.ErrRefNotInSync); !ok { // We ignore ErrRefNotInSync here, so return the error // in case it is of some other kind. return errs.NewError(task, err) } } // Verify our git hooks are installed and used. for _, kind := range hooks.HookTypes { task := fmt.Sprintf("Check the current git %v hook", kind) log.Run(task) if err := hooks.CheckAndUpsert(kind, force); err != nil { return errs.NewError(task, err) } } // Run other registered init hooks. task = "Running the registered repository init hooks" log.Log(task) if err := executeInitHooks(); err != nil { return errs.NewError(task, err) } // Success! Mark the repository as initialised in git config. task = "Mark the repository as initialised" if err := git.SetConfigString("salsaflow.initialised", metadata.Version); err != nil { return err } asciiart.PrintThumbsUp() fmt.Println() log.Log("The repository is initialised") return nil }