Permalink
Browse files

Automate creation of GitHub PT service hook

  • Loading branch information...
1 parent 5e579e9 commit 2ffad54fd870094546e6e848c2e54e77706d0e02 @jzempel committed Apr 27, 2012
Showing with 103 additions and 50 deletions.
  1. +22 −20 continuity/cli.py
  2. +81 −30 continuity/github.py
View
@@ -89,20 +89,20 @@ def _git():
return ret_val
-def _init_github(configuration):
+def _init_github(configuration, pivotal):
"""Initialize GitHub data.
:param configuration: The GitHub configuration to intialize for.
+ :param pivotal: The Pivotal configuration to initialize for.
"""
+ git = Git()
token = configuration.get("oauth-token")
- branch = configuration.get("merge-branch")
if token:
token = _prompt("GitHub OAuth token", token)
else:
user = _prompt("GitHub user", configuration.get("user"))
password = getpass("GitHub password: ")
- git = Git()
name = "continuity:{0}".format(git.repo.working_dir)
url = "https://github.com/jzempel/continuity"
token = GitHub.create_token(user, password, name, url)
@@ -111,12 +111,16 @@ def _init_github(configuration):
puts_err("Invalid GitHub credentials.")
exit(1)
- branch = _prompt("GitHub merge branch", branch)
+ ret_val = {"oauth-token": token}
+ github = GitHub(git, token)
+ hooks = github.get_hooks()
+ token = hooks.get("pivotaltracker", {}).get("config", {}).get("token")
- return {
- "oauth-token": token,
- "merge-branch": branch
- }
+ if not token:
+ token = pivotal["api-token"]
+ github.create_hook("pivotaltracker", token=token)
+
+ return ret_val
def _init_pivotal(configuration):
@@ -128,7 +132,6 @@ def _init_pivotal(configuration):
project_id = configuration.get("project-id")
email = configuration.get("email")
owner = configuration.get("owner")
- branch = configuration.get("integration-branch")
if token:
token = _prompt("Pivotal Tracker API token", token)
@@ -173,18 +176,11 @@ def _init_pivotal(configuration):
puts_err("No Pivotal Tracker projects found.")
exit(1)
- if not branch:
- git = Git()
- branch = git.branch.name
-
- branch = _prompt("Pivotal Tracker story integration branch", branch)
-
return {
"api-token": token,
"project-id": project_id,
"email": email,
"owner": owner,
- "integration-branch": branch
}
@@ -244,7 +240,7 @@ def finish(arguments):
branch = git.branch.name
story_id = _get_story_id(git)
message = "[finish #{0}]".format(story_id)
- target = _get_section(git, "pivotal").get("integration-branch")
+ target = _get_section(git, "continuity").get("integration-branch")
git.merge_branch(target, message)
puts("Merged branch '{0}' into {1}.".format(branch, git.branch.name))
git.delete_branch(branch)
@@ -267,15 +263,19 @@ def init(arguments):
pivotal = _init_pivotal(configuration)
puts()
configuration = git.get_configuration("github")
- configuration["merge-branch"] = pivotal.get("integration-branch")
- github = _init_github(configuration)
+ github = _init_github(configuration, pivotal)
+ puts()
+ configuration = git.get_configuration("continuity")
+ branch = configuration.get("integration-branch") or git.branch.name
+ branch = _prompt("Integration branch", branch)
except KeyboardInterrupt:
puts()
puts("Initialization aborted. Changes NOT saved.")
exit()
git.set_configuration("pivotal", **pivotal)
git.set_configuration("github", **github)
+ git.set_configuration("continuity", **{"integration-branch": branch})
puts()
puts("Configured git for continuity:")
@@ -286,6 +286,8 @@ def init(arguments):
for key, value in github.iteritems():
puts("github.{0}={1}".format(key, value))
+ puts("continuity.integration-branch={0}".format(branch))
+
aliases = {
"finish": "!continuity finish \"$@\"",
"review": "!continuity review \"$@\"",
@@ -344,7 +346,7 @@ def review(arguments):
description = story.url
git.push_branch()
- branch = _get_value(git, "github", "merge-branch")
+ branch = _get_value(git, "continuity", "integration-branch")
pull_request = github.create_pull_request(title, description,
branch)
puts("Opened pull request: {0}".format(pull_request["url"]))
View
@@ -10,7 +10,7 @@
"""
from json import dumps, loads
-from requests import post, RequestException
+from requests import request, RequestException
import re
@@ -36,33 +36,58 @@ def __init__(self, git, token):
else:
raise GitHubException("No github remote configured.")
+ def _repo_request(self, method, resource, **kwargs):
+ """Send a GitHub repo request.
+
+ :param method: The HTTP method.
+ :param resource: The repo URL resource.
+ :param kwargs: Request keyword-arguments.
+ """
+ match = re.match(self.PATTERN_REPOSITORY, self.git.remote.url)
+ repository = match.group("repository")
+ path = "repos/{0}/{1}".format(repository, resource)
+ headers = kwargs.get("headers", {})
+ headers["Authorization"] = "token {0}".format(self.token)
+ kwargs["headers"] = headers
+
+ return GitHub._request(method, path, **kwargs)
+
@staticmethod
- def create_token(user, password, name, url=None, scopes=["repo"]):
- """Create an OAuth token for the given user.
+ def _request(method, resource, **kwargs):
+ """Send a GitHub request.
- :param user: The GitHub user to create a token for.
- :param password: The user password.
- :param name: The name for the token.
- :param url: Default `None`. A URL associated with the token.
- :param scopes: Default `['repo']`. A list of scopes this token is for.
+ :param method: The HTTP method.
+ :param resource: The URI resource.
+ :param kwargs: Request keyword-arguments.
"""
- url = GitHub.URI_TEMPLATE.format("authorizations")
- data = {
- "scopes": scopes,
- "note": name,
- "note_url": url
- }
- auth = (user, password)
- response = post(url, data=dumps(data), auth=auth, verify=False)
+ url = GitHub.URI_TEMPLATE.format(resource)
+ kwargs["verify"] = False
+
+ if "data" in kwargs:
+ kwargs["data"] = dumps(kwargs["data"])
+
+ response = request(method, url, **kwargs)
try:
response.raise_for_status()
- authorization = loads(response.content)
- ret_val = authorization["token"]
except RequestException, e:
- ret_val = None
+ raise GitHubException(e)
- return ret_val
+ return loads(response.content)
+
+ def create_hook(self, name, **kwargs):
+ """Create a hook.
+
+ :param name: The name for this hook (see https://api.github.com/hooks).
+ :param kwargs: Configuration keyword-arguments.
+ """
+ data = {
+ "name": name,
+ "config": kwargs,
+ "active": True
+ }
+
+ return self._repo_request("post", "hooks", data=data)
def create_pull_request(self, title, description=None, branch=None):
"""Create a pull request.
@@ -72,22 +97,48 @@ def create_pull_request(self, title, description=None, branch=None):
pull request.
:param branch: Default `None`. The base branch the pull request is for.
"""
- match = re.match(self.PATTERN_REPOSITORY, self.git.remote.url)
- repository = match.group("repository")
- path = "repos/{0}/pulls".format(repository)
- url = self.URI_TEMPLATE.format(path)
data = {
"title": title,
"body": description,
"head": self.git.branch.name,
"base": branch or "master"
}
- headers = {"Authorization": "token {0}".format(self.token)}
- response = post(url, data=dumps(data), headers=headers, verify=False)
+
+ return self._repo_request("post", "pulls", data=data)
+
+ @staticmethod
+ def create_token(user, password, name, url=None, scopes=["repo"]):
+ """Create an OAuth token for the given user.
+
+ :param user: The GitHub user to create a token for.
+ :param password: The user password.
+ :param name: The name for the token.
+ :param url: Default `None`. A URL associated with the token.
+ :param scopes: Default `['repo']`. A list of scopes this token is for.
+ """
+ data = {
+ "scopes": scopes,
+ "note": name,
+ "note_url": url
+ }
+ auth = (user, password)
try:
- response.raise_for_status()
- except RequestException, e:
- raise GitHubException(e)
+ response = GitHub._request("post", "authorizations", data=data,
+ auth=auth)
+ ret_val = response["token"]
+ except GitHubException:
+ ret_val = None
- return loads(response.content)
+ return ret_val
+
+ def get_hooks(self):
+ ret_val = {}
+ hooks = self._repo_request("get", "hooks")
+
+ for hook in hooks:
+ name = hook["name"]
+ del hook["name"]
+ ret_val[name] = hook
+
+ return ret_val

0 comments on commit 2ffad54

Please sign in to comment.