Code Monkey home page Code Monkey logo

github.jl's Introduction

GitHub.jl

Coverage Status

GitHub.jl provides a Julia interface to the GitHub API v3. Using GitHub.jl, you can do things like:

  • query for basic repository, organization, and user information
  • programmatically take user-level actions (e.g. starring a repository, commenting on an issue, etc.)
  • set up listeners that can detect and respond to repository events
  • create and retrieve commit statuses (i.e. report CI pending/failure/success statuses to GitHub)

Here's a table of contents for this rather lengthy README:

1. Response Types

2. REST Methods

3. Authentication

4. Pagination

5. Handling Webhook Events

6. GitHub Enterprise

Response Types

GitHub's JSON responses are parsed and returned to the caller as types of the form G<:GitHub.GitHubType. Here's some useful information about these types:

  • All fields are Union{Nothing, T}.

  • Field names generally match the corresponding field in GitHub's JSON representation (the exception is "type", which has the corresponding field name typ to avoid the obvious language conflict).

  • GitHubTypes can be passed as arguments to API methods in place of (and in combination with) regular identifying properties. For example, create_status(repo, commit) could be called as:

    • create_status(::GitHub.Repo, ::GitHub.Commit)
    • create_status(::GitHub.Repo, ::AbstractString) where the second argument is the SHA
    • create_status(::AbstractString, ::GitHub.Commit) where the first argument is the full qualified repo name
    • create_status(::AbstractString, ::AbstractString) where the first argument is the repo name, and the second is the SHA

Here's a table that matches up the provided GitHubTypes with their corresponding API documentation, as well as alternative identifying values:

type alternative identifying property link(s) to documentation
Owner login, e.g. "octocat" organizations, users
Repo full_name, e.g. "JuliaWeb/GitHub.jl" repositories
Commit sha, e.g. "d069993b320c57b2ba27336406f6ec3a9ae39375" repository commits
GitCommit sha, e.g. "d069993b320c57b2ba27336406f6ec3a9ae39375" raw git commits
Branch name, e.g. master repository branches
Content path, e.g. "src/owners/owners.jl" repository contents
Comment id, e.g. 162224613 commit comments, issue comments, PR review comments
Label name, e.g. bug issue labels
Status id, e.g. 366961773 commit statuses
PullRequest number, e.g. 44 pull requests
PullRequestFile filename, e.g. file1.txt pull request files
Issue number, e.g. 31 issues
Team id, e.g. 1 teams
Gist id, e.g. 0bace7cc774df4b3a4b0ee9aaa271ef6 gists
Review id, e.g. 1 reviews
Blob sha, e.g. "95c8d1aa2a7b1e6d672e15b67e0df4abbe57dcbe" raw git blobs
Tree sha, e.g. "78e524d5e979e326a7c144ce195bf94ca9b04fa0" raw git trees
Tag tag name, e.g. v1.0 git tags
References reference name, e.g. heads/master (note: omits leading refs/) references
Secrets secret name, e.g. TAGBOT_SECRET secrets
DeployKeys id, e.g., 12345 deploy keys

You can inspect which fields are available for a type G<:GitHubType by calling fieldnames(G).

REST Methods

GitHub.jl implements a bunch of methods that make REST requests to GitHub's API. The below sections list these methods (note that a return type of Tuple{Vector{T}, Dict} means the result is paginated).

Users and Organizations

method return type documentation
whoami() Owner get currently authenticated user as a user
owner(owner[, isorg = false]) Owner get owner as a user or organization
orgs(owner) Tuple{Vector{Owner}, Dict} get the owner's organizations
followers(owner) Tuple{Vector{Owner}, Dict} get the owner's followers
following(owner) Tuple{Vector{Owner}, Dict} get the users followed by owner
repos(owner[, isorg = false]) Tuple{Vector{Repo}, Dict} get the owner's repositories/get an organization's repositories
teams(owner) Tuple{Vector{Team}, Dict} get the organizations's teams repositories
sshkeys(owner) Tuple{Vector{Dict}, Dict} get the owner's public ssh keys
gpgkeys(owner) Tuple{Vector{Dict}, Dict} get the owner's public gpg keys

Teams

method return type documentation
members(team) Tuple{Vector{Owner}, Dict} get team members as users
repos(owner, team) Tuple{Vector{Repo}, Dict} get team repositories as users

Repositories

method return type documentation
repo(repo) Repo get repo
create_repo(owner, name) Repo create a repository of the given name in the given owner's account
create_fork(repo) Repo create a fork of repo
forks(repo) Tuple{Vector{Repo}, Dict} get repo's forks
contributors(repo) Dict get repo's contributors
collaborators(repo) Tuple{Vector{Owner}, Dict} get repo's collaborators
iscollaborator(repo, user) Bool check if user is a collaborator on repo
add_collaborator(repo, user) HTTP.Response add user as a collaborator to repo
remove_collaborator(repo, user) HTTP.Response remove user as a collaborator from repo
collaborator_permission(repo, user) HTTP.Response get the repo permission of a collaborator
stats(repo, stat[, attempts = 3]) HTTP.Response get information on stat (e.g. "contributors", "code_frequency", "commit_activity", etc.)
topics(repo) Vector{String} get the list of topics of a repository.)
set_topics(repo, topics) Vector{String} set the list of topics of a repository.)
commit(repo, sha) Commit get the commit specified by sha
commits(repo) Tuple{Vector{Commit}, Dict} get repo's commits
commits(repo, pr) Tuple{Vector{Commit}, Dict} get pr's commits for repo
compare(repo, base, head) Comparison compare repo's commits
branch(repo, branch) Branch get the branch specified by branch
branches(repo) Tuple{Vector{Branch}, Dict} get repo's branches
file(repo, path) Content get the file specified by path
directory(repo, path) Tuple{Vector{Content}, Dict} get the contents of the directory specified by path
create_file(repo, path) Dict create a file at path in repo
update_file(repo, path) Dict update a file at path in repo
delete_file(repo, path) Dict delete a file at path in repo
permalink(content::Content, commit) URIs.URI get a permalink for content at the SHA specified by commit
readme(repo) Content get repo's README
create_status(repo, sha) Status create a status for the commit specified by sha
statuses(repo, ref) Tuple{Vector{Status}, Dict} get the statuses posted to ref
status(repo, ref) Status get the combined status for ref
create_webhook(owner, repo) Webhook create a webhook for repo
secrets(repo; auth) Tuple{Vector{Secret}, Dict} get names of all secrets for repo
secret(repo, name; auth) Secret get status of secret in repo
create_secret(repo, name; value, auth) nothing create a secret for repo
delete_secret(repo, name; auth) nothing delete a secret for repo
deploykeys(repo; auth) Tuple{Vector{DeployKey}, Dict} get all deploy keys for repo
deploykey(repo, key; auth) DeployKey get the deploy key in repo
create_deploykey(repo; params=..., auth) nothing create a deploy key for repo
delete_deploykey(repo, key; auth) nothing delete a deploy key for repo
releases(repo, key; auth) nothing get the releases for repo

Pull Requests and Issues

method return type documentation
pull_request(repo, pr) PullRequest get the pull request specified by pr
pull_requests(repo) Tuple{Vector{PullRequest}, Dict} get repo's pull requests
pull_request_files(repo, pr) Tuple{Vector{PullRequestFiles}, Dict} get this repo's pr's file changes
create_pull_request(repo) PullRequest create pull request in repo
update_pull_request(repo, pr) PullRequest update the given pr in repo
close_pull_request(repo, pr) PullRequest close the given pr in repo
issue(repo, issue) Issue get the issue specified by issue
issues(repo) Tuple{Vector{Issue}, Dict} get repo's issues
create_issue(repo) Issue create an issue in repo
edit_issue(repo, issue) Issue edit issue in repo
reviews(repo, pr) Tuple{Vector{PullRequest}, Dict} get a pr's reviews
dismiss_review(repo, review) HTTP.Response dismiss review in repo

Comments

method return type documentation
comment(repo, comment, :issue) Comment get an issue comment from repo
comment(repo, comment, :pr) Comment get a PR comment from repo
comment(repo, comment, :review) Comment get an review comment from repo
comment(repo, comment, :commit) Comment get a commit comment from repo
comments(repo, issue, :issue) Tuple{Vector{Comment}, Dict} get the comments on issue in repo
comments(repo, pr, :pr) Tuple{Vector{Comment}, Dict} get the comments on pr in repo
comments(repo, pr, :review) Tuple{Vector{Comment}, Dict} get the review comments on pr in repo
comments(repo, commit, :commit) Tuple{Vector{Comment}, Dict} get the comments on commit in repo
create_comment(repo, issue, :issue) Comment create a comment on issue in repo
create_comment(repo, pr, :pr) Comment create a comment on pr in repo
create_comment(repo, pr, :review) Comment create a review comment on pr in repo
create_comment(repo, commit, :commit) Comment create a comment on commit in repo
edit_comment(repo, comment, :issue) Comment edit the issue comment in repo
edit_comment(repo, comment, :pr) Comment edit the PR comment in repo
edit_comment(repo, comment, :review) Comment edit the review comment in repo
edit_comment(repo, comment, :commit) Comment edit the commit comment in repo
delete_comment(repo, comment, :issue) HTTP.Response delete the issue comment from repo
delete_comment(repo, comment, :pr) HTTP.Response delete the PR comment from repo
delete_comment(repo, comment, :review) HTTP.Response delete the review comment from repo
delete_comment(repo, comment, :commit) HTTP.Response delete the commitcomment from repo
delete_comment(repo, comment, :commit) HTTP.Response delete the commitcomment from repo
reply_to(repo, review, comment, body) HTTP.Response reply to the comment (of review in repo) creating a new comment with the specified body

Labels

method return type documentation
labels(repo,issue) Vector{Label} list labels from issue
add_labels(repo, issue, labels) Vector{Label} add labels to an issue
set_labels(repo, issue, labels) Vector{Label} set the labels for an issue
remove_all_labels(repo, issue) HTTP.Response remove all labels from an issue
remove_label(repo, issue, label) HTTP.Response remove a label from an issue

Social Activity

method return type documentation
star(repo) HTTP.Response star repo
unstar(repo) HTTP.Response unstar repo
stargazers(repo) Tuple{Vector{Owner}, Dict} get repo's stargazers
starred(user) Tuple{Vector{Repo}, Dict} get repositories starred by user
watchers(repo) Tuple{Vector{Owner}, Dict} get repo's watchers
watched(user) Tuple{Vector{Repo}, Dict} get repositories watched by user
watch(repo) HTTP.Response watch repo
unwatch(repo) HTTP.Response unwatch repo

Gists

method return type documentation
gist(id) Gist get the gist specified by id
gist(id, revision) Gist get the gist specified by id and revision
gists() Tuple{Vector{Gist}, Dict} get all public gists
gists(owner) Tuple{Vector{Gist}, Dict} get all gists for owner
create_gist() Gist create a gist
edit_gist(gist) Gist edit a gist
delete_gist(gist) HTTP.Response delete a gist
create_gist_fork(gist) Gist fork a gist
gist_forks(gist) Tuple{Vector{Gist}, Dict} list the forks of a gist
star_gist(gist) HTTP.Response star gist
starred_gists() Tuple{Vector{Gist}, Dict} get the starred gists
unstar_gist(gist) HTTP.Response unstar gist

Git Data

method return type documentation
blob(repo, sha) Blob Look up a blob in the repo by its SHA
create_blob(repo) Blob Create a blob in the repo
gitcommit(repo, sha) GitCommit Look up a commit in the repo by its SHA
create_gitcommit(repo) GitCommit Create a commit in the repo
tree(repo, sha) Tree Look up a tree in the repo by its SHA
create_tree(repo) Tree Create a tree in the repo
tag(repo, sha) Tag Look up a tag in the repo by its name
create_tag(repo) Tag Create a tag in the repo
reference(repo, name) Reference Look up a ref in the repo by its name
references(repo) Vector{Reference} Get all refs of the repo
create_reference(repo) Reference Create a reference in the repo
update_reference(repo) Reference Update a reference in the repo
delete_reference(repo) GitCommit Delete a the repo
tag(repo) Reference Update a reference in the repo
delete_reference(repo) GitCommit Delete a the repo

GitHub Apps

method return type documentation
app(id) App get the GitHub app with the specified id
app(slug) App get the GitHub app with the specified slug
app(;auth=auth) App get the GitHub app authenticated by the corresponding auth
installations(auth) Vector{Installation} get the installations for the GitHub app authenticated by the corresponding auth
repos(i::Installation) Tuple{Vector{Repo}, Dict} get the active repositories for this installation

GitHub Check Runs

method return type documentation
create_check_run(repo; params=...) CheckRun Create a new check run
update_check_run(repo, id::Int; params=...) CheckRun Update the check run with the given id

Licenses

method return type documentation
licenses(; params=...) Vector{License} Get all commonly used licenses
license(license_id; params=...) License Get a license
repo_license(repo; params=...) Content Get the license for a respository

Miscellaneous

method return type documentation
rate_limit() Dict get your rate limit status
authenticate(token) OAuth2 validate token and return an authentication object

Keyword Arguments

All REST methods accept the following keyword arguments:

keyword type default value description
auth GitHub.Authorization GitHub.AnonymousAuth() The request's authorization
params Dict Dict() The request's query parameters
headers Dict Dict() The request's headers. Note that these headers will be mutated by GitHub.jl request methods.
handle_error Bool true If true, a Julia error will be thrown in the event that GitHub's response reports an error.
page_limit Real Inf The number of pages to return (only applies to paginated results, obviously)

Authentication

To authenticate your requests to GitHub, you'll need to generate an appropriate access token. Then, you can do stuff like the following (this example assumes that you set an environmental variable GITHUB_AUTH containing the access token):

import GitHub
myauth = GitHub.authenticate(ENV["GITHUB_AUTH"]) # don't hardcode your access tokens!
GitHub.star("JuliaWeb/GitHub.jl"; auth = myauth)  # star the GitHub.jl repo as the user identified by myauth

As you can see, you can propagate the identity/permissions of the myauth token to GitHub.jl's methods by passing auth = myauth as a keyword argument.

Note that if authentication is not provided, they'll be subject to the restrictions GitHub imposes on unauthenticated requests (such as stricter rate limiting)

Authenticating as a GitHub app

GitHub apps (formerly called integrations) have their own authentication format based on JSON Web Tokens. When creating a GitHub app, you will be prompted to download your app's private key. You can use this private key to authenticate as a Github App using the JWTAuth type:

appauth = JWTAuth(1234, "privkey.pem") # Replace with your app id/privkey file

The following shows a complete example that opens an issue on every repository on which your application gets installed:

listener = GitHub.EventListener() do event
    # On installation, open an issue on every repository we got installed in
    if event.kind == "installation"
        # Authenticate as the application
        appauth = GitHub.JWTAuth(1234, "privkey.pem")
        # Now, get permissions for this particular installation
        installation = Installation(event.payload["installation"])
        auth = create_access_token(installation, appauth)
        for repo in event.payload["repositories"]
            create_issue(GitHub.Repo(repo), auth=auth,
                params = Dict(
                    :title => "Hello World",
                    :body => "Thank you for installing me - I needed that"
            ))
        end
    end
    return HTTP.Response(200)
end
GitHub.run(listener, host=IPv4(0,0,0,0), port=8888)

Pagination

GitHub will often paginate results for requests that return multiple items. On the GitHub.jl side of things, it's pretty easy to see which methods return paginated results by referring to the REST Methods documentation; if a method returns a Tuple{Vector{T}, Dict}, that means its results are paginated.

Paginated methods return both the response values, and some pagination metadata. You can use the per_page/page query parameters and the page_limit keyword argument to configure result pagination.

For example, let's request a couple pages of GitHub.jl's PRs, and configure our result pagination to see how it works:

# show all PRs (both open and closed), and give me 3 items per page starting at page 2
julia> myparams = Dict("state" => "all", "per_page" => 3, "page" => 2);

julia> prs, page_data = pull_requests("JuliaWeb/GitHub.jl"; params = myparams, page_limit = 2);

julia> prs # 3 items per page * 2 page limit == 6 items, as expected
6-element Array{GitHub.PullRequest,1}:
 GitHub.PullRequest(44)
 GitHub.PullRequest(43)
 GitHub.PullRequest(42)
 GitHub.PullRequest(41)
 GitHub.PullRequest(39)
 GitHub.PullRequest(38)

julia> page_data
Dict{String,String} with 4 entries:
  "prev"  => "https://api.github.com/repositories/16635105/pulls?page=2&per_page=3&state=all"
  "next"  => "https://api.github.com/repositories/16635105/pulls?page=4&per_page=3&state=all"
  "first" => "https://api.github.com/repositories/16635105/pulls?page=1&per_page=3&state=all"
  "last"  => "https://api.github.com/repositories/16635105/pulls?page=7&per_page=3&state=all"

In the above, prs contains the results from page 2 and 3. We know this because we specified page 2 as our starting page ("page" => 2), and limited the response to 2 pages max (page_limit = 2). In addition, we know that exactly 2 pages were actually retrieved, since there are 6 items and we said each page should only contain 3 items ("per_page" => 3).

The values provided by page_data are the same values that are included in the Link header of the last requested item. You can continue paginating by starting a new paginated request at one of these links using the start_page keyword argument:

# Continue paging, starting with `page_data["next"]`.
# Note that the `params` kwarg can't be used here because
# the link passed to `start_page` has its own parameters
julia> prs2, page_data2 = pull_requests("JuliaWeb/GitHub.jl"; page_limit = 2, start_page = page_data["next"]);

julia> prs2
6-element Array{GitHub.PullRequest,1}:
 GitHub.PullRequest(37)
 GitHub.PullRequest(34)
 GitHub.PullRequest(32)
 GitHub.PullRequest(30)
 GitHub.PullRequest(24)
 GitHub.PullRequest(22)

julia> page_data2
Dict{String,String} with 4 entries:
  "prev"  => "https://api.github.com/repositories/16635105/pulls?page=4&per_page=3&state=all"
  "next"  => "https://api.github.com/repositories/16635105/pulls?page=6&per_page=3&state=all"
  "first" => "https://api.github.com/repositories/16635105/pulls?page=1&per_page=3&state=all"
  "last"  => "https://api.github.com/repositories/16635105/pulls?page=7&per_page=3&state=all"

Handling Webhook Events

GitHub.jl comes with configurable EventListener and CommentListener types that can be used as basic servers for parsing and responding to events delivered by GitHub's repository Webhooks.

EventListener

When an EventListener receives an event, it performs some basic validation and wraps the event payload (and some other data) in a WebhookEvent type. This WebhookEvent instance, along with the provided Authorization, is then fed to the server's handler function, which the user defines to determine the server's response behavior. The handler function is expected to return an HTTP.Response that is then sent back to GitHub.

The EventListener constructor 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. If a secret is not provided, the server won't validate the secret signature of incoming requests.
  • repos: A vector of Repos (or fully qualified repository names) listing all acceptable repositories. All repositories are whitelisted by default.
  • events: A vector of event names listing all acceptable events (e.g. ["commit_comment", "pull_request"]). All events are whitelisted by default.
  • forwards: A vector of URIs.URIs (or URI 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 an EventListener that does benchmarking on every commit and PR:

import GitHub
import URIs
# EventListener settings
myauth = GitHub.authenticate(ENV["GITHUB_AUTH"])
mysecret = ENV["MY_SECRET"]
myevents = ["pull_request", "push"]
myrepos = [GitHub.Repo("owner1/repo1"), "owner2/repo2"] # can be Repos or repo names
myforwards = [URIs.URI("http://myforward1.com"), "http://myforward2.com"] # can be URIs.URIs or URI strings

# Set up Status parameters
pending_params = Dict(
    "state" => "pending",
    "context" => "Benchmarker",
    "description" => "Running benchmarks..."
)

success_params = Dict(
    "state" => "success",
    "context" => "Benchmarker",
    "description" => "Benchmarks complete!"
)

error_params(err) = Dict(
    "state" => "error",
    "context" => "Benchmarker",
    "description" => "Error: $err"
)

# We can use Julia's `do` notation to set up the listener's handler function
listener = GitHub.EventListener(auth = myauth,
                                secret = mysecret,
                                repos = myrepos,
                                events = myevents,
                                forwards = myforwards) do event
    kind, payload, repo = event.kind, event.payload, event.repository

    if kind == "pull_request" && payload["action"] == "closed"
        return HTTP.Response(200)
    end

    if event.kind == "push"
        sha = event.payload["after"]
    elseif event.kind == "pull_request"
        sha = event.payload["pull_request"]["head"]["sha"]
    end

    GitHub.create_status(repo, sha; auth = myauth, params = pending_params)

    try
        # run_and_log_benchmarks isn't actually a defined function, but you get the point
        run_and_log_benchmarks(event, "\$(sha)-benchmarks.csv")
    catch err
        GitHub.create_status(repo, sha; auth = myauth, params = error_params(err))
        return HTTP.Response(500)
    end

    GitHub.create_status(repo, sha; auth = myauth, params = success_params)

    return HTTP.Response(200)
end

# Start the listener on localhost at port 8000
GitHub.run(listener, IPv4(127,0,0,1), 8000)

CommentListener

A CommentListener is a special kind of EventListener that allows users to pass data to the listener's handler function via commenting. This is useful for triggering events on repositories that require configuration settings.

A CommentListener automatically filters out all non-comment events, and then checks the body of each comment event against a trigger Regex supplied by the user. If a match is found in the comment, then the CommentListener calls its handler function, passing it the event and the corresponding RegexMatch.

The CommentListener constructor takes the following keyword arguments:

  • auth: same as EventListener
  • secret: same as EventListener
  • repos: same as EventListener
  • forwards: same as EventListener
  • check_collab: If true, only acknowledge comments made by repository collaborators. Note that, if check_collab is true, auth must have the appropriate permissions to query the comment's repository for the collaborator status of the commenter. check_collab is true by default.
  • use_access_token: If check_collab is set to true and auth is using JWT authentication for GitHub Apps, then set this to true.

For example, let's set up a silly CommentListener that responds to the commenter with a greeting. To give a demonstration of the desired behavior, if a collaborator makes a comment like:

Man, I really would like to be greeted today.

`sayhello("Bob", "outgoing")`

We want the CommentLister to reply:

Hello, Bob, you look very outgoing today!

Here's the code that will make this happen:

import GitHub

# CommentListener settings
trigger = r"`sayhello\(.*?\)`"
myauth = GitHub.authenticate(ENV["GITHUB_AUTH"])
mysecret = ENV["MY_SECRET"]

# We can use Julia's `do` notation to set up the listener's handler function.
# Note that, in our example case, `phrase` will be "`sayhello(\"Bob\", \"outgoing\")`"
listener = GitHub.CommentListener(trigger; auth = myauth, secret = mysecret) do event, phrase
    # In our example case, this code sets name to "Bob" and adjective to "outgoing"
    name, adjective = matchall(r"\".*?\"", phrase)
    comment_params = Dict("body" => "Hello, $name, you look very $adjective today!")

    # Parse the original comment event for all the necessary reply info
    comment = GitHub.Comment(event.payload["comment"])

    if event.kind == "issue_comment"
        comment_kind = :issue
        reply_to = event.payload["issue"]["number"]
    elseif event.kind == "commit_comment"
        comment_kind = :commit
        reply_to = comment.commit_id
    elseif event.kind == "pull_request_review_comment"
        comment_kind = :review
        reply_to = event.payload["pull_request"]["number"]
        # load required query params for review comment creation
        comment_params["commit_id"] = comment.commit_id
        comment_params["path"] = comment.path
        comment_params["position"] = comment.position
    end

    # send the comment creation request to GitHub
    GitHub.create_comment(event.repository, reply_to, comment_kind; auth = myauth, params = comment_params)

    return HTTP.Response(200)
end

# Start the listener on localhost at port 8000
GitHub.run(listener, IPv4(127,0,0,1), 8000)

GitHub Enterprise

This library work with github.com, and also with self-hosted github, a.k.a. GitHub Enterprise.

To use it with self-hosted github, you need to create GitHubWebAPI structure and pass it to functions when needed. Following example shows obtaining repository info private/Package.jl on github instance with API https://git.company.com/api/v3.

import GitHub
import URIs

api = GitHub.GitHubWebAPI(URIs.URI("https://git.company.com/api/v3"))
myauth = GitHub.authenticate(api, ENV["GITHUB_AUTH"])
myrepo = GitHub.repo(api, "private/Package.jl", auth=myauth)

SSH keys

You can generate public-private key pairs with GitHub.genkeys. Here's an example adding a deploy key and secret, in this case to deploy documentation via GitHub Actions:

pubkey, privkey = GitHub.genkeys()
create_deploykey(repo; auth, params=Dict("key"=>pubkey, "title"=>"Documenter", "read_only"=>false))
create_secret(repo, "DOCUMENTER_KEY"; auth, value=privkey)

privkey is sent in encrypted form to GitHub. Do not share privkey with others or post it publicly; doing so breaches the security of your repository. You can read more about the meaning of SSH keys and their security implications.

github.jl's People

Contributors

andreasnoack avatar ararslan avatar astrieanna avatar christopher-dg avatar dilumaluthge avatar femtocleaner[bot] avatar fredrikekre avatar ianbutterworth avatar jaakkor2 avatar jbn avatar jeremiahpslewis avatar jiahao avatar jrevels avatar keno avatar kristofferc avatar logankilpatrick avatar maleadt avatar nkottary avatar quinnj avatar racinmat avatar rick2047 avatar saschamann avatar simonbyrne avatar staticfloat avatar tanmaykm avatar timholy avatar tk3369 avatar tkelman avatar viralbshah avatar westleyargentum avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

github.jl's Issues

Missing operations

Maybe I'm being dumb (correct me if I'm wrong), but I don't see any methods for:

  • creating repositories
  • deleting repositories
  • creating deploy keys

incorrect base64 format

I was using GitHub.file() to download some of the url files from Metadata.jl and found some did not base64decode correctly. Example:

file("JuliaLang/METADATA.jl", "ACME/url")

produces

GitHub.Content (all fields are Nullable):
  typ: "file"
  name: "url"
  path: "ACME/url"
  encoding: "base64"
  content: "Z2l0Oi8vZ2l0aHViLmNvbS9IU1UtQU5UL0FDTUUuamwuZ2l0Cg==\n"
  sha: "b5b82f0d5f1f349298b604abd2f1f6e77ca1ae64"
...

but
file("JuliaLang/METADATA.jl", "AWS/url").content.value
gives
"Z2l0Oi8vZ2l0aHViLmNvbS9KdWxpYUNsb3VkL0FXUy5qbC5naXQK\n"
and

base64decode("Z2l0Oi8vZ2l0aHViLmNvbS9KdWxpYUNsb3VkL0FXUy5qbC5naXQK\n")

ArgumentError: incorrect base64 format, block must be at least 2 and at most 4 bytes

 in b64decode!(::Array{UInt8,1}, ::Array{UInt8,1}) at ./base64.jl:68
 in read(::Base64DecodePipe, ::Type{UInt8}) at ./base64.jl:192
 in readbytes!(::Base64DecodePipe, ::Array{UInt8,1}, ::Int64) at ./io.jl:345
 in read(::Base64DecodePipe, ::Int64) at ./io.jl:368
 in base64decode(::String) at ./base64.jl:203

Out of the 1000 files I downloaded, about a third gave this error. I'm not sure if this is an issue with how the Content gets parsed internally and need something deeper. For my own purposes, I just fixed the strings by adding a = before the \n.

Tests!

Harder, Better, Faster!

[PkgEval] GitHub may have a testing issue on Julia 0.3 (2014-08-16)

PackageEvaluator.jl is a script that runs nightly. It attempts to load all Julia packages and run their tests (if available) on both the stable version of Julia (0.3) and the nightly build of the unstable version (0.4). The results of this script are used to generate a package listing enhanced with testing results.

On Julia 0.3

  • On 2014-08-15 the testing status was Tests pass.
  • On 2014-08-16 the testing status changed to Package doesn't load.

Tests pass. means that PackageEvaluator found the tests for your package, executed them, and they all passed.

Package doesn't load. means that PackageEvaluator did not find tests for your package. Additionally, trying to load your package with using failed.

This issue was filed because your testing status became worse. No additional issues will be filed if your package remains in this state, and no issue will be filed if it improves. If you'd like to opt-out of these status-change messages, reply to this message saying you'd like to and @IainNZ will add an exception. If you'd like to discuss PackageEvaluator.jl please file an issue at the repository. For example, your package may be untestable on the test machine due to a dependency - an exception can be added.

Test log:

>>> 'Pkg.add("GitHub")' log
INFO: Cloning cache of GitHub from git://github.com/WestleyArgentum/GitHub.jl.git
INFO: Installing BinDeps v0.3.0
INFO: Installing Calendar v0.4.2
INFO: Installing Codecs v0.1.2
INFO: Installing FactCheck v0.1.2
INFO: Installing GitHub v0.0.4
INFO: Installing GnuTLS v0.0.1
INFO: Installing HttpCommon v0.0.5
INFO: Installing HttpParser v0.0.9
INFO: Installing ICU v0.4.1
INFO: Installing JSON v0.3.7
INFO: Installing Nettle v0.1.4
INFO: Installing Requests v0.0.5
INFO: Installing SHA v0.0.2
INFO: Installing URIParser v0.0.2
INFO: Building ICU
=================================[ ERROR: ICU ]=================================

None of the selected providers can install dependency icu.
Use BinDeps.debug(package_name) to see available providers

while loading /home/idunning/pkgtest/.julia/v0.3/ICU/deps/build.jl, in expression starting on line 28

================================================================================
INFO: Building HttpParser
INFO: Building Nettle
INFO: Building GnuTLS

================================[ BUILD ERRORS ]================================

WARNING: ICU had build errors.

 - packages with build errors remain installed in /home/idunning/pkgtest/.julia/v0.3
 - build a package and all its dependencies with `Pkg.build(pkg)`
 - build a single package by running its `deps/build.jl` script

================================================================================
INFO: Package database updated
INFO: METADATA is out-of-date a you may not have the latest version of GitHub
INFO: Use `Pkg.update()` to get the latest versions of your packages
 - Library "libhttp_parser"


>>> 'using GitHub' log

ERROR: could not open file /home/idunning/pkgtest/.julia/v0.3/ICU/src/../deps/deps.jl
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in reload_path at loading.jl:152
 in _require at loading.jl:67
 in require at loading.jl:54
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in reload_path at loading.jl:152
 in _require at loading.jl:67
 in require at loading.jl:54
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in reload_path at loading.jl:152
 in _require at loading.jl:67
 in require at loading.jl:54
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in reload_path at loading.jl:152
 in _require at loading.jl:67
 in require at loading.jl:54
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in reload_path at loading.jl:152
 in _require at loading.jl:67
 in require at loading.jl:54
 in include at ./boot.jl:245
 in include_from_node1 at ./loading.jl:128
 in reload_path at loading.jl:152
 in _require at loading.jl:67
 in require at loading.jl:51
 in include at ./boot.jl:245
 in include_from_node1 at loading.jl:128
 in process_options at ./client.jl:285
 in _start at ./client.jl:354
 in _start_3B_1699 at /home/idunning/julia03/usr/bin/../lib/julia/sys.so
while loading /home/idunning/pkgtest/.julia/v0.3/ICU/src/ICU.jl, in expression starting on line 54
while loading /home/idunning/pkgtest/.julia/v0.3/Calendar/src/Calendar.jl, in expression starting on line 1
while loading /home/idunning/pkgtest/.julia/v0.3/HttpCommon/src/HttpCommon.jl, in expression starting on line 3
while loading /home/idunning/pkgtest/.julia/v0.3/HttpParser/src/HttpParser.jl, in expression starting on line 9
while loading /home/idunning/pkgtest/.julia/v0.3/Requests/src/Requests.jl, in expression starting on line 6
while loading /home/idunning/pkgtest/.julia/v0.3/GitHub/src/GitHub.jl, in expression starting on line 6
while loading /home/idunning/pkgtest/.julia/v0.3/GitHub/testusing.jl, in expression starting on line 1

>>> test log
no tests to run
>>> end of log

Error in receiving webhook events to EventListener

I get the following error on the server on recieving the webhook ping event from github.com:

┌ Error: error handling request
│   exception =
│    MethodError: no method matching (::getfield(GitHub, Symbol("##165#167")){GitHub.OAuth2,String,Array{String,1},typeof(Main.Registrator.RegServer.event_handler)})(::HTTP.Streams.Stream{HTTP.Messages.Request,HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}})
│    Closest candidates are:
│      #165(!Matched::HTTP.Messages.Request) at /home/nkottary/.julia/packages/GitHub/Y0gpt/src/activity/events.jl:79
│    Stacktrace:
│     [1] macro expansion at /home/nkottary/.julia/packages/HTTP/GN0Te/src/Servers.jl:352 [inlined]
│     [2] (::getfield(HTTP.Servers, Symbol("##13#14")){getfield(GitHub, Symbol("##165#167")){GitHub.OAuth2,String,Array{String,1},typeof(Main.Registrator.RegServer.event_handler)},HTTP.ConnectionPool.Transaction{Sockets.TCPSocket},HTTP.Streams.Stream{HTTP.Messages.Request,HTTP.ConnectionPool.Transaction{Sockets.TCPSocket}}})() at ./task.jl:259

I am running the server like this:

listener = GitHub.EventListener(event_handler;
                                auth=GitHub.authenticate("***"),
                                secret="***",
                                events=["ping", "pull_request", "push"])
GitHub.run(listener, ip"0.0.0.0", 8090)

Handle GitHub redirections?

julia> contributors("dlfivefifty", "ApproxFun.jl")

HttpError(404,"Not Found","https://developer.github.com/v3")
while loading In[42], in expression starting on line 103

 in handle_error at /Users/jiahao/.julia/v0.3/GitHub/src/error.jl:36
 in get_pages at /Users/jiahao/.julia/v0.3/GitHub/src/utils.jl:78
 in get_pages at /Users/jiahao/.julia/v0.3/GitHub/src/utils.jl:77
 in contributors at /Users/jiahao/.julia/v0.3/GitHub/src/repos.jl:132
 in contributors at /Users/jiahao/.julia/v0.3/GitHub/src/repos.jl:120

This particular package was moved to https://github.com/ApproxFun/ApproxFun.jl.

Add a function to check your current rate-limit status

There are three parts to your current rate-limit status in the github api:

  1. Your allowed queries/hour
  2. Your remaining queries for this hour
  3. When this hour ends (in unix epoch seconds)

The headers to determine this are on every response we get from the API, but there's also a "free" (doesn't count towards the limit) api call to ask for your rate_limit info. As the pagination features cause a function call to count as >1 API call, checking your rate limit will become more important.

Rate Limiting Overview: https://developer.github.com/v3/#rate-limiting
Checking your rate-limit: https://developer.github.com/v3/rate_limit/

Checking Your Un-authenticated limit:

r = get("https://api.github.com/rate_limit")
r.headers["X-RateLimit-Reset"]  # end of this hour in utc epoch time
r.headers["X-RateLimit-Limit"]   # your max per hour
r.headers["X-RateLimit-Remaining"]  # your remaining for this hour

Checking Your Authenticated limit:

headers = Dict()
GitHub.authenticate_headers(headers, my_auth)
r = get("https://api.github.com/rate_limit"; headers=headers)
r.headers["X-RateLimit-Reset"]
r.headers["X-RateLimit-Limit"]
r.headers["X-RateLimit-Remaining"]

Error occurs when trying to create new repo with organization owner

Steps to reproduce:

import GitHub
github_token = ENV["MY_GITHUB_TOKEN"]
my_github_auth = GitHub.authenticate(github_token)
owner = GitHub.owner("MyGithubOrganization", true; auth = my_github_auth)
repo = GitHub.create_repo(owner, "my-brand-new-repo"; auth = my_github_auth)

Expected behavior:

The repo should be created, and the return value repo should look something like this:

GitHub.Repo (all fields are Union{Nothing, T}):
  name: "my-brand-new-repo"
  full_name: "MyGithubOrganization/my-brand-new-repo"
  default_branch: "master"
  owner: Owner("MyGithubOrganization")
  id: 151316725
  size: 0
  subscribers_count: 0
  forks_count: 0
  stargazers_count: 0
  watchers_count: 0
  open_issues_count: 0
  url: HTTP.URI("https://api.github.com/repos/MyGithubOrganization/my-brand-new-repo")
  html_url: HTTP.URI("https://github.com/MyGithubOrganization/my-brand-new-repo")
  pushed_at: 2018-10-02T20:11:10
  created_at: 2018-10-02T20:11:09
  updated_at: 2018-10-02T20:11:09
  has_issues: true
  has_wiki: true
  has_downloads: true
  has_pages: false
  private: false
  fork: false
  permissions: Dict{String,Any}("admin"=>true,"pull"=>true,"push"=>true)

Actual behavior:

ERROR: MethodError: objects of type String are not callable
Stacktrace:
 [1] #create_repo#52(::Base.Iterators.Pairs{Symbol,GitHub.OAuth2,Tuple{Symbol},NamedTuple{(:auth,),Tuple{GitHub.OAuth2}}}, ::Function, ::GitHub.GitHubWebAPI, ::GitHub.Owner, ::String, ::Dict{String,Any}) at /Users/dilum/.julia/dev/GitHub/src/repositories/repositories.jl:56
 [2] #create_repo at ./none:0 [inlined]
 [3] #create_repo#53 at ./none:0 [inlined]
 [4] #create_repo at ./none:0 [inlined] (repeats 2 times)
 [5] top-level scope at none:0

Why this error occurs

This error occurs because the local function variable name clashes with the function GitHub.name.

I will submit a PR shortly that fixes this issue.

Errors after switch to HTTP

ERROR: LoadError: TypeError: #request: in typeassert, expected Dict{Any,Any}, got Dict{String,String}
Stacktrace:
 [1] (::HTTP.#kw##request)(::Array{Any,1}, ::HTTP.#request, ::HTTP.Client, ::HTTP.Method, ::HTTP.URIs.URI) at ./<missing>:0
 [2] #get#47(::Bool, ::Dict{Any,Any}, ::Array{Any,1}, ::Function, ::String) at /home/keno/.julia/v0.6/HTTP/src/client.jl:508
 [3] (::HTTP.#kw##get)(::Array{Any,1}, ::HTTP.#get, ::String) at ./<missing>:0
 [4] #github_request#3(::GitHub.AnonymousAuth, ::Bool, ::Dict{Any,Any}, ::Dict{Any,Any}, ::Bool, ::Function, ::GitHub.GitHubWebAPI, ::Function, ::String) at /home/keno/.julia/v0.6/GitHub/src/utils/requests.jl:58
 [5] (::GitHub.#kw##github_request)(::Array{Any,1}, ::GitHub.#github_request, ::GitHub.GitHubWebAPI, ::Function, ::String) at ./<missing>:0
 [6] #gh_get#4 at /home/keno/.julia/v0.6/GitHub/src/utils/requests.jl:66 [inlined]
 [7] (::GitHub.#kw##gh_get)(::Array{Any,1}, ::GitHub.#gh_get, ::GitHub.GitHubWebAPI, ::String) at ./<missing>:0
 [8] #authenticate#24(::Dict{Any,Any}, ::Array{Any,1}, ::Function, ::GitHub.GitHubWebAPI, ::String) at /home/keno/.julia/v0.6/GitHub/src/utils/auth.jl:54
 [9] #authenticate#25(::Array{Any,1}, ::Function, ::String) at ./<missing>:0
 [10] authenticate(::String) at ./<missing>:0
 [11] include_from_node1(::String) at ./loading.jl:569
 [12] include(::String) at ./sysimg.jl:14
 [13] process_options(::Base.JLOptions) at ./client.jl:305
 [14] _start() at ./client.jl:371

Auth with pagination seems off

julia> GitHub.rate_limit(auth=getauth())
Dict{String,Any} with 2 entries:
  "rate"      => Dict{String,Any}("remaining"=>4997,"reset"=>1542057303,"limit"=>5000)
  "resources" => Dict{String,Any}("graphql"=>Dict{String,Any}("remaining"=>4999,"reset"=>

julia> prs, page_data = GitHub.pull_requests(REPO;
                page_limit = 1, auth=getauth(),
                params = myparams)
(GitHub.PullRequest[PullRequest(30004), PullRequest(30000), PullRequest(29998), PullRequest(29997), PullRequest(29994), PullRequest(29993), PullRequest(29992), PullRequest(29991), PullRequest(29990), PullRequest(29986), PullRequest(29978), PullRequest(29976), PullRequest(29975), PullRequest(29973), PullRequest(29969), PullRequest(29965), PullRequest(29963), PullRequest(29962), PullRequest(29961), PullRequest(29959)], Dict("next"=>"https://api.github.com/repositories/1644196/pulls?page=2&per_page=20&state=all","last"=>"https://api.github.com/repositories/1644196/pulls?page=739&per_page=20&state=all"))

julia> prs, page_data = GitHub.pull_requests(REPO;
                page_limit = 1, auth=getauth(),
                start_page = page_data["next"])
ERROR: HTTP.ExceptionRequest.StatusError(403, HTTP.Messages.Response:
"""
HTTP/1.1 403 Forbidden
Server: GitHub.com
Date: Mon, 12 Nov 2018 20:19:36 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 247
Status: 403 Forbidden
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1542054575
X-GitHub-Media-Type: github.v3; format=json
Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Content-Security-Policy: default-src 'none'
X-GitHub-Request-Id: E5A0:2238:1A83900:3F68591:5BE9E051

{"message":"API rate limit exceeded for 97.106.76.121. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)","documentation_url":"https://developer.github.com/v3/#rate-limiting"}""")

Rate should be ok but it seemst hat the auth is unused when calling this with pagination?

Comment constructor confused by what GitHub returns

when fetching issue comments with comments(), the Comment constructor gets confused by timestamps because GitHub returns them in ISO DateTime format, but with an extra Z for the timezone, and the default Dates constructor is confused by the extra Z.

Creating issues?

First of all, great work, love the package.

I wanted to know if creating issues through the API is coming any time soon? If not I could try to make a PR.

POST operations need to handle intermittent network failure.

The GitHub doc says that they have been careful to use HTTP methods with semantics appropriate to the API operations.

HTTP.jl retries most request automatically in the event of network failure. However, POST operations are not generally idempotent and cannot be automatically retried. GitHub.jl should implement system-state-aware retry loops around POST requests. i.e. when a POST operation throws an HTTP.IOError GitHub.jl should retry the operation in a way that avoids duplicate changes to system state.

In the case of the create_status operation that is the subject of JuliaWeb/HTTP.jl#220, POST /repos/:owner/:repo/statuses/:sha, it seems that double-posting would create two statuses, https://developer.github.com/v3/repos/statuses/, so in the event of a failure, the GitHub.jl create_status function should do a GET to check if the status was created before retrying (or, if duplicate statuses are not considered harmful to overall system correctness, just set retry_non_idempotent=true).

@api_default function create_status(api::GitHubAPI, repo, sha; options...)
result = gh_post_json(api, "/repos/$(name(repo))/statuses/$(name(sha))"; options...)
return Status(result)
end

See also JuliaWeb/HTTP.jl#214.

This issue may apply in other places that use gh_post_json.

owner("knarz") throws unexpected error

julia> owner("knarz")
julia> owner("knarz")
ERROR: Unexpected character / after scheme
 in parse_url at /Users/jiahao/.julia/v0.4/URIParser/src/parser.jl:213
 in call at /Users/jiahao/.julia/v0.4/URIParser/src/parser.jl:295
 in extract_nullable at /Users/jiahao/.julia/v0.4/GitHub/src/utils/GitHubType.jl:59
 in json2github at /Users/jiahao/.julia/v0.4/GitHub/src/utils/GitHubType.jl:85
 in call at /Users/jiahao/.julia/v0.4/GitHub/src/owners/owners.jl:43
 in owner at /Users/jiahao/.julia/v0.4/GitHub/src/owners/owners.jl:60
 in owner at /Users/jiahao/.julia/v0.4/GitHub/src/owners/owners.jl:59

Possibly an upstream error in the web stack due to an unescaped slash somewhere.

Needs test

Since this is in JuliaWeb, it would be good to get its testing up to par with the other packages in the org.

So:

  • Actually get some tests in runtests.jl
  • Including AppVeyor testing
  • Collect testing coverage and link to it from the README

Incomplete schema mapping from GitHub API to Owner type

The GitHub.Owner type is missing several fields which can be returned from a GitHub API query returning a representation of a GitHub user.

For example, a GitHub API query to https://api.github.com/repos/JuliaLang/julia/contributors (as would be accessed by contributors("JuliaLang/julia") returns records in raw JSON of the form

  {
    "login": "jiahao",
    "id": 1732,
    "avatar_url": "https://avatars.githubusercontent.com/u/1732?v=3",
    "gravatar_id": "",
    "url": "https://api.github.com/users/jiahao",
    "html_url": "https://github.com/jiahao",
    "followers_url": "https://api.github.com/users/jiahao/followers",
    "following_url": "https://api.github.com/users/jiahao/following{/other_user}",
    "gists_url": "https://api.github.com/users/jiahao/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/jiahao/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/jiahao/subscriptions",
    "organizations_url": "https://api.github.com/users/jiahao/orgs",
    "repos_url": "https://api.github.com/users/jiahao/repos",
    "events_url": "https://api.github.com/users/jiahao/events{/privacy}",
    "received_events_url": "https://api.github.com/users/jiahao/received_events",
    "type": "User",
    "site_admin": false,
    "contributions": 716
  },

Several of these fields, notably the *_url fields like avatar_url, have no corresponding field representation in the GitHub.Owner type. Unfortunately, the lack of this information completely breaks code that relied on having this data, such as the World of Julia notebook (which wants the avatar_url fields).

cc @jrevels

Failed to create repo

julia> auth = GitHub.authenticate(ENV["github_token"])
GitHub.OAuth2(9d**********************************)

julia> owner = GitHub.owner("kindlychung")
Owner (all fields are Union{Nothing, T}):
...

julia> GitHub.create_repo(owner, "testjl")
ERROR: Error found in GitHub reponse:
	Status Code: 401
	Message: Requires authentication
	Docs URL: https://developer.github.com/v3/repos/#create
	Errors: 
Stacktrace:
 [1] error(::String, ::String, ::String, ::String, ::String) at ./error.jl:42
 [2] handle_response_error(::HTTP.Messages.Response) at /home/kaiyin/.julia/packages/GitHub/hKBtB/src/utils/requests.jl:159
 [3] #github_request#3(::GitHub.AnonymousAuth, ::Bool, ::Dict{Any,Any}, ::Dict{String,Any}, ::Bool, ::Function, ::GitHub.GitHubWebAPI, ::Function, ::String) at /home/kaiyin/.julia/packages/GitHub/hKBtB/src/utils/requests.jl:63
 [4] #gh_post_json#10(::Base.Iterators.Pairs{Symbol,Dict{String,Any},Tuple{Symbol},NamedTuple{(:params,),Tuple{Dict{String,Any}}}}, ::Function, ::GitHub.GitHubWebAPI, ::String) at ./none:0
 [5] #gh_post_json at ./none:0 [inlined]
 [6] #create_repo#52(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::GitHub.GitHubWebAPI, ::Owner, ::String, ::Dict{String,Any}) at /home/kaiyin/.julia/packages/GitHub/hKBtB/src/repositories/repositories.jl:58
 [7] create_repo at /home/kaiyin/.julia/packages/GitHub/hKBtB/src/repositories/repositories.jl:54 [inlined]
 [8] #create_repo#53 at ./none:0 [inlined]
 [9] create_repo at ./none:0 [inlined] (repeats 2 times)
 [10] top-level scope at none:0

I do have 2-factor auth turned on (by company policy). Could that be the cause?

can't use Github packge?

I ran a Pkg.update() and then did...

julia> Pkg.add("GitHub")
INFO: Nothing to be done

julia> using Github
Warning: replacing module GitHub
Warning: requiring "Github" did not define a corresponding module.

julia> using Github
Warning: requiring "Github" did not define a corresponding module.

What am I doing wrong?
Thanks!

GitHub.reference fails if multiple branches matches

If the ref doesn't exist in the repository, but existing refs start with ref they will be returned as an array. I

julia> GitHub.reference("JuliaLang/julia", "heads/v"; handle_error=false)
ERROR: MethodError: no method matching Reference(::Array{Any,1})
Closest candidates are:
  Reference(::Any, ::Any, ::Any) at /home/kc/.julia/packages/GitHub/hKBtB/src/git/reference.jl:2
  Reference(::Union{Nothing, String}, ::Union{Nothing, HTTP.URIs.URI}, ::Union{Nothing, Dict}) at /home/kc/.julia/packages/GitHub/hKBtB/src/git/reference.jl:2
  Reference(::Dict) at /home/kc/.julia/packages/GitHub/hKBtB/src/git/reference.jl:7
Stacktrace:
 [1] #reference#219(::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:handle_error,),Tuple{Bool}}}, ::typeof(reference), ::GitHub.GitHubWebAPI, ::String, ::String) at /home/kc/.julia/packages/GitHub/hKBtB/src/git/reference.jl:13
 [2] #reference at ./none:0 [inlined]
 [3] #reference#220 at ./none:0 [inlined]
 [4] (::GitHub.var"#kw##reference")(::NamedTuple{(:handle_error,),Tuple{Bool}}, ::typeof(reference), ::String, ::String) at ./none:0
 [5] top-level scope at REPL[8]:1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.