Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

`hub merge` should use GitHub's merge-button API #273

Closed
wants to merge 8 commits into from

2 participants

@wking

The hub merge functionality implemented in #164 creates the merge commit locally, but leaves the pull request open. It would be better to use GitHub's merge-button API directly. I'm agnostic on whether the commit created using the merge-button API should be fetched and merged locally after it is created on GitHub.

@wking

Fixing this should make #186 a good deal easier.

@wking

As I say in the 4a7b507 commit message, this is pull request is a work in progress. I'll put off changes to the code until I hear some positive comments on the revised scenarios (and possibly make further scenario revisions).

@wking wking referenced this pull request in swcarpentry/boot-camps
Merged

SQL cheat sheet #7

wking added some commits
@wking wking WIP merge.feature: Rework pull-request merges for the merge-button
I'm not sure if the second (private) merge is supposed to succeed or
not.  I'm also not sure if `hub merge …pull/…` should update the local
branch to reflect the changes (making it more like `git merge`) or if
the user should do that with a traditional Git fetch/merge (making it
more like the GitHub Merge Button).
d62de6b
@wking wking github_api.rb: Add PUT support
Parameter processing should be shared between POST and PUT.
95ea261
@wking wking referenced this pull request from a commit in wking/email-issue-reply-testing
@wking wking Testing for github/hub#273 1f1f707
wking added some commits
@wking wking github_api.rb: Add GitHub Merge Button (TM) support 7cbcfd5
@wking wking commands.rb: Add a 'merge-button' command
This may be sufficiently different from Git's 'merge' command to
deserve its own name.
b12e4ca
@wking wking commands.rb: Teach merge-button the '-m COMMIT_MESSAGE' option a772761
@wking wking commands.rb: Teach merge-button the '-i PULL_ID' option
I also make the successful-merge message more explicit
($owner/$repo#$pull_id), now that the source project may be
auto-detected.
043159a
@wking

I haven't heard anything with respect to d62de6b, so here's an implementation that adds a new merge-button command. Having a new command reduces the surprise when we don't touch the local repository. No tests yet, I'll wait for some feedback first.

@mislav
Admin

Thanks for all the work on this, but I've decided I don't want to use the Merge Button API from hub. The Merge Button was created for scenarios where you don't have the git repository at hand. Since with hub you have the repo, it would make more sense to make a real merge and mark the pull-request as closed.

However, I don't want to mark the PR as closed immediately after merge, but only when the merge is pushed. I have to think about how to achieve this technically

@wking
@mislav
Admin

I'd have hub merge cache the PR ID and merge commit hash in $GIT_DIR/hub-merge. Then you'd need a hub push hook to see when you were pushing that commit hash to GitHub

That's a good suggestion!

Personally, I think it would be better to add a new --close option to hub merge (for cases where you know you're going to push the merge immediately). I'd also add --close SHA1 -i ISSUE processing to hub pull-request

Not sure, it sounds like too complex syntax to remember, and the whole workflow is a bit too manual for my taste. In most cases I would rather add new commands than new flags to existing commands

@wking
@wking
wking added some commits
@wking wking Document the 'merge-button' command 1dcd569
@wking wking commands.rb: Extend 'display_api_exception' to print error messages
So you can see what GitHub is complaining about.  For example,

  $ hub merge-button https://github.com/defunkt/hub/pull/9999999999
  Error pushing merge button: Not Found (HTTP 404)
  #<Net::HTTPNotFound:0x7f4cf845c670>
  {"message":"Not Found"}

This was useful for debugging, when I originally thought that the
whole PUT body was optional if you didn't want to specify
'commit_message'.  In that case, I got:

  $ hub merge-button wking/email-issue-reply-testing#2
  Error pushing merge button: Bad Request (HTTP 400)
  #<Net::HTTPBadRequest:0x7f944f75a450>
  {"message":"Body should be a JSON Hash"}

Which is a lot more helpful than just "Bad Request".  It would be nice
if the 'Net::HTTP*' object hash was not printed, but I lack sufficient
Ruby-foo to know how to do that.
95f45ee
@mislav mislav referenced this pull request in git-merge/hack-day
Closed

Improving `pull-request` and other features of hub CLI tool #1

@mislav
Admin

I'm going to close this since I already explained why I don't want to go in the Merge Button API direction. Here's the current state of things:

  • When you merge a pull request with hub merge and push it to the master branch, GitHub will detect the merge commit and automatically close the PR. So I guess the original problem that this issue was about got solved.
  • If you cherry-pick, rebase, or otherwise change the pull request commit SHA, GitHub won't be able to detect that the PR landed in master and you'll have to close the PR manually.
@mislav mislav closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 15, 2013
  1. @wking

    WIP merge.feature: Rework pull-request merges for the merge-button

    wking authored
    I'm not sure if the second (private) merge is supposed to succeed or
    not.  I'm also not sure if `hub merge …pull/…` should update the local
    branch to reflect the changes (making it more like `git merge`) or if
    the user should do that with a traditional Git fetch/merge (making it
    more like the GitHub Merge Button).
  2. @wking

    github_api.rb: Add PUT support

    wking authored
    Parameter processing should be shared between POST and PUT.
  3. @wking
  4. @wking

    commands.rb: Add a 'merge-button' command

    wking authored
    This may be sufficiently different from Git's 'merge' command to
    deserve its own name.
  5. @wking
  6. @wking

    commands.rb: Teach merge-button the '-i PULL_ID' option

    wking authored
    I also make the successful-merge message more explicit
    ($owner/$repo#$pull_id), now that the source project may be
    auto-detected.
Commits on Jan 25, 2013
  1. @wking
  2. @wking

    commands.rb: Extend 'display_api_exception' to print error messages

    wking authored
    So you can see what GitHub is complaining about.  For example,
    
      $ hub merge-button https://github.com/defunkt/hub/pull/9999999999
      Error pushing merge button: Not Found (HTTP 404)
      #<Net::HTTPNotFound:0x7f4cf845c670>
      {"message":"Not Found"}
    
    This was useful for debugging, when I originally thought that the
    whole PUT body was optional if you didn't want to specify
    'commit_message'.  In that case, I got:
    
      $ hub merge-button wking/email-issue-reply-testing#2
      Error pushing merge button: Bad Request (HTTP 400)
      #<Net::HTTPBadRequest:0x7f944f75a450>
      {"message":"Body should be a JSON Hash"}
    
    Which is a lot more helpful than just "Bad Request".  It would be nice
    if the 'Net::HTTP*' object hash was not printed, but I lack sufficient
    Ruby-foo to know how to do that.
This page is out of date. Refresh to see the latest.
View
14 README.md
@@ -257,6 +257,20 @@ superpowers:
> git fetch git://github.com/mislav/hub.git +refs/heads/feature:refs/remotes/mislav/feature
> git merge mislav/feature --no-ff -m 'Merge pull request #73 from mislav/feature...'
+### git merge-button
+
+ # explicit owner/repo
+ $ git merge-button https://github.com/defunkt/hub/pull/73
+ [ push the GitHub Merge Button (TM) for pull request #73 ]
+
+ # use the owner/repo referenced by the "origin" remote
+ $ git merge-button -i 73
+ [ push the GitHub Merge Button (TM) for pull request #73 ]
+
+ # add additional comments to the merge commit
+ $ git merge-button -m 'This fixes #some-bug.' -i 73
+ [ push the GitHub Merge Button (TM) for pull request #73 ]
+
### git create
$ git create
View
13 features/merge.feature
@@ -18,13 +18,11 @@ Feature: hub merge
"""
And there is a commit named "jfirebaugh/hub_merge"
When I successfully run `hub merge https://github.com/defunkt/hub/pull/164`
- Then "git fetch git://github.com/jfirebaugh/hub.git +refs/heads/hub_merge:refs/remotes/jfirebaugh/hub_merge" should be run
- When I successfully run `git show -s --format=%B`
+ And I successfully run `git fetch origin`
+ And I successfully run `git log --oneline HEAD..origin/master`
Then the output should contain:
"""
Merge pull request #164 from jfirebaugh/hub_merge
-
- Add `hub merge` command
"""
Scenario: Merge private pull request
@@ -41,7 +39,12 @@ Feature: hub merge
"""
And there is a commit named "jfirebaugh/hub_merge"
When I successfully run `hub merge https://github.com/defunkt/hub/pull/164`
- Then "git fetch git@github.com:jfirebaugh/hub.git +refs/heads/hub_merge:refs/remotes/jfirebaugh/hub_merge" should be run
+ And I successfully run `git fetch origin`
+ And I successfully run `git log --oneline HEAD..origin/master`
+ Then the output should contain:
+ """
+ Merge pull request #164 from jfirebaugh/hub_merge
+ """
Scenario: Missing repo
Given the GitHub API server:
View
50 lib/hub/commands.rb
@@ -38,7 +38,7 @@ module Commands
OWNER_RE = /[a-zA-Z0-9-]+/
NAME_WITH_OWNER_RE = /^(?:#{NAME_RE}|#{OWNER_RE}\/#{NAME_RE})$/
- CUSTOM_COMMANDS = %w[alias create browse compare fork pull-request]
+ CUSTOM_COMMANDS = %w[alias create browse compare fork pull-request merge-button]
def run(args)
slurp_global_flags(args)
@@ -362,6 +362,48 @@ def checkout(args)
end
end
+ # $ git merge-button https://github.com/defunkt/hub/pull/73
+ # > push the GitHub Merge Button (TM) for #73
+ def merge_button(args)
+ args.shift
+ project = local_repo.main_project
+ pull_id = commit_message = nil
+ while arg = args.shift
+ case arg
+ when '-m'
+ commit_message = args.shift
+ when '-i'
+ pull_id = args.shift
+ else
+ if url = resolve_github_url(arg) and url.project_path =~ /^pull\/(\d+)/
+ pull_id = $1
+ project = url.project
+ else
+ abort "invalid argument: #{arg}"
+ end
+ end
+ end
+ if !project
+ abort "usage: project not specified"
+ end
+ if !pull_id
+ abort "usage: pull ID not specified"
+ end
+ options = {
+ :project => project,
+ :pull_id => pull_id,
+ }
+ if commit_message
+ options[:commit_message] = commit_message
+ end
+ merge = api_client.merge_pullrequest(options)
+ args.executable = 'echo'
+ args.replace ['merged', '%s#%s' % [project.name_with_owner, pull_id]]
+ rescue GitHubAPI::Exceptions
+ display_api_exception("pushing merge button", $!.response, $!.data)
+ exit 1
+ end
+
# $ git merge https://github.com/defunkt/hub/pull/73
# > git fetch git://github.com/mislav/hub.git +refs/heads/feature:refs/remotes/mislav/feature
# > git merge mislav/feature --no-ff -m 'Merge pull request #73 from mislav/feature...'
@@ -815,6 +857,7 @@ def improved_help_text
GitHub Commands:
pull-request Open a pull request on GitHub
+ merge-button Push the GitHub Merge Button (TM) for a pull request
fork Make a fork of a remote repository on GitHub and add as remote
create Create this repository on GitHub and add GitHub as origin
browse Open a GitHub page in the default browser
@@ -1005,8 +1048,11 @@ def expand_alias(cmd)
end
end
- def display_api_exception(action, response)
+ def display_api_exception(action, response, message=nil)
$stderr.puts "Error #{action}: #{response.message.strip} (HTTP #{response.status})"
+ if message
+ $stderr.puts message
+ end
if 422 == response.status and response.error_message?
# display validation errors
msg = response.error_message
View
25 lib/hub/github_api.rb
@@ -110,6 +110,21 @@ def create_pullrequest options
res.data
end
+ # Press the GitHub Merge Button (TM) for a given pull request.
+ def merge_pullrequest options
+ project = options.fetch(:project)
+ pull_id = options.fetch(:pull_id)
+ params = {}
+ if options[:commit_message]
+ params[:commit_message] = options.fetch(:commit_message)
+ end
+ res = put "https://%s/repos/%s/%s/pulls/%s/merge" %
+ [api_host(project.host), project.owner, project.name, pull_id], params
+
+ res.error! unless res.success?
+ res.data
+ end
+
# Methods for performing HTTP requests
#
# Requires access to a `config` object that implements:
@@ -146,7 +161,15 @@ def get url, &block
end
def post url, params = nil
- perform_request url, :Post do |req|
+ _post url, :Post, params
+ end
+
+ def put url, params = nil
+ _post url, :Put, params
+ end
+
+ def _post url, type, params = nil
+ perform_request url, type do |req|
if params
req.body = JSON.dump params
req['Content-Type'] = 'application/json;charset=utf-8'
View
10 man/hub.1
@@ -63,6 +63,9 @@
.br
\fBgit pull\-request\fR [\fB\-f\fR] [\fITITLE\fR|\fB\-i\fR \fIISSUE\fR] [\fB\-b\fR \fIBASE\fR] [\fB\-h\fR \fIHEAD\fR]
.
+.br
+\fBgit merge\-button\fR [\fB\-m\fR \fIMESSAGE\fR] (\fB\-i\fR \fIPULLREQ\-ID\fR|\fIPULLREQ\-URL\fR)
+.
.SH "DESCRIPTION"
hub enhances various git commands to ease most common workflows with GitHub\.
.
@@ -151,6 +154,13 @@ If \fITITLE\fR is omitted, a text editor will open in which title and body of th
.IP
If instead of normal \fITITLE\fR an issue number is given with \fB\-i\fR, the pull request will be attached to an existing GitHub issue\. Alternatively, instead of title you can paste a full URL to an issue on GitHub\.
.
+.TP
+\fBgit merge\-button\fR [\fB\-m\fR \fIMESSAGE\fR] (\fB\-i\fR \fIPULLREQ\-ID\fR|\fIPULLREQ\-URL\fR)
+Push the GitHub Merge Button (TM) for the pull request\. The pull request may be specified with either the full GitHub URL or the \fB-i\fR flag\. With \fB-i\fR, the "owner/repo" defaults to the project that the "origin" remote points to.
+.
+.IP
+If \fIMESSAGE\fR is given, it is used as the body of the commit message. The summary line will still be GitHub's usual Merge Button summary.
+.
.SH "CONFIGURATION"
Hub will prompt for GitHub username & password the first time it needs to access the API and exchange it for an OAuth token, which it saves in "~/\.config/hub"\.
.
View
13 man/hub.1.html
@@ -100,7 +100,8 @@ <h3 id="Custom-git-commands-">Custom git commands:</h3>
<code>git browse</code> [<code>-u</code>] [[<var>USER</var><code>/</code>]<var>REPOSITORY</var>] [SUBPAGE]<br />
<code>git compare</code> [<code>-u</code>] [<var>USER</var>] [<var>START</var>...]<var>END</var><br />
<code>git fork</code> [<code>--no-remote</code>]<br />
-<code>git pull-request</code> [<code>-f</code>] [<var>TITLE</var>|<code>-i</code> <var>ISSUE</var>] [<code>-b</code> <var>BASE</var>] [<code>-h</code> <var>HEAD</var>]</p>
+<code>git pull-request</code> [<code>-f</code>] [<var>TITLE</var>|<code>-i</code> <var>ISSUE</var>] [<code>-b</code> <var>BASE</var>] [<code>-h</code> <var>HEAD</var>]<br />
+<code>git merge-button</code> [<code>-m</code> <var>MESSAGE</var>] (<code>-i</code> <var>PULLREQ-ID</var>|<var>PULLREQ-URL</var>)</p>
<h2 id="DESCRIPTION">DESCRIPTION</h2>
@@ -191,6 +192,16 @@ <h2 id="DESCRIPTION">DESCRIPTION</h2>
<p>If instead of normal <var>TITLE</var> an issue number is given with <code>-i</code>, the pull
request will be attached to an existing GitHub issue. Alternatively, instead
of title you can paste a full URL to an issue on GitHub.</p></dd>
+<dt><code>git merge-button</code> [<code>-m</code> <var>MESSAGE</var>] (<code>-i</code>
+<var>PULLREQ-ID</var>|<var>PULLREQ-URL</var>)</dt>
+<dd><p>Push the GitHub Merge Button (TM) for the pull request. The
+pull request may be specified with either the full GitHub URL or
+the <code>-i</code> flag. With <code>-i</code>, the "owner/repo"
+defaults to the project that the "origin" remote points to.</p>
+
+<p>If <var>MESSAGE</var> is given, it is used as the body of the
+commit message. The summary line will still be GitHub's usual Merge
+Button summary.</p></dd>
</dl>
View
11 man/hub.1.ronn
@@ -28,6 +28,7 @@ hub(1) -- git + hub = github
`git compare` [`-u`] [<USER>] [<START>...]<END>
`git fork` [`--no-remote`]
`git pull-request` [`-f`] [<TITLE>|`-i` <ISSUE>] [`-b` <BASE>] [`-h` <HEAD>]
+`git merge-button` [`-m` <MESSAGE>] (`-i` <PULLREQ-ID>|<PULLREQ-URL>)
## DESCRIPTION
@@ -151,6 +152,16 @@ hub also adds some custom commands that are otherwise not present in git:
request will be attached to an existing GitHub issue. Alternatively, instead
of title you can paste a full URL to an issue on GitHub.
+ * `git merge-button` [`-m` <MESSAGE>] (`-i` <PULLREQ-ID>|<PULLREQ-URL>):
+ Push the GitHub Merge Button (TM) for the pull request. The pull
+ request may be specified with either the full GitHub URL or the
+ `-i` flag. With `-i`, the "owner/repo" defaults to the project
+ that the "origin" remote points to.
+
+ If <MESSAGE> is given, it is used as the body of the commit
+ message. The summary line will still be GitHub's usual Merge
+ Button summary.
+
## CONFIGURATION
Hub will prompt for GitHub username & password the first time it needs to access
Something went wrong with that request. Please try again.