/* $ hub issue */ func issue(cmd *Command, args *Args) { runInLocalRepo(func(localRepo *github.GitHubRepo, project *github.Project, gh *github.Client) { if args.Noop { ui.Printf("Would request list of issues for %s\n", project) } else { issues, err := gh.Issues(project) utils.Check(err) for _, issue := range issues { var url string // use the pull request URL if we have one if issue.PullRequest.HTMLURL != "" { url = issue.PullRequest.HTMLURL } else { url = issue.HTMLURL } if flagIssueAssignee == "" || strings.EqualFold(issue.Assignee.Login, flagIssueAssignee) { // "nobody" should have more than 1 million github issues ui.Printf("% 7d] %s ( %s )\n", issue.Number, issue.Title, url) } } } }) }
/* $ gh ci-status > (prints CI state of HEAD and exits with appropriate code) > One of: success (0), error (1), failure (1), pending (2), no status (3) $ gh ci-status -v > (prints CI state of HEAD, the URL to the CI build results and exits with appropriate code) > One of: success (0), error (1), failure (1), pending (2), no status (3) $ gh ci-status BRANCH > (prints CI state of BRANCH and exits with appropriate code) > One of: success (0), error (1), failure (1), pending (2), no status (3) $ gh ci-status SHA > (prints CI state of SHA and exits with appropriate code) > One of: success (0), error (1), failure (1), pending (2), no status (3) */ func ciStatus(cmd *Command, args *Args) { ref := "HEAD" if !args.IsParamsEmpty() { ref = args.RemoveParam(0) } localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) sha, err := git.Ref(ref) if err != nil { err = fmt.Errorf("Aborted: no revision could be determined from '%s'", ref) } utils.Check(err) if args.Noop { ui.Printf("Would request CI status for %s\n", sha) } else { state, targetURL, exitCode, err := fetchCiStatus(project, sha) utils.Check(err) if flagCiStatusVerbose && targetURL != "" { ui.Printf("%s: %s\n", state, targetURL) } else { ui.Println(state) } os.Exit(exitCode) } }
func downloadRelease(cmd *Command, args *Args) { tagName := cmd.Arg(0) if tagName == "" { utils.Check(fmt.Errorf("Missing argument TAG")) } localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) release, err := gh.FetchRelease(project, tagName) utils.Check(err) for _, asset := range release.Assets { ui.Printf("Downloading %s ...\n", asset.Name) err := downloadReleaseAsset(asset, gh) utils.Check(err) } args.NoForward() }
func (updater *Updater) PromptForUpdate() (err error) { config := autoUpdateConfig() if config == "never" || !updater.timeToUpdate() { return } releaseName, version := updater.latestReleaseNameAndVersion() if version != "" && version != updater.CurrentVersion { switch config { case "always": err = updater.updateTo(releaseName, version) default: ui.Println("There is a newer version of hub available.") ui.Printf("Would you like to update? ([Y]es/[N]o/[A]lways/N[e]ver): ") var confirm string fmt.Scan(&confirm) always := utils.IsOption(confirm, "a", "always") if always || utils.IsOption(confirm, "y", "yes") { err = updater.updateTo(releaseName, version) } saveAutoUpdateConfiguration(confirm, always) } } return }
func (c *Command) PrintUsage() { if c.Runnable() { ui.Printf("usage: %s\n\n", c.FormattedUsage()) } ui.Println(strings.Trim(c.Long, "\n")) }
func fork(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() if err != nil { utils.Check(fmt.Errorf("Error: repository under 'origin' remote is not a GitHub project")) } config := github.CurrentConfig() host, err := config.PromptForHost(project.Host) if err != nil { utils.Check(github.FormatError("forking repository", err)) } originRemote, err := localRepo.OriginRemote() if err != nil { utils.Check(fmt.Errorf("Error creating fork: %s", err)) } forkProject := github.NewProject(host.User, project.Name, project.Host) newRemoteName := forkProject.Owner client := github.NewClient(project.Host) existingRepo, err := client.Repository(forkProject) if err == nil { var parentURL *github.URL if parent := existingRepo.Parent; parent != nil { parentURL, _ = github.ParseURL(parent.HTMLURL) } if parentURL == nil || !project.SameAs(parentURL.Project) { err = fmt.Errorf("Error creating fork: %s already exists on %s", forkProject, forkProject.Host) utils.Check(err) } } else { if !args.Noop { newRepo, err := client.ForkRepository(project) utils.Check(err) forkProject.Owner = newRepo.Owner.Login forkProject.Name = newRepo.Name } } args.NoForward() if !flagForkNoRemote { originURL := originRemote.URL.String() url := forkProject.GitURL("", "", true) args.Before("git", "remote", "add", "-f", newRemoteName, originURL) args.Before("git", "remote", "set-url", newRemoteName, url) args.AfterFn(func() error { ui.Printf("new remote: %s\n", newRemoteName) return nil }) } }
func ciStatus(cmd *Command, args *Args) { ref := "HEAD" if !args.IsParamsEmpty() { ref = args.RemoveParam(0) } localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) sha, err := git.Ref(ref) if err != nil { err = fmt.Errorf("Aborted: no revision could be determined from '%s'", ref) } utils.Check(err) if args.Noop { ui.Printf("Would request CI status for %s\n", sha) } else { gh := github.NewClient(project.Host) response, err := gh.FetchCIStatus(project, sha) utils.Check(err) state := response.State if len(response.Statuses) == 0 { state = "" } var exitCode int switch state { case "success": exitCode = 0 case "failure", "error": exitCode = 1 case "pending": exitCode = 2 default: exitCode = 3 } if flagCiStatusVerbose && len(response.Statuses) > 0 { verboseFormat(response.Statuses) } else { if state != "" { ui.Println(state) } else { ui.Println("no status") } } os.Exit(exitCode) } }
func listIssues(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) if args.Noop { ui.Printf("Would request list of issues for %s\n", project) } else { filters := map[string]interface{}{} if cmd.FlagPassed("state") { filters["state"] = flagIssueState } if cmd.FlagPassed("assignee") { filters["assignee"] = flagIssueAssignee } issues, err := gh.FetchIssues(project, filters) utils.Check(err) maxNumWidth := 0 for _, issue := range issues { if numWidth := len(strconv.Itoa(issue.Number)); numWidth > maxNumWidth { maxNumWidth = numWidth } } colorize := ui.IsTerminal(os.Stdout) for _, issue := range issues { if issue.PullRequest != nil { continue } ui.Printf(formatIssue(issue, flagIssueFormat, colorize)) } } os.Exit(0) }
func (c *Config) PromptForUser(host string) (user string) { user = os.Getenv("GITHUB_USER") if user != "" { return } ui.Printf("%s username: ", host) user = c.scanLine() return }
func showRelease(cmd *Command, args *Args) { tagName := cmd.Arg(0) if tagName == "" { utils.Check(fmt.Errorf("Missing argument TAG")) } localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) if args.Noop { ui.Printf("Would display information for `%s' release\n", tagName) } else { release, err := gh.FetchRelease(project, tagName) utils.Check(err) body := strings.TrimSpace(release.Body) ui.Println(release.Name) if body != "" { ui.Printf("\n%s\n", body) } if flagReleaseShowDownloads { ui.Printf("\n## Downloads\n\n") for _, asset := range release.Assets { ui.Println(asset.DownloadUrl) } if release.ZipballUrl != "" { ui.Println(release.ZipballUrl) ui.Println(release.TarballUrl) } } } args.NoForward() }
func (c *Config) PromptForPassword(host, user string) (pass string) { pass = os.Getenv("GITHUB_PASSWORD") if pass != "" { return } ui.Printf("%s password for %s (never stored): ", host, user) if IsTerminal(os.Stdout) { pass = string(gopass.GetPasswd()) } else { pass = c.scanLine() } return }
func verboseFormat(statuses []github.CIStatus) { colorize := ui.IsTerminal(os.Stdout) contextWidth := 0 for _, status := range statuses { if len(status.Context) > contextWidth { contextWidth = len(status.Context) } } for _, status := range statuses { var color int var stateMarker string switch status.State { case "success": stateMarker = "✔︎" color = 32 case "failure", "error": stateMarker = "✖︎" color = 31 case "pending": stateMarker = "●" color = 33 } if colorize { stateMarker = fmt.Sprintf("\033[%dm%s\033[0m", color, stateMarker) } if status.TargetUrl == "" { ui.Printf("%s\t%s\n", stateMarker, status.Context) } else { ui.Printf("%s\t%-*s\t%s\n", stateMarker, contextWidth, status.Context, status.TargetUrl) } } }
func (c *Config) PromptForPassword(host, user string) (pass string) { pass = os.Getenv("GITHUB_PASSWORD") if pass != "" { return } ui.Printf("%s password for %s (never stored): ", host, user) if ui.IsTerminal(os.Stdin) { if password, err := getPassword(); err == nil { pass = password } } else { pass = c.scanLine() } return }
func release(cmd *Command, args *Args) { runInLocalRepo(func(localRepo *github.GitHubRepo, project *github.Project, client *github.Client) { if args.Noop { ui.Printf("Would request list of releases for %s\n", project) } else { releases, err := client.Releases(project) utils.Check(err) var outputs []string for _, release := range releases { out := fmt.Sprintf("%s (%s)\n%s", release.Name, release.TagName, release.Body) outputs = append(outputs, out) } ui.Println(strings.Join(outputs, "\n\n")) } }) }
func (updater *Updater) updateTo(releaseName, version string) (err error) { ui.Printf("Updating gh to %s...\n", version) downloadURL := fmt.Sprintf("https://%s/github/hub/releases/download/%s/hub%s_%s_%s.zip", updater.Host, releaseName, version, runtime.GOOS, runtime.GOARCH) path, err := downloadFile(downloadURL) if err != nil { return } exec, err := unzipExecutable(path) if err != nil { return } err, _ = goupdate.New().FromFile(exec) if err == nil { ui.Println("Done!") } return }
func createIssue(cmd *Command, args *Args) { runInLocalRepo(func(localRepo *github.GitHubRepo, project *github.Project, gh *github.Client) { if args.Noop { ui.Printf("Would create an issue for %s\n", project) } else { title, body, err := getTitleAndBodyFromFlags(flagIssueMessage, flagIssueFile) utils.Check(err) if title == "" { title, body, err = writeIssueTitleAndBody(project) utils.Check(err) } issue, err := gh.CreateIssue(project, title, body, flagIssueLabels) utils.Check(err) ui.Println(issue.HTMLURL) } }) }
func (updater *Updater) Update() (err error) { config := autoUpdateConfig() if config == "never" { ui.Println("Update is disabled") return } releaseName, version := updater.latestReleaseNameAndVersion() if version == "" { ui.Println("There is no newer version of hub available.") return } if version == updater.CurrentVersion { ui.Printf("You're already on the latest version: %s\n", version) } else { err = updater.updateTo(releaseName, version) } return }
func (c *Config) selectHost() *Host { options := len(c.Hosts) if options == 1 { return c.Hosts[0] } prompt := "Select host:\n" for idx, host := range c.Hosts { prompt += fmt.Sprintf(" %d. %s\n", idx+1, host.Host) } prompt += fmt.Sprint("> ") ui.Printf(prompt) index := c.scanLine() i, err := strconv.Atoi(index) if err != nil || i < 1 || i > options { utils.Check(fmt.Errorf("Error: must enter a number [1-%d]", options)) } return c.Hosts[i-1] }
func runHelp(helpCmd *Command, args *Args) { if args.IsParamsEmpty() { args.AfterFn(func() error { ui.Println(helpText) return nil }) return } if args.HasFlags("-a", "--all") { args.AfterFn(func() error { ui.Printf("\nhub custom commands\n\n %s\n", strings.Join(customCommands(), " ")) return nil }) return } command := args.FirstParam() if command == "hub" { err := displayManPage("hub.1", args) if err != nil { utils.Check(err) } } if c := lookupCmd(command); c != nil { if !args.HasFlags("--plain-text") { manPage := fmt.Sprintf("hub-%s.1", c.Name()) err := displayManPage(manPage, args) if err == nil { return } } ui.Println(c.HelpText()) args.NoForward() } }
func listReleases(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) if args.Noop { ui.Printf("Would request list of releases for %s\n", project) } else { releases, err := gh.FetchReleases(project) utils.Check(err) for _, release := range releases { if !release.Draft || flagReleaseIncludeDrafts { ui.Println(release.TagName) } } } args.NoForward() }
func printError(err error, stack string) { ui.Printf("%v\n\n", err) ui.Println(stack) }
func create(command *Command, args *Args) { _, err := git.Dir() if err != nil { err = fmt.Errorf("'create' must be run from inside a git repository") utils.Check(err) } var newRepoName string if args.IsParamsEmpty() { newRepoName, err = utils.DirName() utils.Check(err) } else { reg := regexp.MustCompile("^[^-]") if !reg.MatchString(args.FirstParam()) { err = fmt.Errorf("invalid argument: %s", args.FirstParam()) utils.Check(err) } newRepoName = args.FirstParam() } config := github.CurrentConfig() host, err := config.DefaultHost() if err != nil { utils.Check(github.FormatError("creating repository", err)) } owner := host.User if strings.Contains(newRepoName, "/") { split := strings.SplitN(newRepoName, "/", 2) owner = split[0] newRepoName = split[1] } project := github.NewProject(owner, newRepoName, host.Host) gh := github.NewClient(project.Host) var action string if gh.IsRepositoryExist(project) { ui.Printf("%s already exists on %s\n", project, project.Host) action = "set remote origin" } else { action = "created repository" if !args.Noop { repo, err := gh.CreateRepository(project, flagCreateDescription, flagCreateHomepage, flagCreatePrivate) utils.Check(err) project = github.NewProject(repo.FullName, "", project.Host) } } localRepo, err := github.LocalRepo() utils.Check(err) remote, _ := localRepo.OriginRemote() if remote == nil || remote.Name != "origin" { url := project.GitURL("", "", true) args.Replace("git", "remote", "add", "-f", "origin", url) } else { args.Replace("git", "remote", "-v") } args.After("echo", fmt.Sprintf("%s:", action), project.String()) }
func listIssues(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) if args.Noop { ui.Printf("Would request list of issues for %s\n", project) } else { flagFilters := map[string]string{ "state": flagIssueState, "assignee": flagIssueAssignee, "milestone": flagIssueMilestoneFilter, "creator": flagIssueCreator, "mentioned": flagIssueMentioned, "labels": flagIssueLabelsFilter, "sort": flagIssueSort, } filters := map[string]interface{}{} for flag, filter := range flagFilters { if cmd.FlagPassed(flag) { filters[flag] = filter } } if flagIssueSortAscending { filters["direction"] = "asc" } if cmd.FlagPassed("since") { if sinceTime, err := time.ParseInLocation("2006-01-02", flagIssueSince, time.Local); err == nil { filters["since"] = sinceTime.Format(time.RFC3339) } else { filters["since"] = flagIssueSince } } issues, err := gh.FetchIssues(project, filters) utils.Check(err) maxNumWidth := 0 for _, issue := range issues { if numWidth := len(strconv.Itoa(issue.Number)); numWidth > maxNumWidth { maxNumWidth = numWidth } } colorize := ui.IsTerminal(os.Stdout) for _, issue := range issues { if issue.PullRequest != nil { continue } ui.Printf(formatIssue(issue, flagIssueFormat, colorize)) } } args.NoForward() }
func createIssue(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) var title string var body string var editor *github.Editor if cmd.FlagPassed("message") { title, body = readMsg(flagIssueMessage) } else if cmd.FlagPassed("file") { title, body, editor, err = readMsgFromFile(flagIssueFile, flagIssueEdit, "ISSUE", "issue") utils.Check(err) } else { cs := git.CommentChar() message := strings.Replace(fmt.Sprintf(` # Creating an issue for %s # # Write a message for this issue. The first block of # text is the title and the rest is the description. `, project), "#", cs, -1) workdir, err := git.WorkdirName() utils.Check(err) template, err := github.ReadTemplate(github.IssueTemplate, workdir) utils.Check(err) if template != "" { message = template + "\n" + message } editor, err := github.NewEditor("ISSUE", "issue", message) utils.Check(err) title, body, err = editor.EditTitleAndBody() utils.Check(err) } if editor != nil { defer editor.DeleteFile() } if title == "" { utils.Check(fmt.Errorf("Aborting creation due to empty issue title")) } params := map[string]interface{}{ "title": title, "body": body, } if len(flagIssueLabels) > 0 { params["labels"] = flagIssueLabels } if len(flagIssueAssignees) > 0 { params["assignees"] = flagIssueAssignees } if flagIssueMilestone > 0 { params["milestone"] = flagIssueMilestone } args.NoForward() if args.Noop { ui.Printf("Would create issue `%s' for %s\n", params["title"], project) } else { issue, err := gh.CreateIssue(project, params) utils.Check(err) printBrowseOrCopy(args, issue.HtmlUrl, flagIssueBrowse, flagIssueCopy) } }
func sync(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) remote, err := localRepo.MainRemote() utils.Check(err) defaultBranch := localRepo.MasterBranch().ShortName() fullDefaultBranch := fmt.Sprintf("refs/remotes/%s/%s", remote.Name, defaultBranch) currentBranch := "" if curBranch, err := localRepo.CurrentBranch(); err == nil { currentBranch = curBranch.ShortName() } err = git.Spawn("fetch", "--prune", "--quiet", "--progress", remote.Name) utils.Check(err) branchToRemote := map[string]string{} if lines, err := git.ConfigAll("branch.*.remote"); err == nil { configRe := regexp.MustCompile(`^branch\.(.+?)\.remote (.+)`) for _, line := range lines { if matches := configRe.FindStringSubmatch(line); len(matches) > 0 { branchToRemote[matches[1]] = matches[2] } } } branches, err := git.LocalBranches() utils.Check(err) var green, lightGreen, red, lightRed, resetColor string if ui.IsTerminal(os.Stdout) { green = "\033[32m" lightGreen = "\033[32;1m" red = "\033[31m" lightRed = "\033[31;1m" resetColor = "\033[0m" } for _, branch := range branches { fullBranch := fmt.Sprintf("refs/heads/%s", branch) remoteBranch := fmt.Sprintf("refs/remotes/%s/%s", remote.Name, branch) gone := false if branchToRemote[branch] == remote.Name { if upstream, err := git.SymbolicFullName(fmt.Sprintf("%s@{upstream}", branch)); err == nil { remoteBranch = upstream } else { remoteBranch = "" gone = true } } else if !git.HasFile(strings.Split(remoteBranch, "/")...) { remoteBranch = "" } if remoteBranch != "" { diff, err := git.NewRange(fullBranch, remoteBranch) utils.Check(err) if diff.IsIdentical() { continue } else if diff.IsAncestor() { if branch == currentBranch { git.Quiet("merge", "--ff-only", "--quiet", remoteBranch) } else { git.Quiet("update-ref", fullBranch, remoteBranch) } ui.Printf("%sUpdated branch %s%s%s (was %s).\n", green, lightGreen, branch, resetColor, diff.A[0:7]) } else { ui.Errorf("warning: `%s' seems to contain unpushed commits\n", branch) } } else if gone { diff, err := git.NewRange(fullBranch, fullDefaultBranch) utils.Check(err) if diff.IsAncestor() { if branch == currentBranch { git.Quiet("checkout", "--quiet", defaultBranch) currentBranch = defaultBranch } git.Quiet("branch", "-D", branch) ui.Printf("%sDeleted branch %s%s%s (was %s).\n", red, lightRed, branch, resetColor, diff.A[0:7]) } else { ui.Errorf("warning: `%s' was deleted on %s, but appears not merged into %s\n", branch, remote.Name, defaultBranch) } } } args.NoForward() }
func createRelease(cmd *Command, args *Args) { if args.IsParamsEmpty() { utils.Check(fmt.Errorf("Missed argument TAG")) return } tag := args.LastParam() runInLocalRepo(func(localRepo *github.GitHubRepo, project *github.Project, client *github.Client) { release, err := client.Release(project, tag) utils.Check(err) if release == nil { commitish := flagReleaseCommitish if commitish == "" { currentBranch, err := localRepo.CurrentBranch() utils.Check(err) commitish = currentBranch.ShortName() } title, body, err := getTitleAndBodyFromFlags(flagReleaseMessage, flagReleaseFile) utils.Check(err) var editor *github.Editor if title == "" { cs := git.CommentChar() message, err := renderReleaseTpl(cs, tag, project.Name, commitish) utils.Check(err) editor, err = github.NewEditor("RELEASE", "release", message) utils.Check(err) title, body, err = editor.EditTitleAndBody() utils.Check(err) } params := octokit.ReleaseParams{ TagName: tag, TargetCommitish: commitish, Name: title, Body: body, Draft: flagReleaseDraft, Prerelease: flagReleasePrerelease, } release, err = client.CreateRelease(project, params) utils.Check(err) if editor != nil { defer editor.DeleteFile() } } if len(flagReleaseAssets) > 0 { paths := make([]string, 0) for _, asset := range flagReleaseAssets { finder := assetFinder{} p, err := finder.Find(asset) utils.Check(err) paths = append(paths, p...) } uploader := assetUploader{ Client: client, Release: release, } err = uploader.UploadAll(paths) if err != nil { ui.Println("") utils.Check(err) } } ui.Printf("\n%s\n", release.HTMLURL) }) }
func createIssue(cmd *Command, args *Args) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.MainProject() utils.Check(err) gh := github.NewClient(project.Host) var title string var body string var editor *github.Editor if cmd.FlagPassed("message") { title, body = readMsg(flagIssueMessage) } else if cmd.FlagPassed("file") { title, body, err = readMsgFromFile(flagIssueFile) utils.Check(err) } else { cs := git.CommentChar() message := strings.Replace(fmt.Sprintf(` # Creating an issue for %s # # Write a message for this issue. The first block of # text is the title and the rest is the description. `, project), "#", cs, -1) editor, err := github.NewEditor("ISSUE", "issue", message) utils.Check(err) title, body, err = editor.EditTitleAndBody() utils.Check(err) } if title == "" { utils.Check(fmt.Errorf("Aborting creation due to empty issue title")) } params := map[string]interface{}{ "title": title, "body": body, "labels": flagIssueLabels, "assignees": flagIssueAssignees, } if flagIssueMilestone > 0 { params["milestone"] = flagIssueMilestone } if args.Noop { ui.Printf("Would create issue `%s' for %s\n", params["title"], project) os.Exit(0) } else { issue, err := gh.CreateIssue(project, params) utils.Check(err) if editor != nil { editor.DeleteFile() } if flagIssueBrowse { launcher, err := utils.BrowserLauncher() utils.Check(err) args.Replace(launcher[0], "", launcher[1:]...) args.AppendParams(issue.HtmlUrl) } else { ui.Println(issue.HtmlUrl) os.Exit(0) } } }
func createRelease(cmd *Command, args *Args) { tagName := cmd.Arg(0) if tagName == "" { utils.Check(fmt.Errorf("Missing argument TAG")) return } localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.CurrentProject() utils.Check(err) gh := github.NewClient(project.Host) var title string var body string var editor *github.Editor if cmd.FlagPassed("message") { title, body = readMsg(flagReleaseMessage) } else if cmd.FlagPassed("file") { title, body, editor, err = readMsgFromFile(flagReleaseFile, flagReleaseEdit, "RELEASE", "release") utils.Check(err) } else { cs := git.CommentChar() message, err := renderReleaseTpl("Creating", cs, tagName, project.String(), flagReleaseCommitish) utils.Check(err) editor, err := github.NewEditor("RELEASE", "release", message) utils.Check(err) title, body, err = editor.EditTitleAndBody() utils.Check(err) } if title == "" { utils.Check(fmt.Errorf("Aborting release due to empty release title")) } params := &github.Release{ TagName: tagName, TargetCommitish: flagReleaseCommitish, Name: title, Body: body, Draft: flagReleaseDraft, Prerelease: flagReleasePrerelease, } var release *github.Release args.NoForward() if args.Noop { ui.Printf("Would create release `%s' for %s with tag name `%s'\n", title, project, tagName) } else { release, err = gh.CreateRelease(project, params) utils.Check(err) printBrowseOrCopy(args, release.HtmlUrl, flagReleaseBrowse, flagReleaseCopy) } if editor != nil { editor.DeleteFile() } uploadAssets(gh, release, flagReleaseAssets, args) }
func editRelease(cmd *Command, args *Args) { tagName := cmd.Arg(0) if tagName == "" { utils.Check(fmt.Errorf("Missing argument TAG")) return } localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.CurrentProject() utils.Check(err) gh := github.NewClient(project.Host) release, err := gh.FetchRelease(project, tagName) utils.Check(err) params := map[string]interface{}{} commitish := release.TargetCommitish if cmd.FlagPassed("commitish") { params["target_commitish"] = flagReleaseCommitish commitish = flagReleaseCommitish } if cmd.FlagPassed("draft") { params["draft"] = flagReleaseDraft } if cmd.FlagPassed("prerelease") { params["prerelease"] = flagReleasePrerelease } var title string var body string var editor *github.Editor if cmd.FlagPassed("message") { title, body = readMsg(flagReleaseMessage) } else if cmd.FlagPassed("file") { title, body, editor, err = readMsgFromFile(flagReleaseFile, flagReleaseEdit, "RELEASE", "release") utils.Check(err) if title == "" { utils.Check(fmt.Errorf("Aborting editing due to empty release title")) } } else { cs := git.CommentChar() message, err := renderReleaseTpl("Editing", cs, tagName, project.String(), commitish) utils.Check(err) message = fmt.Sprintf("%s\n\n%s\n%s", release.Name, release.Body, message) editor, err := github.NewEditor("RELEASE", "release", message) utils.Check(err) title, body, err = editor.EditTitleAndBody() utils.Check(err) if title == "" { utils.Check(fmt.Errorf("Aborting editing due to empty release title")) } } if title != "" { params["name"] = title } if body != "" { params["body"] = body } if len(params) > 0 { if args.Noop { ui.Printf("Would edit release `%s'\n", tagName) } else { release, err = gh.EditRelease(release, params) utils.Check(err) } if editor != nil { editor.DeleteFile() } } uploadAssets(gh, release, flagReleaseAssets, args) args.NoForward() }