Create bounties for existing issues when enabling a repository
* Create bounties for existing bounty-tagged issues when a repository is toggled on * added commiteth.bounties ns for sharing code Fixes: #12
This commit is contained in:
parent
f89a83ea32
commit
985b72754d
|
@ -0,0 +1,46 @@
|
|||
(ns commiteth.bounties
|
||||
(:require [commiteth.db.issues :as issues]
|
||||
[commiteth.db.users :as users]
|
||||
[commiteth.db.repositories :as repos]
|
||||
[commiteth.eth.core :as eth]
|
||||
[commiteth.github.core :as github]
|
||||
[commiteth.eth.core :as eth]
|
||||
[clojure.tools.logging :as log]))
|
||||
|
||||
|
||||
(def ^:const label-name "bounty")
|
||||
|
||||
(defn has-bounty-label?
|
||||
[issue]
|
||||
(let [labels (:labels issue)]
|
||||
(some #(= label-name (:name %)) labels)))
|
||||
|
||||
|
||||
(defn add-bounty-for-issue [repo-map issue]
|
||||
(log/debug "add-bounty-for-issue" issue)
|
||||
(let [{issue-id :id
|
||||
issue-number :number
|
||||
issue-title :title} issue
|
||||
{repo :repo
|
||||
repo-id :repo_id
|
||||
user :login} repo-map
|
||||
created-issue (issues/create repo-id issue-id issue-number issue-title)
|
||||
repo-owner (:address (users/get-repo-owner repo-id))]
|
||||
(log/info (format "Issue %s/%s/%s labeled as bounty" user repo issue-number))
|
||||
(if (= 1 created-issue)
|
||||
(let [transaction-hash (eth/deploy-contract repo-owner)]
|
||||
(log/info "Contract deployed, transaction-hash:" transaction-hash )
|
||||
(issues/update-transaction-hash issue-id transaction-hash))
|
||||
(log/debug "Issue already exists in DB, ignoring"))))
|
||||
|
||||
|
||||
(defn add-bounties-for-existing-issues [repo-map]
|
||||
(let [{repo :repo
|
||||
user :login} repo-map
|
||||
issues (github/get-issues user repo)
|
||||
bounty-issues (filter has-bounty-label? issues)]
|
||||
(log/debug bounty-issues)
|
||||
(log/debug "adding bounties for"
|
||||
(count bounty-issues) " existing issues")
|
||||
(doall
|
||||
(map (partial add-bounty-for-issue repo-map) bounty-issues))))
|
|
@ -10,7 +10,7 @@
|
|||
[mount.core :as mount])
|
||||
(:gen-class))
|
||||
|
||||
(def cli-options
|
||||
(def ^:const cli-options
|
||||
[["-p" "--port PORT" "Port number"
|
||||
:parse-fn #(Integer/parseInt %)]])
|
||||
|
||||
|
@ -58,4 +58,3 @@ repl-server
|
|||
(System/exit 0))
|
||||
:else
|
||||
(start-app args)))
|
||||
|
||||
|
|
|
@ -160,7 +160,8 @@
|
|||
(defn update-comment
|
||||
[user repo comment-id issue-number balance]
|
||||
(let [comment (generate-comment user repo issue-number balance)]
|
||||
(log/debug (str "Updating " user "/" repo "/" issue-number " comment #" comment-id " with contents: " comment))
|
||||
(log/debug (str "Updating " user "/" repo "/" issue-number
|
||||
" comment #" comment-id " with contents: " comment))
|
||||
(let [req (make-patch-request "repos/%s/%s/issues/comments/%s"
|
||||
[user repo comment-id]
|
||||
(assoc (self-auth-params) :body comment))]
|
||||
|
@ -170,6 +171,11 @@
|
|||
[user repo issue-number]
|
||||
(issues/specific-issue user repo issue-number (self-auth-params)))
|
||||
|
||||
(defn get-issues
|
||||
[user repo]
|
||||
(issues/issues user repo))
|
||||
|
||||
|
||||
(defn get-issue-events
|
||||
[user repo issue-id]
|
||||
(issues/issue-events user repo issue-id (self-auth-params)))
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
[buddy.auth :refer [authenticated?]]
|
||||
[commiteth.db.users :as users]
|
||||
[commiteth.db.repositories :as repositories]
|
||||
[commiteth.db.bounties :as bounties]
|
||||
[commiteth.db.bounties :as bounties-db]
|
||||
[commiteth.bounties :as bounties]
|
||||
[commiteth.github.core :as github]
|
||||
[clojure.tools.logging :as log]
|
||||
[commiteth.eth.core :as eth]))
|
||||
|
@ -56,13 +57,15 @@
|
|||
:current-user user
|
||||
(ok (repositories/get-enabled (:id user))))
|
||||
(GET "/bounties" []
|
||||
(ok (bounties/list-all-bounties)))
|
||||
(ok (bounties-db/list-all-bounties)))
|
||||
(POST "/bounty/:issue{[0-9]{1,9}}/payout" {:keys [params]}
|
||||
:auth-rules authenticated?
|
||||
:current-user user
|
||||
(let [{issue :issue
|
||||
payout-hash :payout-hash} params
|
||||
result (bounties/update-payout-hash (Integer/parseInt issue) payout-hash)]
|
||||
result (bounties-db/update-payout-hash
|
||||
(Integer/parseInt issue)
|
||||
payout-hash)]
|
||||
(if (= 1 result)
|
||||
(ok)
|
||||
(internal-server-error))))
|
||||
|
@ -72,7 +75,7 @@
|
|||
(ok (map #(conj % (let [balance (:balance %)]
|
||||
{:balance-eth (eth/hex->eth balance 6)
|
||||
:balance-wei (eth/hex->big-integer balance)}))
|
||||
(bounties/list-owner-bounties (:id user)))))
|
||||
(bounties-db/list-owner-bounties (:id user)))))
|
||||
(POST "/repository/toggle" {:keys [params]}
|
||||
:auth-rules authenticated?
|
||||
:current-user user
|
||||
|
@ -85,10 +88,11 @@
|
|||
(repositories/create (merge params {:user_id user-id}))
|
||||
(repositories/toggle repo-id))]
|
||||
(if (:enabled result)
|
||||
;; @todo: do we really want to make this call at this moment?
|
||||
(let [created-hook (github/add-webhook repo token)]
|
||||
(log/debug "Created webhook:" created-hook)
|
||||
(github/create-label repo token)
|
||||
(repositories/update-hook-id repo-id (:id created-hook)))
|
||||
(future
|
||||
(github/create-label repo token)
|
||||
(repositories/update-hook-id repo-id (:id created-hook))
|
||||
(bounties/add-bounties-for-existing-issues result)))
|
||||
(github/remove-webhook repo (:hook_id result) token))
|
||||
result)))))
|
||||
|
|
|
@ -4,44 +4,48 @@
|
|||
[commiteth.db.pull-requests :as pull-requests]
|
||||
[commiteth.db.issues :as issues]
|
||||
[commiteth.db.users :as users]
|
||||
[commiteth.eth.core :as eth]
|
||||
[commiteth.bounties :as bounties]
|
||||
[ring.util.http-response :refer [ok]]
|
||||
[clojure.string :refer [join]]
|
||||
[clojure.tools.logging :as log])
|
||||
(:import [java.lang Integer]))
|
||||
|
||||
(def label-name "bounty")
|
||||
|
||||
(defn find-issue-event
|
||||
[events type owner]
|
||||
(first (filter #(and
|
||||
(= owner (get-in % [:actor :login]))
|
||||
(= type (:event %)))
|
||||
events)))
|
||||
events)))
|
||||
|
||||
|
||||
(defn labeled-as-bounty?
|
||||
[action issue]
|
||||
(and
|
||||
(= "labeled" action)
|
||||
(= bounties/label-name (get-in issue [:label :name]))))
|
||||
|
||||
(defn find-commit-id
|
||||
[user repo issue-number event-types]
|
||||
(log/debug "find-commit-id" user repo issue-number event-types)
|
||||
(some identity (map #(->
|
||||
(github/get-issue-events user repo issue-number)
|
||||
(find-issue-event % user)
|
||||
:commit_id)
|
||||
event-types)))
|
||||
event-types)))
|
||||
|
||||
|
||||
(defn handle-issue-labeled
|
||||
[issue]
|
||||
(let [{repo-id :id
|
||||
repo :name
|
||||
{user :login} :owner} (:repository issue)
|
||||
{issue-id :id
|
||||
issue-number :number
|
||||
issue-title :title} (:issue issue)
|
||||
created-issue (issues/create repo-id issue-id issue-number issue-title)
|
||||
repo-owner (:address (users/get-repo-owner repo-id))]
|
||||
(log/debug (format "Issue %s/%s/%s labeled as bounty" user repo issue-number))
|
||||
(when (= 1 created-issue)
|
||||
(issues/update-transaction-hash issue-id (eth/deploy-contract repo-owner)))))
|
||||
[webhook-payload]
|
||||
(let [{issue :issue} webhook-payload
|
||||
{repo-id :id
|
||||
repo-name :name
|
||||
{login :login} :owner} (:repository webhook-payload)
|
||||
repo-map {:repo repo-name :login login :repo_id repo-id}]
|
||||
(bounties/add-bounty-for-issue repo-map issue)))
|
||||
|
||||
(defn handle-issue-closed
|
||||
;; TODO: does not work in case the issue is closed on github web ui
|
||||
[{{{user :login} :owner repo :name} :repository
|
||||
{issue-id :id issue-number :number} :issue}]
|
||||
(future
|
||||
|
@ -49,7 +53,7 @@
|
|||
(log/debug (format "Issue %s/%s/%s closed with commit %s" user repo issue-number commit-id))
|
||||
(issues/close commit-id issue-id))))
|
||||
|
||||
(def keywords
|
||||
(def ^:const keywords
|
||||
[#"(?i)close\s+#(\d+)"
|
||||
#"(?i)closes\s+#(\d+)"
|
||||
#"(?i)closed\s+#(\d+)"
|
||||
|
@ -70,16 +74,12 @@
|
|||
(catch NumberFormatException _)))
|
||||
(re-seq % pr-body)) keywords))
|
||||
|
||||
(defn has-bounty-label?
|
||||
[issue]
|
||||
(let [labels (:labels issue)]
|
||||
(some #(= label-name (:name %)) labels)))
|
||||
|
||||
(defn validate-issue-number
|
||||
"Checks if an issue has a bounty label attached and returns its number"
|
||||
[user repo issue-number]
|
||||
(when-let [issue (github/get-issue user repo issue-number)]
|
||||
(when (has-bounty-label? issue)
|
||||
(when (bounties/has-bounty-label? issue)
|
||||
issue-number)))
|
||||
|
||||
(defn handle-pull-request-closed
|
||||
|
@ -92,40 +92,38 @@
|
|||
id :id
|
||||
pr-number :number
|
||||
pr-body :body} :pull_request}]
|
||||
(log/debug "handle-pull-request-closed" owner repo repo-id login pr-body)
|
||||
(future
|
||||
(let [commit-id (find-commit-id owner repo pr-number ["merged"])
|
||||
issue-number (->>
|
||||
(extract-issue-number pr-body)
|
||||
(first)
|
||||
(validate-issue-number owner repo))
|
||||
(extract-issue-number pr-body)
|
||||
(first)
|
||||
(validate-issue-number owner repo))
|
||||
m {:commit_id commit-id :issue_number issue-number}]
|
||||
(log/debug "handle-pull-request-closed" commit-id issue-number)
|
||||
(when (or commit-id issue-number)
|
||||
(log/debug (format "Pull request %s/%s/%s closed with reference to %s"
|
||||
login repo pr-number
|
||||
(if commit-id (str "commit-id " commit-id)
|
||||
(str "issue-number " issue-number))))
|
||||
login repo pr-number
|
||||
(if commit-id (str "commit-id " commit-id)
|
||||
(str "issue-number " issue-number))))
|
||||
(pull-requests/create (merge m {:repo_id repo-id
|
||||
:pr_id id
|
||||
:pr_number pr-number
|
||||
:user_id user-id}))
|
||||
(users/create-user user-id login name nil nil)))))
|
||||
|
||||
(defn labeled-as-bounty?
|
||||
[action issue]
|
||||
(and
|
||||
(= "labeled" action)
|
||||
(= label-name (get-in issue [:label :name]))))
|
||||
|
||||
(defn handle-issue
|
||||
[issue]
|
||||
(when-let [action (:action issue)]
|
||||
(when (labeled-as-bounty? action issue)
|
||||
(handle-issue-labeled issue))
|
||||
[webhook-payload]
|
||||
(when-let [action (:action webhook-payload)]
|
||||
(log/debug "handle-issue")
|
||||
(when (labeled-as-bounty? action webhook-payload)
|
||||
(handle-issue-labeled webhook-payload))
|
||||
(when (and
|
||||
(= "closed" action)
|
||||
(has-bounty-label? (:issue issue)))
|
||||
(handle-issue-closed issue)))
|
||||
(ok (str issue)))
|
||||
(= "closed" action)
|
||||
(bounties/has-bounty-label? (:issue webhook-payload)))
|
||||
(handle-issue-closed webhook-payload)))
|
||||
(ok (str webhook-payload)))
|
||||
|
||||
(defn handle-pull-request
|
||||
[pull-request]
|
||||
|
@ -135,7 +133,7 @@
|
|||
|
||||
(defroutes webhook-routes
|
||||
(POST "/webhook" {:keys [params headers]}
|
||||
(case (get headers "x-github-event")
|
||||
"issues" (handle-issue params)
|
||||
"pull_request" (handle-pull-request params)
|
||||
(ok))))
|
||||
(case (get headers "x-github-event")
|
||||
"issues" (handle-issue params)
|
||||
"pull_request" (handle-pull-request params)
|
||||
(ok))))
|
||||
|
|
Loading…
Reference in New Issue