Initial linear code.
This commit is contained in:
parent
a36202b167
commit
83edc12709
|
|
@ -0,0 +1,4 @@
|
||||||
|
{:paths ["src" "resources"]
|
||||||
|
:deps {}
|
||||||
|
:aliases {:test {:extra-paths ["test"]
|
||||||
|
:extra-deps {}}}}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
(ns org.aplex.rest-linear.core
|
||||||
|
(:require [org.aplex.helpers.interface :as h]))
|
||||||
|
|
||||||
|
(def default-config {:api-host "https://api.linear.app"})
|
||||||
|
(def api-config (atom default-config))
|
||||||
|
|
||||||
|
(defn init-config [cfg]
|
||||||
|
(reset! api-config (merge default-config cfg)))
|
||||||
|
|
||||||
|
(defn- api-key []
|
||||||
|
(or (-> @api-config :api-key)
|
||||||
|
(throw (ex-info "Linear api_key is not configured; call init-config with :api-key"
|
||||||
|
{:component "org.aplex.rest-linear"}))))
|
||||||
|
|
||||||
|
(defn- request [query variables]
|
||||||
|
(let [envelope (cond-> {:query query}
|
||||||
|
variables (assoc :variables variables))]
|
||||||
|
{:method :post
|
||||||
|
:base-url (-> @api-config :api-host)
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers [{:name "Authorization" :value (api-key)}]
|
||||||
|
:auth nil
|
||||||
|
:body (when envelope (h/encode-json envelope))}))
|
||||||
|
|
||||||
|
(defn fetch-teams []
|
||||||
|
(request "query{ teams{ nodes{ id name key } } }" nil))
|
||||||
|
|
||||||
|
(defn fetch-issue [issue-id]
|
||||||
|
(request "query($id: String!){ issue(id: $id){ id identifier title description state{ name } } }"
|
||||||
|
{:id issue-id}))
|
||||||
|
|
||||||
|
(defn fetch-my-issues []
|
||||||
|
(request "query{ viewer{ assignedIssues{ nodes{ id identifier title state{ name } } } } }" nil))
|
||||||
|
|
||||||
|
(defn fetch-team-issues [team-id]
|
||||||
|
(request "query($id: String!){ team(id: $id){ id name key issues{ nodes{ id identifier title state{ name } } } } }"
|
||||||
|
{:id team-id}))
|
||||||
|
|
||||||
|
(defn fetch-active-cycle-issues [team-id]
|
||||||
|
(request "query($id: String!){ team(id: $id){ activeCycle{ id number issues{ nodes{ id identifier title state{ name } assignee{ name } } } } } }"
|
||||||
|
{:id team-id}))
|
||||||
|
|
||||||
|
(defn create-issue
|
||||||
|
([title team-id]
|
||||||
|
(create-issue title team-id nil))
|
||||||
|
([title team-id description]
|
||||||
|
(request "mutation($input: IssueCreateInput!){ issueCreate(input: $input){ success issue{ id identifier } } }"
|
||||||
|
(cond-> {:input {:title title :teamId team-id}}
|
||||||
|
description (assoc-in [:input :description] description)))))
|
||||||
|
|
||||||
|
(defn update-issue [issue-id updates]
|
||||||
|
(request "mutation($id: String!, $input: IssueUpdateInput!){ issueUpdate(id: $id, input: $input){ success issue{ id identifier } } }"
|
||||||
|
{:id issue-id :input updates}))
|
||||||
|
|
||||||
|
(defn fetch-issues [filter]
|
||||||
|
(request "query($filter: IssueFilter){ issues(filter: $filter){ nodes{ id identifier title state{ name } assignee{ name email } } } }"
|
||||||
|
{:filter filter}))
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
(ns org.aplex.rest-linear.interface
|
||||||
|
(:require
|
||||||
|
[org.aplex.rest-linear.core :as c]))
|
||||||
|
|
||||||
|
(defn init-config [cfg]
|
||||||
|
(c/init-config cfg))
|
||||||
|
|
||||||
|
(defn fetch-teams []
|
||||||
|
(c/fetch-teams))
|
||||||
|
|
||||||
|
(defn fetch-issue [issue-id]
|
||||||
|
(c/fetch-issue issue-id))
|
||||||
|
|
||||||
|
(defn fetch-my-issues []
|
||||||
|
(c/fetch-my-issues))
|
||||||
|
|
||||||
|
(defn fetch-team-issues [team-id]
|
||||||
|
(c/fetch-team-issues team-id))
|
||||||
|
|
||||||
|
(defn fetch-active-cycle-issues [team-id]
|
||||||
|
(c/fetch-active-cycle-issues team-id))
|
||||||
|
|
||||||
|
(defn create-issue
|
||||||
|
([title team-id]
|
||||||
|
(c/create-issue title team-id))
|
||||||
|
([title team-id description]
|
||||||
|
(c/create-issue title team-id description)))
|
||||||
|
|
||||||
|
(defn update-issue [issue-id updates]
|
||||||
|
(c/update-issue issue-id updates))
|
||||||
|
|
||||||
|
(defn fetch-issues [filter]
|
||||||
|
(c/fetch-issues filter))
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
(ns org.aplex.rest-linear.interface-test
|
||||||
|
(:require [clojure.test :as test :refer :all]
|
||||||
|
[org.aplex.rest-linear.interface :as rest-linear]))
|
||||||
|
|
||||||
|
(def abstract-keys
|
||||||
|
#{:method :base-url :path :path-params :query-params :headers :auth :body})
|
||||||
|
|
||||||
|
(defn reset-config [cfg]
|
||||||
|
(rest-linear/init-config cfg))
|
||||||
|
|
||||||
|
(defn test-config []
|
||||||
|
{:api-key "lin_api_test"})
|
||||||
|
|
||||||
|
(defn api-key-header []
|
||||||
|
[{:name "Authorization" :value "lin_api_test"}])
|
||||||
|
|
||||||
|
(deftest api-host-defaults-to-linear
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= "https://api.linear.app"
|
||||||
|
(:base-url (rest-linear/fetch-teams)))))
|
||||||
|
|
||||||
|
(deftest api-host-is-overridable
|
||||||
|
(reset-config (merge (test-config) {:api-host "https://linear.example.com"}))
|
||||||
|
(is (= "https://linear.example.com"
|
||||||
|
(:base-url (rest-linear/fetch-teams)))))
|
||||||
|
|
||||||
|
(deftest api-key-is-mandatory
|
||||||
|
(reset-config {:api-key nil})
|
||||||
|
(is (thrown? Exception (rest-linear/fetch-teams))))
|
||||||
|
|
||||||
|
(deftest fetch-teams-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"query{ teams{ nodes{ id name key } } }\"}"}
|
||||||
|
(rest-linear/fetch-teams))))
|
||||||
|
|
||||||
|
(deftest fetch-issue-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"query($id: String!){ issue(id: $id){ id identifier title description state{ name } } }\",\"variables\":{\"id\":\"ABC-123\"}}"}
|
||||||
|
(rest-linear/fetch-issue "ABC-123"))))
|
||||||
|
|
||||||
|
(deftest fetch-my-issues-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"query{ viewer{ assignedIssues{ nodes{ id identifier title state{ name } } } } }\"}"}
|
||||||
|
(rest-linear/fetch-my-issues))))
|
||||||
|
|
||||||
|
(deftest fetch-team-issues-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"query($id: String!){ team(id: $id){ id name key issues{ nodes{ id identifier title state{ name } } } } }\",\"variables\":{\"id\":\"team-1\"}}"}
|
||||||
|
(rest-linear/fetch-team-issues "team-1"))))
|
||||||
|
|
||||||
|
(deftest create-issue-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"mutation($input: IssueCreateInput!){ issueCreate(input: $input){ success issue{ id identifier } } }\",\"variables\":{\"input\":{\"title\":\"My title\",\"teamId\":\"team-1\"}}}"}
|
||||||
|
(rest-linear/create-issue "My title" "team-1"))))
|
||||||
|
|
||||||
|
(deftest create-issue-includes-description-when-given
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"mutation($input: IssueCreateInput!){ issueCreate(input: $input){ success issue{ id identifier } } }\",\"variables\":{\"input\":{\"title\":\"My title\",\"teamId\":\"team-1\",\"description\":\"A description\"}}}"}
|
||||||
|
(rest-linear/create-issue "My title" "team-1" "A description"))))
|
||||||
|
|
||||||
|
(deftest update-issue-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"mutation($id: String!, $input: IssueUpdateInput!){ issueUpdate(id: $id, input: $input){ success issue{ id identifier } } }\",\"variables\":{\"id\":\"issue-1\",\"input\":{\"title\":\"New title\"}}}"}
|
||||||
|
(rest-linear/update-issue "issue-1" {:title "New title"}))))
|
||||||
|
|
||||||
|
(deftest fetch-active-cycle-issues-builds-abstract-request
|
||||||
|
(reset-config (test-config))
|
||||||
|
(is (= {:method :post
|
||||||
|
:base-url "https://api.linear.app"
|
||||||
|
:path "/graphql"
|
||||||
|
:path-params []
|
||||||
|
:query-params []
|
||||||
|
:headers (api-key-header)
|
||||||
|
:auth nil
|
||||||
|
:body "{\"query\":\"query($id: String!){ team(id: $id){ activeCycle{ id number issues{ nodes{ id identifier title state{ name } assignee{ name } } } } } }\",\"variables\":{\"id\":\"team-1\"}}"}
|
||||||
|
(rest-linear/fetch-active-cycle-issues "team-1"))))
|
||||||
|
|
||||||
|
(deftest requests-are-transport-agnostic
|
||||||
|
(reset-config (test-config))
|
||||||
|
(doseq [request [(rest-linear/fetch-teams)
|
||||||
|
(rest-linear/fetch-issue "ABC-123")
|
||||||
|
(rest-linear/fetch-my-issues)
|
||||||
|
(rest-linear/fetch-team-issues "team-1")
|
||||||
|
(rest-linear/fetch-active-cycle-issues "team-1")
|
||||||
|
(rest-linear/create-issue "My title" "team-1")
|
||||||
|
(rest-linear/update-issue "issue-1" {:title "New title"})]]
|
||||||
|
(is (= abstract-keys (set (keys request)))
|
||||||
|
(str "request carries only abstract fields: " request))))
|
||||||
Loading…
Reference in New Issue