Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 13315782a4
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 418 lines (350 sloc) 13.49 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
(ns tentacles.repos
  "Implements the Github Repos API: http://developer.github.com/v3/repos/"
  (:refer-clojure :exclude [keys])
  (:use [clj-http.client :only [post put]]
        [clojure.java.io :only [file]]
        [tentacles.core :only [api-call no-content?]]
        [cheshire.core :only [generate-string]]))

;; ## Primary Repos API

(defn repos
  "List the authenticated user's repositories.
Options are:
type -- all (default), public, private, member."
  [options]
  (api-call :get "user/repos" nil options))

(defn user-repos
  "List a user's repositories.
Options are:
types -- all (default), public, private, member."
  [user & [options]]
  (api-call :get "users/%s/repos" [user] options))

(defn org-repos
  "List repositories for an organization.
Options are:
type -- all (default), public, private."
  [org & [options]]
  (api-call :get "orgs/%s/repos" [org] options))

(defn create-repo
  "Create a new repository.
Options are:
description -- Repository's description.
homepage -- Link to repository's homepage.
public -- true (default), false.
has-issues -- true (default), false.
has-wiki -- true (default), false.
has-downloads -- true (default), false."
  [name options]
  (api-call :post "user/repos" nil (assoc options :name name)))

(defn create-org-repo
  "Create a new repository in an organization..
Options are:
description -- Repository's description.
homepage -- Link to repository's homepage.
public -- true (default), false.
has-issues -- true (default), false.
has-wiki -- true (default), false.
has-downloads -- true (default), false.
team-id -- Team that will be granted access to this
repository."
  [org name options]
  (api-call :post "orgs/%s/repos" [org] (assoc options :name name)))

(defn specific-repo
  "Get a repository."
  [user repo & [options]]
  (api-call :get "repos/%s/%s" [user repo] options))

(defn edit-repo
  "Edit a repository.
Options are:
description -- Repository's description.
name -- Repository's name.
homepage -- Link to repository's homepage.
public -- true, false.
has-issues -- true, false.
has-wiki -- true, false.
has-downloads -- true, false."
  [user repo options]
  (api-call :post "repos/%s/%s"
            [user repo]
            (if (:name options)
              options
              (assoc options :name repo))))

(defn contributors
  "List the contributors for a project.
Options are:
anon -- true, false (default): If true, include
anonymous contributors."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/contributors" [user repo] options))

(defn languages
  "List the languages that a repository uses."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/languages" [user repo] options))

(defn teams
  "List a repository's teams."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/teams" [user repo] options))

(defn tags
  "List a repository's tags."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/tags" [user repo] options))

(defn branches
  "List a repository's branches."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/branches" [user repo] options))

;; ## Repo Collaborators API

(defn collaborators
  "List a repository's collaborators."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/collaborators" [user repo] options))

(defn collaborator?
  "Check if a user is a collaborator."
  [user repo collaborator & [options]]
  (no-content? (api-call :get "repos/%s/%s/collaborators/%s" [user repo collaborator] options)))

(defn add-collaborator
  "Add a collaborator to a repository."
  [user repo collaborator options]
  (no-content? (api-call :put "repos/%s/%s/collaborators/%s" [user repo collaborator] options)))

(defn remove-collaborator
  "Remove a collaborator from a repository."
  [user repo collaborator options]
  (no-content? (api-call :delete "repos/%s/%s/collaborators/%s" [user repo collaborator] options)))

;; ## Repo Commits API

(defn commits
  "List commits for a repository.
Options are:
sha -- Sha or branch to start lising commits from.
path -- Only commits at this path will be returned."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/commits" [user repo] options))

(defn specific-commit
  "Get a specific commit."
  [user repo sha & [options]]
  (api-call :get "repos/%s/%s/commits/%s" [user repo sha] options))

(defn commit-comments
  "List the commit comments for a repository."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/comments" [user repo] options))

(defn specific-commit-comments
  "Get the comments on a specific commit."
  [user repo sha & [options]]
  (api-call :get "repos/%s/%s/commits/%s/comments" [user repo sha] options))

;; 'line' is supposed to be a required argument for this API call, but
;; I'm convinced that it doesn't do anything. The only thing that seems
;; to matter is the 'position' argument. As a matter of fact, we can omit
;; 'line' entirely and Github does not complain, despite it supposedly being
;; a required argument.
;;
;; Furthermore, it requires that the sha be passed in the URL *and* the JSON
;; input. I don't see how they can ever possibly be different, so we're going
;; to just require one sha.
(defn create-commit-comment
  "Create a commit comment. path is the location of the file you're commenting on.
position is the index of the line you're commenting on. Not the actual line number,
but the nth line shown in the diff."
  [user repo sha path position body options]
  (api-call :post "repos/%s/%s/commits/%s/comments" [user repo sha]
            (assoc options
              :body body
              :commit-id sha
              :path path
              :position position)))

(defn specific-commit-comment
  "Get a specific commit comment."
  [user repo id & [options]]
  (api-call :get "repos/%s/%s/comments/%s" [user repo id] options))

(defn update-commit-comment
  "Update a commit comment."
  [user repo id body options]
  (api-call :post "repos/%s/%s/comments/%s" [user repo id] (assoc options :body body)))

(defn compare-commits
  [user repo base head & [options]]
  (api-call :get "repos/%s/%s/compare/%s...%s" [user repo base head] options))

(defn delete-commit-comment
  [user repo id options]
  (no-content? (api-call :delete "repos/%s/%s/comments/%s" [user repo id] options)))

;; ## Repo Downloads API

(defn downloads
  "List the downloads for a repository."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/downloads" [user repo] options))

(defn specific-download
  "Get a specific download."
  [user repo id & [options]]
  (api-call :get "repos/%s/%s/downloads/%s" [user repo id] options))

(defn delete-download
  "Delete a download"
  [user repo id options]
  (no-content? (api-call :delete "repos/%s/%s/downloads/%s" [user repo id] options)))

;; Github uploads are a two step process. First we get a download resource and then
;; we use that to upload the file.
(defn download-resource
  "Get a download resource for a file you want to upload. You can pass it
to upload-file to actually upload your file."
  [user repo path options]
  (let [path (file path)]
    (assoc (api-call :post "repos/%s/%s/downloads"
                     [user repo]
                     (assoc options
                       :name (.getName path)
                       :size (.length path)))
      :filepath path)))

;; This isn't really even a Github API call, since it calls an Amazon API.
;; As such, it doesn't provide the same guarentees as the rest of the API.
;; We'll just return the raw response.
(defn upload-file
  "Upload a file given a download resource obtained from download-resource."
  [resp]
  (post (:s3_url resp)
        {:multipart [["key" (:path resp)]
                     ["acl" (:acl resp)]
                     ["success_action_status" "201"]
                     ["Filename" (:name resp)]
                     ["AWSAccessKeyId" (:accesskeyid resp)]
                     ["Policy" (:policy resp)]
                     ["Signature" (:signature resp)]
                     ["Content-Type" (:mime_type resp)]
                     ["file" (:filepath resp)]]}))

;; Repo Forks API

(defn forks
  "Get a list of a repository's forks."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/forks" [user repo] options))

(defn create-fork
  "Create a new fork.
Options are:
org -- If present, the repo is forked to this organization."
  [user repo options]
  (api-call :post "repos/%s/%s/forks" [user repo] options))

;; Repo Deploy Keys API

(defn keys
  "List deploy keys for a repo."
  [user repo options]
  (api-call :get "repos/%s/%s/keys" [user repo] options))

(defn specific-key
  "Get a specific deploy key."
  [user repo id options]
  (api-call :get "repos/%s/%s/keys/%s" [user repo id] options))

(defn create-key
  "Create a new deploy key."
  [user repo title key options]
  (api-call :post "repos/%s/%s/keys" [user repo]
            (assoc options :title title :key key)))

(defn edit-key
  "Edit a deploy key.
Options are:
title -- New title.
key -- New key."
  [user repo id options]
  (api-call :post "repos/%s/%s/keys/%s" [user repo id] options))

(defn delete-key
  "Delete a deploy key."
  [user repo id options]
  (api-call :delete "repos/%s/%s/keys/%s" [user repo id] options))

;; Repo Watcher API

(defn watchers
  "List a repository's watchers."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/watchers" [user repo] options))

(defn watching
  "List all the repositories that a user is watching."
  [user & [options]]
  (api-call :get "users/%s/watched" [user] options))

(defn watching?
  "Check if you are watching a repository."
  [user repo options]
  (no-content? (api-call :get "user/watched/%s/%s" [user repo] options)))

(defn watch
  "Watch a repository."
  [user repo options]
  (no-content? (api-call :put "user/watched/%s/%s" [user repo] options)))

(defn unwatch
  "Unwatch a repository."
  [user repo options]
  (no-content? (api-call :delete "user/watched/%s/%s" [user repo] options)))

;; ## Repo Stargazers

(defn stargazers
  "List a repository's stargazers."
  [user repo & [options]]
  (api-call :get "repos/%s/%s/stargazers" [user repo] options))

(defn starring
  "List all the repositories that a user is starring."
  [user & [options]]
  (api-call :get "users/%s/starred" [user] options))

(defn starring?
  "Check if you are watching a repository."
  [user repo options]
  (no-content? (api-call :get "user/starred/%s/%s" [user repo] options)))

(defn star
  "Star a repository."
  [user repo options]
  (no-content? (api-call :put "user/starred/%s/%s" [user repo] options)))

(defn unstar
  "Unstar a repository"
  [user repo options]
  (no-content? (api-call :delete "user/starred/%s/%s" [user repo] options)))

;; ## Repo Hooks API

(defn hooks
  "List the hooks on a repository."
  [user repo options]
  (api-call :get "repos/%s/%s/hooks" [user repo] options))

(defn specific-hook
  "Get a specific hook."
  [user repo id options]
  (api-call :get "repos/%s/%s/hooks/%s" [user repo id] options))

(defn create-hook
  "Create a hook.
Options are:
events -- A sequence of event strings. Only 'push' by default.
active -- true or false; determines if the hook is actually triggered
on pushes."
  [user repo name config options]
  (api-call :post "repos/%s/%s/hooks" [user repo name config]
            (assoc options
              :name name, :config config)))

(defn edit-hook
  "Edit an existing hook.
Options are:
name -- Name of the hook.
config -- Modified config.
events -- A sequence of event strings. Replaces the events.
add_events -- A sequence of event strings to be added.
remove_events -- A sequence of event strings to remove.
active -- true or false; determines if the hook is actually
triggered on pushes."
  [user repo id options]
  (api-call :post "repos/%s/%s/hooks/%s" [user repo id] options))

(defn test-hook
  "Test a hook."
  [user repo id options]
  (no-content? (api-call :post "repos/%s/%s/hooks/%s/test" [user repo id] options)))

(defn delete-hook
  "Delete a hook."
  [user repo id options]
  (no-content? (api-call :delete "repos/%s/%s/hooks/%s" [user repo id] options)))

;; ## PubSubHubbub

(defn pubsubhubub
  "Create or modify a pubsubhubub subscription.
Options are:
secret -- A shared secret key that generates an SHA HMAC of the
payload content."
  [user repo mode event callback & [options]]
  (no-content?
   (post "https://api.github.com/hub"
         {:basic-auth (:auth options)
          :form-params
          (merge
           {"hub.mode" mode
            "hub.topic" (format "https://github.com/%s/%s/events/%s"
                                user repo event)
            "hub.callback" callback}
           (when-let [secret (:secret options)]
             {"hub.secret" secret}))})))

;; ## Repo Contents API

(defn readme
  "Get the preferred README for a repository."
  [user repo options]
  (api-call :get "repos/%s/%s/readme" [user repo] options))

(defn contents
  "Get the contents of any file or directory in a repository."
  [user repo path options]
  (api-call :get "repos/%s/%s/contents/%s" [user repo path] options))
Something went wrong with that request. Please try again.