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 fetchCiStatus(p *github.Project, sha string) (state, targetURL string, exitCode int, err error) { gh := github.NewClient(p.Host) status, err := gh.CIStatus(p, sha) if err != nil { return } if status == nil { state = "no status" } else { state = status.State targetURL = status.TargetURL } switch state { case "success": exitCode = 0 case "failure", "error": exitCode = 1 case "pending": exitCode = 2 default: exitCode = 3 } return }
func tranformFetchArgs(args *Args) error { names := parseRemoteNames(args) localRepo, err := github.LocalRepo() utils.Check(err) currentProject, currentProjectErr := localRepo.CurrentProject() projects := make(map[*github.Project]bool) ownerRegexp := regexp.MustCompile(fmt.Sprintf("^%s$", OwnerRe)) for _, name := range names { if ownerRegexp.MatchString(name) && !isCloneable(name) { _, err := localRepo.RemoteByName(name) if err != nil { utils.Check(currentProjectErr) project := github.NewProject(name, currentProject.Name, "") gh := github.NewClient(project.Host) repo, err := gh.Repository(project) if err != nil { continue } projects[project] = repo.Private } } } for project, private := range projects { args.Before("git", "remote", "add", project.Owner, project.GitURL("", "", private)) } return nil }
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() { dirName, err := git.WorkdirName() utils.Check(err) newRepoName = github.SanitizeProjectName(dirName) } 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) if gh.IsRepositoryExist(project) { ui.Errorln("Existing repository detected. Updating git remote") } else { 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.Before("git", "remote", "add", "-f", "origin", url) } webUrl := project.WebURL("", "", "") args.NoForward() printBrowseOrCopy(args, webUrl, flagCreateBrowse, flagCreateCopy) }
func transformApplyArgs(args *Args) { gistRegexp := regexp.MustCompile("^https?://gist\\.github\\.com/([\\w.-]+/)?([a-f0-9]+)") pullRegexp := regexp.MustCompile("^(pull|commit)/([0-9a-f]+)") for _, arg := range args.Params { var ( patch io.ReadCloser apiError error ) projectURL, err := github.ParseURL(arg) if err == nil { gh := github.NewClient(projectURL.Project.Host) match := pullRegexp.FindStringSubmatch(projectURL.ProjectPath()) if match != nil { if match[1] == "pull" { patch, apiError = gh.PullRequestPatch(projectURL.Project, match[2]) } else { patch, apiError = gh.CommitPatch(projectURL.Project, match[2]) } } } else { match := gistRegexp.FindStringSubmatch(arg) if match != nil { // TODO: support Enterprise gist gh := github.NewClient(github.GitHubHost) patch, apiError = gh.GistPatch(match[2]) } } utils.Check(apiError) if patch == nil { continue } idx := args.IndexOfParam(arg) patchFile, err := ioutil.TempFile("", "hub") utils.Check(err) _, err = io.Copy(patchFile, patch) utils.Check(err) patchFile.Close() patch.Close() args.Params[idx] = patchFile.Name() } }
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 transformMergeArgs(args *Args) error { words := args.Words() if len(words) == 0 { return nil } mergeURL := words[0] url, err := github.ParseURL(mergeURL) if err != nil { return nil } pullURLRegex := regexp.MustCompile("^pull/(\\d+)") projectPath := url.ProjectPath() if !pullURLRegex.MatchString(projectPath) { return nil } id := pullURLRegex.FindStringSubmatch(projectPath)[1] gh := github.NewClient(url.Project.Host) pullRequest, err := gh.PullRequest(url.Project, id) if err != nil { return err } repo, err := github.LocalRepo() if err != nil { return err } remote, err := repo.RemoteForRepo(pullRequest.Base.Repo) if err != nil { return err } branch := pullRequest.Head.Ref headRepo := pullRequest.Head.Repo if headRepo == nil { return fmt.Errorf("Error: that fork is not available anymore") } args.Before("git", "fetch", remote.Name, fmt.Sprintf("refs/pull/%s/head", id)) // Remove pull request URL idx := args.IndexOfParam(mergeURL) args.RemoveParam(idx) mergeMsg := fmt.Sprintf("Merge pull request #%s from %s/%s\n\n%s", id, headRepo.Owner.Login, branch, pullRequest.Title) args.AppendParams("FETCH_HEAD", "-m", mergeMsg) if args.IndexOfParam("--ff-only") == -1 && args.IndexOfParam("--squash") == -1 && args.IndexOfParam("--ff") == -1 { i := args.IndexOfParam("-m") args.InsertParam(i, "--no-ff") } 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 runInLocalRepo(fn func(localRepo *github.GitHubRepo, project *github.Project, client *github.Client)) { localRepo, err := github.LocalRepo() utils.Check(err) project, err := localRepo.CurrentProject() utils.Check(err) client := github.NewClient(project.Host) fn(localRepo, project, client) os.Exit(0) }
func transformCloneArgs(args *Args) { isSSH := parseClonePrivateFlag(args) hasValueRegxp := regexp.MustCompile("^(--(upload-pack|template|depth|origin|branch|reference|name)|-[ubo])$") nameWithOwnerRegexp := regexp.MustCompile(NameWithOwnerRe) for i := 0; i < args.ParamsSize(); i++ { a := args.Params[i] if strings.HasPrefix(a, "-") { if hasValueRegxp.MatchString(a) { i++ } } else { if nameWithOwnerRegexp.MatchString(a) && !isDir(a) { name, owner := parseCloneNameAndOwner(a) var host *github.Host if owner == "" { config := github.CurrentConfig() h, err := config.DefaultHost() if err != nil { utils.Check(github.FormatError("cloning repository", err)) } host = h owner = host.User } var hostStr string if host != nil { hostStr = host.Host } project := github.NewProject(owner, name, hostStr) if !isSSH && args.Command != "submodule" && !github.IsHttpsProtocol() { client := github.NewClient(project.Host) repo, err := client.Repository(project) isSSH = (err == nil) && (repo.Private || repo.Permissions.Push) } url := project.GitURL(name, owner, isSSH) args.ReplaceParam(i, url) } break } } }
func discover(cmd *Command, args *Args) { if args.ParamsSize() < 1 { utils.Check(fmt.Errorf("Error: you must specify a username.")) } client := github.NewClient(github.GitHubHost) repos, err := client.Repositories(args.GetParam(0)) if err != nil { utils.Check(err) } for _, repo := range repos { fmt.Println(repo.Name) } os.Exit(0) }
func parseCherryPickProjectAndSha(ref string) (project *github.Project, sha string, isPrivate bool) { shaRe := "[a-f0-9]{7,40}" var mainProject *github.Project localRepo, mainProjectErr := github.LocalRepo() if mainProjectErr == nil { mainProject, mainProjectErr = localRepo.MainProject() } url, err := github.ParseURL(ref) if err == nil { projectPath := url.ProjectPath() commitRegex := regexp.MustCompile(fmt.Sprintf("^commit/(%s)", shaRe)) if matches := commitRegex.FindStringSubmatch(projectPath); len(matches) > 0 { sha = matches[1] project = url.Project return } pullRegex := regexp.MustCompile(fmt.Sprintf(`^pull/(\d+)/commits/(%s)`, shaRe)) if matches := pullRegex.FindStringSubmatch(projectPath); len(matches) > 0 { pullId := matches[1] sha = matches[2] utils.Check(mainProjectErr) api := github.NewClient(mainProject.Host) pullRequest, err := api.PullRequest(url.Project, pullId) utils.Check(err) headRepo := pullRequest.Head.Repo project = github.NewProject(headRepo.Owner.Login, headRepo.Name, mainProject.Host) isPrivate = headRepo.Private return } } ownerWithShaRegexp := regexp.MustCompile(fmt.Sprintf("^(%s)@(%s)$", OwnerRe, shaRe)) if matches := ownerWithShaRegexp.FindStringSubmatch(ref); len(matches) > 0 { utils.Check(mainProjectErr) project = mainProject project.Owner = matches[1] sha = matches[2] } return }
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 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 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 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 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 transformCheckoutArgs(args *Args) error { words := args.Words() if len(words) == 0 { return nil } checkoutURL := words[0] var newBranchName string if len(words) > 1 { newBranchName = words[1] } url, err := github.ParseURL(checkoutURL) if err != nil { // not a valid GitHub URL return nil } pullURLRegex := regexp.MustCompile("^pull/(\\d+)") projectPath := url.ProjectPath() if !pullURLRegex.MatchString(projectPath) { // not a valid PR URL return nil } err = sanitizeCheckoutFlags(args) if err != nil { return err } id := pullURLRegex.FindStringSubmatch(projectPath)[1] gh := github.NewClient(url.Project.Host) pullRequest, err := gh.PullRequest(url.Project, id) if err != nil { return err } if idx := args.IndexOfParam(newBranchName); idx >= 0 { args.RemoveParam(idx) } repo, err := github.LocalRepo() if err != nil { return err } baseRemote, err := repo.RemoteForRepo(pullRequest.Base.Repo) if err != nil { return err } var headRemote *github.Remote if pullRequest.IsSameRepo() { headRemote = baseRemote } else if pullRequest.Head.Repo != nil { headRemote, _ = repo.RemoteForRepo(pullRequest.Head.Repo) } var newArgs []string if headRemote != nil { if newBranchName == "" { newBranchName = pullRequest.Head.Ref } remoteBranch := fmt.Sprintf("%s/%s", headRemote.Name, pullRequest.Head.Ref) refSpec := fmt.Sprintf("+refs/heads/%s:refs/remotes/%s", pullRequest.Head.Ref, remoteBranch) if git.HasFile("refs", "heads", newBranchName) { newArgs = append(newArgs, newBranchName) args.After("git", "merge", "--ff-only", fmt.Sprintf("refs/remotes/%s", remoteBranch)) } else { newArgs = append(newArgs, "-b", newBranchName, "--track", remoteBranch) } args.Before("git", "fetch", headRemote.Name, refSpec) } else { if newBranchName == "" { if pullRequest.Head.Repo == nil { newBranchName = fmt.Sprintf("pr-%s", id) } else { newBranchName = fmt.Sprintf("%s-%s", pullRequest.Head.Repo.Owner.Login, pullRequest.Head.Ref) } } refSpec := fmt.Sprintf("refs/pull/%s/head:%s", id, newBranchName) newArgs = append(newArgs, newBranchName) args.Before("git", "fetch", baseRemote.Name, refSpec) } replaceCheckoutParam(args, checkoutURL, newArgs...) return nil }
func transformCheckoutArgs(args *Args) error { words := args.Words() if len(words) == 0 { return nil } checkoutURL := words[0] var newBranchName string if len(words) > 1 { newBranchName = words[1] } url, err := github.ParseURL(checkoutURL) if err != nil { // not a valid GitHub URL return nil } pullURLRegex := regexp.MustCompile("^pull/(\\d+)") projectPath := url.ProjectPath() if !pullURLRegex.MatchString(projectPath) { // not a valid PR URL return nil } err = sanitizeCheckoutFlags(args) if err != nil { return err } id := pullURLRegex.FindStringSubmatch(projectPath)[1] gh := github.NewClient(url.Project.Host) pullRequest, err := gh.PullRequest(url.Project, id) if err != nil { return err } if idx := args.IndexOfParam(newBranchName); idx >= 0 { args.RemoveParam(idx) } branch := pullRequest.Head.Ref headRepo := pullRequest.Head.Repo if headRepo == nil { return fmt.Errorf("Error: that fork is not available anymore") } user := headRepo.Owner.Login if newBranchName == "" { newBranchName = fmt.Sprintf("%s-%s", user, branch) } repo, err := github.LocalRepo() utils.Check(err) _, err = repo.RemoteByName(user) if err == nil { args.Before("git", "remote", "set-branches", "--add", user, branch) remoteURL := fmt.Sprintf("+refs/heads/%s:refs/remotes/%s/%s", branch, user, branch) args.Before("git", "fetch", user, remoteURL) } else { u := url.Project.GitURL(pullRequest.Head.Repo.Name, user, pullRequest.Head.Repo.Private) args.Before("git", "remote", "add", "-f", "--no-tags", "-t", branch, user, u) } remoteName := fmt.Sprintf("%s/%s", user, branch) replaceCheckoutParam(args, checkoutURL, newBranchName, remoteName) return nil }
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() }
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 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 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 transformCloneArgs(args *Args) { isSSH := parseClonePrivateFlag(args) hasValueRegxp := regexp.MustCompile("^(--(upload-pack|template|depth|origin|branch|reference|name)|-[ubo])$") nameWithOwnerRegexp := regexp.MustCompile(NameWithOwnerRe) for i := 0; i < args.ParamsSize(); i++ { a := args.Params[i] if strings.HasPrefix(a, "-") { if hasValueRegxp.MatchString(a) { i++ } } else { if nameWithOwnerRegexp.MatchString(a) && !isCloneable(a) { name, owner := parseCloneNameAndOwner(a) var host *github.Host if owner == "" { config := github.CurrentConfig() h, err := config.DefaultHost() if err != nil { utils.Check(github.FormatError("cloning repository", err)) } host = h owner = host.User } var hostStr string if host != nil { hostStr = host.Host } expectWiki := strings.HasSuffix(name, ".wiki") if expectWiki { name = strings.TrimSuffix(name, ".wiki") } project := github.NewProject(owner, name, hostStr) gh := github.NewClient(project.Host) repo, err := gh.Repository(project) if err != nil { if strings.Contains(err.Error(), "HTTP 404") { err = fmt.Errorf("Error: repository %s/%s doesn't exist", project.Owner, project.Name) } utils.Check(err) } owner = repo.Owner.Login name = repo.Name if expectWiki { if !repo.HasWiki { utils.Check(fmt.Errorf("Error: %s/%s doesn't have a wiki", owner, name)) } else { name = name + ".wiki" } } if !isSSH && args.Command != "submodule" && !github.IsHttpsProtocol() { isSSH = repo.Private || repo.Permissions.Push } url := project.GitURL(name, owner, isSSH) args.ReplaceParam(i, url) } break } } }