Skip to content

Commit

Permalink
Merge pull request #44 from JuliaWeb/partial-docs
Browse files Browse the repository at this point in the history
docs + clean up pagination code + a bunch of minor changes
  • Loading branch information
jrevels committed Dec 2, 2015
2 parents a3facf3 + 4dd2c39 commit 168393d
Show file tree
Hide file tree
Showing 19 changed files with 677 additions and 525 deletions.
538 changes: 293 additions & 245 deletions README.md

Large diffs are not rendered by default.

27 changes: 14 additions & 13 deletions src/GitHub.jl
Expand Up @@ -26,11 +26,7 @@ export # auth.jl
authenticate

export # requests.jl
github_get,
github_post,
github_put,
github_patch,
github_delete
rate_limit

##################################
# Owners (organizations + users) #
Expand Down Expand Up @@ -60,14 +56,13 @@ include("repositories/repositories.jl")
include("repositories/contents.jl")
include("repositories/commits.jl")
include("repositories/statuses.jl")
include("repositories/comments.jl")

# export -------

export # repositories.jl
Repo,
repo,
fork,
create_fork,
forks,
contributors,
collaborators,
Expand All @@ -93,10 +88,8 @@ export # contents.jl
export # statuses.jl
Status,
create_status,
statuses

export # comments.jl
Comment
statuses,
status

##########
# Issues #
Expand All @@ -106,6 +99,7 @@ export # comments.jl

include("issues/pull_requests.jl")
include("issues/issues.jl")
include("issues/comments.jl")

# export -------

Expand All @@ -119,8 +113,15 @@ export # issues.jl
issue,
issues,
create_issue,
edit_issue,
issue_comments
edit_issue

export # comments.jl
Comment,
comment,
comments,
create_comment,
edit_comment,
delete_comment

############
# Activity #
Expand Down
36 changes: 12 additions & 24 deletions src/activity/activity.jl
Expand Up @@ -3,45 +3,33 @@
############

function stargazers(repo; options...)
path = "/repos/$(name(repo))/stargazers"
return map(Owner, github_get_json(path; options...))
results, page_data = gh_get_paged_json("/repos/$(name(repo))/stargazers"; options...)
return map(Owner, results), page_data
end

function starred(user; options...)
path = "/users/$(name(user))/starred"
return map(Repo, github_get_json(path; options...))
results, page_data = gh_get_paged_json("/users/$(name(user))/starred"; options...)
return map(Repo, results), page_data
end

function star(repo; options...)
path = "/user/starred/$(name(repo))"
return github_put(path; options...)
end
star(repo; options...) = gh_put("/user/starred/$(name(repo))"; options...)

function unstar(repo; options...)
path = "/user/starred/$(name(repo))"
return github_delete(path; options...)
end
unstar(repo; options...) = gh_delete("/user/starred/$(name(repo))"; options...)

############
# Watching #
############

function watchers(repo; options...)
path = "/repos/$(name(repo))/subscribers"
return map(Owner, github_get_json(path; options...))
results, page_data = gh_get_paged_json("/repos/$(name(repo))/subscribers"; options...)
return map(Owner, results), page_data
end

function watched(owner; options...)
path = "/users/$(name(owner))/subscriptions"
return map(Repo, github_get_json(path; options...))
results, page_data = gh_get_paged_json("/users/$(name(owner))/subscriptions"; options...)
return map(Repo, results), page_data
end

function watch(repo; options...)
path = "/repos/$(name(repo))/subscription"
return github_put(path; options...)
end
watch(repo; options...) = gh_put("/repos/$(name(repo))/subscription"; options...)

function watch(repo; options...)
path = "/repos/$(name(repo))/subscription"
return github_delete(path; options...)
end
unwatch(repo; options...) = gh_delete("/repos/$(name(repo))/subscription"; options...)
22 changes: 16 additions & 6 deletions src/activity/events/events.jl
Expand Up @@ -5,15 +5,25 @@
type WebhookEvent
kind::GitHubString
payload::Dict
repository::Nullable{Repo}
sender::Nullable{Owner}
repository::Repo
sender::Owner
end

function event_from_payload!(kind, data::Dict)
repository = extract_nullable(data, "repository", Repo)
sender = extract_nullable(data, "sender", Owner)
haskey(data, "repository") && delete!(data, "repository")
haskey(data, "sender") && delete!(data, "sender")
if haskey(data, "repository")
repository = Repo(data["repository"])
elseif kind == "membership"
repository = Repo("")
else
error("event payload is missing repository field")
end

if haskey(data, "sender")
sender = Owner(data["sender"])
else
error("event payload is missing sender")
end

return WebhookEvent(kind, data, repository, sender)
end

Expand Down
92 changes: 14 additions & 78 deletions src/activity/events/listeners.jl
Expand Up @@ -8,7 +8,7 @@ event_header(request::HttpCommon.Request) = request.headers["X-GitHub-Event"]
has_sig_header(request::HttpCommon.Request) = haskey(request.headers, "X-Hub-Signature")
sig_header(request::HttpCommon.Request) = request.headers["X-Hub-Signature"]

function is_valid_secret(request::HttpCommon.Request, secret)
function has_valid_secret(request::HttpCommon.Request, secret)
if has_sig_header(request)
secret_sha = "sha1="*bytes2hex(MbedTLS.digest(MbedTLS.MD_SHA1, request.data, secret))
return sig_header(request) == secret_sha
Expand All @@ -20,74 +20,14 @@ function is_valid_event(request::HttpCommon.Request, events)
return (has_event_header(request) && in(event_header(request), events))
end

is_valid_repo(payload::Dict, repos) = in(payload["repository"]["full_name"], repos)
function from_valid_repo(event, repos)
return (name(event.repository) == "" || in(name(event.repository), repos))
end

#################
# EventListener #
#################

"""
A `GitHub.EventListener` is a server that handles events sent from a GitHub repo (usually via a webhook). When a `GitHub.EventListener` receives an event, it performs some basic validation and wraps the event payload in a `GitHub.WebhookEvent` type (use the REPL's `help` mode for more info on `GitHub.WebhookEvent`). This `GitHub.WebhookEvent` is then fed to the server's `handle` function, which defines how the server responds to the event.
The `GitHub.EventListener` constructor takes in a handler function which should take in a `GitHub.WebhookEvent` and `GitHub.Authorization` and return an `HttpCommon.Response`. It also takes the following keyword arguments:
- `auth`: GitHub authorization (usually with repo-level permissions)
- `secret`: A string used to verify the event source. If the event is from a GitHub webhook, it's the webhook's secret
- `repos`: A collection of fully qualified names of whitelisted repostories. All repostories are whitelisted by default
- `events`: A collection of webhook event name strings that contains all whitelisted events. All events are whitelisted by default
- `forwards`: A collection of address strings to which any incoming requests should be forwarded (after being validated by the listener)
Here's an example that demonstrates how to construct and run a `GitHub.EventListener` that does some really basic benchmarking on every commit and PR:
import GitHub
# EventListener settings
myauth = GitHub.OAuth2(ENV["GITHUB_AUTH_TOKEN"])
mysecret = ENV["MY_SECRET"]
myevents = ["pull_request", "push"]
myrepos = ["owner1/repo1", "owner2/repo2"]
myforwards = ["http://myforward1.com", "http://myforward2.com"]
# Set up Status parameters
pending_params = Dict(
"state" => "pending",
"context" => "Benchmarker",
"description" => "Running benchmarks..."
)
success_params = Dict(
"state" => "success",
"context" => "Benchmarker",
"description" => "Benchmarks complete!"
)
listener = GitHub.EventListener(auth = myauth,
secret = mysecret,
repos = myrepos,
events = myevents,
forwards = myforwards) do event, auth
kind, payload = event.kind, event.payload
if kind == "pull_request" && payload["action"] == "closed"
return HttpCommon.Response(200)
end
sha = GitHub.most_recent_commit_sha(event)
GitHub.create_status(event, sha; auth = auth, params = pending_params)
# run_and_log_benchmarks isn't actually a defined function, but you get the point
run_and_log_benchmarks("\$(sha)-benchmarks.csv")
GitHub.create_status(event, sha; auth = auth, params = success_params)
return HttpCommon.Response(200)
end
# Start the server on port 8000
GitHub.run(listener, 8000)
"""
immutable EventListener
server::HttpServer.Server
function EventListener(handle; auth::Authorization = AnonymousAuth(),
Expand All @@ -97,6 +37,10 @@ immutable EventListener
forwards = map(HttpCommon.URI, forwards)
end

if !(ias(repos, Void))
repos = map(name, repos)
end

server = HttpServer.Server() do request, response
try
handle_event_request(request, handle; auth = auth,
Expand All @@ -122,30 +66,26 @@ function handle_event_request(request, handle;
auth::Authorization = AnonymousAuth(),
secret = nothing, events = nothing,
repos = nothing, forwards = nothing)
if !(isa(secret, Void)) && !(is_valid_secret(request, secret))
if !(isa(secret, Void)) && !(has_valid_secret(request, secret))
return HttpCommon.Response(400, "invalid signature")
end

if !(isa(events, Void)) && !(is_valid_event(request, events))
return HttpCommon.Response(400, "invalid event")
end

payload = Requests.json(request)
event = event_from_payload!(event_header(request), Requests.json(request))

if !(isa(repos, Void)) && !(is_valid_repo(payload, repos))
if !(isa(repos, Void)) && !(from_valid_repo(event, repos))
return HttpCommon.Response(400, "invalid repo")
end

if !(isa(forwards, Void))
for address in forwards
Requests.post(address,
UTF8String(request.data),
headers=request.headers)
Requests.post(address, request)
end
end

event = event_from_payload!(event_header(request), payload)

return handle(event, auth)
end

Expand All @@ -165,7 +105,7 @@ immutable CommentListener
listener::EventListener
function CommentListener(handle, trigger::AbstractString;
auth::Authorization = AnonymousAuth(),
check_collab = true,
check_collab::Bool = true,
secret = nothing,
repos = nothing,
forwards = nothing)
Expand Down Expand Up @@ -194,11 +134,7 @@ function extract_trigger_string(event::WebhookEvent,
trigger_regex = Regex("\`$trigger\(.*?\)\`")

# extract repo/owner info from event
if isnull(event.repository)
return (false, "event is missing repo information")
end

repo = get(event.repository)
repo = event.repository

if isnull(repo.owner)
return (false, "event repository is missing owner information")
Expand Down

0 comments on commit 168393d

Please sign in to comment.